Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Account.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Account.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Account.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1390 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Account.c
+// アカウントマネージャ
+
+#include "CedarPch.h"
+
+// ポリシー項目
+POLICY_ITEM policy_item[] =
+{
+//  番号,   数値,   省略可能, 最小, 最大, デフォルト, 単位文字列
+// Ver 2.0
+	{0,		false,	false,	0,	0,	0,		NULL},			// Access
+	{1,		false,	false,	0,	0,	0,		NULL},			// DHCPFilter
+	{2,		false,	false,	0,	0,	0,		NULL},			// DHCPNoServer
+	{3,		false,	false,	0,	0,	0,		NULL},			// DHCPForce
+	{4,		false,	false,	0,	0,	0,		NULL},			// NoBridge
+	{5,		false,	false,	0,	0,	0,		NULL},			// NoRouting
+	{6,		false,	false,	0,	0,	0,		NULL},			// CheckMac
+	{7,		false,	false,	0,	0,	0,		NULL},			// CheckIP
+	{8,		false,	false,	0,	0,	0,		NULL},			// ArpDhcpOnly
+	{9,		false,	false,	0,	0,	0,		NULL},			// PrivacyFilter
+	{10,	false,	false,	0,	0,	0,		NULL},			// NoServer
+	{11,	false,	false,	0,	0,	0,		NULL},			// NoBroadcastLimiter
+	{12,	false,	false,	0,	0,	0,		NULL},			// MonitorPort
+	{13,	true,	false,	1,	32,	32,		"POL_INT_COUNT"},	// MaxConnection
+	{14,	true,	false,	5,	60,	20,		"POL_INT_SEC"},	// TimeOut
+	{15,	true,	true,	1,	65535,	0,	"POL_INT_COUNT"},	// MaxMac
+	{16,	true,	true,	1,	65535,	0,	"POL_INT_COUNT"},	// MaxIP
+	{17,	true,	true,	1,	4294967295UL,	0,	"POL_INT_BPS"},	// MaxUpload
+	{18,	true,	true,	1,	4294967295UL,	0,	"POL_INT_BPS"},	// MaxDownload
+	{19,	false,	false,	0,	0,	0,		NULL},			// FixPassword
+	{20,	true,	true,	1,	65535,	0,	"POL_INT_COUNT"},	// MultiLogins
+	{21,	false,	false,	0,	0,	0,		NULL},			// NoQoS
+// Ver 3.0
+	{22,	false,	false,	0,	0,	0,		NULL},			// RSandRAFilter
+	{23,	false,	false,	0,	0,	0,		NULL},			// RAFilter
+	{24,	false,	false,	0,	0,	0,		NULL},			// DHCPv6Filter
+	{25,	false,	false,	0,	0,	0,		NULL},			// DHCPv6NoServer
+	{26,	false,	false,	0,	0,	0,		NULL},			// NoRoutingV6
+	{27,	false,	false,	0,	0,	0,		NULL},			// CheckIPv6
+	{28,	false,	false,	0,	0,	0,		NULL},			// NoServerV6
+	{29,	true,	true,	1,	65535,	0,	"POL_INT_COUNT"},	// MaxIPv6
+	{30,	false,	false,	0,	0,	0,		NULL},			// NoSavePassword
+	{31,	true,	true,	1,	4294967295UL,	0,	"POL_INT_SEC"},	// AutoDisconnect
+	{32,	false,	false,	0,	0,	0,		NULL},			// FilterIPv4
+	{33,	false,	false,	0,	0,	0,		NULL},			// FilterIPv6
+	{34,	false,	false,	0,	0,	0,		NULL},			// FilterNonIP
+	{35,	false,	false,	0,	0,	0,		NULL},			// NoIPv6DefaultRouterInRA
+	{36,	false,	false,	0,	0,	0,		NULL},			// NoIPv6DefaultRouterInRAWhenIPv6
+	{37,	true,	true,	1,	4095,	0,	"POL_INT_VLAN"},	// VLanId
+};
+
+// ポリシー名を正規化する
+char *NormalizePolicyName(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	return PolicyIdToStr(PolicyStrToId(name));
+}
+
+// ポリシーの値をフォーマット
+void FormatPolicyValue(wchar_t *str, UINT size, UINT id, UINT value)
+{
+	POLICY_ITEM *p;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	p = GetPolicyItem(id);
+
+	if (p->TypeInt == false)
+	{
+		// bool 型
+		if (value == 0)
+		{
+			UniStrCpy(str, size, L"No");
+		}
+		else
+		{
+			UniStrCpy(str, size, L"Yes");
+		}
+	}
+	else
+	{
+		// int 型
+		if (value == 0 && p->AllowZero)
+		{
+			UniStrCpy(str, size, _UU("CMD_NO_SETTINGS"));
+		}
+		else
+		{
+			UniFormat(str, size, _UU(p->FormatStr), value);
+		}
+	}
+}
+
+// ポリシーとして設定可能な値の範囲を説明する文字列を取得
+void GetPolicyValueRangeStr(wchar_t *str, UINT size, UINT id)
+{
+	POLICY_ITEM *p;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	p = GetPolicyItem(id);
+
+	if (p->TypeInt == false)
+	{
+		// bool 型
+		UniStrCpy(str, size, _UU("CMD_PolicyList_Range_Bool"));
+	}
+	else
+	{
+		wchar_t *tag;
+		wchar_t tmp1[256], tmp2[256];
+
+		// int 型
+		if (p->AllowZero)
+		{
+			tag = _UU("CMD_PolicyList_Range_Int_2");
+		}
+		else
+		{
+			tag = _UU("CMD_PolicyList_Range_Int_1");
+		}
+
+		UniFormat(tmp1, sizeof(tmp1), _UU(p->FormatStr), p->MinValue);
+		UniFormat(tmp2, sizeof(tmp2), _UU(p->FormatStr), p->MaxValue);
+
+		UniFormat(str, size, tag, tmp1, tmp2);
+	}
+}
+
+// ポリシーアイテムの取得
+POLICY_ITEM *GetPolicyItem(UINT id)
+{
+	return &policy_item[id];
+}
+
+// 指定されたポリシーがカスケード接続でサポートされているかどうか
+bool PolicyIsSupportedForCascade(UINT i)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	if (i == 0 || i == 4 || i == 5 || i == 9 || i == 12 || i == 13 ||
+		i == 14 || i == 19 || i == 20 || i == 21 || i == 26 || i == 30 || i == 31 || i == 36)
+	{
+		// これらの項目はカスケード接続でサポートされていない
+		return false;
+	}
+
+	return true;
+}
+
+// ID をポリシーの名前に変換
+char *PolicyIdToStr(UINT i)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	switch (i)
+	{
+	// Ver 2.0
+	case 0:		return "Access";
+	case 1:		return "DHCPFilter";
+	case 2:		return "DHCPNoServer";
+	case 3:		return "DHCPForce";
+	case 4:		return "NoBridge";
+	case 5:		return "NoRouting";
+	case 6:		return "CheckMac";
+	case 7:		return "CheckIP";
+	case 8:		return "ArpDhcpOnly";
+	case 9:		return "PrivacyFilter";
+	case 10:	return "NoServer";
+	case 11:	return "NoBroadcastLimiter";
+	case 12:	return "MonitorPort";
+	case 13:	return "MaxConnection";
+	case 14:	return "TimeOut";
+	case 15:	return "MaxMac";
+	case 16:	return "MaxIP";
+	case 17:	return "MaxUpload";
+	case 18:	return "MaxDownload";
+	case 19:	return "FixPassword";
+	case 20:	return "MultiLogins";
+	case 21:	return "NoQoS";
+
+	// Ver 3.0
+	case 22:	return "RSandRAFilter";
+	case 23:	return "RAFilter";
+	case 24:	return "DHCPv6Filter";
+	case 25:	return "DHCPv6NoServer";
+	case 26:	return "NoRoutingV6";
+	case 27:	return "CheckIPv6";
+	case 28:	return "NoServerV6";
+	case 29:	return "MaxIPv6";
+	case 30:	return "NoSavePassword";
+	case 31:	return "AutoDisconnect";
+	case 32:	return "FilterIPv4";
+	case 33:	return "FilterIPv6";
+	case 34:	return "FilterNonIP";
+	case 35:	return "NoIPv6DefaultRouterInRA";
+	case 36:	return "NoIPv6DefaultRouterInRAWhenIPv6";
+	case 37:	return "VLanId";
+	}
+
+	return NULL;
+}
+
+// ポリシーの名前を ID に変換
+UINT PolicyStrToId(char *name)
+{
+	UINT i;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return INFINITE;
+	}
+
+	for (i = 0;i < NUM_POLICY_ITEM;i++)
+	{
+		if (StartWith(PolicyIdToStr(i), name))
+		{
+			return i;
+		}
+	}
+
+	return INFINITE;
+}
+
+// ポリシーの総数を取得
+UINT PolicyNum()
+{
+	return NUM_POLICY_ITEM;
+}
+
+// 指定した名前をアカウント名として使用できるかどうか確認する
+bool IsUserName(char *name)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(tmp, sizeof(tmp), name);
+	name = tmp;
+
+	Trim(name);
+
+	if (StrLen(name) == 0)
+	{
+		return false;
+	}
+
+	if (StrCmpi(name, "*") == 0)
+	{
+		return true;
+	}
+
+	if (IsSafeStr(name) == false)
+	{
+		return false;
+	}
+
+	if (StrCmpi(name, LINK_USER_NAME) == 0)
+	{
+		return false;
+	}
+
+	if (StartWith(name, L3_USERNAME))
+	{
+		return false;
+	}
+
+	if (StrCmpi(name, LINK_USER_NAME_PRINT) == 0)
+	{
+		return false;
+	}
+
+	if (StrCmpi(name, SNAT_USER_NAME) == 0)
+	{
+		return false;
+	}
+
+	if (StrCmpi(name, SNAT_USER_NAME_PRINT) == 0)
+	{
+		return false;
+	}
+
+	if (StrCmpi(name, BRIDGE_USER_NAME) == 0)
+	{
+		return false;
+	}
+
+	if (StrCmpi(name, BRIDGE_USER_NAME_PRINT) == 0)
+	{
+		return false;
+	}
+
+	if (StrCmpi(name, ADMINISTRATOR_USERNAME) == 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ポリシーのタイトルを取得する
+wchar_t *GetPolicyTitle(UINT id)
+{
+	char tmp[MAX_SIZE];
+	Format(tmp, sizeof(tmp), "POL_%u", id);
+
+	return _UU(tmp);
+}
+
+// ポリシーの説明を取得する
+wchar_t *GetPolicyDescription(UINT id)
+{
+	char tmp[MAX_SIZE];
+	Format(tmp, sizeof(tmp), "POL_EX_%u", id);
+
+	return _UU(tmp);
+}
+
+// ポリシーデータのクローン
+POLICY *ClonePolicy(POLICY *policy)
+{
+	POLICY *ret;
+	// 引数チェック
+	if (policy == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(POLICY));
+	Copy(ret, policy, sizeof(POLICY));
+
+	return ret;
+}
+
+// ポリシーを上書きする (古いバージョンを上書きする場合は新しいバージョンのデータは残す)
+void OverwritePolicy(POLICY **target, POLICY *p)
+{
+	// 引数チェック
+	if (target == NULL)
+	{
+		return;
+	}
+
+	if (p == NULL)
+	{
+		// ポリシー消去
+		if (*target != NULL)
+		{
+			Free(*target);
+			*target = NULL;
+		}
+	}
+	else
+	{
+		if (p->Ver3)
+		{
+			// Ver 3
+			if (*target != NULL)
+			{
+				Free(*target);
+				*target = NULL;
+			}
+
+			*target = ClonePolicy(p);
+		}
+		else
+		{
+			// Ver 2
+			if (*target == NULL)
+			{
+				*target = ClonePolicy(p);
+			}
+			else
+			{
+				Copy(*target, p, NUM_POLICY_ITEM_FOR_VER2 * sizeof(UINT));
+			}
+		}
+	}
+}
+
+// ユーザーポリシーの設定
+void SetUserPolicy(USER *u, POLICY *policy)
+{
+	// 引数チェック
+	if (u == NULL)
+	{
+		return;
+	}
+
+	Lock(u->lock);
+	{
+		OverwritePolicy(&u->Policy, policy);
+	}
+	Unlock(u->lock);
+}
+
+// ユーザーポリシーの取得
+POLICY *GetUserPolicy(USER *u)
+{
+	POLICY *ret;
+	// 引数チェック
+	if (u == NULL)
+	{
+		return NULL;
+	}
+
+	Lock(u->lock);
+	{
+		if (u->Policy == NULL)
+		{
+			ret = NULL;
+		}
+		else
+		{
+			ret = ClonePolicy(u->Policy);
+		}
+	}
+	Unlock(u->lock);
+
+	return ret;
+}
+
+// グループポリシーの設定
+void SetGroupPolicy(USERGROUP *g, POLICY *policy)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	Lock(g->lock);
+	{
+		OverwritePolicy(&g->Policy, policy);
+	}
+	Unlock(g->lock);
+}
+
+// グループポリシーの取得
+POLICY *GetGroupPolicy(USERGROUP *g)
+{
+	POLICY *ret;
+	// 引数チェック
+	if (g == NULL)
+	{
+		return NULL;
+	}
+
+	Lock(g->lock);
+	{
+		if (g->Policy == NULL)
+		{
+			ret = NULL;
+		}
+		else
+		{
+			ret = ClonePolicy(g->Policy);
+		}
+	}
+	Unlock(g->lock);
+
+	return ret;
+}
+
+// デフォルトのポリシーを返す
+POLICY *GetDefaultPolicy()
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	static POLICY def_policy =
+	{
+		true,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		32,
+		20,
+		0,
+		0,
+		0,
+		0,
+		false,
+		0,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		false,
+		0,
+		false,
+		0,
+		false,
+		false,
+		false,
+		false,
+		false,
+	};
+
+	return &def_policy;
+}
+
+// NT 認証データの作成
+void *NewNTAuthData(wchar_t *username)
+{
+	AUTHNT *a;
+	// 引数チェック
+	a = ZeroMallocEx(sizeof(AUTHNT), true);
+	a->NtUsername = CopyUniStr(username);
+
+	return a;
+}
+
+// Radius 認証データの作成
+void *NewRadiusAuthData(wchar_t *username)
+{
+	AUTHRADIUS *a;
+	// 引数チェック
+	a = ZeroMallocEx(sizeof(AUTHRADIUS), true);
+	a->RadiusUsername = CopyUniStr(username);
+
+	return a;
+}
+
+// ルート証明書による認証データの作成
+void *NewRootCertAuthData(X_SERIAL *serial, wchar_t *common_name)
+{
+	AUTHROOTCERT *a;
+
+	a = ZeroMallocEx(sizeof(AUTHROOTCERT), true);
+	if (common_name != NULL && UniIsEmptyStr(common_name) == false)
+	{
+		a->CommonName = CopyUniStr(common_name);
+	}
+	if (serial != NULL && serial->size >= 1)
+	{
+		a->Serial = CloneXSerial(serial);
+	}
+
+	return a;
+}
+
+// ユーザー証明書認証データの作成
+void *NewUserCertAuthData(X *x)
+{
+	AUTHUSERCERT *a;
+
+	a = ZeroMalloc(sizeof(AUTHUSERCERT));
+	a->UserX = CloneX(x);
+
+	return a;
+}
+
+// パスワードのハッシュ
+void HashPassword(void *dst, char *username, char *password)
+{
+	BUF *b;
+	char *username_upper;
+	// 引数チェック
+	if (dst == NULL || username == NULL || password == NULL)
+	{
+		return;
+	}
+
+	b = NewBuf();
+	username_upper = CopyStr(username);
+	StrUpper(username_upper);
+	WriteBuf(b, password, StrLen(password));
+	WriteBuf(b, username_upper, StrLen(username_upper));
+	Hash(dst, b->Buf, b->Size, true);
+
+	FreeBuf(b);
+	Free(username_upper);
+}
+
+// パスワード認証データの作成
+void *NewPasswordAuthData(char *username, char *password)
+{
+	AUTHPASSWORD *pw;
+	// 引数チェック
+	if (username == NULL || password == NULL)
+	{
+		return NULL;
+	}
+
+	pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+	HashPassword(pw->HashedKey, username, password);
+
+	return pw;
+}
+void *NewPasswordAuthDataRaw(UCHAR *hashed_password)
+{
+	AUTHPASSWORD *pw;
+	// 引数チェック
+	if (hashed_password == NULL)
+	{
+		return NULL;
+	}
+
+	pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+	Copy(pw->HashedKey, hashed_password, SHA1_SIZE);
+
+	return pw;
+}
+
+// ユーザーの認証データのコピー
+void *CopyAuthData(void *authdata, UINT authtype)
+{
+	AUTHPASSWORD *pw = (AUTHPASSWORD *)authdata;
+	AUTHUSERCERT *usercert = (AUTHUSERCERT *)authdata;
+	AUTHROOTCERT *rootcert = (AUTHROOTCERT *)authdata;
+	AUTHRADIUS *radius = (AUTHRADIUS *)authdata;
+	AUTHNT *nt = (AUTHNT *)authdata;
+	// 引数チェック
+	if (authdata == NULL || authtype == AUTHTYPE_ANONYMOUS)
+	{
+		return NULL;
+	}
+
+	switch (authtype)
+	{
+	case AUTHTYPE_PASSWORD:
+		{
+			AUTHPASSWORD *ret = ZeroMalloc(sizeof(AUTHPASSWORD));
+			Copy(ret, pw, sizeof(AUTHPASSWORD));
+			return ret;
+		}
+		break;
+
+	case AUTHTYPE_USERCERT:
+		{
+			AUTHUSERCERT *ret = ZeroMalloc(sizeof(AUTHUSERCERT));
+			ret->UserX = CloneX(usercert->UserX);
+			return ret;
+		}
+		break;
+
+	case AUTHTYPE_ROOTCERT:
+		{
+			AUTHROOTCERT *ret = ZeroMalloc(sizeof(AUTHROOTCERT));
+			ret->CommonName = CopyUniStr(rootcert->CommonName);
+			ret->Serial = CloneXSerial(rootcert->Serial);
+			return ret;
+		}
+		break;
+
+	case AUTHTYPE_RADIUS:
+		{
+			AUTHRADIUS *ret = ZeroMalloc(sizeof(AUTHRADIUS));
+			ret->RadiusUsername = UniCopyStr(radius->RadiusUsername);
+			return ret;
+		}
+		break;
+
+	case AUTHTYPE_NT:
+		{
+			AUTHNT *ret = ZeroMalloc(sizeof(AUTHNT));
+			ret->NtUsername = UniCopyStr(nt->NtUsername);
+			return ret;
+		}
+		break;
+	}
+
+	return NULL;
+}
+
+// ユーザーの認証データのセット
+void SetUserAuthData(USER *u, UINT authtype, void *authdata)
+{
+	// 引数チェック
+	if (u == NULL)
+	{
+		return;
+	}
+	if (authtype != AUTHTYPE_ANONYMOUS && authdata == NULL)
+	{
+		return;
+	}
+
+	Lock(u->lock);
+	{
+		if (u->AuthType != AUTHTYPE_ANONYMOUS)
+		{
+			// 現在の認証データの解放
+			FreeAuthData(u->AuthType, u->AuthData);
+		}
+		// 新しい認証データの設定
+		u->AuthType = authtype;
+		u->AuthData = authdata;
+	}
+	Unlock(u->lock);
+}
+
+// グループのトラフィックデータを加算
+void AddGroupTraffic(USERGROUP *g, TRAFFIC *diff)
+{
+	// 引数チェック
+	if (g == NULL || diff == NULL)
+	{
+		return;
+	}
+
+	Lock(g->lock);
+	{
+		AddTraffic(g->Traffic, diff);
+	}
+	Unlock(g->lock);
+}
+
+// ユーザーのトラフィックデータを加算
+void AddUserTraffic(USER *u, TRAFFIC *diff)
+{
+	// 引数チェック
+	if (u == NULL || diff == NULL)
+	{
+		return;
+	}
+
+	Lock(u->lock);
+	{
+		AddTraffic(u->Traffic, diff);
+	}
+	Unlock(u->lock);
+}
+
+// グループのトラフィック情報をセット
+void SetGroupTraffic(USERGROUP *g, TRAFFIC *t)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	Lock(g->lock);
+	{
+		if (t != NULL)
+		{
+			Copy(g->Traffic, t, sizeof(TRAFFIC));
+		}
+		else
+		{
+			Zero(g->Traffic, sizeof(TRAFFIC));
+		}
+	}
+	Unlock(g->lock);
+}
+
+// ユーザーのトラフィック情報をセット
+void SetUserTraffic(USER *u, TRAFFIC *t)
+{
+	// 引数チェック
+	if (u == NULL)
+	{
+		return;
+	}
+
+	Lock(u->lock);
+	{
+		if (t != NULL)
+		{
+			Copy(u->Traffic, t, sizeof(TRAFFIC));
+		}
+		else
+		{
+			Zero(u->Traffic, sizeof(TRAFFIC));
+		}
+	}
+	Unlock(u->lock);
+}
+
+// ユーザーをグループに所属させる
+void JoinUserToGroup(USER *u, USERGROUP *g)
+{
+	// 引数チェック
+	if (u == NULL)
+	{
+		return;
+	}
+
+	if (g != NULL)
+	{
+		// 参加
+		Lock(u->lock);
+		{
+			Lock(g->lock);
+			{
+				if (u->Group != NULL)
+				{
+					// まずユーザーをグループから外す
+					ReleaseGroup(u->Group);
+					u->Group = NULL;
+					Free(u->GroupName);
+					u->GroupName = NULL;
+				}
+				// ユーザーをグループに追加する
+				u->GroupName = CopyStr(g->Name);
+				u->Group = g;
+				AddRef(g->ref);
+			}
+			Unlock(g->lock);
+		}
+		Unlock(u->lock);
+	}
+	else
+	{
+		// 脱退
+		Lock(u->lock);
+		{
+			if (u->Group != NULL)
+			{
+				// ユーザーをグループから外す
+				ReleaseGroup(u->Group);
+				u->Group = NULL;
+				Free(u->GroupName);
+				u->GroupName = NULL;
+			}
+		}
+		Unlock(u->lock);
+	}
+}
+
+// グループ名チェック
+bool AcIsGroup(HUB *h, char *name)
+{
+	USERGROUP *g;
+	// 引数チェック
+	if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+	{
+		return false;
+	}
+
+	g = AcGetGroup(h, name);
+	if (g == NULL)
+	{
+		return false;
+	}
+	ReleaseGroup(g);
+
+	return true;
+}
+
+// ユーザー名チェック
+bool AcIsUser(HUB *h, char *name)
+{
+	USER *u;
+	// 引数チェック
+	if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+	{
+		return false;
+	}
+
+	u = AcGetUser(h, name);
+	if (u == NULL)
+	{
+		return false;
+	}
+	ReleaseUser(u);
+
+	return true;
+}
+
+// グループの取得
+USERGROUP *AcGetGroup(HUB *h, char *name)
+{
+	USERGROUP *g, t;
+	// 引数チェック
+	if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+	{
+		return NULL;
+	}
+
+	t.Name = name;
+	g = Search(h->HubDb->GroupList, &t);
+	if (g == NULL)
+	{
+		return NULL;
+	}
+	AddRef(g->ref);
+
+	return g;
+}
+
+// ユーザーの取得
+USER *AcGetUser(HUB *h, char *name)
+{
+	USER *u, t;
+	// 引数チェック
+	if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+	{
+		return NULL;
+	}
+
+	t.Name = name;
+	u = Search(h->HubDb->UserList, &t);
+	if (u == NULL)
+	{
+		return NULL;
+	}
+	AddRef(u->ref);
+
+	return u;
+}
+
+// ユーザーの削除
+bool AcDeleteUser(HUB *h, char *name)
+{
+	USER *u;
+	// 引数チェック
+	if (h == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	u = AcGetUser(h, name);
+	if (u == NULL)
+	{
+		return false;
+	}
+
+	if (Delete(h->HubDb->UserList, u))
+	{
+		ReleaseUser(u);
+	}
+
+	ReleaseUser(u);
+
+	return true;
+}
+
+// グループの削除
+bool AcDeleteGroup(HUB *h, char *name)
+{
+	USERGROUP *g;
+	UINT i;
+	// 引数チェック
+	if (h == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	g = AcGetGroup(h, name);
+	if (g == NULL)
+	{
+		return false;
+	}
+
+	if (Delete(h->HubDb->GroupList, g))
+	{
+		ReleaseGroup(g);
+	}
+
+	for (i = 0;i < LIST_NUM(h->HubDb->UserList);i++)
+	{
+		USER *u = LIST_DATA(h->HubDb->UserList, i);
+		Lock(u->lock);
+		{
+			if (u->Group == g)
+			{
+				JoinUserToGroup(u, NULL);
+			}
+		}
+		Unlock(u->lock);
+	}
+
+	ReleaseGroup(g);
+
+	return true;
+}
+
+// グループの追加
+bool AcAddGroup(HUB *h, USERGROUP *g)
+{
+	// 引数チェック
+	if (h == NULL || g == NULL || NO_ACCOUNT_DB(h))
+	{
+		return false;
+	}
+
+	if (LIST_NUM(h->HubDb->GroupList) >= MAX_GROUPS)
+	{
+		return false;
+	}
+
+	if (AcIsGroup(h, g->Name) != false)
+	{
+		return false;
+	}
+
+	Insert(h->HubDb->GroupList, g);
+	AddRef(g->ref);
+
+	return true;
+}
+
+// ユーザーの追加
+bool AcAddUser(HUB *h, USER *u)
+{
+	// 引数チェック
+	if (h == NULL || u == NULL || NO_ACCOUNT_DB(h))
+	{
+		return false;
+	}
+
+	if (LIST_NUM(h->HubDb->UserList) >= MAX_USERS)
+	{
+		return false;
+	}
+
+	if (AcIsUser(h, u->Name) != false)
+	{
+		return false;
+	}
+
+	Insert(h->HubDb->UserList, u);
+	AddRef(u->ref);
+
+	return true;
+}
+
+// ユーザーの解放
+void ReleaseUser(USER *u)
+{
+	// 引数チェック
+	if (u == NULL)
+	{
+		return;
+	}
+
+	if (Release(u->ref) == 0)
+	{
+		CleanupUser(u);
+	}
+}
+
+// ユーザーのクリーンアップ
+void CleanupUser(USER *u)
+{
+	// 引数チェック
+	if (u == NULL)
+	{
+		return;
+	}
+
+	DeleteLock(u->lock);
+	Free(u->Name);
+	Free(u->RealName);
+	Free(u->Note);
+	Free(u->GroupName);
+	if (u->Group != NULL)
+	{
+		ReleaseGroup(u->Group);
+	}
+
+	// 認証データの解放
+	FreeAuthData(u->AuthType, u->AuthData);
+
+	if (u->Policy)
+	{
+		// ポリシー解放
+		Free(u->Policy);
+	}
+
+	FreeTraffic(u->Traffic);
+
+	Free(u);
+}
+
+// 認証データの解放
+void FreeAuthData(UINT authtype, void *authdata)
+{
+	AUTHPASSWORD *pw = (AUTHPASSWORD *)authdata;
+	AUTHUSERCERT *uc = (AUTHUSERCERT *)authdata;
+	AUTHROOTCERT *rc = (AUTHROOTCERT *)authdata;
+	AUTHRADIUS *rd = (AUTHRADIUS *)authdata;
+	AUTHNT *nt = (AUTHNT *)authdata;
+	// 引数チェック
+	if (authtype == AUTHTYPE_ANONYMOUS || authdata == NULL)
+	{
+		return;
+	}
+
+	switch (authtype)
+	{
+	case AUTHTYPE_PASSWORD:
+		// パスワード認証
+		// 何も解放しない
+		break;
+
+	case AUTHTYPE_USERCERT:
+		// ユーザー証明書
+		FreeX(uc->UserX);
+		break;
+
+	case AUTHTYPE_ROOTCERT:
+		// ルート証明書
+		if (rc->Serial != NULL)
+		{
+			FreeXSerial(rc->Serial);
+		}
+		if (rc->CommonName != NULL)
+		{
+			Free(rc->CommonName);
+		}
+		break;
+
+	case AUTHTYPE_RADIUS:
+		// Radius 認証
+		Free(rd->RadiusUsername);
+		break;
+
+	case AUTHTYPE_NT:
+		// Windows NT 認証
+		Free(nt->NtUsername);
+		break;
+	}
+
+	Free(authdata);
+}
+
+// ユーザーの作成
+USER *NewUser(char *name, wchar_t *realname, wchar_t *note, UINT authtype, void *authdata)
+{
+	USER *u;
+	// 引数チェック
+	if (name == NULL || realname == NULL || note == NULL)
+	{
+		return NULL;
+	}
+	if (authtype != AUTHTYPE_ANONYMOUS && authdata == NULL)
+	{
+		return NULL;
+	}
+
+	u = ZeroMalloc(sizeof(USER));
+	u->lock = NewLock();
+	u->ref = NewRef();
+	u->Name = CopyStr(name);
+	u->RealName = CopyUniStr(realname);
+	u->Note = CopyUniStr(note);
+	u->GroupName = NULL;
+	u->Group = NULL;
+	u->AuthType = authtype;
+	u->AuthData = authdata;
+	u->CreatedTime = SystemTime64();
+	u->UpdatedTime = SystemTime64();
+
+	u->Policy = NULL;
+	u->Traffic = NewTraffic();
+
+	return u;
+}
+
+// グループの解放
+void ReleaseGroup(USERGROUP *g)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	if (Release(g->ref) == 0)
+	{
+		CleanupGroup(g);
+	}
+}
+
+// グループのクリーンアップ
+void CleanupGroup(USERGROUP *g)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	Free(g->Name);
+	Free(g->RealName);
+	Free(g->Note);
+
+	if (g->Policy)
+	{
+		// ポリシー解放
+		Free(g->Policy);
+	}
+
+
+	FreeTraffic(g->Traffic);
+
+	DeleteLock(g->lock);
+	Free(g);
+}
+
+// 新しいグループを作成
+USERGROUP *NewGroup(char *name, wchar_t *realname, wchar_t *note)
+{
+	USERGROUP *g;
+	// 引数チェック
+	if (name == NULL || realname == NULL || note == NULL)
+	{
+		return NULL;
+	}
+
+	g = ZeroMalloc(sizeof(USERGROUP));
+	g->lock = NewLock();
+	g->ref = NewRef();
+	g->Name = CopyStr(name);
+	g->RealName = CopyUniStr(realname);
+	g->Note = CopyUniStr(note);
+	g->Policy = NULL;
+	g->Traffic = NewTraffic();
+
+	return g;
+}
+
+// HUB のアカウントデータベースのロック
+void AcLock(HUB *h)
+{
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+	if (NO_ACCOUNT_DB(h))
+	{
+		return;
+	}
+
+	// グループとユーザーをロック
+	LockList(h->HubDb->GroupList);
+	LockList(h->HubDb->UserList);
+}
+
+// HUB のアカウントデータベースのロック解除
+void AcUnlock(HUB *h)
+{
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+	if (NO_ACCOUNT_DB(h))
+	{
+		return;
+	}
+
+	// グループとユーザーをロック解除
+	UnlockList(h->HubDb->UserList);
+	UnlockList(h->HubDb->GroupList);
+}
+
+// グループ名比較関数
+int CompareGroupName(void *p1, void *p2)
+{
+	USERGROUP *g1, *g2;
+	// 引数チェック
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	g1 = *(USERGROUP **)p1;
+	g2 = *(USERGROUP **)p2;
+	if (g1 == NULL || g2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(g1->Name, g2->Name);
+}
+
+// ユーザー名比較関数
+int CompareUserName(void *p1, void *p2)
+{
+	USER *u1, *u2;
+	// 引数チェック
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	u1 = *(USER **)p1;
+	u2 = *(USER **)p2;
+	if (u1 == NULL || u2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(u1->Name, u2->Name);
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Account.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Account.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Account.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,285 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Account.h
+// Account.c のヘッダ
+
+#ifndef	ACCOUNT_H
+#define	ACCOUNT_H
+
+// ポリシー項目
+struct POLICY_ITEM
+{
+	UINT Index;
+	bool TypeInt;
+	bool AllowZero;
+	UINT MinValue;
+	UINT MaxValue;
+	UINT DefaultValue;
+	char *FormatStr;
+};
+
+// ポリシー
+struct POLICY
+{
+	// ポリシー Ver 2.0
+	bool Access;					// アクセスを許可
+	bool DHCPFilter;				// DHCP パケットをフィルタリング (IPv4)
+	bool DHCPNoServer;				// DHCP サーバーの動作を禁止 (IPv4)
+	bool DHCPForce;					// DHCP が割り当てた IP アドレスを強制 (IPv4)
+	bool NoBridge;					// ブリッジを禁止
+	bool NoRouting;					// ルータ動作を禁止 (IPv4)
+	bool CheckMac;					// MAC アドレスの重複を禁止
+	bool CheckIP;					// IP アドレスの重複を禁止 (IPv4)
+	bool ArpDhcpOnly;				// ARP・DHCP・ICMPv6 以外のブロードキャストを禁止
+	bool PrivacyFilter;				// プライバシーフィルタモード
+	bool NoServer;					// TCP/IP サーバーとしての動作を禁止 (IPv4)
+	bool NoBroadcastLimiter;		// ブロードキャスト数を制限しない
+	bool MonitorPort;				// モニタリングモードを許可
+	UINT MaxConnection;				// TCP コネクション数の最大値
+	UINT TimeOut;					// 通信タイムアウト時間
+	UINT MaxMac;					// MAC アドレスの上限数
+	UINT MaxIP;						// IP アドレスの上限数 (IPv4)
+	UINT MaxUpload;					// アップロード帯域幅
+	UINT MaxDownload;				// ダウンロード帯域幅
+	bool FixPassword;				// ユーザーはパスワードを変更できない
+	UINT MultiLogins;				// 多重ログイン制限数
+	bool NoQoS;						// VoIP / QoS 対応機能の使用を禁止
+
+	// ポリシー Ver 3.0
+	bool RSandRAFilter;				// ルータ要請/広告パケットをフィルタリング (IPv6)
+	bool RAFilter;					// ルータ広告パケットをフィルタリング (IPv6)
+	bool DHCPv6Filter;				// DHCP パケットをフィルタリング (IPv6)
+	bool DHCPv6NoServer;			// DHCP サーバーの動作を禁止 (IPv6)
+	bool NoRoutingV6;				// ルータ動作を禁止 (IPv6)
+	bool CheckIPv6;					// IP アドレスの重複を禁止 (IPv6)
+	bool NoServerV6;				// TCP/IP サーバーとしての動作を禁止 (IPv6)
+	UINT MaxIPv6;					// IP アドレスの上限数 (IPv6)
+	bool NoSavePassword;			// VPN Client でパスワードの保存を禁止
+	UINT AutoDisconnect;			// VPN Client を一定時間で自動切断
+	bool FilterIPv4;				// IPv4 パケットをすべてフィルタリング
+	bool FilterIPv6;				// IPv6 パケットをすべてフィルタリング
+	bool FilterNonIP;				// 非 IP パケットをすべてフィルタリング
+	bool NoIPv6DefaultRouterInRA;	// IPv6 ルータ広告からデフォルトルータ指定を削除
+	bool NoIPv6DefaultRouterInRAWhenIPv6;	// IPv6 ルータ広告からデフォルトルータ指定を削除 (IPv6 接続時有効化)
+	UINT VLanId;					// VLAN ID を指定
+
+	bool Ver3;						// ポリシーのバージョンが 3.0 以降かどうか
+};
+
+// グループ
+struct USERGROUP
+{
+	LOCK *lock;						// ロック
+	REF *ref;						// 参照カウンタ
+	char *Name;						// グループ名
+	wchar_t *RealName;				// 表示名
+	wchar_t *Note;					// メモ
+	POLICY *Policy;					// ポリシー
+	TRAFFIC *Traffic;				// トラフィックデータ
+};
+
+// ユーザー
+struct USER
+{
+	LOCK *lock;						// ロック
+	REF *ref;						// 参照カウンタ
+	char *Name;						// ユーザー名
+	wchar_t *RealName;				// 本名
+	wchar_t *Note;					// メモ
+	char *GroupName;				// グループ名
+	USERGROUP *Group;				// グループ
+	UINT AuthType;					// 認証の種類
+	void *AuthData;					// 認証データ
+	UINT64 CreatedTime;				// 作成日時
+	UINT64 UpdatedTime;				// 更新日時
+	UINT64 ExpireTime;				// 有効期限
+	UINT64 LastLoginTime;			// 最終ログイン時刻
+	UINT NumLogin;					// ログイン回数の合計
+	POLICY *Policy;					// ポリシー
+	TRAFFIC *Traffic;				// トラフィックデータ
+};
+
+// パスワード認証データ
+struct AUTHPASSWORD
+{
+	UCHAR HashedKey[SHA1_SIZE];		// ハッシュされたパスワード
+};
+
+// ユーザー証明書認証データ
+struct AUTHUSERCERT
+{
+	X *UserX;						// ユーザーの X509 証明書
+};
+
+// ルート証明機関認証データ
+struct AUTHROOTCERT
+{
+	X_SERIAL *Serial;				// シリアル番号
+	wchar_t *CommonName;			// CommonName
+};
+
+// Radius 認証データ
+struct AUTHRADIUS
+{
+	wchar_t *RadiusUsername;		// Radius 上でのユーザー名
+};
+
+// Windows NT 認証データ
+struct AUTHNT
+{
+	wchar_t *NtUsername;			// NT 上でのユーザー名
+};
+
+
+
+// マクロ
+#define	POLICY_CURRENT_VERSION		3
+#define	NUM_POLICY_ITEM		((sizeof(POLICY) / sizeof(UINT)) - 1)
+#define	NUM_POLICY_ITEM_FOR_VER2	22
+#define	NUM_POLICY_ITEM_FOR_VER3	38
+
+#define	IS_POLICY_FOR_VER2(index)	(((index) >= 0) && ((index) < NUM_POLICY_ITEM_FOR_VER2))
+#define	IS_POLICY_FOR_VER3(index)	(((index) >= 0) && ((index) < NUM_POLICY_ITEM_FOR_VER3))
+
+#define	IS_POLICY_FOR_CURRENT_VER(index, ver)	((ver) >= 3 ? IS_POLICY_FOR_VER3(index) : IS_POLICY_FOR_VER2(index))
+
+#define	POLICY_BOOL(p, i)	(((bool *)(p))[(i)])
+#define	POLICY_INT(p, i)	(((UINT *)(p))[(i)])
+
+extern POLICY_ITEM policy_item[];
+
+
+
+
+// 関数プロトタイプ
+int CompareUserName(void *p1, void *p2);
+int CompareGroupName(void *p1, void *p2);
+void AcLock(HUB *h);
+void AcUnlock(HUB *h);
+USERGROUP *NewGroup(char *name, wchar_t *realname, wchar_t *note);
+void ReleaseGroup(USERGROUP *g);
+void CleanupGroup(USERGROUP *g);
+USER *NewUser(char *name, wchar_t *realname, wchar_t *note, UINT authtype, void *authdata);
+void ReleaseUser(USER *u);
+void CleanupUser(USER *u);
+void FreeAuthData(UINT authtype, void *authdata);
+bool AcAddUser(HUB *h, USER *u);
+bool AcAddGroup(HUB *h, USERGROUP *g);
+USER *AcGetUser(HUB *h, char *name);
+USERGROUP *AcGetGroup(HUB *h, char *name);
+bool AcIsUser(HUB *h, char *name);
+bool AcIsGroup(HUB *h, char *name);
+bool AcDeleteUser(HUB *h, char *name);
+bool AcDeleteGroup(HUB *h, char *name);
+void JoinUserToGroup(USER *u, USERGROUP *g);
+void SetUserTraffic(USER *u, TRAFFIC *t);
+void SetGroupTraffic(USERGROUP *g, TRAFFIC *t);
+void AddUserTraffic(USER *u, TRAFFIC *diff);
+void AddGroupTraffic(USERGROUP *g, TRAFFIC *diff);
+void SetUserAuthData(USER *u, UINT authtype, void *authdata);
+void *NewPasswordAuthData(char *username, char *password);
+void *NewPasswordAuthDataRaw(UCHAR *hashed_password);
+void *NewUserCertAuthData(X *x);
+void *NewRootCertAuthData(X_SERIAL *serial, wchar_t *common_name);
+void *NewRadiusAuthData(wchar_t *username);
+void *NewNTAuthData(wchar_t *username);
+void HashPassword(void *dst, char *username, char *password);
+POLICY *GetDefaultPolicy();
+POLICY *ClonePolicy(POLICY *policy);
+void SetUserPolicy(USER *u, POLICY *policy);
+void OverwritePolicy(POLICY **target, POLICY *p);
+POLICY *GetUserPolicy(USER *u);
+void SetGroupPolicy(USERGROUP *g, POLICY *policy);
+POLICY *GetGroupPolicy(USERGROUP *g);
+wchar_t *GetPolicyTitle(UINT id);
+wchar_t *GetPolicyDescription(UINT id);
+bool IsUserName(char *name);
+void *CopyAuthData(void *authdata, UINT authtype);
+UINT PolicyNum();
+bool PolicyIsSupportedForCascade(UINT i);
+UINT PolicyStrToId(char *name);
+char *PolicyIdToStr(UINT i);
+POLICY_ITEM *GetPolicyItem(UINT id);
+void GetPolicyValueRangeStr(wchar_t *str, UINT size, UINT id);
+void FormatPolicyValue(wchar_t *str, UINT size, UINT id, UINT value);
+char *NormalizePolicyName(char *name);
+
+
+#endif	// ACCOUNT_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Admin.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Admin.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Admin.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,12320 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Admin.c
+// 管理用 RPC モジュール
+
+#include "CedarPch.h"
+
+// RPC 関数関係マクロ
+// このあたりは急いで実装したのでコードがあまり美しくない。
+// 本当は Sun RPC のプリプロセッサのようにきれいな処理方法を採用したがったが
+// とりあえず今はマクロの羅列になっている。
+#define	DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc)		\
+	else if (StrCmpi(name, rpc_name) == 0)								\
+	{																	\
+		data_type *t;													\
+		t = ZeroMalloc(sizeof(data_type));								\
+		in_rpc(t, p);													\
+		err = function(a, t);											\
+		if (err == ERR_NO_ERROR)										\
+		{																\
+			out_rpc(ret, t);											\
+		}																\
+		free_rpc(t);													\
+		Free(t);														\
+		ok = true;														\
+	}
+#define	DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc)		\
+	else if (StrCmpi(name, rpc_name) == 0)								\
+	{																	\
+		data_type *t;													\
+		t = ZeroMalloc(sizeof(data_type));								\
+		in_rpc(t, p);													\
+		err = function(a, t);											\
+		if (err == ERR_NO_ERROR)										\
+		{																\
+			out_rpc(ret, t);											\
+		}																\
+		Free(t);														\
+		ok = true;														\
+	}
+#define	DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc)	\
+	UINT function(RPC *r, data_type *t)									\
+	{																	\
+		PACK *p, *ret;													\
+		UINT err;														\
+		if (r == NULL || t == NULL)										\
+		{																\
+			return ERR_INTERNAL_ERROR;									\
+		}																\
+		p = NewPack();													\
+		out_rpc(p, t);													\
+		free_rpc(t);													\
+		Zero(t, sizeof(data_type));										\
+		ret = AdminCall(r, rpc_name, p);								\
+		err = GetErrorFromPack(ret);									\
+		if (err == ERR_NO_ERROR)										\
+		{																\
+			in_rpc(t, ret);												\
+		}																\
+		FreePack(ret);													\
+		return err;														\
+	}
+#define	DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc)		\
+	UINT function(RPC *r, data_type *t)									\
+	{																	\
+		PACK *p, *ret;													\
+		UINT err;														\
+		if (r == NULL || t == NULL)										\
+		{																\
+			return ERR_INTERNAL_ERROR;									\
+		}																\
+		p = NewPack();													\
+		out_rpc(p, t);													\
+		ret = AdminCall(r, rpc_name, p);								\
+		err = GetErrorFromPack(ret);									\
+		if (err == ERR_NO_ERROR)										\
+		{																\
+			in_rpc(t, ret);												\
+		}																\
+		FreePack(ret);													\
+		return err;														\
+	}
+#define	CHECK_RIGHT														\
+	if (a->ServerAdmin == false && (t->HubName == NULL || StrCmpi(a->HubName, t->HubName) != 0))	\
+		return ERR_NOT_ENOUGH_RIGHT;	\
+	if (IsEmptyStr(t->HubName))			\
+		return ERR_INVALID_PARAMETER;
+#define	SERVER_ADMIN_ONLY												\
+	if (a->ServerAdmin == false)										\
+		return ERR_NOT_ENOUGH_RIGHT;
+#define	NO_SUPPORT_FOR_BRIDGE											\
+	if (a->Server->Cedar->Bridge)										\
+		return ERR_NOT_SUPPORTED;
+
+// サーバーの Caps を取得 (取得できない場合はビルド番号から判別)
+CAPSLIST *ScGetCapsEx(RPC *rpc)
+{
+	RPC_SERVER_INFO info;
+	CAPSLIST *t;
+	bool is_bridge = false;
+	// 引数チェック
+	if (rpc == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&info, sizeof(info));
+	ScGetServerInfo(rpc, &info);
+
+	t = ZeroMalloc(sizeof(CAPSLIST));
+
+	// RPC で Caps を取得してみる
+	if (ScGetCaps(rpc, t) != ERR_NO_ERROR)
+	{
+		UINT build;
+
+		Free(t);
+		t = NewCapsList();
+
+		// 取得に失敗したのでビルド番号を取得する
+		// (ものすごく古いバージョンの VPN Server のための対応コード)
+		build = info.ServerBuildInt;
+
+		is_bridge = (SearchStrEx(info.ServerProductName, "bridge", 0, false) == INFINITE) ? false : true;
+
+		AddCapsInt(t, "i_max_packet_size", 1514);
+
+		if (is_bridge == false)
+		{
+			AddCapsInt(t, "i_max_hubs", 4096);
+			AddCapsInt(t, "i_max_sessions", 4096);
+
+			if (info.ServerType != SERVER_TYPE_FARM_MEMBER)
+			{
+				AddCapsInt(t, "i_max_users_per_hub", 10000);
+				AddCapsInt(t, "i_max_groups_per_hub", 10000);
+				AddCapsInt(t, "i_max_access_lists", 4096);
+			}
+			else
+			{
+				AddCapsInt(t, "i_max_users_per_hub", 0);
+				AddCapsInt(t, "i_max_groups_per_hub", 0);
+				AddCapsInt(t, "i_max_access_lists", 0);
+			}
+		}
+		else
+		{
+			AddCapsInt(t, "i_max_hubs", 0);
+			AddCapsInt(t, "i_max_sessions", 0);
+			AddCapsInt(t, "i_max_users_per_hub", 0);
+			AddCapsInt(t, "i_max_groups_per_hub", 0);
+			AddCapsInt(t, "i_max_access_lists", 0);
+		}
+
+		AddCapsInt(t, "i_max_mac_tables", 10000);
+		AddCapsInt(t, "i_max_ip_tables", 10000);
+
+		if (info.ServerType == SERVER_TYPE_STANDALONE)
+		{
+			AddCapsBool(t, "b_support_securenat", (build >= 3600) ? true : false);
+			AddCapsInt(t, "i_max_secnat_tables", 4096);
+		}
+		else
+		{
+			AddCapsBool(t, "b_support_securenat", false);
+			AddCapsInt(t, "i_max_secnat_tables", 0);
+		}
+
+		if (is_bridge)
+		{
+			AddCapsBool(t, "b_bridge", true);
+		}
+		else if (info.ServerType == SERVER_TYPE_STANDALONE)
+		{
+			AddCapsBool(t, "b_standalone", true);
+		}
+		else if (info.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			AddCapsBool(t, "b_cluster_controller", true);
+		}
+		else
+		{
+			AddCapsBool(t, "b_cluster_member", true);
+		}
+
+		AddCapsBool(t, "b_support_config_hub", info.ServerType != SERVER_TYPE_FARM_MEMBER &&
+			is_bridge == false);
+
+		AddCapsBool(t, "b_vpn_client_connect", is_bridge == false ? true : false);
+
+		AddCapsBool(t, "b_support_radius", info.ServerType != SERVER_TYPE_FARM_MEMBER &&
+			is_bridge == false);
+
+		if (build >= 3600)
+		{
+			RPC_BRIDGE_SUPPORT b;
+			Zero(&b, sizeof(b));
+			if (ScGetBridgeSupport(rpc, &b) == ERR_NO_ERROR)
+			{
+				AddCapsBool(t, "b_local_bridge", b.IsBridgeSupportedOs);
+				AddCapsBool(t, "b_must_install_pcap", b.IsWinPcapNeeded);
+			}
+			else
+			{
+				AddCapsBool(t, "b_local_bridge", false);
+				AddCapsBool(t, "b_must_install_pcap", false);
+			}
+		}
+		else
+		{
+			AddCapsBool(t, "b_local_bridge", false);
+			AddCapsBool(t, "b_must_install_pcap", false);
+		}
+
+		AddCapsBool(t, "b_tap_supported", false);
+
+		if (info.ServerType == SERVER_TYPE_STANDALONE)
+		{
+			AddCapsBool(t, "b_support_cascade", true);
+		}
+		else
+		{
+			AddCapsBool(t, "b_support_cascade", false);
+		}
+
+		AddCapsBool(t, "b_support_cascade_cert", false);
+		AddCapsBool(t, "b_support_config_log", info.ServerType != SERVER_TYPE_FARM_MEMBER);
+		AddCapsBool(t, "b_support_autodelete", false);
+	}
+	else
+	{
+		// 成功した場合
+		if (info.ServerBuildInt <= 4350)
+		{
+			if (is_bridge == false)
+			{
+				// Build 4300 以下では必ず b_support_cluster が true
+				CAPS *caps = GetCaps(t, "b_support_cluster");
+				if (caps == NULL)
+				{
+					AddCapsBool(t, "b_support_cluster", true);
+				}
+				else
+				{
+					caps->Value = 1;
+				}
+			}
+		}
+	}
+
+	if (true)
+	{
+		TOKEN_LIST *names;
+
+		// サーバー側に存在しない Caps の一覧を false として登録
+		names = GetTableNameStartWith("CT_b_");
+		if (names != NULL)
+		{
+			UINT i;
+			for (i = 0;i < names->NumTokens;i++)
+			{
+				char *name = names->Token[i] + 3;
+
+				if (GetCaps(t, name) == NULL)
+				{
+					AddCapsBool(t, name, false);
+				}
+			}
+
+			FreeToken(names);
+		}
+	}
+
+	FreeRpcServerInfo(&info);
+
+	return t;
+}
+
+// 管理用 RPC 関数ディスパッチルーチン
+PACK *AdminDispatch(RPC *rpc, char *name, PACK *p)
+{
+	ADMIN *a;
+	PACK *ret;
+	UINT err;
+	SERVER *server = NULL;
+	CEDAR *cedar = NULL;
+	bool ok = false;
+	// 引数チェック
+	if (rpc == NULL || name == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	ret = NewPack();
+	err = ERR_NO_ERROR;
+
+	// 管理構造体
+	a = (ADMIN *)rpc->Param;
+	if (a == NULL)
+	{
+		FreePack(ret);
+		return NULL;
+	}
+
+	server = a->Server;
+
+	if (server != NULL)
+	{
+		cedar = server->Cedar;
+	}
+
+	Lock(cedar->CedarSuperLock);
+
+	if (true)
+	{
+		char tmp[MAX_PATH];
+		char ip[MAX_PATH];
+		UINT rpc_id = 0;
+
+		StrCpy(ip, sizeof(ip), "Unknown");
+
+		if (rpc->Sock != NULL)
+		{
+			IPToStr(ip, sizeof(ip), &rpc->Sock->RemoteIP);
+			rpc_id = rpc->Sock->socket;
+		}
+
+		Format(tmp, sizeof(tmp), "RPC: RPC-%u (%s): Entering RPC [%s]...",
+			rpc_id, ip, name);
+
+		SiDebugLog(a->Server, tmp);
+	}
+
+	if (0) {}
+
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	// 本当は Sun RPC のプリプロセッサのようにきれいな処理方法を採用したがったが
+	// とりあえず今はマクロの羅列になっている。
+
+	// RPC 関数定義: ここから
+	DECLARE_RPC_EX("Test", RPC_TEST, StTest, InRpcTest, OutRpcTest, FreeRpcTest)
+	DECLARE_RPC_EX("GetServerInfo", RPC_SERVER_INFO, StGetServerInfo, InRpcServerInfo, OutRpcServerInfo, FreeRpcServerInfo)
+	DECLARE_RPC("GetServerStatus", RPC_SERVER_STATUS, StGetServerStatus, InRpcServerStatus, OutRpcServerStatus)
+	DECLARE_RPC("CreateListener", RPC_LISTENER, StCreateListener, InRpcListener, OutRpcListener)
+	DECLARE_RPC_EX("EnumListener", RPC_LISTENER_LIST, StEnumListener, InRpcListenerList, OutRpcListenerList, FreeRpcListenerList)
+	DECLARE_RPC("DeleteListener", RPC_LISTENER, StDeleteListener, InRpcListener, OutRpcListener)
+	DECLARE_RPC("EnableListener", RPC_LISTENER, StEnableListener, InRpcListener, OutRpcListener)
+	DECLARE_RPC("SetServerPassword", RPC_SET_PASSWORD, StSetServerPassword, InRpcSetPassword, OutRpcSetPassword)
+	DECLARE_RPC_EX("SetFarmSetting", RPC_FARM, StSetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+	DECLARE_RPC_EX("GetFarmSetting", RPC_FARM, StGetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+	DECLARE_RPC_EX("GetFarmInfo", RPC_FARM_INFO, StGetFarmInfo, InRpcFarmInfo, OutRpcFarmInfo, FreeRpcFarmInfo)
+	DECLARE_RPC_EX("EnumFarmMember", RPC_ENUM_FARM, StEnumFarmMember, InRpcEnumFarm, OutRpcEnumFarm, FreeRpcEnumFarm)
+	DECLARE_RPC("GetFarmConnectionStatus", RPC_FARM_CONNECTION_STATUS, StGetFarmConnectionStatus, InRpcFarmConnectionStatus, OutRpcFarmConnectionStatus)
+	DECLARE_RPC_EX("SetServerCert", RPC_KEY_PAIR, StSetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+	DECLARE_RPC_EX("GetServerCert", RPC_KEY_PAIR, StGetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+	DECLARE_RPC_EX("GetServerCipher", RPC_STR, StGetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+	DECLARE_RPC_EX("SetServerCipher", RPC_STR, StSetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+	DECLARE_RPC("CreateHub", RPC_CREATE_HUB, StCreateHub, InRpcCreateHub, OutRpcCreateHub)
+	DECLARE_RPC("SetHub", RPC_CREATE_HUB, StSetHub, InRpcCreateHub, OutRpcCreateHub)
+	DECLARE_RPC("GetHub", RPC_CREATE_HUB, StGetHub, InRpcCreateHub, OutRpcCreateHub)
+	DECLARE_RPC_EX("EnumHub", RPC_ENUM_HUB, StEnumHub, InRpcEnumHub, OutRpcEnumHub, FreeRpcEnumHub)
+	DECLARE_RPC("DeleteHub", RPC_DELETE_HUB, StDeleteHub, InRpcDeleteHub, OutRpcDeleteHub)
+	DECLARE_RPC("GetHubRadius", RPC_RADIUS, StGetHubRadius, InRpcRadius, OutRpcRadius)
+	DECLARE_RPC("SetHubRadius", RPC_RADIUS, StSetHubRadius, InRpcRadius, OutRpcRadius)
+	DECLARE_RPC_EX("EnumConnection", RPC_ENUM_CONNECTION, StEnumConnection, InRpcEnumConnection, OutRpcEnumConnection, FreeRpcEnumConnetion)
+	DECLARE_RPC("DisconnectConnection", RPC_DISCONNECT_CONNECTION, StDisconnectConnection, InRpcDisconnectConnection, OutRpcDisconnectConnection)
+	DECLARE_RPC("GetConnectionInfo", RPC_CONNECTION_INFO, StGetConnectionInfo, InRpcConnectionInfo, OutRpcConnectionInfo)
+	DECLARE_RPC("SetHubOnline", RPC_SET_HUB_ONLINE, StSetHubOnline, InRpcSetHubOnline, OutRpcSetHubOnline)
+	DECLARE_RPC("GetHubStatus", RPC_HUB_STATUS, StGetHubStatus, InRpcHubStatus, OutRpcHubStatus)
+	DECLARE_RPC("SetHubLog", RPC_HUB_LOG, StSetHubLog, InRpcHubLog, OutRpcHubLog)
+	DECLARE_RPC("GetHubLog", RPC_HUB_LOG, StGetHubLog, InRpcHubLog, OutRpcHubLog)
+	DECLARE_RPC_EX("AddCa", RPC_HUB_ADD_CA, StAddCa, InRpcHubAddCa, OutRpcHubAddCa, FreeRpcHubAddCa)
+	DECLARE_RPC_EX("EnumCa", RPC_HUB_ENUM_CA, StEnumCa, InRpcHubEnumCa, OutRpcHubEnumCa, FreeRpcHubEnumCa)
+	DECLARE_RPC_EX("GetCa", RPC_HUB_GET_CA, StGetCa, InRpcHubGetCa, OutRpcHubGetCa, FreeRpcHubGetCa)
+	DECLARE_RPC("DeleteCa", RPC_HUB_DELETE_CA, StDeleteCa, InRpcHubDeleteCa, OutRpcHubDeleteCa)
+	DECLARE_RPC("SetLinkOnline", RPC_LINK, StSetLinkOnline, InRpcLink, OutRpcLink)
+	DECLARE_RPC("SetLinkOffline", RPC_LINK, StSetLinkOffline, InRpcLink, OutRpcLink)
+	DECLARE_RPC("DeleteLink", RPC_LINK, StDeleteLink, InRpcLink, OutRpcLink)
+	DECLARE_RPC("RenameLink", RPC_RENAME_LINK, StRenameLink, InRpcRenameLink, OutRpcRenameLink)
+	DECLARE_RPC_EX("CreateLink", RPC_CREATE_LINK, StCreateLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+	DECLARE_RPC_EX("GetLink", RPC_CREATE_LINK, StGetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+	DECLARE_RPC_EX("SetLink", RPC_CREATE_LINK, StSetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+	DECLARE_RPC_EX("EnumLink", RPC_ENUM_LINK, StEnumLink, InRpcEnumLink, OutRpcEnumLink, FreeRpcEnumLink)
+	DECLARE_RPC_EX("GetLinkStatus", RPC_LINK_STATUS, StGetLinkStatus, InRpcLinkStatus, OutRpcLinkStatus, FreeRpcLinkStatus)
+	DECLARE_RPC("AddAccess", RPC_ADD_ACCESS, StAddAccess, InRpcAddAccess, OutRpcAddAccess)
+	DECLARE_RPC("DeleteAccess", RPC_DELETE_ACCESS, StDeleteAccess, InRpcDeleteAccess, OutRpcDeleteAccess)
+	DECLARE_RPC_EX("EnumAccess", RPC_ENUM_ACCESS_LIST, StEnumAccess, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+	DECLARE_RPC_EX("SetAccessList", RPC_ENUM_ACCESS_LIST, StSetAccessList, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+	DECLARE_RPC_EX("CreateUser", RPC_SET_USER, StCreateUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+	DECLARE_RPC_EX("SetUser", RPC_SET_USER, StSetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+	DECLARE_RPC_EX("GetUser", RPC_SET_USER, StGetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+	DECLARE_RPC("DeleteUser", RPC_DELETE_USER, StDeleteUser, InRpcDeleteUser, OutRpcDeleteUser)
+	DECLARE_RPC_EX("EnumUser", RPC_ENUM_USER, StEnumUser, InRpcEnumUser, OutRpcEnumUser, FreeRpcEnumUser)
+	DECLARE_RPC_EX("CreateGroup", RPC_SET_GROUP, StCreateGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+	DECLARE_RPC_EX("SetGroup", RPC_SET_GROUP, StSetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+	DECLARE_RPC_EX("GetGroup", RPC_SET_GROUP, StGetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+	DECLARE_RPC("DeleteGroup", RPC_DELETE_USER, StDeleteGroup, InRpcDeleteUser, OutRpcDeleteUser)
+	DECLARE_RPC_EX("EnumGroup", RPC_ENUM_GROUP, StEnumGroup, InRpcEnumGroup, OutRpcEnumGroup, FreeRpcEnumGroup)
+	DECLARE_RPC_EX("EnumSession", RPC_ENUM_SESSION, StEnumSession, InRpcEnumSession, OutRpcEnumSession, FreeRpcEnumSession)
+	DECLARE_RPC_EX("GetSessionStatus", RPC_SESSION_STATUS, StGetSessionStatus, InRpcSessionStatus, OutRpcSessionStatus, FreeRpcSessionStatus)
+	DECLARE_RPC("DeleteSession", RPC_DELETE_SESSION, StDeleteSession, InRpcDeleteSession, OutRpcDeleteSession)
+	DECLARE_RPC_EX("EnumMacTable", RPC_ENUM_MAC_TABLE, StEnumMacTable, InRpcEnumMacTable, OutRpcEnumMacTable, FreeRpcEnumMacTable)
+	DECLARE_RPC("DeleteMacTable", RPC_DELETE_TABLE, StDeleteMacTable, InRpcDeleteTable, OutRpcDeleteTable)
+	DECLARE_RPC_EX("EnumIpTable", RPC_ENUM_IP_TABLE, StEnumIpTable, InRpcEnumIpTable, OutRpcEnumIpTable, FreeRpcEnumIpTable)
+	DECLARE_RPC("DeleteIpTable", RPC_DELETE_TABLE, StDeleteIpTable, InRpcDeleteTable, OutRpcDeleteTable)
+	DECLARE_RPC("SetKeep", RPC_KEEP, StSetKeep, InRpcKeep, OutRpcKeep)
+	DECLARE_RPC("GetKeep", RPC_KEEP, StGetKeep, InRpcKeep, OutRpcKeep)
+	DECLARE_RPC("EnableSecureNAT", RPC_HUB, StEnableSecureNAT, InRpcHub, OutRpcHub)
+	DECLARE_RPC("DisableSecureNAT", RPC_HUB, StDisableSecureNAT, InRpcHub, OutRpcHub)
+	DECLARE_RPC("SetSecureNATOption", VH_OPTION, StSetSecureNATOption, InVhOption, OutVhOption)
+	DECLARE_RPC("GetSecureNATOption", VH_OPTION, StGetSecureNATOption, InVhOption, OutVhOption)
+	DECLARE_RPC_EX("EnumNAT", RPC_ENUM_NAT, StEnumNAT, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+	DECLARE_RPC_EX("EnumDHCP", RPC_ENUM_DHCP, StEnumDHCP, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+	DECLARE_RPC("GetSecureNATStatus", RPC_NAT_STATUS, StGetSecureNATStatus, InRpcNatStatus, OutRpcNatStatus)
+	DECLARE_RPC_EX("EnumEthernet", RPC_ENUM_ETH, StEnumEthernet, InRpcEnumEth, OutRpcEnumEth, FreeRpcEnumEth)
+	DECLARE_RPC("AddLocalBridge", RPC_LOCALBRIDGE, StAddLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+	DECLARE_RPC("DeleteLocalBridge", RPC_LOCALBRIDGE, StDeleteLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+	DECLARE_RPC_EX("EnumLocalBridge", RPC_ENUM_LOCALBRIDGE, StEnumLocalBridge, InRpcEnumLocalBridge, OutRpcEnumLocalBridge, FreeRpcEnumLocalBridge)
+	DECLARE_RPC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, StGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+	DECLARE_RPC("RebootServer", RPC_TEST, StRebootServer, InRpcTest, OutRpcTest)
+	DECLARE_RPC_EX("GetCaps", CAPSLIST, StGetCaps, InRpcCapsList, OutRpcCapsList, FreeRpcCapsList)
+	DECLARE_RPC_EX("GetConfig", RPC_CONFIG, StGetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+	DECLARE_RPC_EX("SetConfig", RPC_CONFIG, StSetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+	DECLARE_RPC_EX("GetDefaultHubAdminOptions", RPC_ADMIN_OPTION, StGetDefaultHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+	DECLARE_RPC_EX("GetHubAdminOptions", RPC_ADMIN_OPTION, StGetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+	DECLARE_RPC_EX("SetHubAdminOptions", RPC_ADMIN_OPTION, StSetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+	DECLARE_RPC_EX("GetHubExtOptions", RPC_ADMIN_OPTION, StGetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+	DECLARE_RPC_EX("SetHubExtOptions", RPC_ADMIN_OPTION, StSetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+	DECLARE_RPC("AddL3Switch", RPC_L3SW, StAddL3Switch, InRpcL3Sw, OutRpcL3Sw)
+	DECLARE_RPC("DelL3Switch", RPC_L3SW, StDelL3Switch, InRpcL3Sw, OutRpcL3Sw)
+	DECLARE_RPC_EX("EnumL3Switch", RPC_ENUM_L3SW, StEnumL3Switch, InRpcEnumL3Sw, OutRpcEnumL3Sw, FreeRpcEnumL3Sw)
+	DECLARE_RPC("StartL3Switch", RPC_L3SW, StStartL3Switch, InRpcL3Sw, OutRpcL3Sw)
+	DECLARE_RPC("StopL3Switch", RPC_L3SW, StStopL3Switch, InRpcL3Sw, OutRpcL3Sw)
+	DECLARE_RPC("AddL3If", RPC_L3IF, StAddL3If, InRpcL3If, OutRpcL3If)
+	DECLARE_RPC("DelL3If", RPC_L3IF, StDelL3If, InRpcL3If, OutRpcL3If)
+	DECLARE_RPC_EX("EnumL3If", RPC_ENUM_L3IF, StEnumL3If, InRpcEnumL3If, OutRpcEnumL3If, FreeRpcEnumL3If)
+	DECLARE_RPC("AddL3Table", RPC_L3TABLE, StAddL3Table, InRpcL3Table, OutRpcL3Table)
+	DECLARE_RPC("DelL3Table", RPC_L3TABLE, StDelL3Table, InRpcL3Table, OutRpcL3Table)
+	DECLARE_RPC_EX("EnumL3Table", RPC_ENUM_L3TABLE, StEnumL3Table, InRpcEnumL3Table, OutRpcEnumL3Table, FreeRpcEnumL3Table)
+	DECLARE_RPC_EX("EnumCrl", RPC_ENUM_CRL, StEnumCrl, InRpcEnumCrl, OutRpcEnumCrl, FreeRpcEnumCrl)
+	DECLARE_RPC_EX("AddCrl", RPC_CRL, StAddCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+	DECLARE_RPC_EX("DelCrl", RPC_CRL, StDelCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+	DECLARE_RPC_EX("GetCrl", RPC_CRL, StGetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+	DECLARE_RPC_EX("SetCrl", RPC_CRL, StSetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+	DECLARE_RPC_EX("SetAcList", RPC_AC_LIST, StSetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+	DECLARE_RPC_EX("GetAcList", RPC_AC_LIST, StGetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+	DECLARE_RPC_EX("EnumLogFile", RPC_ENUM_LOG_FILE, StEnumLogFile, InRpcEnumLogFile, OutRpcEnumLogFile, FreeRpcEnumLogFile)
+	DECLARE_RPC_EX("ReadLogFile", RPC_READ_LOG_FILE, StReadLogFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+	DECLARE_RPC("AddLicenseKey", RPC_TEST, StAddLicenseKey, InRpcTest, OutRpcTest)
+	DECLARE_RPC("DelLicenseKey", RPC_TEST, StDelLicenseKey, InRpcTest, OutRpcTest)
+	DECLARE_RPC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, StEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+	DECLARE_RPC("GetLicenseStatus", RPC_LICENSE_STATUS, StGetLicenseStatus, InRpcLicenseStatus, OutRpcLicenseStatus)
+	DECLARE_RPC("SetSysLog", SYSLOG_SETTING, StSetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+	DECLARE_RPC("GetSysLog", SYSLOG_SETTING, StGetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+	DECLARE_RPC_EX("EnumEthVLan", RPC_ENUM_ETH_VLAN, StEnumEthVLan, InRpcEnumEthVLan, OutRpcEnumEthVLan, FreeRpcEnumEthVLan)
+	DECLARE_RPC("SetEnableEthVLan", RPC_TEST, StSetEnableEthVLan, InRpcTest, OutRpcTest)
+	DECLARE_RPC_EX("SetHubMsg", RPC_MSG, StSetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+	DECLARE_RPC_EX("GetHubMsg", RPC_MSG, StGetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+	DECLARE_RPC("Crash", RPC_TEST, StCrash, InRpcTest, OutRpcTest)
+	DECLARE_RPC_EX("GetAdminMsg", RPC_MSG, StGetAdminMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+	DECLARE_RPC("Flush", RPC_TEST, StFlush, InRpcTest, OutRpcTest)
+	DECLARE_RPC("Debug", RPC_TEST, StDebug, InRpcTest, OutRpcTest)
+	// RPC 関数定義: ここまで
+
+	if (ok == false)
+	{
+		err = ERR_NOT_SUPPORTED;
+	}
+
+	if (err != ERR_NO_ERROR)
+	{
+		PackAddInt(ret, "error", err);
+	}
+
+	if (true)
+	{
+		char tmp[MAX_PATH];
+		char ip[MAX_PATH];
+		UINT rpc_id = 0;
+
+		StrCpy(ip, sizeof(ip), "Unknown");
+
+		if (rpc->Sock != NULL)
+		{
+			IPToStr(ip, sizeof(ip), &rpc->Sock->RemoteIP);
+			rpc_id = rpc->Sock->socket;
+		}
+
+		Format(tmp, sizeof(tmp), "RPC: RPC-%u (%s): Leaving RPC [%s] (Error: %u).",
+			rpc_id, ip, name, err);
+
+		SiDebugLog(a->Server, tmp);
+	}
+
+	Unlock(cedar->CedarSuperLock);
+
+	return ret;
+}
+
+// このあたりは急いで実装したのでコードがあまり美しくない。
+// 本当は Sun RPC のプリプロセッサのようにきれいな処理方法を採用したがったが
+// とりあえず今はマクロの羅列になっている。
+
+// RPC 呼び出し関数定義: ここから
+DECLARE_SC_EX("Test", RPC_TEST, ScTest, InRpcTest, OutRpcTest, FreeRpcTest)
+DECLARE_SC_EX("GetServerInfo", RPC_SERVER_INFO, ScGetServerInfo, InRpcServerInfo, OutRpcServerInfo, FreeRpcServerInfo)
+DECLARE_SC("GetServerStatus", RPC_SERVER_STATUS, ScGetServerStatus, InRpcServerStatus, OutRpcServerStatus)
+DECLARE_SC("CreateListener", RPC_LISTENER, ScCreateListener, InRpcListener, OutRpcListener)
+DECLARE_SC_EX("EnumListener", RPC_LISTENER_LIST, ScEnumListener, InRpcListenerList, OutRpcListenerList, FreeRpcListenerList)
+DECLARE_SC("DeleteListener", RPC_LISTENER, ScDeleteListener, InRpcListener, OutRpcListener)
+DECLARE_SC("EnableListener", RPC_LISTENER, ScEnableListener, InRpcListener, OutRpcListener)
+DECLARE_SC("SetServerPassword", RPC_SET_PASSWORD, ScSetServerPassword, InRpcSetPassword, OutRpcSetPassword)
+DECLARE_SC_EX("SetFarmSetting", RPC_FARM, ScSetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+DECLARE_SC_EX("GetFarmSetting", RPC_FARM, ScGetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+DECLARE_SC_EX("GetFarmInfo", RPC_FARM_INFO, ScGetFarmInfo, InRpcFarmInfo, OutRpcFarmInfo, FreeRpcFarmInfo)
+DECLARE_SC_EX("EnumFarmMember", RPC_ENUM_FARM, ScEnumFarmMember, InRpcEnumFarm, OutRpcEnumFarm, FreeRpcEnumFarm)
+DECLARE_SC("GetFarmConnectionStatus", RPC_FARM_CONNECTION_STATUS, ScGetFarmConnectionStatus, InRpcFarmConnectionStatus, OutRpcFarmConnectionStatus)
+DECLARE_SC_EX("SetServerCert", RPC_KEY_PAIR, ScSetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+DECLARE_SC_EX("GetServerCert", RPC_KEY_PAIR, ScGetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+DECLARE_SC_EX("GetServerCipher", RPC_STR, ScGetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+DECLARE_SC_EX("SetServerCipher", RPC_STR, ScSetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+DECLARE_SC("CreateHub", RPC_CREATE_HUB, ScCreateHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC("SetHub", RPC_CREATE_HUB, ScSetHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC("GetHub", RPC_CREATE_HUB, ScGetHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC_EX("EnumHub", RPC_ENUM_HUB, ScEnumHub, InRpcEnumHub, OutRpcEnumHub, FreeRpcEnumHub)
+DECLARE_SC("DeleteHub", RPC_DELETE_HUB, ScDeleteHub, InRpcDeleteHub, OutRpcDeleteHub)
+DECLARE_SC("GetHubRadius", RPC_RADIUS, ScGetHubRadius, InRpcRadius, OutRpcRadius)
+DECLARE_SC("SetHubRadius", RPC_RADIUS, ScSetHubRadius, InRpcRadius, OutRpcRadius)
+DECLARE_SC_EX("EnumConnection", RPC_ENUM_CONNECTION, ScEnumConnection, InRpcEnumConnection, OutRpcEnumConnection, FreeRpcEnumConnetion)
+DECLARE_SC("DisconnectConnection", RPC_DISCONNECT_CONNECTION, ScDisconnectConnection, InRpcDisconnectConnection, OutRpcDisconnectConnection)
+DECLARE_SC("GetConnectionInfo", RPC_CONNECTION_INFO, ScGetConnectionInfo, InRpcConnectionInfo, OutRpcConnectionInfo)
+DECLARE_SC("SetHubOnline", RPC_SET_HUB_ONLINE, ScSetHubOnline, InRpcSetHubOnline, OutRpcSetHubOnline)
+DECLARE_SC("GetHubStatus", RPC_HUB_STATUS, ScGetHubStatus, InRpcHubStatus, OutRpcHubStatus)
+DECLARE_SC("SetHubLog", RPC_HUB_LOG, ScSetHubLog, InRpcHubLog, OutRpcHubLog)
+DECLARE_SC("GetHubLog", RPC_HUB_LOG, ScGetHubLog, InRpcHubLog, OutRpcHubLog)
+DECLARE_SC_EX("AddCa", RPC_HUB_ADD_CA, ScAddCa, InRpcHubAddCa, OutRpcHubAddCa, FreeRpcHubAddCa)
+DECLARE_SC_EX("EnumCa", RPC_HUB_ENUM_CA, ScEnumCa, InRpcHubEnumCa, OutRpcHubEnumCa, FreeRpcHubEnumCa)
+DECLARE_SC_EX("GetCa", RPC_HUB_GET_CA, ScGetCa, InRpcHubGetCa, OutRpcHubGetCa, FreeRpcHubGetCa)
+DECLARE_SC("DeleteCa", RPC_HUB_DELETE_CA, ScDeleteCa, InRpcHubDeleteCa, OutRpcHubDeleteCa)
+DECLARE_SC_EX("CreateLink", RPC_CREATE_LINK, ScCreateLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetLink", RPC_CREATE_LINK, ScGetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("SetLink", RPC_CREATE_LINK, ScSetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("EnumLink", RPC_ENUM_LINK, ScEnumLink, InRpcEnumLink, OutRpcEnumLink, FreeRpcEnumLink)
+DECLARE_SC_EX("GetLinkStatus", RPC_LINK_STATUS, ScGetLinkStatus, InRpcLinkStatus, OutRpcLinkStatus, FreeRpcLinkStatus)
+DECLARE_SC("SetLinkOnline", RPC_LINK, ScSetLinkOnline, InRpcLink, OutRpcLink)
+DECLARE_SC("SetLinkOffline", RPC_LINK, ScSetLinkOffline, InRpcLink, OutRpcLink)
+DECLARE_SC("DeleteLink", RPC_LINK, ScDeleteLink, InRpcLink, OutRpcLink)
+DECLARE_SC("RenameLink", RPC_RENAME_LINK, ScRenameLink, InRpcRenameLink, OutRpcRenameLink)
+DECLARE_SC("AddAccess", RPC_ADD_ACCESS, ScAddAccess, InRpcAddAccess, OutRpcAddAccess)
+DECLARE_SC("DeleteAccess", RPC_DELETE_ACCESS, ScDeleteAccess, InRpcDeleteAccess, OutRpcDeleteAccess)
+DECLARE_SC_EX("EnumAccess", RPC_ENUM_ACCESS_LIST, ScEnumAccess, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+DECLARE_SC_EX("SetAccessList", RPC_ENUM_ACCESS_LIST, ScSetAccessList, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+DECLARE_SC_EX("CreateUser", RPC_SET_USER, ScCreateUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC_EX("SetUser", RPC_SET_USER, ScSetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC_EX("GetUser", RPC_SET_USER, ScGetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC("DeleteUser", RPC_DELETE_USER, ScDeleteUser, InRpcDeleteUser, OutRpcDeleteUser)
+DECLARE_SC_EX("EnumUser", RPC_ENUM_USER, ScEnumUser, InRpcEnumUser, OutRpcEnumUser, FreeRpcEnumUser)
+DECLARE_SC_EX("CreateGroup", RPC_SET_GROUP, ScCreateGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC_EX("SetGroup", RPC_SET_GROUP, ScSetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC_EX("GetGroup", RPC_SET_GROUP, ScGetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC("DeleteGroup", RPC_DELETE_USER, ScDeleteGroup, InRpcDeleteUser, OutRpcDeleteUser)
+DECLARE_SC_EX("EnumGroup", RPC_ENUM_GROUP, ScEnumGroup, InRpcEnumGroup, OutRpcEnumGroup, FreeRpcEnumGroup)
+DECLARE_SC_EX("EnumSession", RPC_ENUM_SESSION, ScEnumSession, InRpcEnumSession, OutRpcEnumSession, FreeRpcEnumSession)
+DECLARE_SC_EX("GetSessionStatus", RPC_SESSION_STATUS, ScGetSessionStatus, InRpcSessionStatus, OutRpcSessionStatus, FreeRpcSessionStatus)
+DECLARE_SC("DeleteSession", RPC_DELETE_SESSION, ScDeleteSession, InRpcDeleteSession, OutRpcDeleteSession)
+DECLARE_SC_EX("EnumMacTable", RPC_ENUM_MAC_TABLE, ScEnumMacTable, InRpcEnumMacTable, OutRpcEnumMacTable, FreeRpcEnumMacTable)
+DECLARE_SC("DeleteMacTable", RPC_DELETE_TABLE, ScDeleteMacTable, InRpcDeleteTable, OutRpcDeleteTable)
+DECLARE_SC_EX("EnumIpTable", RPC_ENUM_IP_TABLE, ScEnumIpTable, InRpcEnumIpTable, OutRpcEnumIpTable, FreeRpcEnumIpTable)
+DECLARE_SC("DeleteIpTable", RPC_DELETE_TABLE, ScDeleteIpTable, InRpcDeleteTable, OutRpcDeleteTable)
+DECLARE_SC("SetKeep", RPC_KEEP, ScSetKeep, InRpcKeep, OutRpcKeep)
+DECLARE_SC("GetKeep", RPC_KEEP, ScGetKeep, InRpcKeep, OutRpcKeep)
+DECLARE_SC("EnableSecureNAT", RPC_HUB, ScEnableSecureNAT, InRpcHub, OutRpcHub)
+DECLARE_SC("DisableSecureNAT", RPC_HUB, ScDisableSecureNAT, InRpcHub, OutRpcHub)
+DECLARE_SC("SetSecureNATOption", VH_OPTION, ScSetSecureNATOption, InVhOption, OutVhOption)
+DECLARE_SC("GetSecureNATOption", VH_OPTION, ScGetSecureNATOption, InVhOption, OutVhOption)
+DECLARE_SC_EX("EnumNAT", RPC_ENUM_NAT, ScEnumNAT, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+DECLARE_SC_EX("EnumDHCP", RPC_ENUM_DHCP, ScEnumDHCP, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+DECLARE_SC("GetSecureNATStatus", RPC_NAT_STATUS, ScGetSecureNATStatus, InRpcNatStatus, OutRpcNatStatus)
+DECLARE_SC_EX("EnumEthernet", RPC_ENUM_ETH, ScEnumEthernet, InRpcEnumEth, OutRpcEnumEth, FreeRpcEnumEth)
+DECLARE_SC("AddLocalBridge", RPC_LOCALBRIDGE, ScAddLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+DECLARE_SC("DeleteLocalBridge", RPC_LOCALBRIDGE, ScDeleteLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+DECLARE_SC_EX("EnumLocalBridge", RPC_ENUM_LOCALBRIDGE, ScEnumLocalBridge, InRpcEnumLocalBridge, OutRpcEnumLocalBridge, FreeRpcEnumLocalBridge)
+DECLARE_SC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, ScGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+DECLARE_SC("RebootServer", RPC_TEST, ScRebootServer, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("GetCaps", CAPSLIST, ScGetCaps, InRpcCapsList, OutRpcCapsList, FreeRpcCapsList)
+DECLARE_SC_EX("GetConfig", RPC_CONFIG, ScGetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+DECLARE_SC_EX("SetConfig", RPC_CONFIG, ScSetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+DECLARE_SC_EX("GetHubAdminOptions", RPC_ADMIN_OPTION, ScGetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("SetHubAdminOptions", RPC_ADMIN_OPTION, ScSetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("GetHubExtOptions", RPC_ADMIN_OPTION, ScGetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("SetHubExtOptions", RPC_ADMIN_OPTION, ScSetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("GetDefaultHubAdminOptions", RPC_ADMIN_OPTION, ScGetDefaultHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC("AddL3Switch", RPC_L3SW, ScAddL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("DelL3Switch", RPC_L3SW, ScDelL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC_EX("EnumL3Switch", RPC_ENUM_L3SW, ScEnumL3Switch, InRpcEnumL3Sw, OutRpcEnumL3Sw, FreeRpcEnumL3Sw)
+DECLARE_SC("StartL3Switch", RPC_L3SW, ScStartL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("StopL3Switch", RPC_L3SW, ScStopL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("AddL3If", RPC_L3IF, ScAddL3If, InRpcL3If, OutRpcL3If)
+DECLARE_SC("DelL3If", RPC_L3IF, ScDelL3If, InRpcL3If, OutRpcL3If)
+DECLARE_SC_EX("EnumL3If", RPC_ENUM_L3IF, ScEnumL3If, InRpcEnumL3If, OutRpcEnumL3If, FreeRpcEnumL3If)
+DECLARE_SC("AddL3Table", RPC_L3TABLE, ScAddL3Table, InRpcL3Table, OutRpcL3Table)
+DECLARE_SC("DelL3Table", RPC_L3TABLE, ScDelL3Table, InRpcL3Table, OutRpcL3Table)
+DECLARE_SC_EX("EnumL3Table", RPC_ENUM_L3TABLE, ScEnumL3Table, InRpcEnumL3Table, OutRpcEnumL3Table, FreeRpcEnumL3Table)
+DECLARE_SC_EX("EnumCrl", RPC_ENUM_CRL, ScEnumCrl, InRpcEnumCrl, OutRpcEnumCrl, FreeRpcEnumCrl)
+DECLARE_SC_EX("AddCrl", RPC_CRL, ScAddCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("DelCrl", RPC_CRL, ScDelCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("GetCrl", RPC_CRL, ScGetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("SetCrl", RPC_CRL, ScSetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("SetAcList", RPC_AC_LIST, ScSetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+DECLARE_SC_EX("GetAcList", RPC_AC_LIST, ScGetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+DECLARE_SC_EX("EnumLogFile", RPC_ENUM_LOG_FILE, ScEnumLogFile, InRpcEnumLogFile, OutRpcEnumLogFile, FreeRpcEnumLogFile)
+DECLARE_SC_EX("ReadLogFile", RPC_READ_LOG_FILE, ScReadLogFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+DECLARE_SC("AddLicenseKey", RPC_TEST, ScAddLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC("DelLicenseKey", RPC_TEST, ScDelLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, ScEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+DECLARE_SC("GetLicenseStatus", RPC_LICENSE_STATUS, ScGetLicenseStatus, InRpcLicenseStatus, OutRpcLicenseStatus)
+DECLARE_SC("SetSysLog", SYSLOG_SETTING, ScSetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+DECLARE_SC("GetSysLog", SYSLOG_SETTING, ScGetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+DECLARE_SC_EX("EnumEthVLan", RPC_ENUM_ETH_VLAN, ScEnumEthVLan, InRpcEnumEthVLan, OutRpcEnumEthVLan, FreeRpcEnumEthVLan)
+DECLARE_SC("SetEnableEthVLan", RPC_TEST, ScSetEnableEthVLan, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("SetHubMsg", RPC_MSG, ScSetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC_EX("GetHubMsg", RPC_MSG, ScGetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC("Crash", RPC_TEST, ScCrash, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("GetAdminMsg", RPC_MSG, ScGetAdminMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC("Flush", RPC_TEST, ScFlush, InRpcTest, OutRpcTest)
+DECLARE_SC("Debug", RPC_TEST, ScDebug, InRpcTest, OutRpcTest)
+// RPC 呼び出し関数定義: ここまで
+
+
+// メッセージを設定
+UINT StSetHubMsg(ADMIN *a, RPC_MSG *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+	if (UniStrLen(t->Msg) > HUB_MAXMSG_LEN)
+	{
+		return ERR_MEMORY_NOT_ENOUGH;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	h = GetHub(c, hubname);
+
+	if (h == NULL)
+	{
+		ret = ERR_HUB_NOT_FOUND;
+	}
+	else
+	{
+		if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_msg") != 0)
+		{
+			ret = ERR_NOT_ENOUGH_RIGHT;
+		}
+		else
+		{
+			SetHubMsg(h, t->Msg);
+		}
+
+		ReleaseHub(h);
+	}
+
+	IncrementServerConfigRevision(s);
+
+	return ret;
+}
+
+// メッセージを取得
+UINT StGetHubMsg(ADMIN *a, RPC_MSG *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+	if (UniStrLen(t->Msg) > HUB_MAXMSG_LEN)
+	{
+		return ERR_MEMORY_NOT_ENOUGH;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	FreeRpcMsg(t);
+	Zero(t, sizeof(t));
+
+	h = GetHub(c, hubname);
+
+	if (h == NULL)
+	{
+		ret = ERR_HUB_NOT_FOUND;
+	}
+	else
+	{
+		t->Msg = GetHubMsg(h);
+
+		ReleaseHub(h);
+	}
+
+	return ret;
+}
+
+// デバッグ機能を実行する
+UINT StDebug(ADMIN *a, RPC_TEST *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	RPC_TEST t2;
+
+	SERVER_ADMIN_ONLY;
+
+	Zero(&t2, sizeof(t2));
+
+	ret = SiDebug(s, &t2, t->IntValue, t->StrValue);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		Copy(t, &t2, sizeof(RPC_TEST));
+	}
+	else
+	{
+		Zero(t, sizeof(RPC_TEST));
+	}
+
+	return ret;
+}
+
+// 設定ファイルをフラッシュする
+UINT StFlush(ADMIN *a, RPC_TEST *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	UINT size;
+
+	SERVER_ADMIN_ONLY;
+
+	size = SiWriteConfigurationFile(s);
+
+	t->IntValue = size;
+
+	return ERR_NO_ERROR;
+}
+
+// クラッシュさせる (システム管理者だけが実行できる緊急時用コード)
+UINT StCrash(ADMIN *a, RPC_TEST *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+
+	SERVER_ADMIN_ONLY;
+
+#ifdef	OS_WIN32
+	MsSetEnableMinidump(false);
+#endif	// OS_WIN32
+
+	CrashNow();
+
+	return ERR_NO_ERROR;
+}
+
+// 管理者向けメッセージを取得する
+UINT StGetAdminMsg(ADMIN *a, RPC_MSG *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	RPC_WINVER server_ver;
+	RPC_WINVER client_ver;
+	wchar_t winver_msg_client[3800];
+	wchar_t winver_msg_server[3800];
+	wchar_t *utvpn_msg;
+	UINT tmpsize;
+	wchar_t *tmp;
+
+	FreeRpcMsg(t);
+	Zero(t, sizeof(RPC_MSG));
+
+	// Windows バージョンチェック
+	GetWinVer(&server_ver);
+	Copy(&client_ver, &a->ClientWinVer, sizeof(RPC_WINVER));
+
+	Zero(winver_msg_client, sizeof(winver_msg_client));
+	Zero(winver_msg_server, sizeof(winver_msg_server));
+
+	utvpn_msg = _UU("UTVPN_MSG");
+
+	if (IsSupportedWinVer(&client_ver) == false)
+	{
+		SYSTEMTIME st;
+
+		LocalTime(&st);
+
+		UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+			_UU("WINVER_ERROR_PC_LOCAL"),
+			client_ver.Title,
+			_UU("WINVER_ERROR_VPNSERVER"),
+			SUPPORTED_WINDOWS_LIST,
+			_UU("WINVER_ERROR_PC_LOCAL"),
+			_UU("WINVER_ERROR_VPNSERVER"),
+			_UU("WINVER_ERROR_VPNSERVER"),
+			_UU("WINVER_ERROR_VPNSERVER"),
+			st.wYear, st.wMonth);
+	}
+
+	if (IsSupportedWinVer(&server_ver) == false)
+	{
+		SYSTEMTIME st;
+
+		LocalTime(&st);
+
+		UniFormat(winver_msg_server, sizeof(winver_msg_server), _UU("WINVER_ERROR_FORMAT"),
+			_UU("WINVER_ERROR_PC_REMOTE"),
+			server_ver.Title,
+			_UU("WINVER_ERROR_VPNSERVER"),
+			SUPPORTED_WINDOWS_LIST,
+			_UU("WINVER_ERROR_PC_REMOTE"),
+			_UU("WINVER_ERROR_VPNSERVER"),
+			_UU("WINVER_ERROR_VPNSERVER"),
+			_UU("WINVER_ERROR_VPNSERVER"),
+			st.wYear, st.wMonth);
+	}
+
+	tmpsize = UniStrSize(winver_msg_client) + UniStrSize(winver_msg_server) + UniStrSize(utvpn_msg) + 100;
+
+	tmp = ZeroMalloc(tmpsize);
+	UniStrCat(tmp, tmpsize, utvpn_msg);
+	UniStrCat(tmp, tmpsize, winver_msg_client);
+	UniStrCat(tmp, tmpsize, winver_msg_server);
+
+	t->Msg = tmp;
+
+	return ERR_NO_ERROR;
+}
+
+// VLAN 透過設定一覧の取得
+UINT StEnumEthVLan(ADMIN *a, RPC_ENUM_ETH_VLAN *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+
+	SERVER_ADMIN_ONLY;
+
+#ifdef	OS_WIN32
+	if (GetServerCapsBool(s, "b_support_eth_vlan") == false)
+	{
+		ret = ERR_NOT_SUPPORTED;
+	}
+	else
+	{
+		FreeRpcEnumEthVLan(t);
+		Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+		if (EnumEthVLanWin32(t) == false)
+		{
+			ret = ERR_INTERNAL_ERROR;
+		}
+	}
+#else	// OS_WIN32
+	ret = ERR_NOT_SUPPORTED;
+#endif	// OS_WIN32
+
+	return ret;
+}
+
+// VLAN 透過設定の設定
+UINT StSetEnableEthVLan(ADMIN *a, RPC_TEST *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+
+	SERVER_ADMIN_ONLY;
+
+#ifdef	OS_WIN32
+	if (GetServerCapsBool(s, "b_support_eth_vlan") == false)
+	{
+		ret = ERR_NOT_SUPPORTED;
+	}
+	else if (MsIsAdmin() == false)
+	{
+		ret = ERR_NOT_ENOUGH_RIGHT;
+	}
+	else
+	{
+		if (SetVLanEnableStatus(t->StrValue, MAKEBOOL(t->IntValue)) == false)
+		{
+			ret = ERR_INTERNAL_ERROR;
+		}
+	}
+#else	// OS_WIN32
+	ret = ERR_NOT_SUPPORTED;
+#endif	// OS_WIN32
+
+	return ret;
+}
+
+// ライセンス状態の取得
+// (ソフトイーサ社の製品 PacketiX VPN の管理に使えるように互換性を残している)
+UINT StGetLicenseStatus(ADMIN *a, RPC_LICENSE_STATUS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	LICENSE_SYSTEM *ls = s->LicenseSystem;
+	LICENSE_STATUS status;
+
+	if (ls == NULL)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	SERVER_ADMIN_ONLY;
+
+	Zero(t, sizeof(RPC_LICENSE_STATUS));
+
+	// 現在のライセンスステータスを取得
+	LiParseCurrentLicenseStatus(ls, &status);
+
+	t->EditionId = status.Edition;
+	StrCpy(t->EditionStr, sizeof(t->EditionStr), status.EditionStr);
+	t->SystemId = status.SystemId;
+	t->SystemExpires = status.Expires;
+	t->NumClientConnectLicense = status.NumClientLicense;
+	t->NumBridgeConnectLicense = status.NumBridgeLicense;
+	t->NumUserCreationLicense = status.NumUserLicense;
+	t->SubscriptionExpires = status.SubscriptionExpires;
+	t->IsSubscriptionExpired = status.IsSubscriptionExpired;
+	t->NeedSubscription = status.NeedSubscription;
+	t->AllowEnterpriseFunction = status.AllowEnterpriseFunction;
+	t->ReleaseDate = c->BuiltDate;
+
+	return ret;
+}
+
+// ライセンスキーの列挙
+// (ソフトイーサ社の製品 PacketiX VPN の管理に使えるように互換性を残している)
+UINT StEnumLicenseKey(ADMIN *a, RPC_ENUM_LICENSE_KEY *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	LICENSE_SYSTEM *ls = s->LicenseSystem;
+
+	if (ls == NULL)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	SERVER_ADMIN_ONLY;
+
+	FreeRpcEnumLicenseKey(t);
+	Zero(t, sizeof(RPC_ENUM_LICENSE_KEY));
+
+	LockList(ls->LicenseList);
+	{
+		UINT i;
+
+		t->NumItem = LIST_NUM(ls->LicenseList);
+		t->Items = ZeroMalloc(sizeof(RPC_ENUM_LICENSE_KEY_ITEM) * t->NumItem);
+
+		for (i = 0;i < t->NumItem;i++)
+		{
+			RPC_ENUM_LICENSE_KEY_ITEM *k = &t->Items[i];
+			LICENSE *e = LIST_DATA(ls->LicenseList, i);
+
+			k->Id = e->Id;
+			k->Expires = e->Expires;
+			StrCpy(k->LicenseId, sizeof(k->LicenseId), e->LicenseIdStr);
+			StrCpy(k->LicenseKey, sizeof(k->LicenseKey), e->LicenseKeyStr);
+			StrCpy(k->LicenseName, sizeof(k->LicenseName), e->Name);
+			k->Status = e->Status;
+			k->ProductId = e->ProductId;
+			k->SystemId = e->SystemId;
+			k->SerialId = e->SerialId;
+		}
+	}
+	UnlockList(ls->LicenseList);
+
+	return ret;
+}
+
+// ライセンスキーの追加
+// (ソフトイーサ社の製品 PacketiX VPN の管理に使えるように互換性を残している)
+UINT StAddLicenseKey(ADMIN *a, RPC_TEST *t)
+{
+	return ERR_NOT_SUPPORTED;
+}
+
+// ライセンスキーの削除
+// (ソフトイーサ社の製品 PacketiX VPN の管理に使えるように互換性を残している)
+UINT StDelLicenseKey(ADMIN *a, RPC_TEST *t)
+{
+	return ERR_NOT_SUPPORTED;
+}
+
+// ログファイルのダウンロード
+BUF *DownloadFileFromServer(RPC *r, char *server_name, char *filepath, UINT total_size, DOWNLOAD_PROC *proc, void *param)
+{
+	UINT offset;
+	BUF *buf;
+	// 引数チェック
+	if (r == NULL || filepath == NULL)
+	{
+		return NULL;
+	}
+
+	if (server_name == NULL)
+	{
+		server_name = "";
+	}
+
+	offset = 0;
+
+	buf = NewBuf();
+
+	while (true)
+	{
+		DOWNLOAD_PROGRESS g;
+		RPC_READ_LOG_FILE t;
+		UINT ret;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.FilePath, sizeof(t.FilePath), filepath);
+		t.Offset = offset;
+		StrCpy(t.ServerName, sizeof(t.ServerName), server_name);
+
+		ret = ScReadLogFile(r, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// 失敗
+			FreeRpcReadLogFile(&t);
+			FreeBuf(buf);
+			return NULL;
+		}
+
+		if (t.Buffer == NULL)
+		{
+			// 最後まで読み込んだ
+			break;
+		}
+
+		// 現在の状況を更新
+		offset += t.Buffer->Size;
+		Zero(&g, sizeof(g));
+		g.Param = param;
+		g.CurrentSize = offset;
+		g.TotalSize = MAX(total_size, offset);
+		g.ProgressPercent = (UINT)(MAKESURE((UINT64)g.CurrentSize * 100ULL / (UINT64)(MAX(g.TotalSize, 1)), 0, 100ULL));
+
+		WriteBuf(buf, t.Buffer->Buf, t.Buffer->Size);
+
+		FreeRpcReadLogFile(&t);
+
+		if (proc != NULL)
+		{
+			if (proc(&g) == false)
+			{
+				// ユーザーキャンセル
+				FreeBuf(buf);
+				return NULL;
+			}
+		}
+	}
+
+	if (buf->Size == 0)
+	{
+		// ダウンロード失敗
+		FreeBuf(buf);
+		return NULL;
+	}
+
+	return buf;
+}
+
+// ログファイルの読み込み
+UINT StReadLogFile(ADMIN *a, RPC_READ_LOG_FILE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	char logfilename[MAX_PATH];
+	char servername[MAX_HOST_NAME_LEN + 1];
+	UINT offset;
+	bool local = true;
+
+	if (IsEmptyStr(t->FilePath))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	StrCpy(logfilename, sizeof(logfilename), t->FilePath);
+	StrCpy(servername, sizeof(servername), t->ServerName);
+	offset = t->Offset;
+
+	if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		GetMachineName(servername, sizeof(servername));
+	}
+
+	// ログファイルを読み込む権限があるかどうか検査する
+	if (a->LogFileList == NULL)
+	{
+		// キャッシュ無し
+		return ERR_OBJECT_NOT_FOUND;
+	}
+	if (CheckLogFileNameFromEnumList(a->LogFileList, logfilename, servername) == false)
+	{
+		// そのようなファイルは列挙リストに無い
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	FreeRpcReadLogFile(t);
+	Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		UINT i;
+
+		// 要求されたファイルのサーバー名がクラスタメンバのホスト名
+		// と一致した場合はリモートサーバー上にファイルが存在するのでそれを読み込む
+		LockList(s->FarmMemberList);
+		{
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+				if (f->Me == false)
+				{
+					if (StrCmpi(f->hostname, servername) == 0)
+					{
+						RPC_READ_LOG_FILE tt;
+
+						Zero(&tt, sizeof(tt));
+						local = false;
+
+						StrCpy(tt.ServerName, sizeof(tt.ServerName), servername);
+						StrCpy(tt.FilePath, sizeof(tt.FilePath), logfilename);
+						tt.Offset = offset;
+
+						if (SiCallReadLogFile(s, f, &tt))
+						{
+							if (tt.Buffer != NULL && tt.Buffer->Size > 0)
+							{
+								t->Buffer = NewBuf();
+								WriteBuf(t->Buffer, tt.Buffer->Buf, tt.Buffer->Size);
+							}
+						}
+
+						FreeRpcReadLogFile(&tt);
+
+						break;
+					}
+				}
+			}
+		}
+		UnlockList(s->FarmMemberList);
+	}
+
+	// ローカルファイルの読み込み
+	if (local)
+	{
+		SiReadLocalLogFile(s, logfilename, offset, t);
+	}
+
+	if (offset == 0)
+	{
+		ALog(a, NULL, "LA_READ_LOG_FILE", servername, logfilename);
+	}
+
+	return ERR_NO_ERROR;
+}
+
+// ログファイルの列挙
+UINT StEnumLogFile(ADMIN *a, RPC_ENUM_LOG_FILE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT i;
+	bool no_access = false;
+
+	HUB *h;
+
+	if (a->ServerAdmin == false)
+	{
+		h = GetHub(c, a->HubName);
+
+		if (a->ServerAdmin == false && GetHubAdminOption(h, "no_read_log_file") != 0)
+		{
+			no_access = true;
+		}
+
+		ReleaseHub(h);
+	}
+	else
+	{
+		if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			// クラスタコントローラで管理者がログファイルの一覧を取得する
+			// と高負荷になるため制限している
+			return ERR_NOT_SUPPORTED;
+		}
+	}
+
+	if (no_access)
+	{
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	FreeRpcEnumLogFile(t);
+	Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+
+	// ローカルのログファイルを列挙する
+	SiEnumLocalLogFileList(s, a->ServerAdmin ? NULL : a->HubName, t);
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		UINT i;
+		LIST *tt_list = NewListFast(NULL);
+
+		LockList(s->FarmMemberList);
+		{
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+				if (f->Me == false)
+				{
+					// 他のメンバ上のログファイルを列挙する
+					RPC_ENUM_LOG_FILE *tt;
+					tt = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE));
+
+					if (SiCallEnumLogFileList(s, f, tt, a->ServerAdmin ? "" : a->HubName))
+					{
+						UINT i;
+						for (i = 0;i < tt->NumItem;i++)
+						{
+							RPC_ENUM_LOG_FILE_ITEM *e = &tt->Items[i];
+
+							StrCpy(e->ServerName, sizeof(e->ServerName), f->hostname);
+						}
+
+						Add(tt_list, tt);
+					}
+					else
+					{
+						Free(tt);
+					}
+				}
+			}
+		}
+		UnlockList(s->FarmMemberList);
+
+		for (i = 0;i < LIST_NUM(tt_list);i++)
+		{
+			RPC_ENUM_LOG_FILE *tt = LIST_DATA(tt_list, i);
+
+			AdjoinRpcEnumLogFile(t, tt);
+			FreeRpcEnumLogFile(tt);
+
+			Free(tt);
+		}
+
+		ReleaseList(tt_list);
+	}
+
+	// RPC セッションに最後に列挙したログファイル一覧をキャッシュする
+	if (a->LogFileList != NULL)
+	{
+		FreeEnumLogFile(a->LogFileList);
+	}
+
+	a->LogFileList = NewListFast(CmpLogFile);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+		LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+		f->FileSize = e->FileSize;
+		f->UpdatedTime = e->UpdatedTime;
+		StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+		StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+
+		Insert(a->LogFileList, f);
+	}
+
+	return ERR_NO_ERROR;
+}
+
+
+// AC リストの取得
+UINT StGetAcList(ADMIN *a, RPC_AC_LIST *t)
+{
+	return ERR_NOT_SUPPORTED;
+}
+
+// AC リストの設定
+UINT StSetAcList(ADMIN *a, RPC_AC_LIST *t)
+{
+	return ERR_NOT_SUPPORTED;
+}
+
+// CRL の設定
+UINT StSetCrl(ADMIN *a, RPC_CRL *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	UINT key;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	key = t->Key;
+
+	h = GetHub(c, hubname);
+
+	if (h == NULL)
+	{
+		ret = ERR_HUB_NOT_FOUND;
+	}
+	else
+	{
+		if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+		{
+			ret = ERR_NOT_ENOUGH_RIGHT;
+		}
+		else
+		{
+			if (h->HubDb == NULL)
+			{
+				ret = ERR_NOT_SUPPORTED;
+			}
+			else
+			{
+				LockList(h->HubDb->CrlList);
+				{
+					CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+					if (crl == NULL)
+					{
+						ret = ERR_INTERNAL_ERROR;
+					}
+					else
+					{
+						CRL *new_crl = CopyCrl(t->Crl);
+						if (ReplaceListPointer(h->HubDb->CrlList, crl, new_crl))
+						{
+							ALog(a, h, "LA_ADD_CRL");
+							FreeCrl(crl);
+
+							IncrementServerConfigRevision(s);
+						}
+					}
+				}
+				UnlockList(h->HubDb->CrlList);
+			}
+		}
+
+		ReleaseHub(h);
+	}
+
+	return ret;
+}
+
+// CRL の取得
+UINT StGetCrl(ADMIN *a, RPC_CRL *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	UINT key;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	key = t->Key;
+
+	FreeRpcCrl(t);
+	Zero(t, sizeof(RPC_CRL));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+	t->Key = key;
+
+	h = GetHub(c, hubname);
+
+	if (h == NULL)
+	{
+		ret = ERR_HUB_NOT_FOUND;
+	}
+	else
+	{
+		if (h->HubDb == NULL)
+		{
+			ret = ERR_NOT_SUPPORTED;
+		}
+		else
+		{
+			LockList(h->HubDb->CrlList);
+			{
+				CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+				if (crl == NULL)
+				{
+					ret = ERR_INTERNAL_ERROR;
+				}
+				else
+				{
+					t->Crl = CopyCrl(crl);
+				}
+			}
+			UnlockList(h->HubDb->CrlList);
+		}
+
+		ReleaseHub(h);
+	}
+
+	return ret;
+}
+
+// CRL の削除
+UINT StDelCrl(ADMIN *a, RPC_CRL *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	h = GetHub(c, hubname);
+
+	if (h == NULL)
+	{
+		ret = ERR_HUB_NOT_FOUND;
+	}
+	else
+	{
+		if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+		{
+			ret = ERR_NOT_ENOUGH_RIGHT;
+		}
+		else
+		{
+			if (h->HubDb == NULL)
+			{
+				ret = ERR_NOT_SUPPORTED;
+			}
+			else
+			{
+				LockList(h->HubDb->CrlList);
+				{
+					CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+					if (crl == NULL)
+					{
+						ret = ERR_INTERNAL_ERROR;
+					}
+					else
+					{
+						ALog(a, h, "LA_DEL_CRL");
+						FreeCrl(crl);
+						Delete(h->HubDb->CrlList, crl);
+					}
+				}
+				UnlockList(h->HubDb->CrlList);
+			}
+		}
+
+		ReleaseHub(h);
+	}
+
+	return ret;
+}
+
+// CRL の追加
+UINT StAddCrl(ADMIN *a, RPC_CRL *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	if (c->Bridge)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	h = GetHub(c, hubname);
+
+	if (h == NULL)
+	{
+		ret = ERR_HUB_NOT_FOUND;
+	}
+	else
+	{
+		if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+		{
+			ret = ERR_NOT_ENOUGH_RIGHT;
+		}
+		else
+		{
+			if (h->HubDb == NULL)
+			{
+				ret = ERR_NOT_SUPPORTED;
+			}
+			else
+			{
+				LockList(h->HubDb->CrlList);
+				{
+					if (LIST_NUM(h->HubDb->CrlList) < MAX_HUB_CRLS)
+					{
+						CRL *crl = CopyCrl(t->Crl);
+
+						Insert(h->HubDb->CrlList, crl);
+
+						ALog(a, h, "LA_SET_CRL");
+
+						IncrementServerConfigRevision(s);
+					}
+				}
+				UnlockList(h->HubDb->CrlList);
+			}
+		}
+
+		ReleaseHub(h);
+	}
+
+	return ret;
+}
+
+// CRL の列挙
+UINT StEnumCrl(ADMIN *a, RPC_ENUM_CRL *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	FreeRpcEnumCrl(t);
+	Zero(t, sizeof(RPC_ENUM_CRL));
+
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	h = GetHub(c, hubname);
+
+	if (h == NULL)
+	{
+		ret = ERR_HUB_NOT_FOUND;
+	}
+	else
+	{
+		if (h->HubDb == NULL)
+		{
+			ret = ERR_NOT_SUPPORTED;
+		}
+		else
+		{
+			LockList(h->HubDb->CrlList);
+			{
+				UINT i;
+
+				t->NumItem = LIST_NUM(h->HubDb->CrlList);
+				t->Items = ZeroMalloc(sizeof(RPC_ENUM_CRL_ITEM) * t->NumItem);
+
+				for (i = 0;i < LIST_NUM(h->HubDb->CrlList);i++)
+				{
+					CRL *crl = LIST_DATA(h->HubDb->CrlList, i);
+					wchar_t *info = GenerateCrlStr(crl);
+
+					UniStrCpy(t->Items[i].CrlInfo, sizeof(t->Items[i].CrlInfo), info);
+					Free(info);
+
+					t->Items[i].Key = POINTER_TO_KEY(crl);
+				}
+			}
+			UnlockList(h->HubDb->CrlList);
+		}
+
+		ReleaseHub(h);
+	}
+
+	return ret;
+}
+
+// ルーティングテーブルの列挙
+UINT StEnumL3Table(ADMIN *a, RPC_ENUM_L3TABLE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+	char name[MAX_HUBNAME_LEN + 1];
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	StrCpy(name, sizeof(name), t->Name);
+	FreeRpcEnumL3Table(t);
+	Zero(t, sizeof(RPC_ENUM_L3TABLE));
+	StrCpy(t->Name, sizeof(t->Name), name);
+
+	sw = L3GetSw(c, t->Name);
+
+	if (sw == NULL)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		UINT i;
+
+		Lock(sw->lock);
+		{
+			t->NumItem = LIST_NUM(sw->TableList);
+			t->Items = ZeroMalloc(sizeof(RPC_L3TABLE) * t->NumItem);
+
+			for (i = 0;i < t->NumItem;i++)
+			{
+				L3TABLE *tbl = LIST_DATA(sw->TableList, i);
+				RPC_L3TABLE *e = &t->Items[i];
+
+				StrCpy(e->Name, sizeof(e->Name), name);
+				e->NetworkAddress = tbl->NetworkAddress;
+				e->SubnetMask = tbl->SubnetMask;
+				e->GatewayAddress = tbl->GatewayAddress;
+				e->Metric = tbl->Metric;
+			}
+		}
+		Unlock(sw->lock);
+
+		ReleaseL3Sw(sw);
+	}
+
+	return ret;
+}
+
+// ルーティングテーブルの削除
+UINT StDelL3Table(ADMIN *a, RPC_L3TABLE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+
+	SERVER_ADMIN_ONLY;
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	sw = L3GetSw(c, t->Name);
+
+	if (sw == NULL)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		L3TABLE tbl;
+
+		Zero(&tbl, sizeof(tbl));
+		tbl.NetworkAddress = t->NetworkAddress;
+		tbl.SubnetMask = t->SubnetMask;
+		tbl.GatewayAddress = t->GatewayAddress;
+		tbl.Metric = t->Metric;
+
+		if (L3DelTable(sw, &tbl) == false)
+		{
+			ret = ERR_LAYER3_TABLE_DEL_FAILED;
+		}
+		else
+		{
+			char tmp[MAX_SIZE];
+			IPToStr32(tmp, sizeof(tmp), tbl.NetworkAddress);
+			ALog(a, NULL, "LA_DEL_L3_TABLE", tmp, t->Name);
+
+			IncrementServerConfigRevision(s);
+		}
+
+		ReleaseL3Sw(sw);
+	}
+
+	return ret;
+}
+
+// ルーティングテーブルの追加
+UINT StAddL3Table(ADMIN *a, RPC_L3TABLE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+
+	if (IsNetworkAddress32(t->NetworkAddress, t->SubnetMask) == false ||
+		IsHostIPAddress32(t->GatewayAddress) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	sw = L3GetSw(c, t->Name);
+
+	if (sw == NULL)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		L3TABLE tbl;
+
+		Zero(&tbl, sizeof(tbl));
+		tbl.NetworkAddress = t->NetworkAddress;
+		tbl.SubnetMask = t->SubnetMask;
+		tbl.GatewayAddress = t->GatewayAddress;
+		tbl.Metric = t->Metric;
+
+		if (L3AddTable(sw, &tbl) == false)
+		{
+			ret = ERR_LAYER3_TABLE_ADD_FAILED;
+		}
+		else
+		{
+			char tmp[MAX_SIZE];
+			IPToStr32(tmp, sizeof(tmp), tbl.NetworkAddress);
+			ALog(a, NULL, "LA_ADD_L3_TABLE", tmp, t->Name);
+
+			IncrementServerConfigRevision(s);
+		}
+
+		ReleaseL3Sw(sw);
+	}
+
+	return ret;
+}
+
+// インターフェイスの列挙
+UINT StEnumL3If(ADMIN *a, RPC_ENUM_L3IF *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+	char name[MAX_HUBNAME_LEN + 1];
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	StrCpy(name, sizeof(name), t->Name);
+
+	FreeRpcEnumL3If(t);
+	Zero(t, sizeof(RPC_ENUM_L3IF));
+
+	StrCpy(t->Name, sizeof(t->Name), name);
+
+	sw = L3GetSw(c, t->Name);
+
+	if (sw == NULL)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		Lock(sw->lock);
+		{
+			UINT i;
+
+			t->NumItem = LIST_NUM(sw->IfList);
+			t->Items = ZeroMalloc(sizeof(RPC_L3IF) * t->NumItem);
+
+			for (i = 0;i < t->NumItem;i++)
+			{
+				L3IF *f = LIST_DATA(sw->IfList, i);
+				RPC_L3IF *e = &t->Items[i];
+
+				StrCpy(e->Name, sizeof(e->Name), sw->Name);
+				StrCpy(e->HubName, sizeof(e->HubName), f->HubName);
+				e->IpAddress = f->IpAddress;
+				e->SubnetMask = f->SubnetMask;
+			}
+		}
+		Unlock(sw->lock);
+
+		ReleaseL3Sw(sw);
+	}
+
+	return ret;
+}
+
+// インターフェイスの削除
+UINT StDelL3If(ADMIN *a, RPC_L3IF *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	SERVER_ADMIN_ONLY;
+
+	sw = L3GetSw(c, t->Name);
+
+	if (sw == NULL)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		if (L3DelIf(sw, t->HubName) == false)
+		{
+			ret = ERR_LAYER3_IF_DEL_FAILED;
+		}
+		else
+		{
+			ALog(a, NULL, "LA_DEL_L3_IF", t->HubName, t->Name);
+
+			IncrementServerConfigRevision(s);
+		}
+		ReleaseL3Sw(sw);
+	}
+
+	return ret;
+}
+
+// インターフェイスの追加
+UINT StAddL3If(ADMIN *a, RPC_L3IF *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+
+	if (IsSubnetMask32(t->SubnetMask) == false || IsHostIPAddress32(t->IpAddress) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+	if ((t->IpAddress & (~t->SubnetMask)) == 0)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	SERVER_ADMIN_ONLY;
+
+	sw = L3GetSw(c, t->Name);
+
+	if (sw == NULL)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		Lock(sw->lock);
+		{
+			if (L3SearchIf(sw, t->HubName) != NULL)
+			{
+				// すでに存在する
+				ret = ERR_LAYER3_IF_EXISTS;
+			}
+			else
+			{
+				if (L3AddIf(sw, t->HubName, t->IpAddress, t->SubnetMask) == false)
+				{
+					ret = ERR_LAYER3_IF_ADD_FAILED;
+				}
+				else
+				{
+					ALog(a, NULL, "LA_ADD_L3_IF", t->HubName, t->Name);
+
+					IncrementServerConfigRevision(s);
+				}
+			}
+		}
+		Unlock(sw->lock);
+		ReleaseL3Sw(sw);
+	}
+
+	return ret;
+}
+
+// Layer-3 スイッチの停止
+UINT StStopL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	SERVER_ADMIN_ONLY;
+
+	sw = L3GetSw(c, t->Name);
+
+	if (sw == NULL)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		L3SwStop(sw);
+		ALog(a, NULL, "LA_STOP_L3_SW", sw->Name);
+		ReleaseL3Sw(sw);
+
+		IncrementServerConfigRevision(s);
+	}
+
+	return ret;
+}
+
+// Layer-3 スイッチの開始
+UINT StStartL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	SERVER_ADMIN_ONLY;
+
+	sw = L3GetSw(c, t->Name);
+
+	if (sw == NULL)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		Lock(sw->lock);
+		{
+			// 登録されているインターフェイス数を検査する
+			if (LIST_NUM(sw->IfList) >= 1)
+			{
+				L3SwStart(sw);
+
+				ALog(a, NULL, "LA_START_L3_SW", sw->Name);
+
+				IncrementServerConfigRevision(s);
+			}
+			else
+			{
+				ret = ERR_LAYER3_CANT_START_SWITCH;
+			}
+		}
+		Unlock(sw->lock);
+
+		ReleaseL3Sw(sw);
+	}
+
+	return ret;
+}
+
+// Layer-3 スイッチの列挙
+UINT StEnumL3Switch(ADMIN *a, RPC_ENUM_L3SW *t)
+{
+	UINT i;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	FreeRpcEnumL3Sw(t);
+	Zero(t, sizeof(RPC_ENUM_L3SW));
+
+	LockList(c->L3SwList);
+	{
+		t->NumItem = LIST_NUM(c->L3SwList);
+		t->Items = ZeroMalloc(sizeof(RPC_ENUM_L3SW_ITEM) * t->NumItem);
+		for (i = 0;i < LIST_NUM(c->L3SwList);i++)
+		{
+			L3SW *sw = LIST_DATA(c->L3SwList, i);
+			RPC_ENUM_L3SW_ITEM *e = &t->Items[i];
+
+			Lock(sw->lock);
+			{
+				StrCpy(e->Name, sizeof(e->Name), sw->Name);
+				e->NumInterfaces = LIST_NUM(sw->IfList);
+				e->NumTables = LIST_NUM(sw->TableList);
+				e->Active = sw->Active;
+				e->Online = sw->Online;
+			}
+			Unlock(sw->lock);
+		}
+	}
+	UnlockList(c->L3SwList);
+
+	return ret;
+}
+
+// Layer-3 スイッチの削除
+UINT StDelL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	SERVER_ADMIN_ONLY;
+
+	if (L3DelSw(c, t->Name) == false)
+	{
+		ret = ERR_LAYER3_SW_NOT_FOUND;
+	}
+	else
+	{
+		ALog(a, NULL, "LA_DEL_L3_SW", t->Name);
+
+		IncrementServerConfigRevision(s);
+	}
+
+	return ret;
+}
+
+// Layer-3 スイッチの追加
+UINT StAddL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	L3SW *sw;
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (IsSafeStr(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	// 重複チェック
+	sw = L3GetSw(c, t->Name);
+	if (sw != NULL)
+	{
+		// すでに存在する
+		ReleaseL3Sw(sw);
+		ret = ERR_LAYER3_SW_EXISTS;
+	}
+	else
+	{
+		LockList(c->L3SwList);
+		{
+			if (LIST_NUM(c->L3SwList) >= GetServerCapsInt(s, "i_max_l3_sw"))
+			{
+				// これ以上作成できない
+				sw = NULL;
+			}
+			else
+			{
+				// 作成する
+				sw = L3AddSw(c, t->Name);
+
+				if (sw != NULL)
+				{
+					ALog(a, NULL, "LA_ADD_L3_SW", t->Name);
+
+					IncrementServerConfigRevision(s);
+				}
+			}
+		}
+		UnlockList(c->L3SwList);
+
+		if (sw == NULL)
+		{
+			// 失敗
+			ret = ERR_INTERNAL_ERROR;
+		}
+		else
+		{
+			// 成功
+			ReleaseL3Sw(sw);
+		}
+	}
+
+	return ret;
+}
+
+// 仮想 HUB の拡張オプションを設定する
+UINT StSetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	bool not_server_admin = false;
+
+	if (t->NumItem > MAX_HUB_ADMIN_OPTIONS)
+	{
+		return ERR_TOO_MANT_ITEMS;
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	if (a->ServerAdmin == false)
+	{
+		not_server_admin = true;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (GetHubAdminOption(h, "deny_hub_admin_change_ext_option") && not_server_admin)
+	{
+		// 十分な管理権限が無い
+		ReleaseHub(h);
+
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	// 設定の実行
+	Lock(h->lock);
+	{
+		DataToHubOptionStruct(h->Option, t);
+	}
+	Unlock(h->lock);
+
+	ALog(a, NULL, "LA_SET_HUB_EXT_OPTION", h->Name);
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// 仮想 HUB の拡張オプションを取得する
+UINT StGetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	FreeRpcAdminOption(t);
+	Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+	StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+
+	// 設定の取得
+	Lock(h->lock);
+	{
+		HubOptionStructToData(t, h->Option, h->Name);
+	}
+	Unlock(h->lock);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// 仮想 HUB の管理オプションを設定する
+UINT StSetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+	UINT i;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	bool not_server_admin = false;
+
+	if (t->NumItem > MAX_HUB_ADMIN_OPTIONS)
+	{
+		return ERR_TOO_MANT_ITEMS;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	if (a->ServerAdmin == false)
+	{
+		not_server_admin = true;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (GetHubAdminOption(h, "allow_hub_admin_change_option") == false
+		&& not_server_admin)
+	{
+		// 十分な管理権限が無い
+		ReleaseHub(h);
+
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	LockList(h->AdminOptionList);
+	{
+		DeleteAllHubAdminOption(h, false);
+
+		for (i = 0;i < t->NumItem;i++)
+		{
+			ADMIN_OPTION *e = &t->Items[i];
+			ADMIN_OPTION *a = ZeroMalloc(sizeof(ADMIN_OPTION));
+
+			StrCpy(a->Name, sizeof(a->Name), e->Name);
+			a->Value = e->Value;
+
+			Insert(h->AdminOptionList, a);
+		}
+
+		AddHubAdminOptionsDefaults(h, false);
+	}
+	UnlockList(h->AdminOptionList);
+
+	ALog(a, NULL, "LA_SET_HUB_ADMIN_OPTION", h->Name);
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// 仮想 HUB の管理オプションを取得する
+UINT StGetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+	UINT i;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	CHECK_RIGHT;
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	FreeRpcAdminOption(t);
+	Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+	StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+
+	LockList(h->AdminOptionList);
+	{
+		t->NumItem = LIST_NUM(h->AdminOptionList);
+		t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+		for (i = 0;i < t->NumItem;i++)
+		{
+			ADMIN_OPTION *a = LIST_DATA(h->AdminOptionList, i);
+			ADMIN_OPTION *e = &t->Items[i];
+
+			StrCpy(e->Name, sizeof(e->Name), a->Name);
+			e->Value = a->Value;
+		}
+	}
+	UnlockList(h->AdminOptionList);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// デフォルトの管理オプションの一覧を取得する
+UINT StGetDefaultHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+	UINT i;
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (a->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	FreeRpcAdminOption(t);
+	Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+	t->NumItem = num_admin_options;
+	t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		ADMIN_OPTION *a = &t->Items[i];
+
+		StrCpy(a->Name, sizeof(a->Name), admin_options[i].Name);
+		a->Value = admin_options[i].Value;
+	}
+
+	return ERR_NO_ERROR;
+}
+
+// config の取得
+UINT StGetConfig(ADMIN *a, RPC_CONFIG *t)
+{
+	SERVER *s;
+
+	SERVER_ADMIN_ONLY;
+
+	FreeRpcConfig(t);
+	Zero(t, sizeof(RPC_CONFIG));
+
+	s = a->Server;
+
+	ALog(a, NULL, "LA_GET_CONFIG");
+
+	if (s->CfgRw != NULL)
+	{
+		FOLDER *f = SiWriteConfigurationToCfg(s);
+		BUF *b = CfgFolderToBuf(f, true);
+
+		StrCpy(t->FileName, sizeof(t->FileName), s->CfgRw->FileName + (s->CfgRw->FileName[0] == '@' ? 1 : 0));
+
+		t->FileData = ZeroMalloc(b->Size + 1);
+		Copy(t->FileData, b->Buf, b->Size);
+
+		CfgDeleteFolder(f);
+		FreeBuf(b);
+
+		return ERR_NO_ERROR;
+	}
+	else
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+}
+
+// config の設定
+UINT StSetConfig(ADMIN *a, RPC_CONFIG *t)
+{
+	SERVER *s;
+	IO *o;
+	char filename[MAX_PATH];
+
+	SERVER_ADMIN_ONLY;
+
+	s = a->Server;
+	if (s->CfgRw == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	// 新しい Config ファイルに書き込む
+	Format(filename, sizeof(filename), "%s.new", s->CfgRw->FileName);
+
+	o = FileCreate(filename);
+
+	FileWrite(o, t->FileData, StrLen(t->FileData));
+
+	FileClose(o);
+
+	IncrementServerConfigRevision(s);
+
+	ALog(a, NULL, "LA_SET_CONFIG");
+
+	// サーバーを再起動する
+	SiRebootServer(s->Cedar->Bridge);
+
+	return ERR_NO_ERROR;
+}
+
+// Caps の取得
+UINT StGetCaps(ADMIN *a, CAPSLIST *t)
+{
+	FreeRpcCapsList(t);
+	Zero(t, sizeof(CAPSLIST));
+
+	GetServerCapsMain(a->Server, t);
+
+	return ERR_NO_ERROR;
+}
+
+// サーバーの再起動
+UINT StRebootServer(ADMIN *a, RPC_TEST *t)
+{
+	SERVER_ADMIN_ONLY;
+
+	ALog(a, NULL, "LA_REBOOT_SERVER");
+
+	SiRebootServerEx(a->Server->Cedar->Bridge, t->IntValue);
+
+	return ERR_NO_ERROR;
+}
+
+// ローカルブリッジのサポート情報の取得
+UINT StGetBridgeSupport(ADMIN *a, RPC_BRIDGE_SUPPORT *t)
+{
+	Zero(t, sizeof(RPC_BRIDGE_SUPPORT));
+
+	t->IsBridgeSupportedOs = IsBridgeSupported();
+	t->IsWinPcapNeeded = IsNeedWinPcap();
+
+	return ERR_NO_ERROR;
+}
+
+// Ethernet デバイスの列挙
+UINT StEnumEthernet(ADMIN *a, RPC_ENUM_ETH *t)
+{
+	TOKEN_LIST *o;
+	UINT i;
+	char tmp[MAX_SIZE];
+	bool unix_support = false;
+
+	SERVER_ADMIN_ONLY;
+
+#ifdef	OS_UNIX
+	unix_support = EthIsInterfaceDescriptionSupportedUnix();
+#endif	// OS_UNIX
+
+	o = GetEthList();
+
+	FreeRpcEnumEth(t);
+	Zero(t, sizeof(RPC_ENUM_ETH));
+
+	t->NumItem = o->NumTokens;
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_ITEM) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+
+		StrCpy(e->DeviceName, sizeof(e->DeviceName), o->Token[i]);
+
+		StrCpy(tmp, sizeof(tmp), e->DeviceName);
+
+#ifdef OS_WIN32
+		GetEthNetworkConnectionName(e->NetworkConnectionName, sizeof(e->NetworkConnectionName), e->DeviceName);
+#else
+		if (unix_support == false)
+		{
+			StrCpy(tmp, sizeof(tmp), "");
+		}
+		else
+		{
+			if (EthGetInterfaceDescriptionUnix(e->DeviceName, tmp, sizeof(tmp)) == false)
+			{
+				StrCpy(tmp, sizeof(tmp), e->DeviceName);
+			}
+		}
+
+		StrToUni(e->NetworkConnectionName, sizeof(e->NetworkConnectionName), tmp);
+#endif
+	}
+
+	FreeToken(o);
+
+	return ERR_NO_ERROR;
+}
+
+// ローカルブリッジの追加
+UINT StAddLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t)
+{
+	if (IsEmptyStr(t->DeviceName) || IsEmptyStr(t->HubName))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	if (IsEthSupported() == false)
+	{
+		return ERR_LOCAL_BRIDGE_UNSUPPORTED;
+	}
+
+	ALog(a, NULL, "LA_ADD_BRIDGE", t->HubName, t->DeviceName);
+
+	AddLocalBridge(a->Server->Cedar, t->HubName, t->DeviceName, false, false, t->TapMode, NULL, false);
+
+	IncrementServerConfigRevision(a->Server);
+
+	return ERR_NO_ERROR;
+}
+
+// ローカルブリッジの削除
+UINT StDeleteLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t)
+{
+	if (IsEmptyStr(t->DeviceName) || IsEmptyStr(t->HubName))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	ALog(a, NULL, "LA_DELETE_BRIDGE", t->HubName, t->DeviceName);
+
+	if (DeleteLocalBridge(a->Server->Cedar, t->HubName, t->DeviceName) == false)
+	{
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	IncrementServerConfigRevision(a->Server);
+
+	return ERR_NO_ERROR;
+}
+
+// ローカルブリッジの列挙
+UINT StEnumLocalBridge(ADMIN *a, RPC_ENUM_LOCALBRIDGE *t)
+{
+	UINT i;
+	CEDAR *c;
+
+	if (IsEthSupported() == false)
+	{
+		return ERR_LOCAL_BRIDGE_UNSUPPORTED;
+	}
+
+	FreeRpcEnumLocalBridge(t);
+	Zero(t, sizeof(RPC_ENUM_LOCALBRIDGE));
+
+	c = a->Server->Cedar;
+
+	LockList(c->LocalBridgeList);
+	{
+		t->NumItem = LIST_NUM(c->LocalBridgeList);
+		t->Items = ZeroMalloc(sizeof(RPC_LOCALBRIDGE) * t->NumItem);
+
+		for (i = 0;i < t->NumItem;i++)
+		{
+			RPC_LOCALBRIDGE *e = &t->Items[i];
+			LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+
+			if (br->Bridge == false)
+			{
+				e->Online = e->Active = false;
+			}
+			else
+			{
+				e->Online = true;
+				if (br->Bridge->Active)
+				{
+					e->Active = true;
+				}
+				else
+				{
+					e->Active = false;
+				}
+			}
+			StrCpy(e->DeviceName, sizeof(e->DeviceName), br->DeviceName);
+			StrCpy(e->HubName, sizeof(e->HubName), br->HubName);
+
+			e->TapMode = br->TapMode;
+		}
+	}
+	UnlockList(c->LocalBridgeList);
+
+	return ERR_NO_ERROR;
+}
+
+// syslog 設定の書き込み
+UINT StSetSysLog(ADMIN *a, SYSLOG_SETTING *t)
+{
+	return ERR_NOT_SUPPORTED;
+}
+
+// syslog 設定の読み込み
+UINT StGetSysLog(ADMIN *a, SYSLOG_SETTING *t)
+{
+	return ERR_NOT_SUPPORTED;
+}
+
+// KEEP の設定
+UINT StSetKeep(ADMIN *a, RPC_KEEP *t)
+{
+	SERVER *s = a->Server;
+
+	if (t->UseKeepConnect)
+	{
+		if (IsEmptyStr(t->KeepConnectHost) ||
+			t->KeepConnectPort == 0 ||
+			t->KeepConnectPort >= 65536)
+		{
+			return ERR_INVALID_PARAMETER;
+		}
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	Lock(s->Keep->lock);
+	{
+		KEEP *keep = s->Keep;
+		keep->Enable = t->UseKeepConnect;
+		keep->Server = true;
+		StrCpy(keep->ServerName, sizeof(keep->ServerName), t->KeepConnectHost);
+		keep->ServerPort = t->KeepConnectPort;
+		keep->UdpMode = t->KeepConnectProtocol;
+		keep->Interval = t->KeepConnectInterval * 1000;
+		if (keep->Interval < 5000)
+		{
+			keep->Interval = 5000;
+		}
+		else if (keep->Interval > 600000)
+		{
+			keep->Interval = 600000;
+		}
+	}
+	Unlock(s->Keep->lock);
+
+	ALog(a, NULL, "LA_SET_KEEP");
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// KEEP の取得
+UINT StGetKeep(ADMIN *a, RPC_KEEP *t)
+{
+	SERVER *s = a->Server;
+
+	Zero(t, sizeof(RPC_KEEP));
+
+	Lock(s->Keep->lock);
+	{
+		KEEP *k = s->Keep;
+		t->UseKeepConnect = k->Enable;
+		StrCpy(t->KeepConnectHost, sizeof(t->KeepConnectHost), k->ServerName);
+		t->KeepConnectPort = k->ServerPort;
+		t->KeepConnectProtocol = k->UdpMode;
+		t->KeepConnectInterval = k->Interval / 1000;
+	}
+	Unlock(s->Keep->lock);
+
+	return ERR_NO_ERROR;
+}
+
+// IP テーブルの削除
+UINT StDeleteIpTable(ADMIN *a, RPC_DELETE_TABLE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_delete_iptable") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	LockList(h->IpTable);
+	{
+		if (IsInListKey(h->IpTable, t->Key))
+		{
+			IP_TABLE_ENTRY *e = ListKeyToPointer(h->IpTable, t->Key);
+			Free(e);
+			Delete(h->IpTable, e);
+		}
+		else
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+	}
+	UnlockList(h->IpTable);
+
+	if (ret == ERR_OBJECT_NOT_FOUND)
+	{
+		if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			UINT i;
+			LockList(s->FarmMemberList);
+			{
+				for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+				{
+					FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+					if (f->Me == false)
+					{
+						SiCallDeleteIpTable(s, f, t->HubName, t->Key);
+						ret = ERR_NO_ERROR;
+					}
+				}
+			}
+			UnlockList(s->FarmMemberList);
+		}
+	}
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// ローカル IP テーブルの列挙
+UINT SiEnumIpTable(SERVER *s, char *hubname, RPC_ENUM_IP_TABLE *t)
+{
+	CEDAR *c;
+	UINT i;
+	HUB *h = NULL;
+	// 引数チェック
+	if (s == NULL || hubname == NULL || t == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	c = s->Cedar;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, hubname);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	LockList(h->IpTable);
+	{
+		t->NumIpTable = LIST_NUM(h->IpTable);
+		t->IpTables = ZeroMalloc(sizeof(RPC_ENUM_IP_TABLE_ITEM) * t->NumIpTable);
+
+		for (i = 0;i < t->NumIpTable;i++)
+		{
+			RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+			IP_TABLE_ENTRY *table = LIST_DATA(h->IpTable, i);
+
+			e->Key = POINTER_TO_KEY(table);
+			StrCpy(e->SessionName, sizeof(e->SessionName), table->Session->Name);
+			e->Ip = IPToUINT(&table->Ip);
+			Copy(&e->IpV6, &table->Ip, sizeof(IP));
+			e->DhcpAllocated = table->DhcpAllocated;
+			e->CreatedTime = TickToTime(table->CreatedTime);
+			e->UpdatedTime = TickToTime(table->UpdatedTime);
+
+			GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+		}
+	}
+	UnlockList(h->IpTable);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// IP テーブルの列挙
+UINT StEnumIpTable(ADMIN *a, RPC_ENUM_IP_TABLE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i;
+
+	CHECK_RIGHT;
+
+	// ローカルの列挙
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	FreeRpcEnumIpTable(t);
+	Zero(t, sizeof(RPC_ENUM_IP_TABLE));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	ret = SiEnumIpTable(s, hubname, t);
+	if (ret != ERR_NO_ERROR)
+	{
+		return ret;
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// リモートの列挙
+		LockList(s->FarmMemberList);
+		{
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+				if (f->Me == false)
+				{
+					RPC_ENUM_IP_TABLE tmp;
+
+					Zero(&tmp, sizeof(tmp));
+
+					SiCallEnumIpTable(s, f, hubname, &tmp);
+
+					AdjoinRpcEnumIpTable(t, &tmp);
+					FreeRpcEnumIpTable(&tmp);
+				}
+			}
+		}
+		UnlockList(s->FarmMemberList);
+	}
+
+	return ret;
+}
+
+// MAC テーブルの削除
+UINT StDeleteMacTable(ADMIN *a, RPC_DELETE_TABLE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_delete_mactable") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	LockList(h->MacTable);
+	{
+		if (IsInListKey(h->MacTable, t->Key))
+		{
+			MAC_TABLE_ENTRY *e = ListKeyToPointer(h->MacTable, t->Key);
+			Free(e);
+			Delete(h->MacTable, e);
+		}
+		else
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+	}
+	UnlockList(h->MacTable);
+
+	if (ret == ERR_OBJECT_NOT_FOUND)
+	{
+		if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			UINT i;
+			LockList(s->FarmMemberList);
+			{
+				for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+				{
+					FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+					if (f->Me == false)
+					{
+						SiCallDeleteMacTable(s, f, t->HubName, t->Key);
+						ret = ERR_NO_ERROR;
+					}
+				}
+			}
+			UnlockList(s->FarmMemberList);
+		}
+	}
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// ローカル MAC テーブルの列挙
+UINT SiEnumMacTable(SERVER *s, char *hubname, RPC_ENUM_MAC_TABLE *t)
+{
+	CEDAR *c;
+	UINT i;
+	HUB *h = NULL;
+	// 引数チェック
+	if (s == NULL || hubname == NULL || t == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	c = s->Cedar;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, hubname);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	LockList(h->MacTable);
+	{
+		t->NumMacTable = LIST_NUM(h->MacTable);
+		t->MacTables = ZeroMalloc(sizeof(RPC_ENUM_MAC_TABLE_ITEM) * t->NumMacTable);
+
+		for (i = 0;i < t->NumMacTable;i++)
+		{
+			RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+			MAC_TABLE_ENTRY *mac = LIST_DATA(h->MacTable, i);
+
+			e->Key = POINTER_TO_KEY(mac);
+			StrCpy(e->SessionName, sizeof(e->SessionName), mac->Session->Name);
+			Copy(e->MacAddress, mac->MacAddress, sizeof(e->MacAddress));
+			e->CreatedTime = TickToTime(mac->CreatedTime);
+			e->UpdatedTime = TickToTime(mac->UpdatedTime);
+			e->VlanId = mac->VlanId;
+
+			GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+		}
+	}
+	UnlockList(h->MacTable);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// MAC テーブルの列挙
+UINT StEnumMacTable(ADMIN *a, RPC_ENUM_MAC_TABLE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i;
+
+	CHECK_RIGHT;
+
+	// ローカルの MAC テーブルを列挙する
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	FreeRpcEnumMacTable(t);
+	Zero(t, sizeof(RPC_ENUM_MAC_TABLE));
+
+	ret = SiEnumMacTable(s, hubname, t);
+	if (ret != ERR_NO_ERROR)
+	{
+		return ret;
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// リモートの MAC テーブルを列挙する
+		LockList(s->FarmMemberList);
+		{
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+				if (f->Me == false)
+				{
+					RPC_ENUM_MAC_TABLE tmp;
+
+					Zero(&tmp, sizeof(tmp));
+
+					SiCallEnumMacTable(s, f, hubname, &tmp);
+
+					AdjoinRpcEnumMacTable(t, &tmp);
+					FreeRpcEnumMacTable(&tmp);
+				}
+			}
+		}
+		UnlockList(s->FarmMemberList);
+	}
+
+	return ret;
+}
+
+// セッションの削除
+UINT StDeleteSession(ADMIN *a, RPC_DELETE_SESSION *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	char name[MAX_SESSION_NAME_LEN + 1];
+	SESSION *sess;
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	StrCpy(name, sizeof(name), t->Name);
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_disconnect_session") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	sess = GetSessionByName(h, name);
+
+	if (sess == NULL)
+	{
+		if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			// ファームコントローラ
+			UINT i;
+			LockList(s->FarmMemberList);
+			{
+				for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+				{
+					FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+					if (f->Me == false)
+					{
+						// 切断を試行
+						SiCallDeleteSession(s, f, t->HubName, t->Name);
+					}
+				}
+			}
+			UnlockList(s->FarmMemberList);
+		}
+		else
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+	}
+	else
+	{
+		if (sess->LinkModeServer)
+		{
+			ret = ERR_LINK_CANT_DISCONNECT;
+		}
+		else if (sess->SecureNATMode)
+		{
+			ret = ERR_SNAT_CANT_DISCONNECT;
+		}
+		else if (sess->BridgeMode)
+		{
+			ret = ERR_BRIDGE_CANT_DISCONNECT;
+		}
+		else if (sess->L3SwitchMode)
+		{
+			ret = ERR_LAYER3_CANT_DISCONNECT;
+		}
+		else
+		{
+			StopSession(sess);
+		}
+		ReleaseSession(sess);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		ALog(a, h, "LA_DELETE_SESSION", t->Name);
+	}
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// セッション状態の取得
+UINT StGetSessionStatus(ADMIN *a, RPC_SESSION_STATUS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	char name[MAX_SESSION_NAME_LEN + 1];
+	SESSION *sess;
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	StrCpy(name, sizeof(name), t->Name);
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_query_session") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	FreeRpcSessionStatus(t);
+	Zero(t, sizeof(RPC_SESSION_STATUS));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+	StrCpy(t->Name, sizeof(t->Name), name);
+
+	sess = GetSessionByName(h, t->Name);
+
+	if (sess == NULL)
+	{
+		if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+		{
+			// セッションが見つからない
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+		else
+		{
+			UINT i;
+			// 自分以外のメンバのセッションも検索してみる
+			LockList(s->FarmMemberList);
+			{
+				for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+				{
+					FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+					if (f->Me == false)
+					{
+						RPC_SESSION_STATUS tmp;
+						Zero(&tmp, sizeof(tmp));
+						StrCpy(tmp.HubName, sizeof(tmp.HubName), t->HubName);
+						StrCpy(tmp.Name, sizeof(tmp.Name), t->Name);
+
+						if (SiCallGetSessionStatus(s, f, &tmp))
+						{
+							if (StrLen(tmp.HubName) != 0)
+							{
+								// セッション情報の取得に成功した
+								Copy(t, &tmp, sizeof(RPC_SESSION_STATUS));
+								break;
+							}
+							else
+							{
+								FreeRpcSessionStatus(&tmp);
+							}
+						}
+					}
+				}
+
+				if (i == LIST_NUM(s->FarmMemberList))
+				{
+					// 結局見つからない
+					ret = ERR_OBJECT_NOT_FOUND;
+				}
+			}
+			UnlockList(s->FarmMemberList);
+		}
+	}
+	else
+	{
+		SESSION *s = sess;
+
+		Lock(s->lock);
+		{
+			StrCpy(t->Username, sizeof(t->Username), s->Username);
+			StrCpy(t->RealUsername, sizeof(t->RealUsername), s->UserNameReal);
+			StrCpy(t->GroupName, sizeof(t->GroupName), s->GroupName);
+			Copy(&t->NodeInfo, &s->NodeInfo, sizeof(NODE_INFO));
+
+			if (s->Connection != NULL)
+			{
+				t->ClientIp = IPToUINT(&s->Connection->ClientIp);
+				if (IsIP6(&s->Connection->ClientIp))
+				{
+					Copy(&t->ClientIp6, &s->Connection->ClientIp.ipv6_addr, sizeof(t->ClientIp6));
+				}
+
+				StrCpy(t->ClientHostName, sizeof(t->ClientHostName), s->Connection->ClientHostname);
+			}
+		}
+		Unlock(s->lock);
+
+		CiGetSessionStatus(&t->Status, s);
+
+		ReleaseSession(s);
+	}
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// セッションの列挙メイン
+void SiEnumSessionMain(SERVER *s, RPC_ENUM_SESSION *t)
+{
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT ret = ERR_NO_ERROR;
+	UINT num;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	FreeRpcEnumSession(t);
+	Zero(t, sizeof(RPC_ENUM_SESSION));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	// ローカルセッションの列挙
+	num = 0;
+	SiEnumLocalSession(s, hubname, t);
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// リモートセッションの列挙
+		LockList(s->FarmMemberList);
+		{
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+				if (f->Me == false)
+				{
+					RPC_ENUM_SESSION tmp;
+
+					Zero(&tmp, sizeof(tmp));
+
+					SiCallEnumSession(s, f, hubname, &tmp);
+
+					AdjoinRpcEnumSession(t, &tmp);
+					FreeRpcEnumSession(&tmp);
+				}
+			}
+		}
+		UnlockList(s->FarmMemberList);
+	}
+}
+
+// セッションの列挙
+UINT StEnumSession(ADMIN *a, RPC_ENUM_SESSION *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_enum_session") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	SiEnumSessionMain(s, t);
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// グループの列挙
+UINT StEnumGroup(ADMIN *a, RPC_ENUM_GROUP *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	CHECK_RIGHT;
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	AcLock(h);
+	{
+		UINT i, j;
+
+		FreeRpcEnumGroup(t);
+		Zero(t, sizeof(RPC_ENUM_GROUP));
+		StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+		t->NumGroup = LIST_NUM(h->HubDb->GroupList);
+		t->Groups = ZeroMalloc(sizeof(RPC_ENUM_GROUP_ITEM) * t->NumGroup);
+
+		for (i = 0;i < t->NumGroup;i++)
+		{
+			RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+			USERGROUP *g = LIST_DATA(h->HubDb->GroupList, i);
+
+			Lock(g->lock);
+			{
+				StrCpy(e->Name, sizeof(e->Name), g->Name);
+				UniStrCpy(e->Realname, sizeof(e->Realname), g->RealName);
+				UniStrCpy(e->Note, sizeof(e->Note), g->Note);
+				if (g->Policy != NULL)
+				{
+					if (g->Policy->Access == false)
+					{
+						e->DenyAccess = true;
+					}
+				}
+			}
+			Unlock(g->lock);
+
+			e->NumUsers = 0;
+
+
+			LockList(h->HubDb->UserList);
+			{
+				for (j = 0;j < LIST_NUM(h->HubDb->UserList);j++)
+				{
+					USER *u = LIST_DATA(h->HubDb->UserList, j);
+
+					Lock(u->lock);
+					{
+						if (u->Group == g)
+						{
+							e->NumUsers++;
+						}
+					}
+					Unlock(u->lock);
+				}
+			}
+			UnlockList(h->HubDb->UserList);
+		}
+	}
+	AcUnlock(h);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// グループの削除
+UINT StDeleteGroup(ADMIN *a, RPC_DELETE_USER *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+
+	if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CHECK_RIGHT;
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	AcLock(h);
+	{
+		if (AcDeleteGroup(h, t->Name) == false)
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+	}
+	AcUnlock(h);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		ALog(a, h, "LA_DELETE_GROUP", t->Name);
+	}
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ret;
+}
+
+// グループの取得
+UINT StGetGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	AcLock(h);
+	{
+		USERGROUP *g = AcGetGroup(h, t->Name);
+
+		if (g == NULL)
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+		else
+		{
+			FreeRpcSetGroup(t);
+			Zero(t, sizeof(RPC_SET_GROUP));
+
+			StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+			Lock(g->lock);
+			{
+				StrCpy(t->Name, sizeof(t->Name), g->Name);
+				UniStrCpy(t->Realname, sizeof(t->Realname), g->RealName);
+				UniStrCpy(t->Note, sizeof(t->Note), g->Note);
+				Copy(&t->Traffic, g->Traffic, sizeof(TRAFFIC));
+			}
+			Unlock(g->lock);
+
+			t->Policy = GetGroupPolicy(g);
+
+			ReleaseGroup(g);
+		}
+	}
+	AcUnlock(h);
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// グループの設定
+UINT StSetGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+
+	if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	AcLock(h);
+	{
+		USERGROUP *g = AcGetGroup(h, t->Name);
+		if (g == NULL)
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+		else
+		{
+			Lock(g->lock);
+			{
+				Free(g->RealName);
+				Free(g->Note);
+				g->RealName = UniCopyStr(t->Realname);
+				g->Note = UniCopyStr(t->Note);
+			}
+			Unlock(g->lock);
+
+			SetGroupPolicy(g, t->Policy);
+
+			ReleaseGroup(g);
+
+			ALog(a, h, "LA_SET_GROUP", t->Name);
+		}
+	}
+	AcUnlock(h);
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ret;
+}
+
+// グループの作成
+UINT StCreateGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+
+	if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	CHECK_RIGHT;
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	AcLock(h);
+	{
+		if (AcIsGroup(h, t->Name))
+		{
+			ret = ERR_GROUP_ALREADY_EXISTS;
+		}
+		else
+		{
+			USERGROUP *g = NewGroup(t->Name, t->Realname, t->Note);
+			SetGroupPolicy(g, t->Policy);
+
+			if ((LIST_NUM(h->HubDb->GroupList) >= GetServerCapsInt(a->Server, "i_max_users_per_hub")) ||
+				((GetHubAdminOption(h, "max_groups") != 0) && (LIST_NUM(h->HubDb->GroupList) >= GetHubAdminOption(h, "max_groups"))))
+			{
+				ret = ERR_TOO_MANY_GROUP;
+			}
+			else
+			{
+				AcAddGroup(h, g);
+			}
+
+			ReleaseGroup(g);
+
+			ALog(a, h, "LA_CREATE_GROUP", t->Name);
+		}
+	}
+	AcUnlock(h);
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ret;
+}
+
+// ユーザーの列挙
+UINT StEnumUser(ADMIN *a, RPC_ENUM_USER *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i, num;
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	FreeRpcEnumUser(t);
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	Zero(t, sizeof(RPC_ENUM_USER));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	LockList(h->HubDb->UserList);
+	{
+		num = LIST_NUM(h->HubDb->UserList);
+
+		t->NumUser = num;
+		t->Users = ZeroMalloc(sizeof(RPC_ENUM_USER_ITEM) * num);
+
+		for (i = 0;i < num;i++)
+		{
+			USER *u = LIST_DATA(h->HubDb->UserList, i);
+
+			Lock(u->lock);
+			{
+				RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+				StrCpy(e->Name, sizeof(e->Name), u->Name);
+				StrCpy(e->GroupName, sizeof(e->GroupName), u->GroupName);
+				UniStrCpy(e->Realname, sizeof(e->Realname), u->RealName);
+				UniStrCpy(e->Note, sizeof(e->Note), u->Note);
+				e->AuthType = u->AuthType;
+				e->LastLoginTime = u->LastLoginTime;
+				e->NumLogin = u->NumLogin;
+
+				if (u->Policy != NULL)
+				{
+					e->DenyAccess = u->Policy->Access ? false : true;
+				}
+			}
+			Unlock(u->lock);
+		}
+	}
+	UnlockList(h->HubDb->UserList);
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// ユーザーの削除
+UINT StDeleteUser(ADMIN *a, RPC_DELETE_USER *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+
+	if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	ALog(a, h, "LA_DELETE_USER", t->Name);
+
+	AcLock(h);
+	{
+		if (AcDeleteUser(h, t->Name) == false)
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+	}
+	AcUnlock(h);
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ret;
+}
+
+// ユーザーの取得
+UINT StGetUser(ADMIN *a, RPC_SET_USER *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	USER *u = NULL;
+	USERGROUP *g = NULL;
+	char name[MAX_USERNAME_LEN + 1];
+	char hubname[MAX_HUBNAME_LEN + 1];
+	StrCpy(name, sizeof(name), t->Name);
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	FreeRpcSetUser(t);
+	Zero(t, sizeof(RPC_SET_USER));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+	StrCpy(t->Name, sizeof(t->Name), name);
+
+	LockHubList(c);
+	{
+		h = GetHub(c, hubname);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	AcLock(h);
+	{
+		u = AcGetUser(h, name);
+		if (u == NULL)
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+		else
+		{
+			Lock(u->lock);
+			{
+				StrCpy(t->GroupName, sizeof(t->GroupName), u->GroupName);
+				UniStrCpy(t->Realname, sizeof(t->Realname), u->RealName);
+				UniStrCpy(t->Note, sizeof(t->Note), u->Note);
+				t->CreatedTime = u->CreatedTime;
+				t->UpdatedTime = u->UpdatedTime;
+				t->ExpireTime = u->ExpireTime;
+
+				t->AuthType = u->AuthType;
+				t->AuthData = CopyAuthData(u->AuthData, t->AuthType);
+				t->NumLogin = u->NumLogin;
+				Copy(&t->Traffic, u->Traffic, sizeof(TRAFFIC));
+				if (u->Policy != NULL)
+				{
+					t->Policy = ClonePolicy(u->Policy);
+				}
+			}
+			Unlock(u->lock);
+
+			ReleaseUser(u);
+		}
+	}
+	AcUnlock(h);
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// ユーザーの設定
+UINT StSetUser(ADMIN *a, RPC_SET_USER *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	USER *u = NULL;
+	USERGROUP *g = NULL;
+
+	if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	if (StrCmpi(t->Name, "*") == 0)
+	{
+		if (t->AuthType != AUTHTYPE_RADIUS && t->AuthType != AUTHTYPE_NT)
+		{
+			return ERR_INVALID_PARAMETER;
+		}
+	}
+
+	if (t->AuthType == AUTHTYPE_RADIUS ||
+		t->AuthType == AUTHTYPE_ROOTCERT ||
+		t->AuthType == AUTHTYPE_USERCERT ||
+		t->AuthType == AUTHTYPE_NT)
+	{
+		return ERR_UTVPN_NOT_SUPPORT_THIS_AUTH;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	AcLock(h);
+	{
+		u = AcGetUser(h, t->Name);
+		if (u == NULL)
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+		else
+		{
+			Lock(u->lock);
+			{
+				if (StrLen(t->GroupName) != 0)
+				{
+					g = AcGetGroup(h, t->GroupName);
+
+					if (g != NULL)
+					{
+						JoinUserToGroup(u, g);
+						ReleaseGroup(g);
+					}
+					else
+					{
+						ret = ERR_GROUP_NOT_FOUND;
+					}
+				}
+				else
+				{
+					JoinUserToGroup(u, NULL);
+				}
+
+				if (ret != ERR_GROUP_NOT_FOUND)
+				{
+					Free(u->RealName);
+					Free(u->Note);
+					u->RealName = UniCopyStr(t->Realname);
+					u->Note = UniCopyStr(t->Note);
+					SetUserAuthData(u, t->AuthType, CopyAuthData(t->AuthData, t->AuthType));
+					u->ExpireTime = t->ExpireTime;
+					u->UpdatedTime = SystemTime64();
+
+					SetUserPolicy(u, t->Policy);
+				}
+			}
+			Unlock(u->lock);
+
+			IncrementServerConfigRevision(s);
+
+			ReleaseUser(u);
+		}
+	}
+	AcUnlock(h);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		ALog(a, h, "LA_SET_USER", t->Name);
+	}
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// ユーザーの作成
+UINT StCreateUser(ADMIN *a, RPC_SET_USER *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+	UINT ret = ERR_NO_ERROR;
+	USER *u;
+	USERGROUP *g = NULL;
+
+	if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	if (t->AuthType == AUTHTYPE_RADIUS ||
+		t->AuthType == AUTHTYPE_ROOTCERT ||
+		t->AuthType == AUTHTYPE_USERCERT ||
+		t->AuthType == AUTHTYPE_NT)
+	{
+		return ERR_UTVPN_NOT_SUPPORT_THIS_AUTH;
+	}
+
+	if (IsUserName(t->Name) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (StrCmpi(t->Name, "*") == 0)
+	{
+		if (t->AuthType != AUTHTYPE_RADIUS && t->AuthType != AUTHTYPE_NT)
+		{
+			return ERR_INVALID_PARAMETER;
+		}
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	u = NewUser(t->Name, t->Realname, t->Note, t->AuthType, CopyAuthData(t->AuthData, t->AuthType));
+	if (u == NULL)
+	{
+		ReleaseHub(h);
+		return ERR_INTERNAL_ERROR;
+	}
+
+	u->ExpireTime = t->ExpireTime;
+
+	SetUserPolicy(u, t->Policy);
+
+	AcLock(h);
+	{
+		if ((LIST_NUM(h->HubDb->UserList) >= GetServerCapsInt(a->Server, "i_max_users_per_hub")) ||
+			((GetHubAdminOption(h, "max_users") != 0) && (LIST_NUM(h->HubDb->UserList) >= GetHubAdminOption(h, "max_users"))))
+		{
+			ret = ERR_TOO_MANY_USER;
+		}
+		else if (SiTooManyUserObjectsInServer(s, false))
+		{
+			ret = ERR_TOO_MANY_USERS_CREATED;
+			ALog(a, h, "ERR_128");
+		}
+		else if (AcIsUser(h, t->Name))
+		{
+			ret = ERR_USER_ALREADY_EXISTS;
+		}
+		else
+		{
+			if (StrLen(t->GroupName) != 0)
+			{
+				g = AcGetGroup(h, t->GroupName);
+				if (g == NULL)
+				{
+					ret = ERR_GROUP_NOT_FOUND;
+				}
+			}
+
+			if (ret != ERR_GROUP_NOT_FOUND)
+			{
+				if (g != NULL)
+				{
+					JoinUserToGroup(u, g);
+					ReleaseGroup(g);
+				}
+
+				AcAddUser(h, u);
+				ALog(a, h, "LA_CREATE_USER", t->Name);
+
+				IncrementServerConfigRevision(s);
+			}
+		}
+	}
+	AcUnlock(h);
+
+	ReleaseUser(u);
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// アクセスリストの列挙
+UINT StEnumAccess(ADMIN *a, RPC_ENUM_ACCESS_LIST *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT i;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	FreeRpcEnumAccessList(t);
+	Zero(t, sizeof(RPC_ENUM_ACCESS_LIST));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	LockList(h->AccessList);
+	{
+		t->NumAccess = LIST_NUM(h->AccessList);
+		t->Accesses = ZeroMalloc(sizeof(ACCESS) * t->NumAccess);
+
+		for (i = 0;i < LIST_NUM(h->AccessList);i++)
+		{
+			ACCESS *a = &t->Accesses[i];
+			Copy(a, LIST_DATA(h->AccessList, i), sizeof(ACCESS));
+		}
+	}
+	UnlockList(h->AccessList);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// アクセスリストの削除
+UINT StDeleteAccess(ADMIN *a, RPC_DELETE_ACCESS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT i;
+	bool exists;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	exists = false;
+
+	LockList(h->AccessList);
+	{
+		for (i = 0;i < LIST_NUM(h->AccessList);i++)
+		{
+			ACCESS *access = LIST_DATA(h->AccessList, i);
+
+			if (access->Id == t->Id)
+			{
+				Free(access);
+				Delete(h->AccessList, access);
+				exists = true;
+
+				break;
+			}
+		}
+	}
+	UnlockList(h->AccessList);
+
+	if (exists == false)
+	{
+		ReleaseHub(h);
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	ALog(a, h, "LA_DELETE_ACCESS");
+
+	IncrementServerConfigRevision(s);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// アクセスリストの設定
+UINT StSetAccessList(ADMIN *a, RPC_ENUM_ACCESS_LIST *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT i;
+	bool no_jitter = false;
+	UINT ret = ERR_NO_ERROR;
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	if (t->NumAccess > GetServerCapsInt(a->Server, "i_max_access_lists"))
+	{
+		return ERR_TOO_MANY_ACCESS_LIST;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	no_jitter = GetHubAdminOption(h, "no_delay_jitter_packet_loss");
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "max_accesslists") != 0 &&
+		t->NumAccess > GetHubAdminOption(h, "max_accesslists"))
+	{
+		ReleaseHub(h);
+		return ERR_TOO_MANY_ACCESS_LIST;
+	}
+
+	LockList(h->AccessList);
+	{
+		UINT i;
+
+		// 古いバージョンのクライアントで対応できない形式のアクセスリストがすでに
+		// 存在しないかどうかチェックする
+		if (a->ClientBuild < 6560)
+		{
+			for (i = 0;i < LIST_NUM(h->AccessList);i++)
+			{
+				ACCESS *access = LIST_DATA(h->AccessList, i);
+				if (access->IsIPv6 ||
+					access->Jitter != 0 || access->Loss != 0 || access->Delay != 0)
+				{
+					ret = ERR_VERSION_INVALID;
+					break;
+				}
+			}
+		}
+
+		if (ret == ERR_NO_ERROR)
+		{
+			// すべて削除
+			for (i = 0;i < LIST_NUM(h->AccessList);i++)
+			{
+				ACCESS *access = LIST_DATA(h->AccessList, i);
+				Free(access);
+			}
+
+			DeleteAll(h->AccessList);
+		}
+	}
+	UnlockList(h->AccessList);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		ALog(a, h, "LA_SET_ACCESS_LIST", t->NumAccess);
+
+		// すべてのアクセスリストを追加
+		for (i = 0;i < t->NumAccess;i++)
+		{
+			ACCESS *a = &t->Accesses[i];
+
+			if (no_jitter)
+			{
+				a->Jitter = a->Loss = a->Delay = 0;
+			}
+
+			AddAccessList(h, a);
+		}
+
+		IncrementServerConfigRevision(s);
+
+		h->CurrentVersion++;
+		SiHubUpdateProc(h);
+	}
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// アクセスリストの追加
+UINT StAddAccess(ADMIN *a, RPC_ADD_ACCESS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	bool no_jitter = false;
+
+	NO_SUPPORT_FOR_BRIDGE;
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	no_jitter = GetHubAdminOption(h, "no_delay_jitter_packet_loss");
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	if ((LIST_NUM(h->AccessList) >= GetServerCapsInt(a->Server, "i_max_access_lists") ||
+		(GetHubAdminOption(h, "max_accesslists") != 0) && (LIST_NUM(h->AccessList) >= GetHubAdminOption(h, "max_accesslists"))))
+	{
+		ReleaseHub(h);
+		return ERR_TOO_MANY_ACCESS_LIST;
+	}
+
+	ALog(a, h, "LA_ADD_ACCESS");
+
+	if (no_jitter)
+	{
+		t->Access.Jitter = t->Access.Delay = t->Access.Loss = 0;
+	}
+
+	AddAccessList(h, &t->Access);
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// リンクの名前を変更する
+UINT StRenameLink(ADMIN *a, RPC_RENAME_LINK *t)
+{
+	UINT i;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	LINK *k;
+	bool exists = false;
+
+	if (UniIsEmptyStr(t->OldAccountName) || UniIsEmptyStr(t->NewAccountName))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	if (UniStrCmpi(t->NewAccountName, t->OldAccountName) == 0)
+	{
+		// 古い名前と新しい名前が同一
+		return ERR_NO_ERROR;
+	}
+
+	h = GetHub(c, t->HubName);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	k = NULL;
+
+	// リンクを検索する
+	LockList(h->LinkList);
+	{
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *kk = LIST_DATA(h->LinkList, i);
+			Lock(kk->lock);
+			{
+				if (UniStrCmpi(kk->Option->AccountName, t->OldAccountName) == 0)
+				{
+					k = kk;
+					AddRef(kk->ref);
+				}
+			}
+			Unlock(kk->lock);
+
+			if (k != NULL)
+			{
+				break;
+			}
+		}
+
+		exists = false;
+
+		if (k != NULL)
+		{
+			// 新しい名前がすでに存在しているリンクの名前と重複するかどうか検査
+			for (i = 0;i < LIST_NUM(h->LinkList);i++)
+			{
+				LINK *kk = LIST_DATA(h->LinkList, i);
+				Lock(kk->lock);
+				{
+					if (UniStrCmpi(kk->Option->AccountName, t->NewAccountName) == 0)
+					{
+						// 重複した
+						exists = true;
+					}
+				}
+				Unlock(kk->lock);
+			}
+
+			if (exists)
+			{
+				// すでに同一の名前が存在している
+				ret = ERR_LINK_ALREADY_EXISTS;
+			}
+			else
+			{
+				// 変更作業を実施する
+				UniStrCpy(k->Option->AccountName, sizeof(k->Option->AccountName), t->NewAccountName);
+
+				ALog(a, h, "LA_RENAME_LINK", t->OldAccountName, t->NewAccountName);
+
+				IncrementServerConfigRevision(s);
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+
+	if (k == NULL)
+	{
+		// リンクが見つからない
+		ReleaseHub(h);
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	ReleaseLink(k);
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// リンクを削除する
+UINT StDeleteLink(ADMIN *a, RPC_LINK *t)
+{
+	UINT i;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+	LINK *k;
+
+	if (UniIsEmptyStr(t->AccountName))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+	k = NULL;
+
+	// リンクを検索する
+	LockList(h->LinkList);
+	{
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *kk = LIST_DATA(h->LinkList, i);
+			Lock(kk->lock);
+			{
+				if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+				{
+					k = kk;
+					AddRef(kk->ref);
+				}
+			}
+			Unlock(kk->lock);
+
+			if (k != NULL)
+			{
+				break;
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+
+	if (k == NULL)
+	{
+		// リンクが見つからない
+		ReleaseHub(h);
+
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	ALog(a, h, "LA_DELETE_LINK", t->AccountName);
+
+	SetLinkOffline(k);
+
+	IncrementServerConfigRevision(s);
+
+	DelLink(h, k);
+
+	ReleaseLink(k);
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// リンクをオフラインにする
+UINT StSetLinkOffline(ADMIN *a, RPC_LINK *t)
+{
+	UINT i;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+	LINK *k;
+
+	if (UniIsEmptyStr(t->AccountName))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+	k = NULL;
+
+	// リンクを検索する
+	LockList(h->LinkList);
+	{
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *kk = LIST_DATA(h->LinkList, i);
+			Lock(kk->lock);
+			{
+				if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+				{
+					k = kk;
+					AddRef(kk->ref);
+				}
+			}
+			Unlock(kk->lock);
+
+			if (k != NULL)
+			{
+				break;
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+
+	if (k == NULL)
+	{
+		// リンクが見つからない
+		ReleaseHub(h);
+
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	ALog(a, h, "LA_SET_LINK_OFFLINE", t->AccountName);
+
+	SetLinkOffline(k);
+
+	IncrementServerConfigRevision(s);
+
+	ReleaseLink(k);
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// リンクをオンラインにする
+UINT StSetLinkOnline(ADMIN *a, RPC_LINK *t)
+{
+	UINT i;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+	LINK *k;
+
+	if (UniIsEmptyStr(t->AccountName))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+	k = NULL;
+
+	// リンクを検索する
+	LockList(h->LinkList);
+	{
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *kk = LIST_DATA(h->LinkList, i);
+			Lock(kk->lock);
+			{
+				if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+				{
+					k = kk;
+					AddRef(kk->ref);
+				}
+			}
+			Unlock(kk->lock);
+
+			if (k != NULL)
+			{
+				break;
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+
+	if (k == NULL)
+	{
+		// リンクが見つからない
+		ReleaseHub(h);
+
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	ALog(a, h, "LA_SET_LINK_ONLINE", t->AccountName);
+
+	SetLinkOnline(k);
+
+	ReleaseLink(k);
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ret;
+}
+
+// リンク状態の取得
+UINT StGetLinkStatus(ADMIN *a, RPC_LINK_STATUS *t)
+{
+	UINT i;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+	LINK *k;
+	SESSION *sess;
+
+	if (UniIsEmptyStr(t->AccountName))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+	FreeRpcLinkStatus(t);
+	Zero(t, sizeof(RPC_LINK_STATUS));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+	UniStrCpy(t->AccountName, sizeof(t->AccountName), accountname);
+
+	k = NULL;
+
+	// リンクを検索する
+	LockList(h->LinkList);
+	{
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *kk = LIST_DATA(h->LinkList, i);
+			Lock(kk->lock);
+			{
+				if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+				{
+					k = kk;
+					AddRef(kk->ref);
+				}
+			}
+			Unlock(kk->lock);
+
+			if (k != NULL)
+			{
+				break;
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+
+	if (k == NULL)
+	{
+		// リンクが見つからない
+		ReleaseHub(h);
+
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	// セッションからステータス情報を取得する
+	Lock(k->lock);
+	{
+		sess = k->ClientSession;
+		if (sess != NULL)
+		{
+			AddRef(sess->ref);
+		}
+	}
+	Unlock(k->lock);
+
+	if (sess != NULL && k->Offline == false)
+	{
+		CiGetSessionStatus(&t->Status, sess);
+	}
+	else
+	{
+		ret = ERR_LINK_IS_OFFLINE;
+	}
+	ReleaseSession(sess);
+
+	ReleaseLink(k);
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// リンクの列挙
+UINT StEnumLink(ADMIN *a, RPC_ENUM_LINK *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i;
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	FreeRpcEnumLink(t);
+	Zero(t, sizeof(RPC_ENUM_LINK));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	LockList(h->LinkList);
+	{
+		t->NumLink = LIST_NUM(h->LinkList);
+		t->Links = ZeroMalloc(sizeof(RPC_ENUM_LINK_ITEM) * t->NumLink);
+
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *k = LIST_DATA(h->LinkList, i);
+			RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+			Lock(k->lock);
+			{
+				UniStrCpy(e->AccountName, sizeof(e->AccountName), k->Option->AccountName);
+				StrCpy(e->Hostname, sizeof(e->Hostname), k->Option->Hostname);
+				StrCpy(e->HubName, sizeof(e->HubName), k->Option->HubName);
+				e->Online = k->Offline ? false : true;
+
+				if (e->Online)
+				{
+					if (k->ClientSession != NULL)
+					{
+						e->ConnectedTime = TickToTime(k->ClientSession->CurrentConnectionEstablishTime);
+						e->Connected = (k->ClientSession->ClientStatus == CLIENT_STATUS_ESTABLISHED);
+						e->LastError = k->ClientSession->Err;
+					}
+				}
+			}
+			Unlock(k->lock);
+		}
+	}
+	UnlockList(h->LinkList);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// リンクの取得
+UINT StGetLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	UINT i;
+	char hubname[MAX_SIZE];
+	LINK *k;
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_LINK_CANT_CREATE_ON_FARM;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	k = NULL;
+
+	// リンクを検索する
+	LockList(h->LinkList);
+	{
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *kk = LIST_DATA(h->LinkList, i);
+			Lock(kk->lock);
+			{
+				if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+				{
+					k = kk;
+					AddRef(kk->ref);
+				}
+			}
+			Unlock(kk->lock);
+
+			if (k != NULL)
+			{
+				break;
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+
+	if (k == NULL)
+	{
+		// 見つからなかった
+		ReleaseHub(h);
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	FreeRpcCreateLink(t);
+	Zero(t, sizeof(t));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	Lock(k->lock);
+	{
+		// 設定の取得
+		t->Online = k->Offline ? false : true;
+		t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		Copy(t->ClientOption, k->Option, sizeof(CLIENT_OPTION));
+		t->ClientAuth = CopyClientAuth(k->Auth);
+		Copy(&t->Policy, k->Policy, sizeof(POLICY));
+
+		t->CheckServerCert = k->CheckServerCert;
+		t->ServerCert = CloneX(k->ServerCert);
+	}
+	Unlock(k->lock);
+
+	ReleaseLink(k);
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// リンクの設定
+UINT StSetLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	UINT i;
+	LINK *k;
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_LINK_CANT_CREATE_ON_FARM;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	k = NULL;
+
+	// リンクを検索する
+	LockList(h->LinkList);
+	{
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *kk = LIST_DATA(h->LinkList, i);
+			Lock(kk->lock);
+			{
+				if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+				{
+					k = kk;
+					AddRef(kk->ref);
+				}
+			}
+			Unlock(kk->lock);
+
+			if (k != NULL)
+			{
+				break;
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+
+	if (k == NULL)
+	{
+		// 見つからなかった
+		ReleaseHub(h);
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	ALog(a, h, "LA_SET_LINK", t->ClientOption->AccountName);
+
+	Lock(k->lock);
+	{
+		// 設定の更新
+		if (k->ServerCert != NULL)
+		{
+			FreeX(k->ServerCert);
+			k->ServerCert = NULL;
+		}
+
+		Copy(k->Option, t->ClientOption, sizeof(CLIENT_OPTION));
+		StrCpy(k->Option->DeviceName, sizeof(k->Option->DeviceName), LINK_DEVICE_NAME);
+		k->Option->NumRetry = INFINITE;
+		k->Option->RetryInterval = 10;
+		k->Option->NoRoutingTracking = true;
+		CiFreeClientAuth(k->Auth);
+		k->Auth = CopyClientAuth(t->ClientAuth);
+
+		if (t->Policy.Ver3 == false)
+		{
+			Copy(k->Policy, &t->Policy, sizeof(UINT) * NUM_POLICY_ITEM_FOR_VER2);
+		}
+		else
+		{
+			Copy(k->Policy, &t->Policy, sizeof(POLICY));
+		}
+
+		k->Option->RequireBridgeRoutingMode = true;	// ブリッジ / ルーティングモード有効
+		k->Option->RequireMonitorMode = false;	// モニタモード無効
+
+		k->CheckServerCert = t->CheckServerCert;
+		k->ServerCert = CloneX(t->ServerCert);
+	}
+	Unlock(k->lock);
+
+	IncrementServerConfigRevision(s);
+
+	ReleaseLink(k);
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// リンクの作成
+UINT StCreateLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	UINT i;
+	LINK *k;
+
+	CHECK_RIGHT;
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		return ERR_LINK_CANT_CREATE_ON_FARM;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	k = NULL;
+
+	// 既に同じ名前のリンクが存在しないかどうか調べる
+	LockList(h->LinkList);
+	{
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *kk = LIST_DATA(h->LinkList, i);
+			Lock(kk->lock);
+			{
+				if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+				{
+					k = kk;
+					AddRef(kk->ref);
+				}
+			}
+			Unlock(kk->lock);
+
+			if (k != NULL)
+			{
+				break;
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+
+	if (k != NULL)
+	{
+		// すでに同じ名前のリンクが存在する
+		ReleaseLink(k);
+		ReleaseHub(h);
+		return ERR_LINK_ALREADY_EXISTS;
+	}
+
+	ALog(a, h, "LA_CREATE_LINK", t->ClientOption->AccountName);
+
+	// リンクの作成
+	k = NewLink(c, h, t->ClientOption, t->ClientAuth, &t->Policy);
+
+	if (k == NULL)
+	{
+		// 作成失敗
+		ret = ERR_INTERNAL_ERROR;
+	}
+	else
+	{
+		// サーバー証明書検証設定
+		k->CheckServerCert = t->CheckServerCert;
+		k->ServerCert = CloneX(t->ServerCert);
+
+		// オフラインにしておく
+		k->Offline = false;
+		SetLinkOffline(k);
+		ReleaseLink(k);
+
+		IncrementServerConfigRevision(s);
+	}
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// HUB の CA を削除
+UINT StDeleteCa(ADMIN *a, RPC_HUB_DELETE_CA *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_cert_list") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	LockList(h->HubDb->RootCertList);
+	{
+		if (IsInListKey(h->HubDb->RootCertList, t->Key))
+		{
+			X *x = ListKeyToPointer(h->HubDb->RootCertList, t->Key);
+			Delete(h->HubDb->RootCertList, x);
+			FreeX(x);
+
+			ALog(a, h, "LA_DELETE_CA");
+
+			IncrementServerConfigRevision(s);
+		}
+		else
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+	}
+	UnlockList(h->HubDb->RootCertList);
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// HUB の CA を取得
+UINT StGetCa(ADMIN *a, RPC_HUB_GET_CA *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT key;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+	key = t->Key;
+
+	FreeRpcHubGetCa(t);
+	Zero(t, sizeof(RPC_HUB_GET_CA));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	LockList(h->HubDb->RootCertList);
+	{
+		if (IsInListKey(h->HubDb->RootCertList, key))
+		{
+			X *x = ListKeyToPointer(h->HubDb->RootCertList, key);
+
+			t->Cert = CloneX(x);
+		}
+		else
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+	}
+	UnlockList(h->HubDb->RootCertList);
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// HUB の CA を列挙
+UINT StEnumCa(ADMIN *a, RPC_HUB_ENUM_CA *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	FreeRpcHubEnumCa(t);
+	Zero(t, sizeof(RPC_HUB_ENUM_CA));
+
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, hubname);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	Zero(t, sizeof(RPC_HUB_ENUM_CA));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+	if (h->HubDb->RootCertList != NULL)
+	{
+		LockList(h->HubDb->RootCertList);
+		{
+			t->NumCa = LIST_NUM(h->HubDb->RootCertList);
+			t->Ca = ZeroMalloc(sizeof(RPC_HUB_ENUM_CA_ITEM) * t->NumCa);
+
+			for (i = 0;i < t->NumCa;i++)
+			{
+				RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+				X *x = LIST_DATA(h->HubDb->RootCertList, i);
+
+				e->Key = POINTER_TO_KEY(x);
+				GetAllNameFromNameEx(e->SubjectName, sizeof(e->SubjectName), x->subject_name);
+				GetAllNameFromNameEx(e->IssuerName, sizeof(e->IssuerName), x->issuer_name);
+				e->Expires = x->notAfter;
+			}
+		}
+		UnlockList(h->HubDb->RootCertList);
+	}
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB へ CA を追加
+UINT StAddCa(ADMIN *a, RPC_HUB_ADD_CA *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (c->Bridge)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	if (t->Cert == NULL)
+	{
+		ERR_INVALID_PARAMETER;
+	}
+
+	if (t->Cert->is_compatible_bit == false)
+	{
+		return ERR_NOT_RSA_1024;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_cert_list") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	IncrementServerConfigRevision(s);
+
+	ALog(a, h, "LA_ADD_CA");
+
+	AddRootCert(h, t->Cert);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB ログ設定の取得
+UINT StGetHubLog(ADMIN *a, RPC_HUB_LOG *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	GetHubLogSetting(h, &t->LogSetting);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB ログ設定の設定
+UINT StSetHubLog(ADMIN *a, RPC_HUB_LOG *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_log_config") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	ALog(a, h, "LA_SET_HUB_LOG");
+
+	SetHubLogSettingEx(h, &t->LogSetting,
+		(a->ServerAdmin == false && GetHubAdminOption(h, "no_change_log_switch_type") != 0));
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB 状態の取得
+UINT StGetHubStatus(ADMIN *a, RPC_HUB_STATUS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	Zero(t, sizeof(RPC_HUB_STATUS));
+
+	Lock(h->lock);
+	{
+		StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+		t->HubType = h->Type;
+		t->Online = h->Offline ? false : true;
+		t->NumSessions = LIST_NUM(h->SessionList);
+		t->NumSessionsClient = Count(h->NumSessionsClient);
+		t->NumSessionsBridge = Count(h->NumSessionsBridge);
+		t->NumAccessLists = LIST_NUM(h->AccessList);
+
+		if (h->HubDb != NULL)
+		{
+			t->NumUsers = LIST_NUM(h->HubDb->UserList);
+			t->NumGroups = LIST_NUM(h->HubDb->GroupList);
+		}
+
+		t->NumMacTables = LIST_NUM(h->MacTable);
+		t->NumIpTables = LIST_NUM(h->IpTable);
+
+		Lock(h->TrafficLock);
+		{
+			Copy(&t->Traffic, h->Traffic, sizeof(TRAFFIC));
+		}
+		Unlock(h->TrafficLock);
+
+		t->NumLogin = h->NumLogin;
+		t->LastCommTime = h->LastCommTime;
+		t->LastLoginTime = h->LastLoginTime;
+		t->CreatedTime = h->CreatedTime;
+	}
+	Unlock(h->lock);
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		UINT i;
+		LockList(s->FarmMemberList);
+		{
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				UINT k;
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+				if (f->Me == false)
+				{
+					LockList(f->HubList);
+					{
+						for (k = 0;k < LIST_NUM(f->HubList);k++)
+						{
+							HUB_LIST *h = LIST_DATA(f->HubList, k);
+
+							if (StrCmpi(h->Name, t->HubName) == 0)
+							{
+								t->NumSessions += h->NumSessions;
+								t->NumSessionsClient += h->NumSessionsClient;
+								t->NumSessionsBridge += h->NumSessionsBridge;
+								t->NumMacTables += h->NumMacTables;
+								t->NumIpTables += h->NumIpTables;
+							}
+						}
+					}
+					UnlockList(f->HubList);
+				}
+			}
+		}
+		UnlockList(s->FarmMemberList);
+	}
+
+	if (h->Type != HUB_TYPE_FARM_STATIC)
+	{
+		t->SecureNATEnabled = h->EnableSecureNAT;
+	}
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB の SecureNAT を有効にする
+UINT StEnableSecureNAT(ADMIN *a, RPC_HUB *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_SUPPORTED;
+	}
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	ALog(a, h, "LA_ENABLE_SNAT");
+
+	EnableSecureNAT(h, true);
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	IncrementServerConfigRevision(s);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB の SecureNAT を無効にする
+UINT StDisableSecureNAT(ADMIN *a, RPC_HUB *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_SUPPORTED;
+	}
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	ALog(a, h, "LA_DISABLE_SNAT");
+
+	EnableSecureNAT(h, false);
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	IncrementServerConfigRevision(s);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// NAT エントリの列挙
+UINT StEnumNAT(ADMIN *a, RPC_ENUM_NAT *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i;
+
+	CHECK_RIGHT;
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_SUPPORTED;
+	}
+
+	Lock(h->lock_online);
+	{
+		if (h->SecureNAT == NULL)
+		{
+			ret = ERR_SNAT_NOT_RUNNING;
+		}
+		else
+		{
+			NtEnumNatList(h->SecureNAT->Nat, t);
+		}
+	}
+	Unlock(h->lock_online);
+
+	if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+	{
+		if (ret == ERR_SNAT_NOT_RUNNING)
+		{
+			// リモートの SecureNAT の状態取得
+			LockList(s->FarmMemberList);
+			{
+				for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+				{
+					FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+					if (f->Me == false)
+					{
+						RPC_ENUM_NAT tmp;
+
+						Zero(&tmp, sizeof(tmp));
+
+						SiCallEnumNat(s, f, hubname, &tmp);
+
+						if (tmp.NumItem >= 1)
+						{
+							FreeRpcEnumNat(t);
+							Copy(t, &tmp, sizeof(RPC_ENUM_NAT));
+							ret = ERR_NO_ERROR;
+							break;
+						}
+						else
+						{
+							FreeRpcEnumNat(&tmp);
+						}
+					}
+				}
+			}
+			UnlockList(s->FarmMemberList);
+		}
+	}
+
+	ReleaseHub(h);
+
+	ret = ERR_NO_ERROR;
+
+	return ret;
+}
+
+// SecureNAT の状態の取得
+UINT StGetSecureNATStatus(ADMIN *a, RPC_NAT_STATUS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i;
+
+	CHECK_RIGHT;
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_SUPPORTED;
+	}
+
+	Lock(h->lock_online);
+	{
+		if (h->SecureNAT == NULL)
+		{
+			ret = ERR_SNAT_NOT_RUNNING;
+		}
+		else
+		{
+			NtGetStatus(h->SecureNAT->Nat, t);
+		}
+	}
+	Unlock(h->lock_online);
+
+	if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+	{
+		if (ret == ERR_SNAT_NOT_RUNNING)
+		{
+			// リモートの SecureNAT の状態取得
+			LockList(s->FarmMemberList);
+			{
+				for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+				{
+					FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+					if (f->Me == false)
+					{
+						RPC_NAT_STATUS tmp;
+
+						Zero(&tmp, sizeof(tmp));
+
+						SiCallGetNatStatus(s, f, hubname, &tmp);
+
+						if (tmp.NumDhcpClients == 0 && tmp.NumTcpSessions == 0 && tmp.NumUdpSessions == 0)
+						{
+						}
+						else
+						{
+							Copy(t, &tmp, sizeof(RPC_NAT_STATUS));
+							ret = ERR_NO_ERROR;
+							break;
+						}
+					}
+				}
+			}
+			UnlockList(s->FarmMemberList);
+		}
+	}
+
+	ReleaseHub(h);
+
+	ret = ERR_NO_ERROR;
+
+	return ret;
+}
+
+// DHCP エントリの列挙
+UINT StEnumDHCP(ADMIN *a, RPC_ENUM_DHCP *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i;
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_SUPPORTED;
+	}
+
+	Lock(h->lock_online);
+	{
+		if (h->SecureNAT == NULL)
+		{
+			ret = ERR_SNAT_NOT_RUNNING;
+		}
+		else
+		{
+			NtEnumDhcpList(h->SecureNAT->Nat, t);
+		}
+	}
+	Unlock(h->lock_online);
+
+	if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+	{
+		if (ret == ERR_SNAT_NOT_RUNNING)
+		{
+			// リモートの DHCP の状態取得
+			LockList(s->FarmMemberList);
+			{
+				for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+				{
+					FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+					if (f->Me == false)
+					{
+						RPC_ENUM_DHCP tmp;
+
+						Zero(&tmp, sizeof(tmp));
+
+						SiCallEnumDhcp(s, f, hubname, &tmp);
+
+						if (tmp.NumItem >= 1)
+						{
+							FreeRpcEnumDhcp(t);
+							Copy(t, &tmp, sizeof(RPC_ENUM_DHCP));
+							ret = ERR_NO_ERROR;
+							break;
+						}
+						else
+						{
+							FreeRpcEnumDhcp(&tmp);
+						}
+					}
+				}
+			}
+			UnlockList(s->FarmMemberList);
+		}
+	}
+
+	ReleaseHub(h);
+
+	ret = ERR_NO_ERROR;
+
+	return ret;
+}
+
+// SecureNATOption を設定する
+UINT StSetSecureNATOption(ADMIN *a, VH_OPTION *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	if (IsZero(t->MacAddress, sizeof(t->MacAddress)) ||
+		IsHostIPAddress4(&t->Ip) == false ||
+		IsSubnetMask4(&t->Mask) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+	if ((IPToUINT(&t->Ip) & (~(IPToUINT(&t->Mask)))) == 0)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_SUPPORTED;
+	}
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	if (h->SecureNATOption->UseNat == false && t->UseNat)
+	{
+		if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat_enablenat") != 0)
+		{
+			ReleaseHub(h);
+			return ERR_NOT_ENOUGH_RIGHT;
+		}
+	}
+
+	if (h->SecureNATOption->UseDhcp == false && t->UseDhcp)
+	{
+		if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat_enabledhcp") != 0)
+		{
+			ReleaseHub(h);
+			return ERR_NOT_ENOUGH_RIGHT;
+		}
+	}
+
+	Copy(h->SecureNATOption, t, sizeof(VH_OPTION));
+
+	if (h->Type != HUB_TYPE_STANDALONE && h->Cedar != NULL && h->Cedar->Server != NULL &&
+		h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption, false);
+	}
+
+	Lock(h->lock_online);
+	{
+		if (h->SecureNAT != NULL)
+		{
+			SetVirtualHostOption(h->SecureNAT->Nat->Virtual, t);
+		}
+	}
+	Unlock(h->lock_online);
+
+	ALog(a, h, "LA_SET_SNAT_OPTION");
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	IncrementServerConfigRevision(s);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// SecureNATOption を取得する
+UINT StGetSecureNATOption(ADMIN *a, VH_OPTION *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	char hubname[MAX_HUBNAME_LEN + 1];
+
+	StrCpy(hubname, sizeof(hubname), t->HubName);
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_SUPPORTED;
+	}
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	Zero(t, sizeof(VH_OPTION));
+	StrCpy(t->HubName, sizeof(t->HubName), hubname);
+	Copy(t, h->SecureNATOption, sizeof(VH_OPTION));
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB をオンラインまたはオフラインにする
+UINT StSetHubOnline(ADMIN *a, RPC_SET_HUB_ONLINE *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (a->ServerAdmin == false && t->Online && GetHubAdminOption(h, "no_online") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	if (a->ServerAdmin == false && t->Online == false && GetHubAdminOption(h, "no_offline") != 0)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_ENOUGH_RIGHT;
+	}
+
+	if (t->Online)
+	{
+		ALog(a, h, "LA_SET_HUB_ONLINE");
+		SetHubOnline(h);
+	}
+	else
+	{
+		ALog(a, h, "LA_SET_HUB_OFFLINE");
+		SetHubOffline(h);
+	}
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	IncrementServerConfigRevision(s);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// コネクション情報の取得
+UINT StGetConnectionInfo(ADMIN *a, RPC_CONNECTION_INFO *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	CONNECTION *connection;
+	char name[MAX_CONNECTION_NAME_LEN + 1];
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	LockList(c->ConnectionList);
+	{
+		CONNECTION tt;
+		Zero(&tt, sizeof(tt));
+		tt.Name = t->Name;
+		StrCpy(name, sizeof(name), t->Name);
+
+		connection = Search(c->ConnectionList, &tt);
+
+		if (connection != NULL)
+		{
+			AddRef(connection->ref);
+		}
+	}
+	UnlockList(c->ConnectionList);
+
+	if (connection == NULL)
+	{
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	Zero(t, sizeof(RPC_CONNECTION_INFO));
+	StrCpy(t->Name, sizeof(t->Name), name);
+
+	Lock(connection->lock);
+	{
+		SOCK *s = connection->FirstSock;
+
+		if (s != NULL)
+		{
+			t->Ip = IPToUINT(&s->RemoteIP);
+			t->Port = s->RemotePort;
+			StrCpy(t->Hostname, sizeof(t->Hostname), s->RemoteHostname);
+		}
+
+		StrCpy(t->Name, sizeof(t->Name), connection->Name);
+		t->ConnectedTime = TickToTime(connection->ConnectedTick);
+		t->Type = connection->Type;
+
+		StrCpy(t->ServerStr, sizeof(t->ServerStr), connection->ServerStr);
+		StrCpy(t->ClientStr, sizeof(t->ClientStr), connection->ClientStr);
+		t->ServerVer = connection->ServerVer;
+		t->ServerBuild = connection->ServerBuild;
+		t->ClientVer = connection->ClientVer;
+		t->ClientBuild = connection->ClientBuild;
+	}
+	Unlock(connection->lock);
+
+	ReleaseConnection(connection);
+
+	return ERR_NO_ERROR;
+}
+
+// コネクションの切断
+UINT StDisconnectConnection(ADMIN *a, RPC_DISCONNECT_CONNECTION *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	CONNECTION *connection;
+
+	if (IsEmptyStr(t->Name))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	LockList(c->ConnectionList);
+	{
+		CONNECTION tt;
+		Zero(&tt, sizeof(tt));
+		tt.Name = t->Name;
+
+		connection = Search(c->ConnectionList, &tt);
+		if (connection != NULL)
+		{
+			AddRef(connection->ref);
+		}
+	}
+	UnlockList(c->ConnectionList);
+
+	if (connection == NULL)
+	{
+		return ERR_OBJECT_NOT_FOUND;
+	}
+
+	StopConnection(connection, true);
+
+	ReleaseConnection(connection);
+
+	ALog(a, NULL, "LA_DISCONNECT_CONN", t->Name);
+
+	return ERR_NO_ERROR;
+}
+
+// コネクションの列挙
+UINT StEnumConnection(ADMIN *a, RPC_ENUM_CONNECTION *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+
+	SERVER_ADMIN_ONLY;
+
+	FreeRpcEnumConnetion(t);
+	Zero(t, sizeof(RPC_ENUM_CONNECTION));
+
+	LockList(c->ConnectionList);
+	{
+		UINT i;
+		t->NumConnection = LIST_NUM(c->ConnectionList);
+		t->Connections = ZeroMalloc(sizeof(RPC_ENUM_CONNECTION_ITEM) * t->NumConnection);
+		
+		for (i = 0;i < t->NumConnection;i++)
+		{
+			RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+			CONNECTION *connection = LIST_DATA(c->ConnectionList, i);
+
+			Lock(connection->lock);
+			{
+				SOCK *s = connection->FirstSock;
+
+				if (s != NULL)
+				{
+					e->Ip = IPToUINT(&s->RemoteIP);
+					e->Port = s->RemotePort;
+					StrCpy(e->Hostname, sizeof(e->Hostname), s->RemoteHostname);
+				}
+
+				StrCpy(e->Name, sizeof(e->Name), connection->Name);
+				e->ConnectedTime = TickToTime(connection->ConnectedTick);
+				e->Type = connection->Type;
+			}
+			Unlock(connection->lock);
+		}
+	}
+	UnlockList(c->ConnectionList);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB の Radius オプションの設定
+UINT StSetHubRadius(ADMIN *a, RPC_RADIUS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	SetRadiusServerEx(h, t->RadiusServerName, t->RadiusPort, t->RadiusSecret, t->RadiusRetryInterval);
+
+	ALog(a, h, "LA_SET_HUB_RADIUS");
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB の Radius オプションの取得
+UINT StGetHubRadius(ADMIN *a, RPC_RADIUS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+
+	CHECK_RIGHT;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_SUPPORTED;
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	Zero(t, sizeof(t));
+	GetRadiusServerEx(h, t->RadiusServerName, sizeof(t->RadiusServerName),
+		&t->RadiusPort, t->RadiusSecret, sizeof(t->RadiusSecret), &t->RadiusRetryInterval);
+
+	ReleaseHub(h);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB の削除
+UINT StDeleteHub(ADMIN *a, RPC_DELETE_HUB *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	SERVER_ADMIN_ONLY;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	StopHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	DelHub(c, h);
+	ReleaseHub(h);
+
+	ALog(a, NULL, "LA_DELETE_HUB", t->HubName);
+
+	return ERR_NO_ERROR;
+}
+
+// HUB の列挙
+UINT StEnumHub(ADMIN *a, RPC_ENUM_HUB *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h = NULL;
+
+	FreeRpcEnumHub(t);
+
+	Zero(t, sizeof(RPC_ENUM_HUB));
+
+	LockHubList(c);
+	{
+		UINT i, num, j;
+
+		num = 0;
+
+		for (i = 0;i < LIST_NUM(c->HubList);i++)
+		{
+			HUB *h = LIST_DATA(c->HubList, i);
+
+			Lock(h->lock);
+
+			if (a->ServerAdmin == false &&
+				h->Option != NULL &&
+				StrCmpi(h->Name, a->HubName) != 0)
+			{
+				// 列挙を許可しない
+			}
+			else
+			{
+				// 列挙を許可する
+				num++;
+			}
+		}
+
+		t->NumHub = num;
+
+		t->Hubs = ZeroMalloc(sizeof(RPC_ENUM_HUB_ITEM) * num);
+
+		i = 0;
+		for (j = 0;j < LIST_NUM(c->HubList);j++)
+		{
+			HUB *h = LIST_DATA(c->HubList, j);
+
+			if (a->ServerAdmin == false &&
+				h->Option != NULL &&
+				StrCmpi(h->Name, a->HubName) != 0)
+			{
+				// 列挙許可しない
+			}
+			else
+			{
+				// 列挙許可
+				RPC_ENUM_HUB_ITEM *e = &t->Hubs[i++];
+
+				StrCpy(e->HubName, sizeof(e->HubName), h->Name);
+				e->Online = h->Offline ? false : true;
+				e->HubType = h->Type;
+
+				e->NumSessions = LIST_NUM(h->SessionList);
+
+				LockList(h->MacTable);
+				{
+					e->NumMacTables = LIST_NUM(h->MacTable);
+				}
+				UnlockList(h->MacTable);
+
+				LockList(h->IpTable);
+				{
+					e->NumIpTables = LIST_NUM(h->IpTable);
+				}
+				UnlockList(h->IpTable);
+
+				if (h->HubDb != NULL)
+				{
+					LockList(h->HubDb->UserList);
+					{
+						e->NumUsers = LIST_NUM(h->HubDb->UserList);
+					}
+					UnlockList(h->HubDb->UserList);
+
+					LockList(h->HubDb->GroupList);
+					{
+						e->NumGroups = LIST_NUM(h->HubDb->GroupList);
+					}
+					UnlockList(h->HubDb->GroupList);
+				}
+
+				e->LastCommTime = h->LastCommTime;
+				e->LastLoginTime = h->LastLoginTime;
+				e->NumLogin = h->NumLogin;
+				e->CreatedTime = h->CreatedTime;
+			}
+
+			Unlock(h->lock);
+		}
+	}
+	UnlockHubList(c);
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		UINT i, j, k;
+		LockList(s->FarmMemberList);
+		{
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+				LockList(f->HubList);
+				{
+					if (f->Me == false)
+					{
+						for (j = 0;j < LIST_NUM(f->HubList);j++)
+						{
+							HUB_LIST *o = LIST_DATA(f->HubList, j);
+
+							for (k = 0;k < t->NumHub;k++)
+							{
+								RPC_ENUM_HUB_ITEM *e = &t->Hubs[k];
+
+								if (StrCmpi(e->HubName, o->Name) == 0)
+								{
+									e->NumIpTables += o->NumIpTables;
+									e->NumMacTables += o->NumMacTables;
+									e->NumSessions += o->NumSessions;
+								}
+							}
+						}
+					}
+				}
+				UnlockList(f->HubList);
+			}
+		}
+		UnlockList(s->FarmMemberList);
+	}
+
+	return ERR_NO_ERROR;
+}
+
+// HUB 設定を取得する
+UINT StGetHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT ret = ERR_NO_ERROR;
+	HUB *h;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+	CHECK_RIGHT;
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	Zero(t, sizeof(RPC_CREATE_HUB));
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	Lock(h->lock);
+	{
+		StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+		t->Online = h->Offline ? false : true;
+		t->HubOption.MaxSession = h->Option->MaxSession;
+		t->HubOption.NoEnum = h->Option->NoEnum;
+		t->HubType = h->Type;
+	}
+	Unlock(h->lock);
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// HUB 設定を更新する
+UINT StSetHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	UINT ret = ERR_NO_ERROR;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CHECK_RIGHT;
+	NO_SUPPORT_FOR_BRIDGE;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (s->ServerType == SERVER_TYPE_STANDALONE)
+	{
+		if (t->HubType != HUB_TYPE_STANDALONE)
+		{
+			return ERR_INVALID_PARAMETER;
+		}
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		if (t->HubType == HUB_TYPE_STANDALONE)
+		{
+			return ERR_INVALID_PARAMETER;
+		}
+	}
+
+	LockHubList(c);
+	{
+		h = GetHub(c, t->HubName);
+	}
+	UnlockHubList(c);
+
+	if (h == NULL)
+	{
+		return ERR_HUB_NOT_FOUND;
+	}
+
+	if (h->Type != t->HubType)
+	{
+		ReleaseHub(h);
+		return ERR_NOT_SUPPORTED;
+	}
+
+	if (IsZero(t->HashedPassword, sizeof(t->HashedPassword)) == false &&
+		IsZero(t->SecurePassword, sizeof(t->SecurePassword)) == false)
+	{
+		if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_admin_password") != 0)
+		{
+			ReleaseHub(h);
+			return ERR_NOT_ENOUGH_RIGHT;
+		}
+	}
+
+	// 設定しようとしているパスワードが空白かどうか調べる
+	{
+		UCHAR hash1[SHA1_SIZE], hash2[SHA1_SIZE];
+		HashPassword(hash1, ADMINISTRATOR_USERNAME, "");
+		Hash(hash2, "", 0, true);
+
+		if (Cmp(t->HashedPassword, hash2, SHA1_SIZE) == 0 || Cmp(t->SecurePassword, hash1, SHA1_SIZE) == 0)
+		{
+			if (a->ServerAdmin == false && a->Rpc->Sock->RemoteIP.addr[0] != 127)
+			{
+				// ローカル以外から仮想 NUB 管理者モードで接続中に
+				// 仮想 HUB のパスワードを空白に設定しようとすると拒否する
+				ReleaseHub(h);
+				return ERR_INVALID_PARAMETER;
+			}
+		}
+	}
+
+	Lock(h->lock);
+	{
+		if (a->ServerAdmin == false && h->Type != t->HubType)
+		{
+			ret = ERR_NOT_ENOUGH_RIGHT;
+		}
+		else
+		{
+			h->Type = t->HubType;
+			h->Option->MaxSession = t->HubOption.MaxSession;
+			h->Option->NoEnum = t->HubOption.NoEnum;
+			if (IsZero(t->HashedPassword, sizeof(t->HashedPassword)) == false &&
+				IsZero(t->SecurePassword, sizeof(t->SecurePassword)) == false)
+			{
+				Copy(h->HashedPassword, t->HashedPassword, SHA1_SIZE);
+				Copy(h->SecurePassword, t->SecurePassword, SHA1_SIZE);
+			}
+		}
+	}
+	Unlock(h->lock);
+
+	if (t->Online)
+	{
+		if (a->ServerAdmin || GetHubAdminOption(h, "no_online") == 0)
+		{
+			SetHubOnline(h);
+		}
+	}
+	else
+	{
+		if (a->ServerAdmin || GetHubAdminOption(h, "no_offline") == 0)
+		{
+			SetHubOffline(h);
+		}
+	}
+
+	if (h->Type == HUB_TYPE_FARM_STATIC)
+	{
+		EnableSecureNAT(h, false);
+	}
+
+	h->CurrentVersion++;
+	SiHubUpdateProc(h);
+
+	IncrementServerConfigRevision(s);
+
+	ALog(a, h, "LA_SET_HUB");
+
+	ReleaseHub(h);
+
+	return ret;
+}
+
+// HUB を作成する
+UINT StCreateHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	HUB *h;
+	HUB_OPTION o;
+	UINT current_hub_num;
+	bool b;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	NO_SUPPORT_FOR_BRIDGE;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	Trim(t->HubName);
+	if (StrLen(t->HubName) == 0)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+	if (StartWith(t->HubName, ".") || EndWith(t->HubName, "."))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	if (s->ServerType == SERVER_TYPE_STANDALONE)
+	{
+		if (t->HubType != HUB_TYPE_STANDALONE)
+		{
+			return ERR_INVALID_PARAMETER;
+		}
+	}
+	else if (t->HubType != HUB_TYPE_FARM_DYNAMIC && t->HubType != HUB_TYPE_FARM_STATIC)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// HUB の作成
+	Zero(&o, sizeof(o));
+	o.MaxSession = t->HubOption.MaxSession;
+	o.NoEnum = t->HubOption.NoEnum;
+	o.ManageOnlyPrivateIP = true;
+	o.ManageOnlyLocalUnicastIPv6 = true;
+	o.NoMacAddressLog = true;
+	o.NoIPv6DefaultRouterInRAWhenIPv6 = true;
+
+	LockList(c->HubList);
+	{
+		current_hub_num = LIST_NUM(c->HubList);
+	}
+	UnlockList(c->HubList);
+
+	if (current_hub_num > GetServerCapsInt(a->Server, "i_max_hubs"))
+	{
+		return ERR_TOO_MANY_HUBS;
+	}
+
+	LockList(c->HubList);
+	{
+		b = IsHub(c, t->HubName);
+	}
+	UnlockList(c->HubList);
+
+	if (b)
+	{
+		return ERR_HUB_ALREADY_EXISTS;
+	}
+
+	ALog(a, NULL, "LA_CREATE_HUB", t->HubName);
+
+	h = NewHub(c, t->HubName, &o);
+	Copy(h->HashedPassword, t->HashedPassword, SHA1_SIZE);
+	Copy(h->SecurePassword, t->SecurePassword, SHA1_SIZE);
+
+	h->Type = t->HubType;
+
+	AddHub(c, h);
+
+	if (t->Online)
+	{
+		h->Offline = true;
+		SetHubOnline(h);
+	}
+	else
+	{
+		h->Offline = false;
+		SetHubOffline(h);
+	}
+
+	h->CreatedTime = SystemTime64();
+
+	ReleaseHub(h);
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// 暗号化アルゴリズムを設定する
+UINT StSetServerCipher(ADMIN *a, RPC_STR *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+
+	if (IsEmptyStr(t->String))
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	StrUpper(t->String);
+
+	if (CheckCipherListName(t->String) == false)
+	{
+		return ERR_CIPHER_NOT_SUPPORTED;
+	}
+	else
+	{
+		ALog(a, NULL, "LA_SET_SERVER_CIPHER", t->String);
+	}
+
+	Lock(c->lock);
+	{
+		SetCedarCipherList(c, t->String);
+	}
+	Unlock(c->lock);
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// 暗号化アルゴリズムを取得する
+UINT StGetServerCipher(ADMIN *a, RPC_STR *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+
+	FreeRpcStr(t);
+	Zero(t, sizeof(RPC_STR));
+
+	Lock(c->lock);
+	{
+		t->String = CopyStr(c->CipherList);
+	}
+	Unlock(c->lock);
+
+	return ERR_NO_ERROR;
+}
+
+// サーバー証明書を取得する
+UINT StGetServerCert(ADMIN *a, RPC_KEY_PAIR *t)
+{
+	bool admin;
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+
+	admin = a->ServerAdmin;
+
+	FreeRpcKeyPair(t);
+	Zero(t, sizeof(RPC_KEY_PAIR));
+
+	Lock(c->lock);
+	{
+		t->Cert = CloneX(c->ServerX);
+		if (admin)
+		{
+			t->Key = CloneK(c->ServerK);
+		}
+	}
+	Unlock(c->lock);
+
+	return ERR_NO_ERROR;
+}
+
+// サーバー証明書を設定する
+UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+
+	SERVER_ADMIN_ONLY;
+
+	if (t->Cert == NULL || t->Key == NULL)
+	{
+		return ERR_PROTOCOL_ERROR;
+	}
+
+	if (t->Cert->is_compatible_bit == false)
+	{
+		return ERR_NOT_RSA_1024;
+	}
+
+	if (CheckXandK(t->Cert, t->Key) == false)
+	{
+		return ERR_PROTOCOL_ERROR;
+	}
+
+	SetCedarCert(c, t->Cert, t->Key);
+
+	ALog(a, NULL, "LA_SET_SERVER_CERT");
+
+	IncrementServerConfigRevision(s);
+
+	return ERR_NO_ERROR;
+}
+
+// サーバーファームコントローラへの接続状態を取得する
+UINT StGetFarmConnectionStatus(ADMIN *a, RPC_FARM_CONNECTION_STATUS *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	FARM_CONTROLLER *fc;
+
+	if (s->ServerType != SERVER_TYPE_FARM_MEMBER)
+	{
+		return ERR_NOT_FARM_MEMBER;
+	}
+
+	Zero(t, sizeof(RPC_FARM_CONNECTION_STATUS));
+
+	fc = s->FarmController;
+
+	Lock(fc->lock);
+	{
+		if (fc->Sock != NULL)
+		{
+			t->Ip = IPToUINT(&fc->Sock->RemoteIP);
+			t->Port = fc->Sock->RemotePort;
+		}
+
+		t->Online = fc->Online;
+		t->LastError = ERR_NO_ERROR;
+
+		if (t->Online == false)
+		{
+			t->LastError = fc->LastError;
+		}
+		else
+		{
+			t->CurrentConnectedTime = fc->CurrentConnectedTime;
+		}
+
+		t->StartedTime = fc->StartedTime;
+		t->FirstConnectedTime = fc->FirstConnectedTime;
+
+		t->NumConnected = fc->NumConnected;
+		t->NumTry = fc->NumTry;
+		t->NumFailed = fc->NumFailed;
+	}
+	Unlock(fc->lock);
+
+	return ERR_NO_ERROR;
+}
+
+// サーバーファームメンバ列挙
+UINT StEnumFarmMember(ADMIN *a, RPC_ENUM_FARM *t)
+{
+	SERVER *s = a->Server;
+	CEDAR *c = s->Cedar;
+	UINT i;
+
+	FreeRpcEnumFarm(t);
+	Zero(t, sizeof(RPC_ENUM_FARM));
+
+	if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_FARM));
+
+	LockList(s->FarmMemberList);
+	{
+		t->NumFarm = LIST_NUM(s->FarmMemberList);
+		t->Farms = ZeroMalloc(sizeof(RPC_ENUM_FARM_ITEM) * t->NumFarm);
+
+		for (i = 0;i < t->NumFarm;i++)
+		{
+			FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+			RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+			e->Id = POINTER_TO_KEY(f);
+			e->Controller = f->Me;
+
+			if (e->Controller)
+			{
+				e->ConnectedTime = TickToTime(c->CreatedTick);
+				e->Ip = 0x0100007f;
+				GetMachineName(e->Hostname, sizeof(e->Hostname));
+				e->Point = f->Point;
+				e->NumSessions = Count(c->CurrentSessions);
+				e->NumTcpConnections = Count(c->CurrentTcpConnections);
+
+				e->AssignedBridgeLicense = Count(c->AssignedBridgeLicense);
+				e->AssignedClientLicense = Count(c->AssignedClientLicense);
+			}
+			else
+			{
+				e->ConnectedTime = f->ConnectedTime;
+				e->Ip = f->Ip;
+				StrCpy(e->Hostname, sizeof(e->Hostname), f->hostname);
+				e->Point = f->Point;
+				e->NumSessions = f->NumSessions;
+				e->NumTcpConnections = f->NumTcpConnections;
+
+				e->AssignedBridgeLicense = f->AssignedBridgeLicense;
+				e->AssignedClientLicense = f->AssignedClientLicense;
+			}
+			e->NumHubs = LIST_NUM(f->HubList);
+		}
+	}
+	UnlockList(s->FarmMemberList);
+
+	return ERR_NO_ERROR;
+}
+
+// サーバーファームメンバ情報の取得
+UINT StGetFarmInfo(ADMIN *a, RPC_FARM_INFO *t)
+{
+	SERVER *s = a->Server;
+	UINT id = t->Id;
+	UINT i;
+	UINT ret = ERR_NO_ERROR;
+
+	FreeRpcFarmInfo(t);
+	Zero(t, sizeof(RPC_FARM_INFO));
+
+	if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		return ERR_NOT_FARM_CONTROLLER;
+	}
+
+	LockList(s->FarmMemberList);
+	{
+		if (IsInListKey(s->FarmMemberList, id))
+		{
+			FARM_MEMBER *f = ListKeyToPointer(s->FarmMemberList, id);
+
+			t->Id = id;
+			t->Controller = f->Me;
+			t->Weight = f->Weight;
+
+			LockList(f->HubList);
+			{
+				t->NumFarmHub = LIST_NUM(f->HubList);
+				t->FarmHubs = ZeroMalloc(sizeof(RPC_FARM_HUB) * t->NumFarmHub);
+
+				for (i = 0;i < t->NumFarmHub;i++)
+				{
+					RPC_FARM_HUB *h = &t->FarmHubs[i];
+					HUB_LIST *hh = LIST_DATA(f->HubList, i);
+
+					h->DynamicHub = hh->DynamicHub;
+					StrCpy(h->HubName, sizeof(h->HubName), hh->Name);
+				}
+			}
+			UnlockList(f->HubList);
+
+			if (t->Controller)
+			{
+				t->ConnectedTime = TickToTime(s->Cedar->CreatedTick);
+				t->Ip = 0x0100007f;
+				GetMachineName(t->Hostname, sizeof(t->Hostname));
+				t->Point = f->Point;
+
+				LockList(s->ServerListenerList);
+				{
+					UINT i, n;
+					t->NumPort = 0;
+					for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+					{
+						SERVER_LISTENER *o = LIST_DATA(s->ServerListenerList, i);
+						if (o->Enabled)
+						{
+							t->NumPort++;
+						}
+					}
+					t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+					n = 0;
+					for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+					{
+						SERVER_LISTENER *o = LIST_DATA(s->ServerListenerList, i);
+						if (o->Enabled)
+						{
+							t->Ports[n++] = o->Port;
+						}
+					}
+				}
+				UnlockList(s->ServerListenerList);
+
+				t->ServerCert = CloneX(s->Cedar->ServerX);
+				t->NumSessions = Count(s->Cedar->CurrentSessions);
+				t->NumTcpConnections = Count(s->Cedar->CurrentTcpConnections);
+			}
+			else
+			{
+				t->ConnectedTime = f->ConnectedTime;
+				t->Ip = f->Ip;
+				StrCpy(t->Hostname, sizeof(t->Hostname), f->hostname);
+				t->Point = f->Point;
+				t->NumPort = f->NumPort;
+				t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+				Copy(t->Ports, f->Ports, sizeof(UINT) * t->NumPort);
+				t->ServerCert = CloneX(f->ServerCert);
+				t->NumSessions = f->NumSessions;
+				t->NumTcpConnections = f->NumTcpConnections;
+			}
+		}
+		else
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+		}
+	}
+	UnlockList(s->FarmMemberList);
+
+	return ret;
+}
+
+// サーバーファーム設定の取得
+UINT StGetFarmSetting(ADMIN *a, RPC_FARM *t)
+{
+	SERVER *s;
+	FreeRpcFarm(t);
+	Zero(t, sizeof(RPC_FARM));
+
+	s = a->Server;
+	t->ServerType = s->ServerType;
+	t->ControllerOnly = s->ControllerOnly;
+	t->Weight = s->Weight;
+
+	if (t->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		t->NumPort = s->NumPublicPort;
+		t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+		Copy(t->Ports, s->PublicPorts, sizeof(UINT) * t->NumPort);
+		t->PublicIp = s->PublicIp;
+		StrCpy(t->ControllerName, sizeof(t->ControllerName), s->ControllerName);
+		t->ControllerPort = s->ControllerPort;
+	}
+	else
+	{
+		t->NumPort = 0;
+		t->Ports = ZeroMalloc(0);
+	}
+
+	return ERR_NO_ERROR;
+}
+
+// サーバーファーム設定の設定
+UINT StSetFarmSetting(ADMIN *a, RPC_FARM *t)
+{
+	bool cluster_allowed = false;
+
+	SERVER_ADMIN_ONLY;
+	NO_SUPPORT_FOR_BRIDGE;
+
+	cluster_allowed = GetServerCapsInt(a->Server, "b_support_cluster");
+
+	if (t->ServerType != SERVER_TYPE_STANDALONE && cluster_allowed == false)
+	{
+		// クラスタとして動作が許可されていないのにクラスタ化しようとすると
+		// エラーを発生する
+		return ERR_NOT_SUPPORTED;
+	}
+
+	ALog(a, NULL, "LA_SET_FARM_SETTING");
+
+	IncrementServerConfigRevision(a->Server);
+
+	SiSetServerType(a->Server, t->ServerType, t->PublicIp, t->NumPort, t->Ports,
+		t->ControllerName, t->ControllerPort, t->MemberPassword, t->Weight, t->ControllerOnly);
+
+	return ERR_NO_ERROR;
+}
+
+// パスワードの設定
+UINT StSetServerPassword(ADMIN *a, RPC_SET_PASSWORD *t)
+{
+	SERVER_ADMIN_ONLY;
+
+	Copy(a->Server->HashedPassword, t->HashedPassword, SHA1_SIZE);
+
+	ALog(a, NULL, "LA_SET_SERVER_PASSWORD");
+
+	IncrementServerConfigRevision(a->Server);
+
+	return ERR_NO_ERROR;
+}
+
+// リスナーの有効化 / 無効化
+UINT StEnableListener(ADMIN *a, RPC_LISTENER *t)
+{
+	UINT ret = ERR_NO_ERROR;
+
+	SERVER_ADMIN_ONLY;
+
+	LockList(a->Server->ServerListenerList);
+	{
+		if (t->Enable)
+		{
+			if (SiEnableListener(a->Server, t->Port) == false)
+			{
+				ret = ERR_LISTENER_NOT_FOUND;
+			}
+			else
+			{
+				ALog(a, NULL, "LA_ENABLE_LISTENER", t->Port);
+			}
+		}
+		else
+		{
+			if (SiDisableListener(a->Server, t->Port) == false)
+			{
+				ret = ERR_LISTENER_NOT_FOUND;
+			}
+			else
+			{
+				ALog(a, NULL, "LA_DISABLE_LISTENER", t->Port);
+			}
+		}
+	}
+	UnlockList(a->Server->ServerListenerList);
+
+	IncrementServerConfigRevision(a->Server);
+
+	SleepThread(250);
+
+	return ret;
+}
+
+// リスナーの削除
+UINT StDeleteListener(ADMIN *a, RPC_LISTENER *t)
+{
+	UINT ret = ERR_NO_ERROR;
+
+	SERVER_ADMIN_ONLY;
+
+	LockList(a->Server->ServerListenerList);
+	{
+		if (SiDeleteListener(a->Server, t->Port) == false)
+		{
+			ret = ERR_LISTENER_NOT_FOUND;
+		}
+		else
+		{
+			ALog(a, NULL, "LA_DELETE_LISTENER", t->Port);
+
+			IncrementServerConfigRevision(a->Server);
+		}
+	}
+	UnlockList(a->Server->ServerListenerList);
+
+	return ret;
+}
+
+// リスナーの列挙
+UINT StEnumListener(ADMIN *a, RPC_LISTENER_LIST *t)
+{
+	CEDAR *c = a->Server->Cedar;
+	UINT i;
+
+	FreeRpcListenerList(t);
+	Zero(t, sizeof(RPC_LISTENER_LIST));
+
+	LockList(a->Server->ServerListenerList);
+	{
+		t->NumPort = LIST_NUM(a->Server->ServerListenerList);
+		t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+		t->Enables = ZeroMalloc(sizeof(bool) * t->NumPort);
+		t->Errors = ZeroMalloc(sizeof(bool) * t->NumPort);
+
+		for (i = 0;i < t->NumPort;i++)
+		{
+			SERVER_LISTENER *o = LIST_DATA(a->Server->ServerListenerList, i);
+
+			t->Ports[i] = o->Port;
+			t->Enables[i] = o->Enabled;
+			if (t->Enables[i])
+			{
+				if (o->Listener->Status == LISTENER_STATUS_TRYING)
+				{
+					t->Errors[i] = true;
+				}
+			}
+		}
+	}
+	UnlockList(a->Server->ServerListenerList);
+
+	return ERR_NO_ERROR;
+}
+
+// リスナーの作成
+UINT StCreateListener(ADMIN *a, RPC_LISTENER *t)
+{
+	UINT ret = ERR_NO_ERROR;
+	CEDAR *c = a->Server->Cedar;
+
+	if (t->Port == 0 || t->Port > 65535)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	SERVER_ADMIN_ONLY;
+
+	LockList(a->Server->ServerListenerList);
+	{
+		if (SiAddListener(a->Server, t->Port, t->Enable) == false)
+		{
+			ret = ERR_LISTENER_ALREADY_EXISTS;
+		}
+		else
+		{
+			ALog(a, NULL, "LA_CREATE_LISTENER", t->Port);
+
+			IncrementServerConfigRevision(a->Server);
+		}
+	}
+	UnlockList(a->Server->ServerListenerList);
+
+	SleepThread(250);
+
+	return ret;
+}
+
+// サーバー状態の取得
+UINT StGetServerStatus(ADMIN *a, RPC_SERVER_STATUS *t)
+{
+	CEDAR *c;
+	UINT i;
+
+	c = a->Server->Cedar;
+
+	Zero(t, sizeof(RPC_SERVER_STATUS));
+
+	Lock(c->TrafficLock);
+	{
+		Copy(&t->Traffic, c->Traffic, sizeof(TRAFFIC));
+	}
+	Unlock(c->TrafficLock);
+
+	GetMemInfo(&t->MemInfo);
+
+	t->ServerType = a->Server->ServerType;
+	t->NumTcpConnections = t->NumTcpConnectionsLocal = t->NumTcpConnectionsRemote = 0;
+	t->NumSessionsTotal = t->NumSessionsLocal = t->NumSessionsRemote = 0;
+
+	t->NumTcpConnectionsLocal = Count(c->CurrentTcpConnections);
+
+	if (a->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		LockList(a->Server->FarmMemberList);
+		{
+			for (i = 0;i < LIST_NUM(a->Server->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(a->Server->FarmMemberList, i);
+
+				if (f->Me == false)
+				{
+					t->NumTcpConnectionsRemote += f->NumTcpConnections;
+					t->NumSessionsRemote += f->NumSessions;
+					AddTraffic(&t->Traffic, &f->Traffic);
+				}
+			}
+		}
+		UnlockList(a->Server->FarmMemberList);
+	}
+
+	t->NumMacTables = t->NumIpTables = t->NumUsers = t->NumGroups = 0;
+
+	// HUB 数の情報
+	LockList(c->HubList);
+	{
+		t->NumHubTotal = LIST_NUM(c->HubList);
+
+		t->NumHubStandalone = t->NumHubDynamic = t->NumHubStatic = 0;
+
+		for (i = 0;i < LIST_NUM(c->HubList);i++)
+		{
+			HUB *h = LIST_DATA(c->HubList, i);
+			Lock(h->lock);
+			{
+				switch (h->Type)
+				{
+				case HUB_TYPE_STANDALONE:
+					t->NumHubStandalone++;
+					break;
+
+				case HUB_TYPE_FARM_STATIC:
+					t->NumHubStatic++;
+					break;
+
+				case HUB_TYPE_FARM_DYNAMIC:
+					t->NumHubDynamic++;
+					break;
+				}
+			}
+
+			t->NumMacTables += LIST_NUM(h->MacTable);
+			t->NumIpTables += LIST_NUM(h->IpTable);
+
+			if (h->HubDb != NULL)
+			{
+				t->NumUsers += LIST_NUM(h->HubDb->UserList);
+				t->NumGroups += LIST_NUM(h->HubDb->GroupList);
+			}
+
+			Unlock(h->lock);
+		}
+	}
+	UnlockList(c->HubList);
+
+	// セッション数の情報
+	t->NumSessionsLocal = Count(c->CurrentSessions);
+	t->NumSessionsTotal = t->NumSessionsLocal + t->NumSessionsRemote;
+	t->NumTcpConnections = t->NumTcpConnectionsLocal + t->NumTcpConnectionsRemote;
+
+	t->AssignedBridgeLicenses = Count(c->AssignedBridgeLicense);
+	t->AssignedClientLicenses = Count(c->AssignedClientLicense);
+
+	t->AssignedBridgeLicensesTotal = a->Server->CurrentAssignedBridgeLicense;
+	t->AssignedClientLicensesTotal = a->Server->CurrentAssignedClientLicense;
+
+	t->CurrentTick = Tick64();
+	t->CurrentTime = SystemTime64();
+
+	t->StartTime = a->Server->StartTime;
+
+	return ERR_NO_ERROR;
+}
+
+// サーバー情報の取得
+UINT StGetServerInfo(ADMIN *a, RPC_SERVER_INFO *t)
+{
+	CEDAR *c;
+	OS_INFO *info;
+	// 引数チェック
+	if (a == NULL || t == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	FreeRpcServerInfo(t);
+	Zero(t, sizeof(RPC_SERVER_INFO));
+
+	c = a->Server->Cedar;
+
+	GetServerProductName(a->Server, t->ServerProductName, sizeof(t->ServerProductName));
+
+	StrCpy(t->ServerVersionString, sizeof(t->ServerVersionString), c->VerString);
+	StrCpy(t->ServerBuildInfoString, sizeof(t->ServerBuildInfoString), c->BuildInfo);
+	t->ServerVerInt = c->Version;
+	t->ServerBuildInt = c->Build;
+	GetMachineName(t->ServerHostName, sizeof(t->ServerHostName));
+	t->ServerType = c->Server->ServerType;
+
+	info = GetOsInfo();
+	if (info != NULL)
+	{
+		CopyOsInfo(&t->OsInfo, info);
+	}
+
+	return ERR_NO_ERROR;
+}
+
+// OS_INFO のコピー
+void CopyOsInfo(OS_INFO *dst, OS_INFO *info)
+{
+	// 引数チェック
+	if (info == NULL || dst == NULL)
+	{
+		return;
+	}
+
+	dst->OsType = info->OsType;
+	dst->OsServicePack = info->OsServicePack;
+	dst->OsSystemName = CopyStr(info->OsSystemName);
+	dst->OsProductName = CopyStr(info->OsProductName);
+	dst->OsVendorName = CopyStr(info->OsVendorName);
+	dst->OsVersion = CopyStr(info->OsVersion);
+	dst->KernelName = CopyStr(info->KernelName);
+	dst->KernelVersion = CopyStr(info->KernelVersion);
+}
+
+// RPC_WINVER
+void InRpcWinVer(RPC_WINVER *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_WINVER));
+
+	t->IsWindows = PackGetBool(p, "V_IsWindows");
+	t->IsNT = PackGetBool(p, "V_IsNT");
+	t->IsServer = PackGetBool(p, "V_IsServer");
+	t->IsBeta = PackGetBool(p, "V_IsBeta");
+	t->VerMajor = PackGetInt(p, "V_VerMajor");
+	t->VerMinor = PackGetInt(p, "V_VerMinor");
+	t->Build = PackGetInt(p, "V_Build");
+	t->ServicePack = PackGetInt(p, "V_ServicePack");
+	PackGetStr(p, "V_Title", t->Title, sizeof(t->Title));
+}
+void OutRpcWinVer(PACK *p, RPC_WINVER *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddBool(p, "V_IsWindows", t->IsWindows);
+	PackAddBool(p, "V_IsNT", t->IsNT);
+	PackAddBool(p, "V_IsServer", t->IsServer);
+	PackAddBool(p, "V_IsBeta", t->IsBeta);
+	PackAddInt(p, "V_VerMajor", t->VerMajor);
+	PackAddInt(p, "V_VerMinor", t->VerMinor);
+	PackAddInt(p, "V_Build", t->Build);
+	PackAddInt(p, "V_ServicePack", t->ServicePack);
+	PackAddStr(p, "V_Title", t->Title);
+}
+
+// RPC_MSG
+void InRpcMsg(RPC_MSG *t, PACK *p)
+{
+	UINT size;
+	char *utf8;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_MSG));
+
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	size = PackGetDataSize(p, "Msg");
+	utf8 = ZeroMalloc(size + 8);
+	PackGetData(p, "Msg", utf8);
+	t->Msg = CopyUtfToUni(utf8);
+	Free(utf8);
+}
+void OutRpcMsg(PACK *p, RPC_MSG *t)
+{
+	UINT size;
+	char *utf8;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	utf8 = CopyUniToUtf(t->Msg);
+	size = StrLen(utf8);
+	PackAddData(p, "Msg", utf8, size);
+	Free(utf8);
+}
+void FreeRpcMsg(RPC_MSG *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Msg);
+}
+
+// RPC_ENUM_ETH_VLAN
+void InRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+	t->NumItem = PackGetIndexCount(p, "DeviceName");
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_ETH_VLAN_ITEM *e = &t->Items[i];
+
+		PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+		PackGetStrEx(p, "Guid", e->Guid, sizeof(e->Guid), i);
+		PackGetStrEx(p, "DeviceInstanceId", e->DeviceInstanceId, sizeof(e->DeviceInstanceId), i);
+		PackGetStrEx(p, "DriverName", e->DriverName, sizeof(e->DriverName), i);
+		PackGetStrEx(p, "DriverType", e->DriverType, sizeof(e->DriverType), i);
+		e->Support = PackGetBoolEx(p, "Support", i);
+		e->Enabled = PackGetBoolEx(p, "Enabled", i);
+	}
+}
+void OutRpcEnumEthVLan(PACK *p, RPC_ENUM_ETH_VLAN *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_ETH_VLAN_ITEM *e = &t->Items[i];
+
+		PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+		PackAddStrEx(p, "Guid", e->Guid, i, t->NumItem);
+		PackAddStrEx(p, "DeviceInstanceId", e->DeviceInstanceId, i, t->NumItem);
+		PackAddStrEx(p, "DriverName", e->DriverName, i, t->NumItem);
+		PackAddStrEx(p, "DriverType", e->DriverType, i, t->NumItem);
+		PackAddBoolEx(p, "Support", e->Support, i, t->NumItem);
+		PackAddBoolEx(p, "Enabled", e->Enabled, i, t->NumItem);
+	}
+}
+void FreeRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_ENUM_LOG_FILE
+void InRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+	t->NumItem = PackGetInt(p, "NumItem");
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+		PackGetStrEx(p, "FilePath", e->FilePath, sizeof(e->FilePath), i);
+		PackGetStrEx(p, "ServerName", e->ServerName, sizeof(e->ServerName), i);
+		e->FileSize = PackGetIntEx(p, "FileSize", i);
+		e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+	}
+}
+void OutRpcEnumLogFile(PACK *p, RPC_ENUM_LOG_FILE *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+		PackAddStrEx(p, "FilePath", e->FilePath, i, t->NumItem);
+		PackAddStrEx(p, "ServerName", e->ServerName, i, t->NumItem);
+		PackAddIntEx(p, "FileSize", e->FileSize, i, t->NumItem);
+		PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumItem);
+	}
+}
+void FreeRpcEnumLogFile(RPC_ENUM_LOG_FILE *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+void AdjoinRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, RPC_ENUM_LOG_FILE *src)
+{
+	LIST *o;
+	UINT i;
+	// 引数チェック
+	if (t == NULL || src == NULL)
+	{
+		return;
+	}
+
+	o = NewListFast(CmpLogFile);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+		LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+		f->FileSize = e->FileSize;
+		StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+		StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+		f->UpdatedTime = e->UpdatedTime;
+
+		Add(o, f);
+	}
+
+	for (i = 0;i < src->NumItem;i++)
+	{
+		RPC_ENUM_LOG_FILE_ITEM *e = &src->Items[i];
+		LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+		f->FileSize = e->FileSize;
+		StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+		StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+		f->UpdatedTime = e->UpdatedTime;
+
+		Add(o, f);
+	}
+
+	FreeRpcEnumLogFile(t);
+
+	Sort(o);
+
+	Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+	t->NumItem = LIST_NUM(o);
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		LOG_FILE *f = LIST_DATA(o, i);
+		RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+		StrCpy(e->FilePath, sizeof(e->FilePath), f->Path);
+		StrCpy(e->ServerName, sizeof(e->ServerName), f->ServerName);
+		e->FileSize = f->FileSize;
+		e->UpdatedTime = f->UpdatedTime;
+	}
+
+	FreeEnumLogFile(o);
+}
+
+// RPC_READ_LOG_FILE
+void InRpcReadLogFile(RPC_READ_LOG_FILE *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_READ_LOG_FILE));
+	PackGetStr(p, "FilePath", t->FilePath, sizeof(t->FilePath));
+	PackGetStr(p, "ServerName", t->ServerName, sizeof(t->ServerName));
+	t->Offset = PackGetInt(p, "Offset");
+
+	t->Buffer = PackGetBuf(p, "Buffer");
+}
+void OutRpcReadLogFile(PACK *p, RPC_READ_LOG_FILE *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "FilePath", t->FilePath);
+	PackAddStr(p, "ServerName", t->ServerName);
+	PackAddInt(p, "Offset", t->Offset);
+
+	if (t->Buffer != NULL)
+	{
+		PackAddBuf(p, "Buffer", t->Buffer);
+	}
+}
+void FreeRpcReadLogFile(RPC_READ_LOG_FILE *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	if (t->Buffer != NULL)
+	{
+		FreeBuf(t->Buffer);
+	}
+}
+
+// RPC_AC_LIST
+void InRpcAcList(RPC_AC_LIST *t, PACK *p)
+{
+	UINT i;
+	LIST *o;
+	UINT num;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_AC_LIST));
+	o = NewAcList();
+
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	num = PackGetInt(p, "NumItem");
+
+	for (i = 0;i < num;i++)
+	{
+		AC *ac = ZeroMalloc(sizeof(AC));
+
+		ac->Deny = PackGetBoolEx(p, "Deny", i);
+		PackGetIpEx(p, "IpAddress", &ac->IpAddress, i);
+		ac->Masked = PackGetBoolEx(p, "Masked", i);
+
+		if (ac->Masked)
+		{
+			PackGetIpEx(p, "SubnetMask", &ac->SubnetMask, i);
+		}
+
+		PackGetIntEx(p, "testtest", i);
+
+		ac->Priority = PackGetIntEx(p, "Priority", i);
+
+		AddAc(o, ac);
+
+		Free(ac);
+	}
+
+	t->o = o;
+}
+void OutRpcAcList(PACK *p, RPC_AC_LIST *t)
+{
+	UINT i, num;
+	LIST *o;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	o = t->o;
+	num = LIST_NUM(o);
+
+	PackAddInt(p, "NumItem", num);
+
+	PackAddStr(p, "HubName", t->HubName);
+
+	for (i = 0;i < num;i++)
+	{
+		AC *ac = LIST_DATA(o, i);
+
+		PackAddBoolEx(p, "Deny", ac->Deny, i, num);
+		PackAddIpEx(p, "IpAddress", &ac->IpAddress, i, num);
+		PackAddBoolEx(p, "Masked", ac->Masked, i, num);
+
+		PackAddIpEx(p, "SubnetMask", &ac->SubnetMask, i, num);
+
+		PackAddIntEx(p, "Priority", ac->Priority, i, num);
+	}
+}
+void FreeRpcAcList(RPC_AC_LIST *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FreeAcList(t->o);
+}
+
+// RPC_INT
+void InRpcInt(RPC_INT *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_INT));
+	t->IntValue = PackGetInt(p, "IntValue");
+}
+void OutRpcInt(PACK *p, RPC_INT *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "IntValue", t->IntValue);
+}
+
+// RPC_ENUM_CRL
+void InRpcEnumCrl(RPC_ENUM_CRL *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_CRL));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->NumItem = PackGetInt(p, "NumItem");
+
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_CRL_ITEM) * t->NumItem);
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_CRL_ITEM *e = &t->Items[i];
+
+		e->Key = PackGetIntEx(p, "Key", i);
+		PackGetUniStrEx(p, "CrlInfo", e->CrlInfo, sizeof(e->CrlInfo), i);
+	}
+}
+void OutRpcEnumCrl(PACK *p, RPC_ENUM_CRL *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddInt(p, "NumItem", t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_CRL_ITEM *e = &t->Items[i];
+
+		PackAddIntEx(p, "Key", e->Key, i, t->NumItem);
+		PackAddUniStrEx(p, "CrlInfo", e->CrlInfo, i, t->NumItem);
+	}
+}
+void FreeRpcEnumCrl(RPC_ENUM_CRL *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_CRL
+void InRpcCrl(RPC_CRL *t, PACK *p)
+{
+	BUF *b;
+	NAME *n;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_CRL));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Key = PackGetInt(p, "Key");
+	b = PackGetBuf(p, "Serial");
+	t->Crl = ZeroMalloc(sizeof(CRL));
+	if (b != NULL)
+	{
+		t->Crl->Serial = NewXSerial(b->Buf, b->Size);
+		FreeBuf(b);
+	}
+	t->Crl->Name = ZeroMalloc(sizeof(NAME));
+	n = t->Crl->Name;
+	if (PackGetUniStr(p, "CommonName", tmp, sizeof(tmp)))
+	{
+		n->CommonName = CopyUniStr(tmp);
+	}
+	if (PackGetUniStr(p, "Organization", tmp, sizeof(tmp)))
+	{
+		n->Organization = CopyUniStr(tmp);
+	}
+	if (PackGetUniStr(p, "Unit", tmp, sizeof(tmp)))
+	{
+		n->Unit = CopyUniStr(tmp);
+	}
+	if (PackGetUniStr(p, "Country", tmp, sizeof(tmp)))
+	{
+		n->Country = CopyUniStr(tmp);
+	}
+	if (PackGetUniStr(p, "State", tmp, sizeof(tmp)))
+	{
+		n->State = CopyUniStr(tmp);
+	}
+	if (PackGetUniStr(p, "Local", tmp, sizeof(tmp)))
+	{
+		n->Local = CopyUniStr(tmp);
+	}
+	if (PackGetDataSize(p, "DigestMD5") == MD5_SIZE)
+	{
+		PackGetData(p, "DigestMD5", t->Crl->DigestMD5);
+	}
+	if (PackGetDataSize(p, "DigestSHA1") == SHA1_SIZE)
+	{
+		PackGetData(p, "DigestSHA1", t->Crl->DigestSHA1);
+	}
+}
+void OutRpcCrl(PACK *p, RPC_CRL *t)
+{
+	NAME *n;
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddInt(p, "Key", t->Key);
+
+	if (t->Crl == NULL)
+	{
+		return;
+	}
+
+	if (t->Crl->Serial != NULL)
+	{
+		PackAddData(p, "Serial", t->Crl->Serial->data, t->Crl->Serial->size);
+	}
+	n = t->Crl->Name;
+	if (n->CommonName != NULL)
+	{
+		PackAddUniStr(p, "CommonName", n->CommonName);
+	}
+	if (n->Organization != NULL)
+	{
+		PackAddUniStr(p, "Organization", n->Organization);
+	}
+	if (n->Unit != NULL)
+	{
+		PackAddUniStr(p, "Unit", n->Unit);
+	}
+	if (n->Country != NULL)
+	{
+		PackAddUniStr(p, "Country", n->Country);
+	}
+	if (n->State != NULL)
+	{
+		PackAddUniStr(p, "State", n->State);
+	}
+	if (n->Local != NULL)
+	{
+		PackAddUniStr(p, "Local", n->Local);
+	}
+	if (IsZero(t->Crl->DigestMD5, MD5_SIZE) == false)
+	{
+		PackAddData(p, "DigestMD5", t->Crl->DigestMD5, MD5_SIZE);
+	}
+	if (IsZero(t->Crl->DigestSHA1, SHA1_SIZE) == false)
+	{
+		PackAddData(p, "DigestSHA1", t->Crl->DigestSHA1, SHA1_SIZE);
+	}
+}
+void FreeRpcCrl(RPC_CRL *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FreeCrl(t->Crl);
+}
+
+// RPC_ENUM_L3TABLE
+void InRpcEnumL3Table(RPC_ENUM_L3TABLE *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_L3TABLE));
+	t->NumItem = PackGetInt(p, "NumItem");
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+	t->Items = ZeroMalloc(sizeof(RPC_L3TABLE) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_L3TABLE *e = &t->Items[i];
+
+		e->NetworkAddress = PackGetIp32Ex(p, "NetworkAddress", i);
+		e->SubnetMask = PackGetIp32Ex(p, "SubnetMask", i);
+		e->GatewayAddress = PackGetIp32Ex(p, "GatewayAddress", i);
+		e->Metric = PackGetIntEx(p, "Metric", i);
+	}
+}
+void OutRpcEnumL3Table(PACK *p, RPC_ENUM_L3TABLE *t)
+{
+	UINT i;
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+	PackAddStr(p, "Name", t->Name);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_L3TABLE *e = &t->Items[i];
+
+		PackAddIp32Ex(p, "NetworkAddress", e->NetworkAddress, i, t->NumItem);
+		PackAddIp32Ex(p, "SubnetMask", e->SubnetMask, i, t->NumItem);
+		PackAddIp32Ex(p, "GatewayAddress", e->GatewayAddress, i, t->NumItem);
+		PackAddIntEx(p, "Metric", e->Metric, i, t->NumItem);
+	}
+}
+void FreeRpcEnumL3Table(RPC_ENUM_L3TABLE *t)
+{
+	Free(t->Items);
+}
+
+// RPC_L3TABLE
+void InRpcL3Table(RPC_L3TABLE *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_L3TABLE));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+	t->NetworkAddress = PackGetIp32(p, "NetworkAddress");
+	t->SubnetMask = PackGetIp32(p, "SubnetMask");
+	t->GatewayAddress = PackGetIp32(p, "GatewayAddress");
+	t->Metric = PackGetInt(p, "Metric");
+}
+void OutRpcL3Table(PACK *p, RPC_L3TABLE *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "Name", t->Name);
+	PackAddIp32(p, "NetworkAddress", t->NetworkAddress);
+	PackAddIp32(p, "SubnetMask", t->SubnetMask);
+	PackAddIp32(p, "GatewayAddress", t->GatewayAddress);
+	PackAddInt(p, "Metric", t->Metric);
+}
+
+// RPC_ENUM_L3IF
+void InRpcEnumL3If(RPC_ENUM_L3IF *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_L3IF));
+	t->NumItem = PackGetInt(p, "NumItem");
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+	t->Items = ZeroMalloc(sizeof(RPC_L3IF) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_L3IF *f = &t->Items[i];
+
+		PackGetStrEx(p, "HubName", f->HubName, sizeof(f->HubName), i);
+		f->IpAddress = PackGetIp32Ex(p, "IpAddress", i);
+		f->SubnetMask = PackGetIp32Ex(p, "SubnetMask", i);
+	}
+}
+void OutRpcEnumL3If(PACK *p, RPC_ENUM_L3IF *t)
+{
+	UINT i;
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+	PackAddStr(p, "Name", t->Name);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_L3IF *f = &t->Items[i];
+
+		PackAddStrEx(p, "HubName", f->HubName, i, t->NumItem);
+		PackAddIp32Ex(p, "IpAddress", f->IpAddress, i, t->NumItem);
+		PackAddIp32Ex(p, "SubnetMask", f->SubnetMask, i, t->NumItem);
+	}
+}
+void FreeRpcEnumL3If(RPC_ENUM_L3IF *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_L3IF
+void InRpcL3If(RPC_L3IF *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_L3IF));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->IpAddress = PackGetIp32(p, "IpAddress");
+	t->SubnetMask = PackGetIp32(p, "SubnetMask");
+}
+void OutRpcL3If(PACK *p, RPC_L3IF *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "Name", t->Name);
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddIp32(p, "IpAddress", t->IpAddress);
+	PackAddIp32(p, "SubnetMask", t->SubnetMask);
+}
+
+// RPC_L3SW
+void InRpcL3Sw(RPC_L3SW *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_L3SW));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcL3Sw(PACK *p, RPC_L3SW *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_L3SW
+void InRpcEnumL3Sw(RPC_ENUM_L3SW *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_L3SW));
+	t->NumItem = PackGetInt(p, "NumItem");
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_L3SW_ITEM) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_L3SW_ITEM *s = &t->Items[i];
+
+		PackGetStrEx(p, "Name", s->Name, sizeof(s->Name), i);
+		s->NumInterfaces = PackGetIntEx(p, "NumInterfaces", i);
+		s->NumTables = PackGetIntEx(p, "NumTables", i);
+		s->Active = PackGetBoolEx(p, "Active", i);
+		s->Online = PackGetBoolEx(p, "Online", i);
+	}
+}
+void OutRpcEnumL3Sw(PACK *p, RPC_ENUM_L3SW *t)
+{
+	UINT i;
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_L3SW_ITEM *s = &t->Items[i];
+
+		PackAddStrEx(p, "Name", s->Name, i, t->NumItem);
+		PackAddIntEx(p, "NumInterfaces", s->NumInterfaces, i, t->NumItem);
+		PackAddIntEx(p, "NumTables", s->NumTables, i, t->NumItem);
+		PackAddBoolEx(p, "Active", s->Active, i, t->NumItem);
+		PackAddBoolEx(p, "Online", s->Online, i, t->NumItem);
+	}
+}
+void FreeRpcEnumL3Sw(RPC_ENUM_L3SW *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_ENUM_ETH
+void InRpcEnumEth(RPC_ENUM_ETH *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_ETH));
+	t->NumItem = PackGetInt(p, "NumItem");
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_ITEM) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+		PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+		PackGetUniStrEx(p, "NetworkConnectionName", e->NetworkConnectionName, sizeof(e->NetworkConnectionName), i);
+	}
+}
+void OutRpcEnumEth(PACK *p, RPC_ENUM_ETH *t)
+{
+	UINT i;
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+		PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+		PackAddUniStrEx(p, "NetworkConnectionName", e->NetworkConnectionName, i, t->NumItem);
+	}
+}
+void FreeRpcEnumEth(RPC_ENUM_ETH *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_LOCALBRIDGE
+void InRpcLocalBridge(RPC_LOCALBRIDGE *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_LOCALBRIDGE));
+	PackGetStr(p, "DeviceName", t->DeviceName, sizeof(t->DeviceName));
+	PackGetStr(p, "HubNameLB", t->HubName, sizeof(t->HubName));
+	t->TapMode = PackGetBool(p, "TapMode");
+}
+void OutRpcLocalBridge(PACK *p, RPC_LOCALBRIDGE *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "DeviceName", t->DeviceName);
+	PackAddStr(p, "HubNameLB", t->HubName);
+	PackAddBool(p, "TapMode", t->TapMode);
+}
+
+// RPC_ENUM_LOCALBRIDGE
+void InRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_LOCALBRIDGE));
+	t->NumItem = PackGetInt(p, "NumItem");
+	t->Items = ZeroMalloc(sizeof(RPC_LOCALBRIDGE) * t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_LOCALBRIDGE *e = &t->Items[i];
+
+		PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+		PackGetStrEx(p, "HubNameLB", e->HubName, sizeof(e->HubName), i);
+		e->Online = PackGetBoolEx(p, "Online", i);
+		e->Active = PackGetBoolEx(p, "Active", i);
+		e->TapMode = PackGetBoolEx(p, "TapMode", i);
+	}
+}
+void OutRpcEnumLocalBridge(PACK *p, RPC_ENUM_LOCALBRIDGE *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_LOCALBRIDGE *e = &t->Items[i];
+
+		PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+		PackAddStrEx(p, "HubNameLB", e->HubName, i, t->NumItem);
+		PackAddBoolEx(p, "Online", e->Online, i, t->NumItem);
+		PackAddBoolEx(p, "Active", e->Active, i, t->NumItem);
+		PackAddBoolEx(p, "TapMode", e->TapMode, i, t->NumItem);
+	}
+}
+void FreeRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+	Free(t->Items);
+}
+
+// MEMINFO
+void InRpcMemInfo(MEMINFO *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(MEMINFO));
+	t->TotalMemory = PackGetInt64(p, "TotalMemory");
+	t->UsedMemory = PackGetInt64(p, "UsedMemory");
+	t->FreeMemory = PackGetInt64(p, "FreeMemory");
+	t->TotalPhys = PackGetInt64(p, "TotalPhys");
+	t->UsedPhys = PackGetInt64(p, "UsedPhys");
+	t->FreePhys = PackGetInt64(p, "FreePhys");
+}
+void OutRpcMemInfo(PACK *p, MEMINFO *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt64(p, "TotalMemory", t->TotalMemory);
+	PackAddInt64(p, "UsedMemory", t->UsedMemory);
+	PackAddInt64(p, "FreeMemory", t->FreeMemory);
+	PackAddInt64(p, "TotalPhys", t->TotalPhys);
+	PackAddInt64(p, "UsedPhys", t->UsedPhys);
+	PackAddInt64(p, "FreePhys", t->FreePhys);
+}
+
+// OS_INFO
+void InRpcOsInfo(OS_INFO *t, PACK *p)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(OS_INFO));
+	t->OsType = PackGetInt(p, "OsType");
+	t->OsServicePack = PackGetInt(p, "OsServicePack");
+	if (PackGetStr(p, "OsSystemName", tmp, sizeof(tmp)))
+	{
+		t->OsSystemName = CopyStr(tmp);
+	}
+	if (PackGetStr(p, "OsProductName", tmp, sizeof(tmp)))
+	{
+		t->OsProductName = CopyStr(tmp);
+	}
+	if (PackGetStr(p, "OsVendorName", tmp, sizeof(tmp)))
+	{
+		t->OsVendorName = CopyStr(tmp);
+	}
+	if (PackGetStr(p, "OsVersion", tmp, sizeof(tmp)))
+	{
+		t->OsVersion = CopyStr(tmp);
+	}
+	if (PackGetStr(p, "KernelName", tmp, sizeof(tmp)))
+	{
+		t->KernelName = CopyStr(tmp);
+	}
+	if (PackGetStr(p, "KernelVersion", tmp, sizeof(tmp)))
+	{
+		t->KernelVersion = CopyStr(tmp);
+	}
+}
+void OutRpcOsInfo(PACK *p, OS_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "OsType", t->OsType);
+	PackAddInt(p, "OsServicePack", t->OsServicePack);
+	PackAddStr(p, "OsSystemName", t->OsSystemName);
+	PackAddStr(p, "OsProductName", t->OsProductName);
+	PackAddStr(p, "OsVendorName", t->OsVendorName);
+	PackAddStr(p, "OsVersion", t->OsVersion);
+	PackAddStr(p, "KernelName", t->KernelName);
+	PackAddStr(p, "KernelVersion", t->KernelVersion);
+}
+void FreeRpcOsInfo(OS_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->OsSystemName);
+	Free(t->OsProductName);
+	Free(t->OsVendorName);
+	Free(t->OsVersion);
+	Free(t->KernelName);
+	Free(t->KernelVersion);
+}
+
+// ローカルのログファイルを読み込む
+void SiReadLocalLogFile(SERVER *s, char *filepath, UINT offset, RPC_READ_LOG_FILE *t)
+{
+	char exe_dir[MAX_PATH], full_path[MAX_PATH];
+	IO *o;
+	// 引数チェック
+	if (s == NULL || t == NULL || filepath == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+	GetExeDir(exe_dir, sizeof(exe_dir));
+	Format(full_path, sizeof(full_path), "%s/%s", exe_dir, filepath);
+
+	// ファイルを読み込む
+	o = FileOpenEx(full_path, false, false);
+	if (o != NULL)
+	{
+		UINT filesize = FileSize(o);
+
+		if (offset < filesize)
+		{
+			UINT readsize = MIN(filesize - offset, FTP_BLOCK_SIZE);
+			void *buf = ZeroMalloc(readsize);
+
+			FileSeek(o, FILE_BEGIN, offset);
+			FileRead(o, buf, readsize);
+
+			t->Buffer = NewBuf();
+			WriteBuf(t->Buffer, buf, readsize);
+			Free(buf);
+		}
+
+		FileClose(o);
+	}
+}
+
+// ローカルのログファイルを列挙する
+void SiEnumLocalLogFileList(SERVER *s, char *hubname, RPC_ENUM_LOG_FILE *t)
+{
+	LIST *o;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+
+	o = EnumLogFile(hubname);
+
+	t->NumItem = LIST_NUM(o);
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		LOG_FILE *f = LIST_DATA(o, i);
+		RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+		StrCpy(e->FilePath, sizeof(e->FilePath), f->Path);
+		StrCpy(e->ServerName, sizeof(e->ServerName), f->ServerName);
+		e->FileSize = f->FileSize;
+		e->UpdatedTime = f->UpdatedTime;
+	}
+
+	FreeEnumLogFile(o);
+}
+
+// ローカルのセッションを列挙する
+void SiEnumLocalSession(SERVER *s, char *hubname, RPC_ENUM_SESSION *t)
+{
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || hubname == NULL || t == NULL)
+	{
+		return;
+	}
+
+	LockHubList(s->Cedar);
+	h = GetHub(s->Cedar, hubname);
+	UnlockHubList(s->Cedar);
+
+	if (h == NULL)
+	{
+		t->NumSession = 0;
+		t->Sessions = ZeroMalloc(0);
+		return;
+	}
+
+	LockList(h->SessionList);
+	{
+		UINT i;
+		t->NumSession = LIST_NUM(h->SessionList);
+		t->Sessions = ZeroMalloc(sizeof(RPC_ENUM_SESSION_ITEM) * t->NumSession);
+
+		for (i = 0;i < t->NumSession;i++)
+		{
+			SESSION *s = LIST_DATA(h->SessionList, i);
+			RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+			Lock(s->lock);
+			{
+				StrCpy(e->Name, sizeof(e->Name), s->Name);
+				StrCpy(e->Username, sizeof(e->Username), s->Username);
+				e->Ip = IPToUINT(&s->Connection->ClientIp);
+				StrCpy(e->Hostname, sizeof(e->Hostname), s->Connection->ClientHostname);
+				e->MaxNumTcp = s->MaxConnection;
+				e->LinkMode = s->LinkModeServer;
+				e->SecureNATMode = s->SecureNATMode;
+				e->BridgeMode = s->BridgeMode;
+				e->Layer3Mode = s->L3SwitchMode;
+				e->VLanId = s->VLanId;
+				LockList(s->Connection->Tcp->TcpSockList);
+				{
+					e->CurrentNumTcp = s->Connection->Tcp->TcpSockList->num_item;
+				}
+				UnlockList(s->Connection->Tcp->TcpSockList);
+				Lock(s->TrafficLock);
+				{
+					e->PacketSize = GetTrafficPacketSize(s->Traffic);
+					e->PacketNum = GetTrafficPacketNum(s->Traffic);
+				}
+				Unlock(s->TrafficLock);
+				e->Client_BridgeMode = s->IsBridgeMode;
+				e->Client_MonitorMode = s->IsMonitorMode;
+				Copy(e->UniqueId, s->NodeInfo.UniqueId, 16);
+			}
+			Unlock(s->lock);
+			GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+		}
+	}
+	UnlockList(h->SessionList);
+
+	ReleaseHub(h);
+}
+
+// RPC_ENUM_LICENSE_KEY
+void InRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_LICENSE_KEY));
+	t->NumItem = PackGetInt(p, "NumItem");
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_LICENSE_KEY_ITEM) * t->NumItem);
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_LICENSE_KEY_ITEM *e = &t->Items[i];
+
+		e->Id = PackGetIntEx(p, "Id", i);
+		PackGetStrEx(p, "LicenseKey", e->LicenseKey, sizeof(e->LicenseKey), i);
+		PackGetStrEx(p, "LicenseId", e->LicenseId, sizeof(e->LicenseId), i);
+		PackGetStrEx(p, "LicenseName", e->LicenseName, sizeof(e->LicenseName), i);
+		e->Expires = PackGetInt64Ex(p, "Expires", i);
+		e->Status = PackGetIntEx(p, "Status", i);
+		e->ProductId = PackGetIntEx(p, "ProductId", i);
+		e->SystemId = PackGetInt64Ex(p, "SystemId", i);
+		e->SerialId = PackGetIntEx(p, "SerialId", i);
+	}
+}
+void OutRpcEnumLicenseKey(PACK *p, RPC_ENUM_LICENSE_KEY *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_LICENSE_KEY_ITEM *e = &t->Items[i];
+
+		PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+		PackAddStrEx(p, "LicenseKey", e->LicenseKey, i, t->NumItem);
+		PackAddStrEx(p, "LicenseId", e->LicenseId, i, t->NumItem);
+		PackAddStrEx(p, "LicenseName", e->LicenseName, i, t->NumItem);
+		PackAddInt64Ex(p, "Expires", e->Expires, i, t->NumItem);
+		PackAddIntEx(p, "Status", e->Status, i, t->NumItem);
+		PackAddIntEx(p, "ProductId", e->ProductId, i, t->NumItem);
+		PackAddInt64Ex(p, "SystemId", e->SystemId, i, t->NumItem);
+		PackAddIntEx(p, "SerialId", e->SerialId, i, t->NumItem);
+	}
+}
+void FreeRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_LICENSE_STATUS
+void InRpcLicenseStatus(RPC_LICENSE_STATUS *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_LICENSE_STATUS));
+
+	t->EditionId = PackGetInt(p, "EditionId");
+	PackGetStr(p, "EditionStr", t->EditionStr, sizeof(t->EditionStr) );
+	t->SystemId = PackGetInt64(p, "SystemId");
+	t->SystemExpires = PackGetInt64(p, "SystemExpires");
+	t->NumClientConnectLicense = PackGetInt(p, "NumClientConnectLicense");
+	t->NumBridgeConnectLicense = PackGetInt(p, "NumBridgeConnectLicense");
+
+	// v3.0
+	t->NeedSubscription = PackGetBool(p, "NeedSubscription");
+	t->AllowEnterpriseFunction = PackGetBool(p, "AllowEnterpriseFunction");
+	t->SubscriptionExpires = PackGetInt64(p, "SubscriptionExpires");
+	t->IsSubscriptionExpired = PackGetBool(p, "IsSubscriptionExpired");
+	t->NumUserCreationLicense = PackGetInt(p, "NumUserCreationLicense");
+	t->ReleaseDate = PackGetInt64(p, "ReleaseDate");
+}
+void OutRpcLicenseStatus(PACK *p, RPC_LICENSE_STATUS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "EditionId", t->EditionId);
+	PackAddStr(p, "EditionStr", t->EditionStr);
+	PackAddInt64(p, "SystemId", t->SystemId);
+	PackAddInt64(p, "SystemExpires", t->SystemExpires);
+	PackAddInt(p, "NumClientConnectLicense", t->NumClientConnectLicense);
+	PackAddInt(p, "NumBridgeConnectLicense", t->NumBridgeConnectLicense);
+
+	// v3.0
+	PackAddBool(p, "NeedSubscription", t->NeedSubscription);
+	PackAddBool(p, "AllowEnterpriseFunction", t->AllowEnterpriseFunction);
+	PackAddInt64(p, "SubscriptionExpires", t->SubscriptionExpires);
+	PackAddBool(p, "IsSubscriptionExpired", t->IsSubscriptionExpired);
+	PackAddInt(p, "NumUserCreationLicense", t->NumUserCreationLicense);
+	PackAddInt64(p, "ReleaseDate", t->ReleaseDate);
+}
+
+// RPC_ADMIN_OPTION
+void InRpcAdminOption(RPC_ADMIN_OPTION *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ADMIN_OPTION));
+	t->NumItem = PackGetInt(p, "NumItem");
+	t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		ADMIN_OPTION *o = &t->Items[i];
+
+		PackGetStrEx(p, "Name", o->Name, sizeof(o->Name), i);
+		o->Value = PackGetIntEx(p, "Value", i);
+	}
+}
+void OutRpcAdminOption(PACK *p, RPC_ADMIN_OPTION *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+
+	PackAddStr(p, "HubName", t->HubName);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		ADMIN_OPTION *o = &t->Items[i];
+
+		PackAddStrEx(p, "Name", o->Name, i, t->NumItem);
+		PackAddIntEx(p, "Value", o->Value, i, t->NumItem);
+	}
+}
+void FreeRpcAdminOption(RPC_ADMIN_OPTION *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_CONFIG
+void InRpcConfig(RPC_CONFIG *t, PACK *p)
+{
+	UINT size;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_CONFIG));
+	PackGetStr(p, "FileName", t->FileName, sizeof(t->FileName));
+	size = PackGetDataSize(p, "FileData");
+	t->FileData = ZeroMalloc(size + 1);
+	PackGetData(p, "FileData", t->FileData);
+}
+void OutRpcConfig(PACK *p, RPC_CONFIG *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "FileName", t->FileName);
+	PackAddData(p, "FileData", t->FileData, StrLen(t->FileData));
+}
+void FreeRpcConfig(RPC_CONFIG *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->FileData);
+}
+
+// RPC_BRIDGE_SUPPORT
+void InRpcBridgeSupport(RPC_BRIDGE_SUPPORT *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_BRIDGE_SUPPORT));
+
+	t->IsBridgeSupportedOs = PackGetBool(p, "IsBridgeSupportedOs");
+	t->IsWinPcapNeeded = PackGetBool(p, "IsWinPcapNeeded");
+}
+void OutRpcBridgeSupport(PACK *p, RPC_BRIDGE_SUPPORT *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddBool(p, "IsBridgeSupportedOs", t->IsBridgeSupportedOs);
+	PackAddBool(p, "IsWinPcapNeeded",t->IsWinPcapNeeded);
+}
+
+// RPC_ADD_ACCESS
+void InRpcAddAccess(RPC_ADD_ACCESS *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ADD_ACCESS));
+
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	InRpcAccess(&t->Access, p);
+}
+void OutRpcAddAccess(PACK *p, RPC_ADD_ACCESS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	OutRpcAccess(p, &t->Access);
+}
+
+// RPC_DELETE_ACCESS
+void InRpcDeleteAccess(RPC_DELETE_ACCESS *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_DELETE_ACCESS));
+
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Id = PackGetInt(p, "Id");
+}
+void OutRpcDeleteAccess(PACK *p, RPC_DELETE_ACCESS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddInt(p, "Id", t->Id);
+}
+
+
+// RPC_SERVER_INFO
+void InRpcServerInfo(RPC_SERVER_INFO *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_SERVER_INFO));
+
+	PackGetStr(p, "ServerProductName", t->ServerProductName, sizeof(t->ServerProductName));
+	PackGetStr(p, "ServerVersionString", t->ServerVersionString, sizeof(t->ServerVersionString));
+	PackGetStr(p, "ServerBuildInfoString", t->ServerBuildInfoString, sizeof(t->ServerBuildInfoString));
+	t->ServerVerInt = PackGetInt(p, "ServerVerInt");
+	t->ServerBuildInt = PackGetInt(p, "ServerBuildInt");
+	PackGetStr(p, "ServerHostName", t->ServerHostName, sizeof(t->ServerHostName));
+	t->ServerType = PackGetInt(p, "ServerType");
+	InRpcOsInfo(&t->OsInfo, p);
+}
+void OutRpcServerInfo(PACK *p, RPC_SERVER_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "ServerProductName", t->ServerProductName);
+	PackAddStr(p, "ServerVersionString", t->ServerVersionString);
+	PackAddStr(p, "ServerBuildInfoString", t->ServerBuildInfoString);
+	PackAddInt(p, "ServerVerInt", t->ServerVerInt);
+	PackAddInt(p, "ServerBuildInt", t->ServerBuildInt);
+	PackAddStr(p, "ServerHostName", t->ServerHostName);
+	PackAddInt(p, "ServerType", t->ServerType);
+	OutRpcOsInfo(p, &t->OsInfo);
+}
+void FreeRpcServerInfo(RPC_SERVER_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FreeRpcOsInfo(&t->OsInfo);
+}
+
+// RPC_SERVER_STATUS
+void InRpcServerStatus(RPC_SERVER_STATUS *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_SERVER_STATUS));
+	t->ServerType = PackGetInt(p, "ServerType");
+	t->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+	t->NumTcpConnectionsLocal = PackGetInt(p, "NumTcpConnectionsLocal");
+	t->NumTcpConnectionsRemote = PackGetInt(p, "NumTcpConnectionsRemote");
+	t->NumHubTotal = PackGetInt(p, "NumHubTotal");
+	t->NumHubStandalone = PackGetInt(p, "NumHubStandalone");
+	t->NumHubStatic = PackGetInt(p, "NumHubStatic");
+	t->NumHubDynamic = PackGetInt(p, "NumHubDynamic");
+	t->NumSessionsTotal = PackGetInt(p, "NumSessionsTotal");
+	t->NumSessionsLocal = PackGetInt(p, "NumSessionsLocal");
+	t->NumSessionsRemote = PackGetInt(p, "NumSessionsRemote");
+	t->NumMacTables = PackGetInt(p, "NumMacTables");
+	t->NumIpTables = PackGetInt(p, "NumIpTables");
+	t->NumUsers = PackGetInt(p, "NumUsers");
+	t->NumGroups = PackGetInt(p, "NumGroups");
+	t->CurrentTime = PackGetInt64(p, "CurrentTime");
+	t->CurrentTick = PackGetInt64(p, "CurrentTick");
+	t->AssignedBridgeLicenses = PackGetInt(p, "AssignedBridgeLicenses");
+	t->AssignedClientLicenses = PackGetInt(p, "AssignedClientLicenses");
+	t->AssignedBridgeLicensesTotal = PackGetInt(p, "AssignedBridgeLicensesTotal");
+	t->AssignedClientLicensesTotal = PackGetInt(p, "AssignedClientLicensesTotal");
+	t->StartTime = PackGetInt64(p, "StartTime");
+
+	InRpcTraffic(&t->Traffic, p);
+
+	InRpcMemInfo(&t->MemInfo, p);
+}
+void OutRpcServerStatus(PACK *p, RPC_SERVER_STATUS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "ServerType", t->ServerType);
+	PackAddInt(p, "NumTcpConnections", t->NumTcpConnections);
+	PackAddInt(p, "NumHubTotal", t->NumHubTotal);
+	PackAddInt(p, "NumHubStandalone", t->NumHubStandalone);
+	PackAddInt(p, "NumHubStatic", t->NumHubStatic);
+	PackAddInt(p, "NumHubDynamic", t->NumHubDynamic);
+	PackAddInt(p, "NumSessionsTotal", t->NumSessionsTotal);
+	PackAddInt(p, "NumSessionsLocal", t->NumSessionsLocal);
+	PackAddInt(p, "NumSessionsRemote", t->NumSessionsRemote);
+	PackAddInt(p, "NumTcpConnections", t->NumTcpConnections);
+	PackAddInt(p, "NumTcpConnectionsLocal", t->NumTcpConnectionsLocal);
+	PackAddInt(p, "NumTcpConnectionsRemote", t->NumTcpConnectionsRemote);
+	PackAddInt(p, "NumMacTables", t->NumMacTables);
+	PackAddInt(p, "NumIpTables", t->NumIpTables);
+	PackAddInt(p, "NumUsers", t->NumUsers);
+	PackAddInt(p, "NumGroups", t->NumGroups);
+	PackAddInt64(p, "CurrentTime", t->CurrentTime);
+	PackAddInt64(p, "CurrentTick", t->CurrentTick);
+	PackAddInt(p, "AssignedBridgeLicenses", t->AssignedBridgeLicenses);
+	PackAddInt(p, "AssignedClientLicenses", t->AssignedClientLicenses);
+	PackAddInt(p, "AssignedBridgeLicensesTotal", t->AssignedBridgeLicensesTotal);
+	PackAddInt(p, "AssignedClientLicensesTotal", t->AssignedClientLicensesTotal);
+	PackAddInt64(p, "StartTime", t->StartTime);
+
+	OutRpcTraffic(p, &t->Traffic);
+
+	OutRpcMemInfo(p, &t->MemInfo);
+}
+
+// RPC_LISTENER
+void InRpcListener(RPC_LISTENER *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_LISTENER));
+	t->Port = PackGetInt(p, "Port");
+	t->Enable = PackGetBool(p, "Enable");
+}
+void OutRpcListener(PACK *p, RPC_LISTENER *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "Port", t->Port);
+	PackAddBool(p, "Enable", t->Enable);
+}
+
+// RPC_LISTENER_LIST
+void InRpcListenerList(RPC_LISTENER_LIST *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_LISTENER_LIST));
+	t->NumPort = PackGetIndexCount(p, "Ports");
+	t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+	t->Enables = ZeroMalloc(sizeof(UINT) * t->NumPort);
+	t->Errors = ZeroMalloc(sizeof(UINT) * t->NumPort);
+	for (i = 0;i < t->NumPort;i++)
+	{
+		t->Ports[i] = PackGetIntEx(p, "Ports", i);
+		t->Enables[i] = PackGetBoolEx(p, "Enables", i);
+		t->Errors[i] = PackGetBoolEx(p, "Errors", i);
+	}
+}
+void OutRpcListenerList(PACK *p, RPC_LISTENER_LIST *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumPort;i++)
+	{
+		PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+		PackAddBoolEx(p, "Enables", t->Enables[i], i, t->NumPort);
+		PackAddBoolEx(p, "Errors", t->Errors[i], i, t->NumPort);
+	}
+}
+void FreeRpcListenerList(RPC_LISTENER_LIST *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Ports);
+	Free(t->Enables);
+	Free(t->Errors);
+}
+
+// RPC_STR
+void InRpcStr(RPC_STR *t, PACK *p)
+{
+	UINT size = 65536;
+	char *tmp = Malloc(size);
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_STR));
+	if (PackGetStr(p, "String", tmp, size) == false)
+	{
+		t->String = CopyStr("");
+	}
+	else
+	{
+		t->String = CopyStr(tmp);
+	}
+	Free(tmp);
+}
+void OutRpcStr(PACK *p, RPC_STR *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "String", t->String);
+}
+void FreeRpcStr(RPC_STR *t)
+{
+	// 引数チェック
+	if (t == NULL )
+	{
+		return;
+	}
+
+	Free(t->String);
+}
+
+// RPC_SET_PASSWORD
+void InRpcSetPassword(RPC_SET_PASSWORD *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_SET_PASSWORD));
+	PackGetData2(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+}
+void OutRpcSetPassword(PACK *p, RPC_SET_PASSWORD *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddData(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+}
+
+// RPC_FARM
+void InRpcFarm(RPC_FARM *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_FARM));
+	t->ServerType = PackGetInt(p, "ServerType");
+	t->NumPort = PackGetIndexCount(p, "Ports");
+	t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+	for (i = 0;i < t->NumPort;i++)
+	{
+		t->Ports[i] = PackGetIntEx(p, "Ports", i);
+	}
+	t->PublicIp = PackGetIp32(p, "PublicIp");
+	PackGetStr(p, "ControllerName", t->ControllerName, sizeof(t->ControllerName));
+	t->ControllerPort = PackGetInt(p, "ControllerPort");
+	PackGetData2(p, "MemberPassword", t->MemberPassword, sizeof(t->MemberPassword));
+	t->Weight = PackGetInt(p, "Weight");
+	t->ControllerOnly = PackGetBool(p, "ControllerOnly");
+}
+void OutRpcFarm(PACK *p, RPC_FARM *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "ServerType", t->ServerType);
+	for (i = 0;i < t->NumPort;i++)
+	{
+		PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+	}
+	PackAddIp32(p, "PublicIp", t->PublicIp);
+	PackAddStr(p, "ControllerName", t->ControllerName);
+	PackAddInt(p, "ControllerPort", t->ControllerPort);
+	PackAddData(p, "MemberPassword", t->MemberPassword, sizeof(t->MemberPassword));
+	PackAddInt(p, "Weight", t->Weight);
+	PackAddBool(p, "ControllerOnly", t->ControllerOnly);
+}
+void FreeRpcFarm(RPC_FARM *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Ports);
+}
+
+// RPC_FARM_HUB
+void InRpcFarmHub(RPC_FARM_HUB *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_FARM_HUB));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->DynamicHub = PackGetBool(p, "DynamicHub");
+}
+void OutRpcFarmHub(PACK *p, RPC_FARM_HUB *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddBool(p, "DynamicHub", t->DynamicHub);
+}
+
+// RPC_FARM_INFO
+void InRpcFarmInfo(RPC_FARM_INFO *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_FARM_INFO));
+	t->Id = PackGetInt(p, "Id");
+	t->Controller = PackGetBool(p, "Controller");
+	t->ConnectedTime = PackGetInt64(p, "ConnectedTime");
+	t->Ip = PackGetIp32(p, "Ip");
+	PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));
+	t->Point = PackGetInt(p, "Point");
+	t->NumPort = PackGetIndexCount(p, "Ports");
+	t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+	for (i = 0;i < t->NumPort;i++)
+	{
+		t->Ports[i] = PackGetIntEx(p, "Ports", i);
+	}
+	t->ServerCert = PackGetX(p, "ServerCert");
+	t->NumFarmHub = PackGetIndexCount(p, "HubName");
+	t->FarmHubs = ZeroMalloc(sizeof(RPC_FARM_HUB) * t->NumFarmHub);
+	for (i = 0;i < t->NumFarmHub;i++)
+	{
+		PackGetStrEx(p, "HubName", t->FarmHubs[i].HubName, sizeof(t->FarmHubs[i].HubName), i);
+		t->FarmHubs[i].DynamicHub = PackGetBoolEx(p, "DynamicHub", i);
+	}
+	t->NumSessions = PackGetInt(p, "NumSessions");
+	t->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+	t->Weight = PackGetInt(p, "Weight");
+}
+void OutRpcFarmInfo(PACK *p, RPC_FARM_INFO *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "Id", t->Id);
+	PackAddBool(p, "Controller", t->Controller);
+	PackAddInt64(p, "ConnectedTime", t->ConnectedTime);
+	PackAddIp32(p, "Ip", t->Ip);
+	PackAddStr(p, "Hostname", t->Hostname);
+	PackAddInt(p, "Point", t->Point);
+	for (i = 0;i < t->NumPort;i++)
+	{
+		PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+	}
+	PackAddX(p, "ServerCert", t->ServerCert);
+	for (i = 0;i < t->NumFarmHub;i++)
+	{
+		PackAddStrEx(p, "HubName", t->FarmHubs[i].HubName, i, t->NumFarmHub);
+		PackAddBoolEx(p, "DynamicHub", t->FarmHubs[i].DynamicHub, i, t->NumFarmHub);
+	}
+	PackAddInt(p, "NumSessions", t->NumSessions);
+	PackAddInt(p, "NumTcpConnections", t->NumTcpConnections);
+	PackAddInt(p, "Weight", t->Weight);
+}
+void FreeRpcFarmInfo(RPC_FARM_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Ports);
+	Free(t->FarmHubs);
+	FreeX(t->ServerCert);
+}
+
+void InRpcEnumFarm(RPC_ENUM_FARM *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_FARM));
+	t->NumFarm = PackGetIndexCount(p, "Id");
+	t->Farms = ZeroMalloc(sizeof(RPC_ENUM_FARM_ITEM) * t->NumFarm);
+
+	for (i = 0;i < t->NumFarm;i++)
+	{
+		RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+		e->Id = PackGetIntEx(p, "Id", i);
+		e->Controller = PackGetBoolEx(p, "Controller", i);
+		e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+		e->Ip = PackGetIp32Ex(p, "Ip", i);
+		PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+		e->Point = PackGetIntEx(p, "Point", i);
+		e->NumSessions = PackGetIntEx(p, "NumSessions", i);
+		e->NumTcpConnections = PackGetIntEx(p, "NumTcpConnections", i);
+		e->NumHubs = PackGetIntEx(p, "NumHubs", i);
+		e->AssignedClientLicense = PackGetIntEx(p, "AssignedClientLicense", i);
+		e->AssignedBridgeLicense = PackGetIntEx(p, "AssignedBridgeLicense", i);
+	}
+}
+void OutRpcEnumFarm(PACK *p, RPC_ENUM_FARM *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumFarm;i++)
+	{
+		RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+		PackAddIntEx(p, "Id", e->Id, i, t->NumFarm);
+		PackAddBoolEx(p, "Controller", e->Controller, i, t->NumFarm);
+		PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumFarm);
+		PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumFarm);
+		PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumFarm);
+		PackAddIntEx(p, "Point", e->Point, i, t->NumFarm);
+		PackAddIntEx(p, "NumSessions", e->NumSessions, i, t->NumFarm);
+		PackAddIntEx(p, "NumTcpConnections", e->NumTcpConnections, i, t->NumFarm);
+		PackAddIntEx(p, "NumHubs", e->NumHubs, i, t->NumFarm);
+		PackAddIntEx(p, "AssignedClientLicense", e->AssignedClientLicense, i, t->NumFarm);
+		PackAddIntEx(p, "AssignedBridgeLicense", e->AssignedBridgeLicense, i, t->NumFarm);
+	}
+}
+void FreeRpcEnumFarm(RPC_ENUM_FARM *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Farms);
+}
+
+// RPC_FARM_CONNECTION_STATUS
+void InRpcFarmConnectionStatus(RPC_FARM_CONNECTION_STATUS *t, PACK *p)
+{
+	Zero(t, sizeof(RPC_FARM_CONNECTION_STATUS));
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	t->Ip = PackGetIp32(p, "Ip");
+	t->Port = PackGetInt(p, "Port");
+	t->Online = PackGetBool(p, "Online");
+	t->LastError = PackGetInt(p, "LastError");
+	t->StartedTime = PackGetInt64(p, "StartedTime");
+	t->CurrentConnectedTime = PackGetInt64(p, "CurrentConnectedTime");
+	t->FirstConnectedTime = PackGetInt64(p, "FirstConnectedTime");
+	t->NumConnected = PackGetInt(p, "NumConnected");
+	t->NumTry = PackGetInt(p, "NumTry");
+	t->NumFailed = PackGetInt(p, "NumFailed");
+}
+void OutRpcFarmConnectionStatus(PACK *p, RPC_FARM_CONNECTION_STATUS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddIp32(p, "Ip", t->Ip);
+	PackAddInt(p, "Port", t->Port);
+	PackAddBool(p, "Online", t->Online);
+	PackAddInt(p, "LastError", t->LastError);
+	PackAddInt64(p, "StartedTime", t->StartedTime);
+	PackAddInt64(p, "CurrentConnectedTime", t->CurrentConnectedTime);
+	PackAddInt64(p, "FirstConnectedTime", t->FirstConnectedTime);
+	PackAddInt(p, "NumConnected", t->NumConnected);
+	PackAddInt(p, "NumTry", t->NumTry);
+	PackAddInt(p, "NumFailed", t->NumFailed);
+}
+
+// RPC_HUB_OPTION
+void InRpcHubOption(RPC_HUB_OPTION *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_HUB_OPTION));
+	t->MaxSession = PackGetInt(p, "MaxSession");
+	t->NoEnum = PackGetBool(p, "NoEnum");
+}
+void OutRpcHubOption(PACK *p, RPC_HUB_OPTION *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "MaxSession", t->MaxSession);
+	PackAddBool(p, "NoEnum", t->NoEnum);
+}
+
+// RPC_RADIUS
+void InRpcRadius(RPC_RADIUS *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_RADIUS));
+	PackGetStr(p, "RadiusServerName", t->RadiusServerName, sizeof(t->RadiusServerName));
+	t->RadiusPort = PackGetInt(p, "RadiusPort");
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetStr(p, "RadiusSecret", t->RadiusSecret, sizeof(t->RadiusSecret));
+	t->RadiusRetryInterval = PackGetInt(p, "RadiusRetryInterval");
+}
+void OutRpcRadius(PACK *p, RPC_RADIUS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "RadiusServerName", t->RadiusServerName);
+	PackAddInt(p, "RadiusPort", t->RadiusPort);
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddStr(p, "RadiusSecret", t->RadiusSecret);
+	PackAddInt(p, "RadiusRetryInterval", t->RadiusRetryInterval);
+}
+
+// RPC_HUB
+void InRpcHub(RPC_HUB *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_HUB));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcHub(PACK *p, RPC_HUB *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+}
+
+// RPC_CREATE_HUB
+void InRpcCreateHub(RPC_CREATE_HUB *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_CREATE_HUB));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetData2(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+	PackGetData2(p, "SecurePassword", t->SecurePassword, sizeof(t->SecurePassword));
+	t->Online = PackGetBool(p, "Online");
+	InRpcHubOption(&t->HubOption, p);
+	t->HubType = PackGetInt(p, "HubType");
+}
+void OutRpcCreateHub(PACK *p, RPC_CREATE_HUB *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddData(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+	PackAddData(p, "SecurePassword", t->SecurePassword, sizeof(t->SecurePassword));
+	PackAddBool(p, "Online", t->Online);
+	OutRpcHubOption(p, &t->HubOption);
+	PackAddInt(p, "HubType", t->HubType);
+}
+
+// RPC_ENUM_HUB
+void InRpcEnumHub(RPC_ENUM_HUB *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_HUB));
+	t->NumHub = PackGetIndexCount(p, "HubName");
+	t->Hubs = ZeroMalloc(sizeof(RPC_ENUM_HUB_ITEM) * t->NumHub);
+
+	for (i = 0;i < t->NumHub;i++)
+	{
+		RPC_ENUM_HUB_ITEM *e = &t->Hubs[i];
+
+		PackGetStrEx(p, "HubName", e->HubName, sizeof(e->HubName), i);
+		e->Online = PackGetBoolEx(p, "Online", i);
+		e->HubType = PackGetIntEx(p, "HubType", i);
+		e->NumSessions = PackGetIntEx(p, "NumSessions", i);
+		e->NumUsers = PackGetIntEx(p, "NumUsers", i);
+		e->NumGroups = PackGetIntEx(p, "NumGroups", i);
+		e->NumMacTables = PackGetIntEx(p, "NumMacTables", i);
+		e->NumIpTables = PackGetIntEx(p, "NumIpTables", i);
+		e->LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);
+		e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+		e->LastLoginTime = PackGetInt64Ex(p, "LastLoginTime", i);
+		e->NumLogin = PackGetIntEx(p, "NumLogin", i);
+	}
+}
+void OutRpcEnumHub(PACK *p, RPC_ENUM_HUB *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumHub;i++)
+	{
+		RPC_ENUM_HUB_ITEM *e = &t->Hubs[i];
+
+		PackAddStrEx(p, "HubName", e->HubName, i, t->NumHub);
+		PackAddBoolEx(p, "Online", e->Online, i, t->NumHub);
+		PackAddIntEx(p, "HubType", e->HubType, i, t->NumHub);
+		PackAddIntEx(p, "NumSessions", e->NumSessions, i, t->NumHub);
+		PackAddIntEx(p, "NumUsers", e->NumUsers, i, t->NumHub);
+		PackAddIntEx(p, "NumGroups", e->NumGroups, i, t->NumHub);
+		PackAddIntEx(p, "NumMacTables", e->NumMacTables, i, t->NumHub);
+		PackAddIntEx(p, "NumIpTables", e->NumIpTables, i, t->NumHub);
+		PackAddInt64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumHub);
+		PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumHub);
+		PackAddInt64Ex(p, "LastLoginTime", e->LastLoginTime, i, t->NumHub);
+		PackAddIntEx(p, "NumLogin", e->NumLogin, i, t->NumHub);
+	}
+}
+void FreeRpcEnumHub(RPC_ENUM_HUB *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Hubs);
+}
+
+// RPC_DELETE_HUB
+void InRpcDeleteHub(RPC_DELETE_HUB *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_DELETE_HUB));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcDeleteHub(PACK *p, RPC_DELETE_HUB *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+}
+
+// RPC_ENUM_CONNECTION
+void InRpcEnumConnection(RPC_ENUM_CONNECTION *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_CONNECTION));
+	t->NumConnection = PackGetIndexCount(p, "Name");
+	t->Connections = ZeroMalloc(sizeof(RPC_ENUM_CONNECTION_ITEM) * t->NumConnection);
+
+	for (i = 0;i < t->NumConnection;i++)
+	{
+		RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+
+		e->Ip = PackGetIp32Ex(p, "Ip", i);
+		e->Port = PackGetIntEx(p, "Port", i);
+		PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+		PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+		e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+		e->Type = PackGetIntEx(p, "Type", i);
+	}
+}
+void OutRpcEnumConnection(PACK *p, RPC_ENUM_CONNECTION *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumConnection;i++)
+	{
+		RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+
+		PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumConnection);
+		PackAddIntEx(p, "Port", e->Port, i, t->NumConnection);
+		PackAddStrEx(p, "Name", e->Name, i, t->NumConnection);
+		PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumConnection);
+		PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumConnection);
+		PackAddIntEx(p, "Type", e->Type, i, t->NumConnection);
+	}
+}
+void FreeRpcEnumConnetion(RPC_ENUM_CONNECTION *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Connections);
+}
+
+// RPC_DISCONNECT_CONNECTION
+void InRpcDisconnectConnection(RPC_DISCONNECT_CONNECTION *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_DISCONNECT_CONNECTION));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDisconnectConnection(PACK *p, RPC_DISCONNECT_CONNECTION *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_CONNECTION_INFO
+void InRpcConnectionInfo(RPC_CONNECTION_INFO *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_CONNECTION_INFO));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+	t->Ip = PackGetIp32(p, "Ip");
+	t->Port = PackGetInt(p, "Port");
+	t->ConnectedTime = PackGetInt64(p, "ConnectedTime");
+	PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));
+	PackGetStr(p, "ServerStr", t->ServerStr, sizeof(t->ServerStr));
+	PackGetStr(p, "ClientStr", t->ClientStr, sizeof(t->ClientStr));
+	t->ServerVer = PackGetInt(p, "ServerVer");
+	t->ServerBuild = PackGetInt(p, "ServerBuild");
+	t->ClientVer = PackGetInt(p, "ClientVer");
+	t->ClientBuild = PackGetInt(p, "ClientBuild");
+	t->Type = PackGetInt(p, "Type");
+}
+void OutRpcConnectionInfo(PACK *p, RPC_CONNECTION_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "Name", t->Name);
+	PackAddIp32(p, "Ip", t->Ip);
+	PackAddInt(p, "Port", t->Port);
+	PackAddInt64(p, "ConnectedTime", t->ConnectedTime);
+	PackAddStr(p, "Hostname", t->Hostname);
+	PackAddStr(p, "ServerStr", t->ServerStr);
+	PackAddStr(p, "ClientStr", t->ClientStr);
+	PackAddInt(p, "ServerVer", t->ServerVer);
+	PackAddInt(p, "ServerBuild", t->ServerBuild);
+	PackAddInt(p, "ClientVer", t->ClientVer);
+	PackAddInt(p, "ClientBuild", t->ClientBuild);
+	PackAddInt(p, "Type", t->Type);
+}
+
+// RPC_SET_HUB_ONLINE
+void InRpcSetHubOnline(RPC_SET_HUB_ONLINE *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_SET_HUB_ONLINE));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Online = PackGetBool(p, "Online");
+}
+void OutRpcSetHubOnline(PACK *p, RPC_SET_HUB_ONLINE *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddBool(p, "Online", t->Online);
+}
+
+// RPC_HUB_STATUS
+void InRpcHubStatus(RPC_HUB_STATUS *t, PACK *p)
+{
+	Zero(t, sizeof(RPC_HUB_STATUS));
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Online = PackGetBool(p, "Online");
+	t->HubType = PackGetInt(p, "HubType");
+	t->NumSessions = PackGetInt(p, "NumSessions");
+	t->NumSessionsClient = PackGetInt(p, "NumSessionsClient");
+	t->NumSessionsBridge = PackGetInt(p, "NumSessionsBridge");
+	t->NumAccessLists = PackGetInt(p, "NumAccessLists");
+	t->NumUsers = PackGetInt(p, "NumUsers");
+	t->NumGroups = PackGetInt(p, "NumGroups");
+	t->NumMacTables = PackGetInt(p, "NumMacTables");
+	t->NumIpTables = PackGetInt(p, "NumIpTables");
+	t->SecureNATEnabled = PackGetBool(p, "SecureNATEnabled");
+	InRpcTraffic(&t->Traffic, p);
+	t->LastCommTime = PackGetInt64(p, "LastCommTime");
+	t->CreatedTime = PackGetInt64(p, "CreatedTime");
+	t->LastLoginTime = PackGetInt64(p, "LastLoginTime");
+	t->NumLogin = PackGetInt(p, "NumLogin");
+}
+void OutRpcHubStatus(PACK *p, RPC_HUB_STATUS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddBool(p, "Online", t->Online);
+	PackAddInt(p, "HubType", t->HubType);
+	PackAddInt(p, "NumSessions", t->NumSessions);
+	PackAddInt(p, "NumSessionsClient", t->NumSessionsClient);
+	PackAddInt(p, "NumSessionsBridge", t->NumSessionsBridge);
+	PackAddInt(p, "NumAccessLists", t->NumAccessLists);
+	PackAddInt(p, "NumUsers", t->NumUsers);
+	PackAddInt(p, "NumGroups", t->NumGroups);
+	PackAddInt(p, "NumMacTables", t->NumMacTables);
+	PackAddInt(p, "NumIpTables", t->NumIpTables);
+	PackAddBool(p, "SecureNATEnabled", t->SecureNATEnabled);
+	OutRpcTraffic(p, &t->Traffic);
+	PackAddInt64(p, "LastCommTime", t->LastCommTime);
+	PackAddInt64(p, "CreatedTime", t->CreatedTime);
+	PackAddInt64(p, "LastLoginTime", t->LastLoginTime);
+	PackAddInt(p, "NumLogin", t->NumLogin);
+}
+
+// RPC_HUB_LOG
+void InRpcHubLog(RPC_HUB_LOG *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_HUB_LOG));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->LogSetting.SaveSecurityLog = PackGetBool(p, "SaveSecurityLog");
+	t->LogSetting.SecurityLogSwitchType = PackGetInt(p, "SecurityLogSwitchType");
+	t->LogSetting.SavePacketLog = PackGetBool(p, "SavePacketLog");
+	t->LogSetting.PacketLogSwitchType = PackGetInt(p, "PacketLogSwitchType");
+	for (i = 0;i < NUM_PACKET_LOG;i++)
+	{
+		t->LogSetting.PacketLogConfig[i] = PackGetIntEx(p, "PacketLogConfig", i);
+	}
+}
+void OutRpcHubLog(PACK *p, RPC_HUB_LOG *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddBool(p, "SaveSecurityLog", t->LogSetting.SaveSecurityLog);
+	PackAddInt(p, "SecurityLogSwitchType", t->LogSetting.SecurityLogSwitchType);
+	PackAddBool(p, "SavePacketLog", t->LogSetting.SavePacketLog);
+	PackAddInt(p, "PacketLogSwitchType", t->LogSetting.PacketLogSwitchType);
+	for (i = 0;i < NUM_PACKET_LOG;i++)
+	{
+		PackAddIntEx(p, "PacketLogConfig", t->LogSetting.PacketLogConfig[i], i, NUM_PACKET_LOG);
+	}
+}
+
+// RPC_HUB_ADD_CA
+void InRpcHubAddCa(RPC_HUB_ADD_CA *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_HUB_ADD_CA));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Cert = PackGetX(p, "Cert");
+}
+void OutRpcHubAddCa(PACK *p, RPC_HUB_ADD_CA *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddX(p, "Cert", t->Cert);
+}
+void FreeRpcHubAddCa(RPC_HUB_ADD_CA *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FreeX(t->Cert);
+}
+
+// RPC_HUB_ENUM_CA
+void InRpcHubEnumCa(RPC_HUB_ENUM_CA *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_HUB_ENUM_CA));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->NumCa = PackGetIndexCount(p, "Key");
+	t->Ca = ZeroMalloc(sizeof(RPC_HUB_ENUM_CA_ITEM) * t->NumCa);
+
+	for (i = 0;i < t->NumCa;i++)
+	{
+		RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+
+		e->Key = PackGetIntEx(p, "Key", i);
+		PackGetUniStrEx(p, "SubjectName", e->SubjectName, sizeof(e->SubjectName), i);
+		PackGetUniStrEx(p, "IssuerName", e->IssuerName, sizeof(e->IssuerName), i);
+		e->Expires = PackGetInt64Ex(p, "Expires", i);
+	}
+}
+void OutRpcHubEnumCa(PACK *p, RPC_HUB_ENUM_CA *t)
+{
+	UINT i;
+	PackAddStr(p, "HubName", t->HubName);
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumCa;i++)
+	{
+		RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+
+		PackAddIntEx(p, "Key", e->Key, i, t->NumCa);
+		PackAddUniStrEx(p, "SubjectName", e->SubjectName, i, t->NumCa);
+		PackAddUniStrEx(p, "IssuerName", e->IssuerName, i, t->NumCa);
+		PackAddInt64Ex(p, "Expires", e->Expires, i, t->NumCa);
+	}
+}
+void FreeRpcHubEnumCa(RPC_HUB_ENUM_CA *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Ca);
+}
+
+// RPC_HUB_GET_CA
+void InRpcHubGetCa(RPC_HUB_GET_CA *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_HUB_GET_CA));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Key = PackGetInt(p, "Key");
+	t->Cert = PackGetX(p, "Cert");
+}
+void OutRpcHubGetCa(PACK *p, RPC_HUB_GET_CA *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddInt(p, "Key", t->Key);
+	PackAddX(p, "Cert", t->Cert);
+}
+void FreeRpcHubGetCa(RPC_HUB_GET_CA *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FreeX(t->Cert);
+}
+
+// RPC_HUB_DELETE_CA
+void InRpcHubDeleteCa(RPC_HUB_DELETE_CA *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_HUB_DELETE_CA));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Key = PackGetInt(p, "Key");
+}
+void OutRpcHubDeleteCa(PACK *p, RPC_HUB_DELETE_CA *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddInt(p, "Key", t->Key);
+}
+
+// RPC_CREATE_LINK
+void InRpcCreateLink(RPC_CREATE_LINK *t, PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_CREATE_LINK));
+	PackGetStr(p, "HubName_Ex", t->HubName, sizeof(t->HubName));
+	t->Online = PackGetBool(p, "Online");
+	t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	InRpcClientOption(t->ClientOption, p);
+	t->ClientAuth  = ZeroMalloc(sizeof(CLIENT_AUTH));
+	InRpcClientAuth(t->ClientAuth, p);
+	InRpcPolicy(&t->Policy, p);
+
+	t->CheckServerCert = PackGetBool(p, "CheckServerCert");
+	b = PackGetBuf(p, "ServerCert");
+	if (b != NULL)
+	{
+		t->ServerCert = BufToX(b, false);
+		FreeBuf(b);
+	}
+}
+void OutRpcCreateLink(PACK *p, RPC_CREATE_LINK *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName_Ex",t->HubName);
+	PackAddBool(p, "Online", t->Online);
+	OutRpcClientOption(p, t->ClientOption);
+	OutRpcClientAuth(p, t->ClientAuth);
+	OutRpcPolicy(p, &t->Policy);
+
+	PackAddBool(p, "CheckServerCert", t->CheckServerCert);
+	if (t->ServerCert != NULL)
+	{
+		BUF *b;
+		b = XToBuf(t->ServerCert, false);
+		PackAddBuf(p, "ServerCert", b);
+		FreeBuf(b);
+	}
+}
+void FreeRpcCreateLink(RPC_CREATE_LINK *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	if (t->ServerCert != NULL)
+	{
+		FreeX(t->ServerCert);
+	}
+	Free(t->ClientOption);
+	CiFreeClientAuth(t->ClientAuth);
+}
+
+// RPC_ENUM_LINK
+void InRpcEnumLink(RPC_ENUM_LINK *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_LINK));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->NumLink = PackGetIndexCount(p, "AccountName");
+	t->Links = ZeroMalloc(sizeof(RPC_ENUM_LINK_ITEM) * t->NumLink);
+
+	for (i = 0;i < t->NumLink;i++)
+	{
+		RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+		PackGetUniStrEx(p, "AccountName", e->AccountName, sizeof(e->AccountName), i);
+		PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+		PackGetStrEx(p, "ConnectedHubName", e->HubName, sizeof(e->HubName), i);
+		e->Online = PackGetBoolEx(p, "Online", i);
+		e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+		e->Connected = PackGetBoolEx(p, "Connected", i);
+		e->LastError = PackGetIntEx(p, "LastError", i);
+	}
+}
+void OutRpcEnumLink(PACK *p, RPC_ENUM_LINK *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+
+	for (i = 0;i < t->NumLink;i++)
+	{
+		RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+		PackAddUniStrEx(p, "AccountName", e->AccountName, i, t->NumLink);
+		PackAddStrEx(p, "ConnectedHubName", e->HubName, i, t->NumLink);
+		PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumLink);
+		PackAddBoolEx(p, "Online", e->Online, i, t->NumLink);
+		PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumLink);
+		PackAddBoolEx(p, "Connected", e->Connected, i, t->NumLink);
+		PackAddIntEx(p, "LastError", e->LastError, i, t->NumLink);
+	}
+}
+void FreeRpcEnumLink(RPC_ENUM_LINK *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Links);
+}
+
+// RPC_LINK_STATUS
+void InRpcLinkStatus(RPC_LINK_STATUS *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_LINK_STATUS));
+	PackGetStr(p, "HubName_Ex", t->HubName, sizeof(t->HubName));
+	PackGetUniStr(p, "AccountName", t->AccountName, sizeof(t->AccountName));
+	InRpcClientGetConnectionStatus(&t->Status, p);
+}
+void OutRpcLinkStatus(PACK *p, RPC_LINK_STATUS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName_Ex", t->HubName);
+	PackAddUniStr(p, "AccountName", t->AccountName);
+	OutRpcClientGetConnectionStatus(p, &t->Status);
+}
+void FreeRpcLinkStatus(RPC_LINK_STATUS *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	CiFreeClientGetConnectionStatus(&t->Status);
+}
+
+// RPC_LINK
+void InRpcLink(RPC_LINK *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_LINK));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetUniStr(p, "AccountName", t->AccountName, sizeof(t->AccountName));
+}
+void OutRpcLink(PACK *p, RPC_LINK *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddUniStr(p, "AccountName", t->AccountName);
+}
+
+// RPC_RENAME_LINK
+void InRpcRenameLink(RPC_RENAME_LINK *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_RENAME_LINK));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetUniStr(p, "OldAccountName", t->OldAccountName, sizeof(t->OldAccountName));
+	PackGetUniStr(p, "NewAccountName", t->NewAccountName, sizeof(t->NewAccountName));
+}
+void OutRpcRenameLink(PACK *p, RPC_RENAME_LINK *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddUniStr(p, "OldAccountName", t->OldAccountName);
+	PackAddUniStr(p, "NewAccountName", t->NewAccountName);
+}
+
+// ACCESS
+void InRpcAccessEx(ACCESS *a, PACK *p, UINT index)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(a, sizeof(ACCESS));
+	a->Id = PackGetIntEx(p, "Id", index);
+	PackGetUniStrEx(p, "Note", a->Note, sizeof(a->Note), index);
+	a->Active = PackGetBoolEx(p, "Active", index);
+	a->Priority = PackGetIntEx(p, "Priority", index);
+	a->Discard = PackGetBoolEx(p, "Discard", index);
+	a->SrcIpAddress = PackGetIp32Ex(p, "SrcIpAddress", index);
+	a->SrcSubnetMask = PackGetIp32Ex(p, "SrcSubnetMask", index);
+	a->DestIpAddress = PackGetIp32Ex(p, "DestIpAddress", index);
+	a->DestSubnetMask = PackGetIp32Ex(p, "DestSubnetMask", index);
+	a->Protocol = PackGetIntEx(p, "Protocol", index);
+	a->SrcPortStart = PackGetIntEx(p, "SrcPortStart", index);
+	a->SrcPortEnd = PackGetIntEx(p, "SrcPortEnd", index);
+	a->DestPortStart = PackGetIntEx(p, "DestPortStart", index);
+	a->DestPortEnd = PackGetIntEx(p, "DestPortEnd", index);
+	a->SrcUsernameHash = PackGetIntEx(p, "SrcUsernameHash", index);
+	PackGetStrEx(p, "SrcUsername", a->SrcUsername, sizeof(a->SrcUsername), index);
+	a->DestUsernameHash = PackGetIntEx(p, "DestUsernameHash", index);
+	PackGetStrEx(p, "DestUsername", a->DestUsername, sizeof(a->DestUsername), index);
+	a->CheckSrcMac = PackGetBoolEx(p, "CheckSrcMac", index);
+	PackGetDataEx2(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), index);
+	PackGetDataEx2(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), index);
+	a->CheckDstMac = PackGetBoolEx(p, "CheckDstMac", index);
+	PackGetDataEx2(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), index);
+	PackGetDataEx2(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), index);
+	a->CheckTcpState = PackGetBoolEx(p, "CheckTcpState", index);
+	a->Established = PackGetBoolEx(p, "Established", index);
+	a->Delay = PackGetIntEx(p, "Delay", index);
+	a->Jitter = PackGetIntEx(p, "Jitter", index);
+	a->Loss = PackGetIntEx(p, "Loss", index);
+	a->IsIPv6 = PackGetBoolEx(p, "IsIPv6", index);
+	if (a->IsIPv6)
+	{
+		PackGetIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, index);
+		PackGetIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, index);
+		PackGetIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, index);
+		PackGetIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, index);
+	}
+}
+void InRpcAccess(ACCESS *a, PACK *p)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	InRpcAccessEx(a, p, 0);
+}
+void OutRpcAccessEx(PACK *p, ACCESS *a, UINT index, UINT total)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddIntEx(p, "Id", a->Id, index, total);
+	PackAddUniStrEx(p, "Note", a->Note, index, total);
+	PackAddBoolEx(p, "Active", a->Active, index, total);
+	PackAddIntEx(p, "Priority", a->Priority, index, total);
+	PackAddBoolEx(p, "Discard", a->Discard, index, total);
+	if (a->IsIPv6)
+	{
+		PackAddIp32Ex(p, "SrcIpAddress", 0xFDFFFFDF, index, total);
+		PackAddIp32Ex(p, "SrcSubnetMask", 0xFFFFFFFF, index, total);
+		PackAddIp32Ex(p, "DestIpAddress", 0xFDFFFFDF, index, total);
+		PackAddIp32Ex(p, "DestSubnetMask", 0xFFFFFFFF, index, total);
+	}
+	else
+	{
+		PackAddIp32Ex(p, "SrcIpAddress", a->SrcIpAddress, index, total);
+		PackAddIp32Ex(p, "SrcSubnetMask", a->SrcSubnetMask, index, total);
+		PackAddIp32Ex(p, "DestIpAddress", a->DestIpAddress, index, total);
+		PackAddIp32Ex(p, "DestSubnetMask", a->DestSubnetMask, index, total);
+	}
+	PackAddIntEx(p, "Protocol", a->Protocol, index, total);
+	PackAddIntEx(p, "SrcPortStart", a->SrcPortStart, index, total);
+	PackAddIntEx(p, "SrcPortEnd", a->SrcPortEnd, index, total);
+	PackAddIntEx(p, "DestPortStart", a->DestPortStart, index, total);
+	PackAddIntEx(p, "DestPortEnd", a->DestPortEnd, index, total);
+	PackAddIntEx(p, "SrcUsernameHash", a->SrcUsernameHash, index, total);
+	PackAddStrEx(p, "SrcUsername", a->SrcUsername, index, total);
+	PackAddIntEx(p, "DestUsernameHash", a->DestUsernameHash, index, total);
+	PackAddStrEx(p, "DestUsername", a->DestUsername, index, total);
+	PackAddBoolEx(p, "CheckSrcMac", a->CheckSrcMac, index, total);
+	PackAddDataEx(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), index, total);
+	PackAddDataEx(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), index, total);
+	PackAddBoolEx(p, "CheckDstMac", a->CheckDstMac, index, total);
+	PackAddDataEx(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), index, total);
+	PackAddDataEx(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), index, total);
+	PackAddBoolEx(p, "CheckTcpState", a->CheckTcpState, index, total);
+	PackAddBoolEx(p, "Established", a->Established, index, total);
+	PackAddIntEx(p, "Delay", a->Delay, index, total);
+	PackAddIntEx(p, "Jitter", a->Jitter, index, total);
+	PackAddIntEx(p, "Loss", a->Loss, index, total);
+	PackAddBoolEx(p, "IsIPv6", a->IsIPv6, index, total);
+	if (a->IsIPv6)
+	{
+		PackAddIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, index, total);
+		PackAddIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, index, total);
+		PackAddIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, index, total);
+		PackAddIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, index, total);
+	}
+	else
+	{
+		IPV6_ADDR zero;
+
+		Zero(&zero, sizeof(zero));
+
+		PackAddIp6AddrEx(p, "SrcIpAddress6", &zero, index, total);
+		PackAddIp6AddrEx(p, "SrcSubnetMask6", &zero, index, total);
+		PackAddIp6AddrEx(p, "DestIpAddress6", &zero, index, total);
+		PackAddIp6AddrEx(p, "DestSubnetMask6", &zero, index, total);
+	}
+}
+void OutRpcAccess(PACK *p, ACCESS *a)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	OutRpcAccessEx(p, a, 0, 1);
+}
+
+// RPC_ENUM_ACCESS_LIST
+void InRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(a, sizeof(RPC_ENUM_ACCESS_LIST));
+	PackGetStr(p, "HubName", a->HubName, sizeof(a->HubName));
+	a->NumAccess = PackGetIndexCount(p, "Protocol");
+	a->Accesses = ZeroMalloc(sizeof(ACCESS) * a->NumAccess);
+
+	for (i = 0;i < a->NumAccess;i++)
+	{
+		ACCESS *e = &a->Accesses[i];
+
+		InRpcAccessEx(e, p, i);
+	}
+}
+void OutRpcEnumAccessList(PACK *p, RPC_ENUM_ACCESS_LIST *a)
+{
+	UINT i;
+	PackAddStr(p, "HubName", a->HubName);
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < a->NumAccess;i++)
+	{
+		ACCESS *e = &a->Accesses[i];
+
+		OutRpcAccessEx(p, e, i, a->NumAccess);
+	}
+}
+void FreeRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a)
+{
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	Free(a->Accesses);
+}
+
+// AUTHDATA
+void *InRpcAuthData(PACK *p, UINT *authtype)
+{
+	wchar_t tmp[MAX_SIZE];
+	AUTHPASSWORD *pw;
+	AUTHUSERCERT *usercert;
+	AUTHROOTCERT *rootcert;
+	AUTHRADIUS *radius;
+	AUTHNT *nt;
+	BUF *b;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return NULL;
+	}
+	if (authtype == NULL)
+	{
+		return NULL;
+	}
+
+	*authtype = PackGetInt(p, "AuthType");
+
+	switch (*authtype)
+	{
+	case AUTHTYPE_PASSWORD:
+		pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+		PackGetData2(p, "HashedKey", pw->HashedKey, sizeof(pw->HashedKey));
+		return pw;
+
+	case AUTHTYPE_USERCERT:
+		usercert = ZeroMalloc(sizeof(AUTHUSERCERT));
+		usercert->UserX = PackGetX(p, "UserX");
+		return usercert;
+
+	case AUTHTYPE_ROOTCERT:
+		rootcert = ZeroMalloc(sizeof(AUTHROOTCERT));
+		b = PackGetBuf(p, "Serial");
+		if (b != NULL)
+		{
+			rootcert->Serial = NewXSerial(b->Buf, b->Size);
+			FreeBuf(b);
+		}
+		if (PackGetUniStr(p, "CommonName", tmp, sizeof(tmp)))
+		{
+			rootcert->CommonName = CopyUniStr(tmp);
+		}
+		return rootcert;
+
+	case AUTHTYPE_RADIUS:
+		radius = ZeroMalloc(sizeof(AUTHRADIUS));
+		if (PackGetUniStr(p, "RadiusUsername", tmp, sizeof(tmp)))
+		{
+			radius->RadiusUsername = CopyUniStr(tmp);
+		}
+		else
+		{
+			radius->RadiusUsername = CopyUniStr(L"");
+		}
+		return radius;
+
+	case AUTHTYPE_NT:
+		nt = ZeroMalloc(sizeof(AUTHNT));
+		if (PackGetUniStr(p, "NtUsername", tmp, sizeof(tmp)))
+		{
+			nt->NtUsername = CopyUniStr(tmp);
+		}
+		else
+		{
+			nt->NtUsername = CopyUniStr(L"");
+		}
+		return nt;
+	}
+
+	return NULL;
+}
+void OutRpcAuthData(PACK *p, void *authdata, UINT authtype)
+{
+	AUTHPASSWORD *pw = authdata;
+	AUTHUSERCERT *usercert = authdata;
+	AUTHROOTCERT *rootcert = authdata;
+	AUTHRADIUS *radius = authdata;
+	AUTHNT *nt = authdata;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "AuthType", authtype);
+
+	switch (authtype)
+	{
+	case AUTHTYPE_PASSWORD:
+		PackAddData(p, "HashedKey", pw->HashedKey, sizeof(pw->HashedKey));
+		break;
+
+	case AUTHTYPE_USERCERT:
+		PackAddX(p, "UserX", usercert->UserX);
+		break;
+
+	case AUTHTYPE_ROOTCERT:
+		if (rootcert->Serial != NULL)
+		{
+			PackAddData(p, "Serial", rootcert->Serial->data, rootcert->Serial->size);
+		}
+		if (rootcert->CommonName != NULL)
+		{
+			PackAddUniStr(p, "CommonName", rootcert->CommonName);
+		}
+		break;
+
+	case AUTHTYPE_RADIUS:
+		PackAddUniStr(p, "RadiusUsername", radius->RadiusUsername);
+		break;
+
+	case AUTHTYPE_NT:
+		PackAddUniStr(p, "NtUsername", nt->NtUsername);
+		break;
+	}
+}
+void FreeRpcAuthData(void *authdata, UINT authtype)
+{
+	FreeAuthData(authtype, authdata);
+}
+
+// RPC_SET_USER
+void InRpcSetUser(RPC_SET_USER *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_SET_USER));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+	PackGetStr(p, "GroupName", t->GroupName, sizeof(t->GroupName));
+	PackGetUniStr(p, "Realname", t->Realname, sizeof(t->Realname));
+	PackGetUniStr(p, "Note", t->Note, sizeof(t->Note));
+	t->CreatedTime = PackGetInt64(p, "CreatedTime");
+	t->UpdatedTime = PackGetInt64(p, "UpdatedTime");
+	t->ExpireTime = PackGetInt64(p, "ExpireTime");
+	t->AuthData = InRpcAuthData(p, &t->AuthType);
+	t->NumLogin = PackGetInt(p, "NumLogin");
+	InRpcTraffic(&t->Traffic, p);
+
+	if (PackGetBool(p, "UsePolicy"))
+	{
+		t->Policy = ZeroMalloc(sizeof(POLICY));
+		InRpcPolicy(t->Policy, p);
+	}
+}
+
+void OutRpcSetUser(PACK *p, RPC_SET_USER *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddStr(p, "Name", t->Name);
+	PackAddStr(p, "GroupName", t->GroupName);
+	PackAddUniStr(p, "Realname", t->Realname);
+	PackAddUniStr(p, "Note", t->Note);
+	PackAddInt64(p, "CreatedTime", t->CreatedTime);
+	PackAddInt64(p, "UpdatedTime", t->UpdatedTime);
+	PackAddInt64(p, "ExpireTime", t->ExpireTime);
+	OutRpcAuthData(p, t->AuthData, t->AuthType);
+	PackAddInt(p, "NumLogin", t->NumLogin);
+	OutRpcTraffic(p, &t->Traffic);
+
+	if (t->Policy != NULL)
+	{
+		PackAddBool(p, "UsePolicy", true);
+		OutRpcPolicy(p, t->Policy);
+	}
+}
+void FreeRpcSetUser(RPC_SET_USER *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FreeRpcAuthData(t->AuthData, t->AuthType);
+	if (t->Policy)
+	{
+		Free(t->Policy);
+	}
+}
+
+// RPC_ENUM_USER
+void InRpcEnumUser(RPC_ENUM_USER *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_USER));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->NumUser = PackGetIndexCount(p, "Name");
+	t->Users = ZeroMalloc(sizeof(RPC_ENUM_USER_ITEM) * t->NumUser);
+
+	for (i = 0;i < t->NumUser;i++)
+	{
+		RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+		PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+		PackGetStrEx(p, "GroupName", e->GroupName, sizeof(e->GroupName), i);
+		PackGetUniStrEx(p, "Realname", e->Realname, sizeof(e->Realname), i);
+		PackGetUniStrEx(p, "Note", e->Note, sizeof(e->Note), i);
+		e->AuthType = PackGetIntEx(p, "AuthType", i);
+		e->LastLoginTime = PackGetInt64Ex(p, "LastLoginTime", i);
+		e->NumLogin = PackGetIntEx(p, "NumLogin", i);
+		e->DenyAccess = PackGetBoolEx(p, "DenyAccess", i);
+	}
+}
+void OutRpcEnumUser(PACK *p, RPC_ENUM_USER *t)
+{
+	UINT i;
+	PackAddStr(p, "HubName", t->HubName);
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumUser;i++)
+	{
+		RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+		PackAddStrEx(p, "Name", e->Name, i, t->NumUser);
+		PackAddStrEx(p, "GroupName", e->GroupName, i, t->NumUser);
+		PackAddUniStrEx(p, "Realname", e->Realname, i, t->NumUser);
+		PackAddUniStrEx(p, "Note", e->Note, i, t->NumUser);
+		PackAddIntEx(p, "AuthType", e->AuthType, i, t->NumUser);
+		PackAddInt64Ex(p, "LastLoginTime", e->LastLoginTime, i, t->NumUser);
+		PackAddIntEx(p, "NumLogin", e->NumLogin, i, t->NumUser);
+		PackAddBoolEx(p, "DenyAccess", e->DenyAccess, i, t->NumUser);
+	}
+}
+void FreeRpcEnumUser(RPC_ENUM_USER *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Users);
+}
+
+// RPC_SET_GROUP
+void InRpcSetGroup(RPC_SET_GROUP *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_SET_GROUP));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+	PackGetUniStr(p, "Realname", t->Realname, sizeof(t->Realname));
+	PackGetUniStr(p, "Note", t->Note, sizeof(t->Note));
+	InRpcTraffic(&t->Traffic, p);
+
+	if (PackGetBool(p, "UsePolicy"))
+	{
+		t->Policy = ZeroMalloc(sizeof(POLICY));
+		InRpcPolicy(t->Policy, p);
+	}
+}
+void OutRpcSetGroup(PACK *p, RPC_SET_GROUP *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddStr(p, "Name", t->Name);
+	PackAddUniStr(p, "Realname", t->Realname);
+	PackAddUniStr(p, "Note", t->Note);
+	OutRpcTraffic(p, &t->Traffic);
+
+	if (t->Policy != NULL)
+	{
+		PackAddBool(p, "UsePolicy", true);
+		OutRpcPolicy(p, t->Policy);
+	}
+}
+void FreeRpcSetGroup(RPC_SET_GROUP *t)
+{
+	Free(t->Policy);
+}
+
+// RPC_ENUM_GROUP
+void InRpcEnumGroup(RPC_ENUM_GROUP *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_GROUP));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->NumGroup = PackGetIndexCount(p, "Name");
+	t->Groups = ZeroMalloc(sizeof(RPC_ENUM_GROUP_ITEM) * t->NumGroup);
+
+	for (i = 0;i < t->NumGroup;i++)
+	{
+		RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+
+		PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+		PackGetUniStrEx(p, "Realname", e->Realname, sizeof(e->Realname), i);
+		PackGetUniStrEx(p, "Note", e->Note, sizeof(e->Note), i);
+		e->NumUsers = PackGetIntEx(p, "NumUsers", i);
+		e->DenyAccess = PackGetBoolEx(p, "DenyAccess", i);
+	}
+}
+void OutRpcEnumGroup(PACK *p, RPC_ENUM_GROUP *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+
+	for (i = 0;i < t->NumGroup;i++)
+	{
+		RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+
+		PackAddStrEx(p, "Name", e->Name, i, t->NumGroup);
+		PackAddUniStrEx(p, "Realname", e->Realname, i, t->NumGroup);
+		PackAddUniStrEx(p, "Note", e->Note, i, t->NumGroup);
+		PackAddIntEx(p, "NumUsers", e->NumUsers, i, t->NumGroup);
+		PackAddBoolEx(p, "DenyAccess", e->DenyAccess, i, t->NumGroup);
+	}
+}
+void FreeRpcEnumGroup(RPC_ENUM_GROUP *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Groups);
+}
+
+// RPC_DELETE_USER
+void InRpcDeleteUser(RPC_DELETE_USER *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_DELETE_USER));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDeleteUser(PACK *p, RPC_DELETE_USER *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_SESSION
+void InRpcEnumSession(RPC_ENUM_SESSION *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_SESSION));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->NumSession = PackGetIndexCount(p, "Name");
+	t->Sessions = ZeroMalloc(sizeof(RPC_ENUM_SESSION_ITEM) * t->NumSession);
+
+	for (i = 0;i < t->NumSession;i++)
+	{
+		RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+
+		PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+		PackGetStrEx(p, "Username", e->Username, sizeof(e->Username), i);
+		e->Ip = PackGetIntEx(p, "Ip", i);
+		PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+		e->MaxNumTcp = PackGetIntEx(p, "MaxNumTcp", i);
+		e->CurrentNumTcp = PackGetIntEx(p, "CurrentNumTcp", i);
+		e->PacketSize = PackGetInt64Ex(p, "PacketSize", i);
+		e->PacketNum = PackGetInt64Ex(p, "PacketNum", i);
+		e->RemoteSession = PackGetBoolEx(p, "RemoteSession", i);
+		e->LinkMode = PackGetBoolEx(p, "LinkMode", i);
+		e->SecureNATMode = PackGetBoolEx(p, "SecureNATMode", i);
+		e->BridgeMode = PackGetBoolEx(p, "BridgeMode", i);
+		e->Layer3Mode = PackGetBoolEx(p, "Layer3Mode", i);
+		e->Client_BridgeMode = PackGetBoolEx(p, "Client_BridgeMode", i);
+		e->Client_MonitorMode = PackGetBoolEx(p, "Client_MonitorMode", i);
+		PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+		e->VLanId = PackGetIntEx(p, "VLanId", i);
+		PackGetDataEx2(p, "UniqueId", e->UniqueId, sizeof(e->UniqueId), i);
+	}
+}
+void OutRpcEnumSession(PACK *p, RPC_ENUM_SESSION *t)
+{
+	UINT i;
+	PackAddStr(p, "HubName", t->HubName);
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumSession;i++)
+	{
+		RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+
+		PackAddStrEx(p, "Name", e->Name, i, t->NumSession);
+		PackAddStrEx(p, "Username", e->Username, i, t->NumSession);
+		PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumSession);
+		PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumSession);
+		PackAddIntEx(p, "MaxNumTcp", e->MaxNumTcp, i, t->NumSession);
+		PackAddIntEx(p, "CurrentNumTcp", e->CurrentNumTcp, i, t->NumSession);
+		PackAddInt64Ex(p, "PacketSize", e->PacketSize, i, t->NumSession);
+		PackAddInt64Ex(p, "PacketNum", e->PacketNum, i, t->NumSession);
+		PackAddBoolEx(p, "RemoteSession", e->RemoteSession, i, t->NumSession);
+		PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumSession);
+		PackAddBoolEx(p, "LinkMode", e->LinkMode, i, t->NumSession);
+		PackAddBoolEx(p, "SecureNATMode", e->SecureNATMode, i, t->NumSession);
+		PackAddBoolEx(p, "BridgeMode", e->BridgeMode, i, t->NumSession);
+		PackAddBoolEx(p, "Layer3Mode", e->Layer3Mode, i, t->NumSession);
+		PackAddBoolEx(p, "Client_BridgeMode", e->Client_BridgeMode, i, t->NumSession);
+		PackAddBoolEx(p, "Client_MonitorMode", e->Client_MonitorMode, i, t->NumSession);
+		PackAddIntEx(p, "VLanId", e->VLanId, i, t->NumSession);
+		PackAddDataEx(p, "UniqueId", e->UniqueId, sizeof(e->UniqueId), i, t->NumSession);
+	}
+}
+void FreeRpcEnumSession(RPC_ENUM_SESSION *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Sessions);
+}
+
+// RPC_KEY_PAIR
+void InRpcKeyPair(RPC_KEY_PAIR *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	t->Cert = PackGetX(p, "Cert");
+	t->Key = PackGetK(p, "Key");
+}
+void OutRpcKeyPair(PACK *p, RPC_KEY_PAIR *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddX(p, "Cert", t->Cert);
+	PackAddK(p, "Key", t->Key);
+}
+void FreeRpcKeyPair(RPC_KEY_PAIR *t)
+{
+	FreeX(t->Cert);
+	FreeK(t->Key);
+}
+
+// NODE_INFO
+void InRpcNodeInfo(NODE_INFO *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(NODE_INFO));
+	PackGetStr(p, "ClientProductName", t->ClientProductName, sizeof(t->ClientProductName));
+	PackGetStr(p, "ServerProductName", t->ServerProductName, sizeof(t->ServerProductName));
+	PackGetStr(p, "ClientOsName", t->ClientOsName, sizeof(t->ClientOsName));
+	PackGetStr(p, "ClientOsVer", t->ClientOsVer, sizeof(t->ClientOsVer));
+	PackGetStr(p, "ClientOsProductId", t->ClientOsProductId, sizeof(t->ClientOsProductId));
+	PackGetStr(p, "ClientHostname", t->ClientHostname, sizeof(t->ClientHostname));
+	PackGetStr(p, "ServerHostname", t->ServerHostname, sizeof(t->ServerHostname));
+	PackGetStr(p, "ProxyHostname", t->ProxyHostname, sizeof(t->ProxyHostname));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetData2(p, "UniqueId", t->UniqueId, sizeof(t->UniqueId));
+
+	t->ClientProductVer = PackGetInt(p, "ClientProductVer");
+	t->ClientProductBuild = PackGetInt(p, "ClientProductBuild");
+	t->ServerProductVer = PackGetInt(p, "ServerProductVer");
+	t->ServerProductBuild = PackGetInt(p, "ServerProductBuild");
+	t->ClientIpAddress = PackGetIp32(p, "ClientIpAddress");
+	PackGetData2(p, "ClientIpAddress6", t->ClientIpAddress6, sizeof(t->ClientIpAddress6));
+	t->ClientPort = PackGetInt(p, "ClientPort");
+	t->ServerIpAddress = PackGetIp32(p, "ServerIpAddress");
+	PackGetData2(p, "ServerIpAddress6", t->ServerIpAddress6, sizeof(t->ServerIpAddress6));
+	t->ServerPort = PackGetInt(p, "ServerPort2");
+	t->ProxyIpAddress = PackGetIp32(p, "ProxyIpAddress");
+	PackGetData2(p, "ProxyIpAddress6", t->ProxyIpAddress6, sizeof(t->ProxyIpAddress6));
+	t->ProxyPort = PackGetInt(p, "ProxyPort");
+}
+void OutRpcNodeInfo(PACK *p, NODE_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "ClientProductName", t->ClientProductName);
+	PackAddStr(p, "ServerProductName", t->ServerProductName);
+	PackAddStr(p, "ClientOsName", t->ClientOsName);
+	PackAddStr(p, "ClientOsVer", t->ClientOsVer);
+	PackAddStr(p, "ClientOsProductId", t->ClientOsProductId);
+	PackAddStr(p, "ClientHostname", t->ClientHostname);
+	PackAddStr(p, "ServerHostname", t->ServerHostname);
+	PackAddStr(p, "ProxyHostname", t->ProxyHostname);
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddData(p, "UniqueId", t->UniqueId, sizeof(t->UniqueId));
+
+	PackAddInt(p, "ClientProductVer", t->ClientProductVer);
+	PackAddInt(p, "ClientProductBuild", t->ClientProductBuild);
+	PackAddInt(p, "ServerProductVer", t->ServerProductVer);
+	PackAddInt(p, "ServerProductBuild", t->ServerProductBuild);
+	PackAddIp32(p, "ClientIpAddress", t->ClientIpAddress);
+	PackAddData(p, "ClientIpAddress6", t->ClientIpAddress6, sizeof(t->ClientIpAddress6));
+	PackAddInt(p, "ClientPort", t->ClientPort);
+	PackAddIp32(p, "ServerIpAddress", t->ServerIpAddress);
+	PackAddData(p, "ServerIpAddress6", t->ServerIpAddress6, sizeof(t->ServerIpAddress6));
+	PackAddInt(p, "ServerPort2", t->ServerPort);
+	PackAddIp32(p, "ProxyIpAddress", t->ProxyIpAddress);
+	PackAddData(p, "ProxyIpAddress6", t->ProxyIpAddress6, sizeof(t->ProxyIpAddress6));
+	PackAddInt(p, "ProxyPort", t->ProxyPort);
+}
+
+// RPC_SESSION_STATUS
+void InRpcSessionStatus(RPC_SESSION_STATUS *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_SESSION_STATUS));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+	PackGetStr(p, "Username", t->Username, sizeof(t->Username));
+	PackGetStr(p, "GroupName", t->GroupName, sizeof(t->GroupName));
+	PackGetStr(p, "RealUsername", t->RealUsername, sizeof(t->RealUsername));
+	t->ClientIp = PackGetIp32(p, "SessionStatus_ClientIp");
+	PackGetData2(p, "SessionStatus_ClientIp6", t->ClientIp6, sizeof(t->ClientIp6));
+	PackGetStr(p, "SessionStatus_ClientHostName", t->ClientHostName, sizeof(t->ClientHostName));
+
+	InRpcClientGetConnectionStatus(&t->Status, p);
+	InRpcNodeInfo(&t->NodeInfo, p);
+}
+void OutRpcSessionStatus(PACK *p, RPC_SESSION_STATUS *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddStr(p, "Name", t->Name);
+	PackAddStr(p, "Username", t->Username);
+	PackAddStr(p, "GroupName", t->GroupName);
+	PackAddStr(p, "RealUsername", t->RealUsername);
+	PackAddIp32(p, "SessionStatus_ClientIp", t->ClientIp);
+	PackAddData(p, "SessionStatus_ClientIp6", t->ClientIp6, sizeof(t->ClientIp6));
+	PackAddStr(p, "SessionStatus_ClientHostName", t->ClientHostName);
+
+	OutRpcClientGetConnectionStatus(p, &t->Status);
+	OutRpcNodeInfo(p, &t->NodeInfo);
+}
+void FreeRpcSessionStatus(RPC_SESSION_STATUS *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	CiFreeClientGetConnectionStatus(&t->Status);
+}
+
+// RPC_DELETE_SESSION
+void InRpcDeleteSession(RPC_DELETE_SESSION *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_DELETE_SESSION));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDeleteSession(PACK *p, RPC_DELETE_SESSION *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_MAC_TABLE
+void InRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_MAC_TABLE));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->NumMacTable = PackGetIndexCount(p, "SessionName");
+	t->MacTables = ZeroMalloc(sizeof(RPC_ENUM_MAC_TABLE_ITEM) * t->NumMacTable);
+
+	for (i = 0;i < t->NumMacTable;i++)
+	{
+		RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+
+		e->Key = PackGetIntEx(p, "Key", i);
+		PackGetStrEx(p, "SessionName", e->SessionName, sizeof(e->SessionName), i);
+		PackGetDataEx2(p, "MacAddress", e->MacAddress, sizeof(e->MacAddress), i);
+		e->VlanId = PackGetIntEx(p, "VlanId", i);
+		e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+		e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+		e->RemoteItem = PackGetBoolEx(p, "RemoteItem", i);
+		PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+	}
+}
+void OutRpcEnumMacTable(PACK *p, RPC_ENUM_MAC_TABLE *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+
+	for (i = 0;i < t->NumMacTable;i++)
+	{
+		RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+
+		PackAddIntEx(p, "Key", e->Key, i, t->NumMacTable);
+		PackAddStrEx(p, "SessionName", e->SessionName, i, t->NumMacTable);
+		PackAddDataEx(p, "MacAddress", e->MacAddress, sizeof(e->MacAddress), i, t->NumMacTable);
+		PackAddIntEx(p, "VlanId", e->VlanId, i, t->NumMacTable);
+		PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumMacTable);
+		PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumMacTable);
+		PackAddBoolEx(p, "RemoteItem", e->RemoteItem, i, t->NumMacTable);
+		PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumMacTable);
+	}
+}
+void FreeRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->MacTables);
+}
+
+// RPC_ENUM_IP_TABLE
+void InRpcEnumIpTable(RPC_ENUM_IP_TABLE *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_IP_TABLE));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->NumIpTable = PackGetIndexCount(p, "SessionName");
+	t->IpTables = ZeroMalloc(sizeof(RPC_ENUM_IP_TABLE_ITEM) * t->NumIpTable);
+
+	for (i = 0;i < t->NumIpTable;i++)
+	{
+		RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+
+		e->Key = PackGetIntEx(p, "Key", i);
+		PackGetStrEx(p, "SessionName", e->SessionName, sizeof(e->SessionName), i);
+		e->Ip = PackGetIp32Ex(p, "Ip", i);
+		if (PackGetIpEx(p, "IpV6", &e->IpV6, i) == false)
+		{
+			UINTToIP(&e->IpV6, e->Ip);
+		}
+		e->DhcpAllocated = PackGetBoolEx(p, "DhcpAllocated", i);
+		e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+		e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+		e->RemoteItem = PackGetBoolEx(p, "RemoteItem", i);
+		PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+	}
+}
+void OutRpcEnumIpTable(PACK *p, RPC_ENUM_IP_TABLE *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+
+	for (i = 0;i < t->NumIpTable;i++)
+	{
+		RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+
+		PackAddIntEx(p, "Key", e->Key, i, t->NumIpTable);
+		PackAddStrEx(p, "SessionName", e->SessionName, i, t->NumIpTable);
+		PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumIpTable);
+		PackAddIpEx(p, "IpV6", &e->IpV6, i, t->NumIpTable);
+		PackAddBoolEx(p, "DhcpAllocated", e->DhcpAllocated, i, t->NumIpTable);
+		PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumIpTable);
+		PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumIpTable);
+		PackAddBoolEx(p, "RemoteItem", e->RemoteItem, i, t->NumIpTable);
+		PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumIpTable);
+	}
+}
+void FreeRpcEnumIpTable(RPC_ENUM_IP_TABLE *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->IpTables);
+}
+
+// RPC_DELETE_TABLE
+void InRpcDeleteTable(RPC_DELETE_TABLE *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_DELETE_TABLE));
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Key = PackGetInt(p, "Key");
+}
+void OutRpcDeleteTable(PACK *p, RPC_DELETE_TABLE *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddInt(p, "Key", t->Key);
+}
+
+// RPC_ENUM_IP_TABLE の結合
+void AdjoinRpcEnumIpTable(RPC_ENUM_IP_TABLE *dest, RPC_ENUM_IP_TABLE *src)
+{
+	UINT old_num;
+	UINT i, n;
+	if (dest == NULL || src == NULL)
+	{
+		return;
+	}
+
+	if (src->NumIpTable == 0)
+	{
+		return;
+	}
+
+	old_num = dest->NumIpTable;
+	dest->NumIpTable += src->NumIpTable;
+	dest->IpTables = ReAlloc(dest->IpTables, sizeof(RPC_ENUM_IP_TABLE_ITEM) * dest->NumIpTable);
+
+	n = 0;
+	for (i = old_num;i < dest->NumIpTable;i++)
+	{
+		Copy(&dest->IpTables[i], &src->IpTables[n++], sizeof(RPC_ENUM_IP_TABLE_ITEM));
+	}
+}
+
+// RPC_ENUM_MAC_TABLE の結合
+void AdjoinRpcEnumMacTable(RPC_ENUM_MAC_TABLE *dest, RPC_ENUM_MAC_TABLE *src)
+{
+	UINT old_num;
+	UINT i, n;
+	if (dest == NULL || src == NULL)
+	{
+		return;
+	}
+
+	if (src->NumMacTable == 0)
+	{
+		return;
+	}
+
+	old_num = dest->NumMacTable;
+	dest->NumMacTable += src->NumMacTable;
+	dest->MacTables = ReAlloc(dest->MacTables, sizeof(RPC_ENUM_MAC_TABLE_ITEM) * dest->NumMacTable);
+
+	n = 0;
+	for (i = old_num;i < dest->NumMacTable;i++)
+	{
+		Copy(&dest->MacTables[i], &src->MacTables[n++], sizeof(RPC_ENUM_MAC_TABLE_ITEM));
+	}
+}
+
+// RPC_ENUM_SESSION の結合
+void AdjoinRpcEnumSession(RPC_ENUM_SESSION *dest, RPC_ENUM_SESSION *src)
+{
+	UINT old_num;
+	UINT i, n;
+	if (dest == NULL || src == NULL)
+	{
+		return;
+	}
+
+	if (src->NumSession == 0)
+	{
+		return;
+	}
+
+	old_num = dest->NumSession;
+	dest->NumSession += src->NumSession;
+	dest->Sessions = ReAlloc(dest->Sessions, sizeof(RPC_ENUM_SESSION_ITEM) * dest->NumSession);
+
+	n = 0;
+	for (i = old_num;i < dest->NumSession;i++)
+	{
+		Copy(&dest->Sessions[i], &src->Sessions[n++], sizeof(RPC_ENUM_SESSION_ITEM));
+	}
+}
+
+// RPC_KEEP
+void InRpcKeep(RPC_KEEP *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_KEEP));
+	t->UseKeepConnect = PackGetBool(p, "UseKeepConnect");
+	PackGetStr(p, "KeepConnectHost", t->KeepConnectHost, sizeof(t->KeepConnectHost));
+	t->KeepConnectPort = PackGetInt(p, "KeepConnectPort");
+	t->KeepConnectProtocol = PackGetInt(p, "KeepConnectProtocol");
+	t->KeepConnectInterval = PackGetInt(p, "KeepConnectInterval");
+}
+void OutRpcKeep(PACK *p, RPC_KEEP *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddBool(p, "UseKeepConnect", t->UseKeepConnect);
+	PackAddStr(p, "KeepConnectHost", t->KeepConnectHost);
+	PackAddInt(p, "KeepConnectPort", t->KeepConnectPort);
+	PackAddInt(p, "KeepConnectProtocol", t->KeepConnectProtocol);
+	PackAddInt(p, "KeepConnectInterval", t->KeepConnectInterval);
+}
+
+// テスト RPC 関数
+UINT StTest(ADMIN *a, RPC_TEST *t)
+{
+	Format(t->StrValue, sizeof(t->StrValue), "%u", t->IntValue);
+
+	return ERR_NO_ERROR;
+}
+
+// RPC_TEST
+void InRpcTest(RPC_TEST *t, PACK *p)
+{
+	Zero(t, sizeof(RPC_TEST));
+	t->IntValue = PackGetInt(p, "IntValue");
+	PackGetStr(p, "StrValue", t->StrValue, sizeof(t->StrValue));
+}
+void OutRpcTest(PACK *p, RPC_TEST *t)
+{
+	PackAddInt(p, "IntValue", t->IntValue);
+	PackAddStr(p, "StrValue", t->StrValue);
+}
+void FreeRpcTest(RPC_TEST *t)
+{
+}
+
+// 管理用呼び出し
+PACK *AdminCall(RPC *rpc, char *function_name, PACK *p)
+{
+	// 引数チェック
+	if (rpc == NULL || function_name == NULL)
+	{
+		return NULL;
+	}
+	if (p == NULL)
+	{
+		p = NewPack();
+	}
+
+	return RpcCall(rpc, function_name, p);
+}
+
+// 管理用コネクションのソースアドレスが許可されているかどうか調べる
+bool CheckAdminSourceAddress(SOCK *sock, char *hubname)
+{
+	BUF *b;
+	char *s;
+	bool ok = false;
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return false;
+	}
+
+	b = ReadDump(ADMINIP_TXT);
+	if (b == NULL)
+	{
+		return true;
+	}
+
+	while (true)
+	{
+		UINT i;
+		TOKEN_LIST *t;
+		IP ip;
+		s = CfgReadNextLine(b);
+
+		if (s == NULL)
+		{
+			break;
+		}
+
+		Trim(s);
+
+		i = SearchStrEx(s, "//", 0, false);
+		if (i != INFINITE)
+		{
+			s[i] = 0;
+		}
+
+		i = SearchStrEx(s, "#", 0, false);
+		if (i != INFINITE)
+		{
+			s[i] = 0;
+		}
+
+		Trim(s);
+
+		t = ParseToken(s, " \t");
+		if (t != NULL)
+		{
+			if (t->NumTokens >= 1)
+			{
+				if (t->NumTokens == 1 || StrCmpi(hubname, t->Token[1]) == 0)
+				{
+					if (StrToIP(&ip, t->Token[0]))
+					{
+						if (CmpIpAddr(&sock->RemoteIP, &ip) == 0)
+						{
+							ok = true;
+						}
+					}
+
+					if (StrCmpi(t->Token[0], "*") == 0)
+					{
+						ok = true;
+					}
+				}
+			}
+
+			FreeToken(t);
+		}
+
+		Free(s);
+	}
+
+	FreeBuf(b);
+
+	return ok;
+}
+
+// 管理用コネクション受け入れ
+UINT AdminAccept(CONNECTION *c, PACK *p)
+{
+	ADMIN *a;
+	UCHAR secure_password[SHA1_SIZE];
+	UCHAR null_password[SHA1_SIZE];
+	UCHAR secure_null_password[SHA1_SIZE];
+	char hubname[MAX_HUBNAME_LEN + 1];
+	CEDAR *cedar;
+	SOCK *sock;
+	RPC *rpc;
+	UINT err;
+	RPC_WINVER ver;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	cedar = c->Cedar;
+	sock = c->FirstSock;
+
+	// クライアント OS を取得
+	InRpcWinVer(&ver, p);
+
+	// HUB 名を取得
+	if (PackGetStr(p, "hubname", hubname, sizeof(hubname)) == false)
+	{
+		// HUB 名無し
+		StrCpy(hubname, sizeof(hubname), "");
+	}
+
+	// IP アドレスを見て許可するかどうか決める
+	if (CheckAdminSourceAddress(sock, hubname) == false)
+	{
+		SLog(c->Cedar, "LA_IP_DENIED", c->Name);
+		return ERR_IP_ADDRESS_DENIED;
+	}
+
+	// パスワードを取得
+	if (PackGetDataSize(p, "secure_password") != SHA1_SIZE)
+	{
+		// プロトコルエラー
+		return ERR_PROTOCOL_ERROR;
+	}
+	PackGetData(p, "secure_password", secure_password);
+
+	if (StrLen(hubname) == 0)
+	{
+		// サーバー管理モード接続
+		SLog(c->Cedar, "LA_CONNECTED_1", c->Name);
+	}
+	else
+	{
+		// 仮想 HUB 管理モード接続
+		if (cedar->Server != NULL && cedar->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+		{
+			// クラスタ メンバには仮想 HUB 管理モードで接続することはできない
+			return ERR_NOT_ENOUGH_RIGHT;
+		}
+		SLog(c->Cedar, "LA_CONNECTED_2", c->Name, hubname);
+	}
+
+	// パスワードチェック
+	err = AdminCheckPassword(cedar, c->Random, secure_password,
+		StrLen(hubname) != 0 ? hubname : NULL);
+
+	if (err != ERR_NO_ERROR)
+	{
+		// エラー発生
+		SLog(c->Cedar, "LA_ERROR", c->Name, GetUniErrorStr(err), err);
+		return err;
+	}
+
+	SLog(c->Cedar, "LA_OK", c->Name);
+
+	HashAdminPassword(null_password, "");
+	SecurePassword(secure_null_password, null_password, c->Random);
+
+	if (Cmp(secure_null_password, secure_password, SHA1_SIZE) == 0)
+	{
+		if (sock->RemoteIP.addr[0] != 127)
+		{
+			// パスワードが空であるがリモート接続しようとした
+			// (仮想 HUB 管理モードのみ)
+			if (StrLen(hubname) != 0)
+			{
+				return ERR_NULL_PASSWORD_LOCAL_ONLY;
+			}
+		}
+	}
+
+	// 成功結果を送信
+	p = NewPack();
+	HttpServerSend(sock, p);
+	FreePack(p);
+
+	// ADMIN 構造体を作成
+	a = ZeroMalloc(sizeof(ADMIN));
+	a->ServerAdmin = ((StrLen(hubname) == 0) ? true : false);
+	a->HubName = (StrLen(hubname) != 0 ? hubname : NULL);
+	a->Server = c->Cedar->Server;
+	a->ClientBuild = c->ClientBuild;
+
+	Copy(&a->ClientWinVer, &ver, sizeof(RPC_WINVER));
+
+	// タイムアウト設定
+	SetTimeout(sock, INFINITE);
+
+	// RPC サーバー
+	rpc = StartRpcServer(sock, AdminDispatch, a);
+
+	a->Rpc = rpc;
+
+	SLog(c->Cedar, "LA_RPC_START", c->Name, rpc->Name);
+
+	RpcServer(rpc);
+	RpcFree(rpc);
+
+	if (a->LogFileList != NULL)
+	{
+		// キャッシュされたログファイル列挙リストがあれば解放する
+		FreeEnumLogFile(a->LogFileList);
+	}
+
+	// ADMIN 構造体を解放
+	Free(a);
+
+	return ERR_NO_ERROR;
+}
+
+// 管理者パスワードのチェック
+UINT AdminCheckPassword(CEDAR *c, void *random, void *secure_password, char *hubname)
+{
+	UCHAR check[SHA1_SIZE];
+	// 引数チェック
+	if (c == NULL || random == NULL || secure_password == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	if (hubname == NULL || StrLen(hubname) == 0)
+	{
+		// サーバー全体の管理モード
+		Lock(c->lock);
+		{
+			SecurePassword(check, c->Server->HashedPassword, random);
+		}
+		Unlock(c->lock);
+
+		if (Cmp(check, secure_password, SHA1_SIZE) != 0)
+		{
+			// パスワード相違
+			return ERR_ACCESS_DENIED;
+		}
+	}
+	else
+	{
+		HUB *h;
+
+#if	0
+		if (c->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+		{
+			// ファームメンバの場合は HUB 管理モードで接続できない
+			return ERR_FARM_MEMBER_HUB_ADMIN;
+		}
+#endif
+
+		// HUB 管理モード
+		LockHubList(c);
+		{
+			h = GetHub(c, hubname);
+		}
+		UnlockHubList(c);
+
+		if (h == NULL)
+		{
+			// HUB が見つからない
+			return ERR_HUB_NOT_FOUND;
+		}
+
+		Lock(h->lock);
+		{
+			SecurePassword(check, h->HashedPassword, random);
+		}
+		Unlock(h->lock);
+
+		ReleaseHub(h);
+
+		if (Cmp(check, secure_password, SHA1_SIZE) != 0)
+		{
+			// パスワード相違
+			return ERR_ACCESS_DENIED;
+		}
+	}
+
+	return ERR_NO_ERROR;
+}
+
+// 管理者パスワードのハッシュ
+void HashAdminPassword(void *hash, char *password)
+{
+	// 引数チェック
+	if (hash == NULL || password == NULL)
+	{
+		return;
+	}
+
+	Hash(hash, password, StrLen(password), true);
+}
+
+// 管理用コネクション切断
+void AdminDisconnect(RPC *rpc)
+{
+	SESSION *s;
+	SOCK *sock;
+	// 引数チェック
+	if (rpc == NULL)
+	{
+		return;
+	}
+
+	s = (SESSION *)rpc->Param;
+	sock = rpc->Sock;
+
+	EndRpc(rpc);
+
+	Disconnect(sock);
+	ReleaseSession(s);
+}
+
+// 管理接続メイン
+SESSION *AdminConnectMain(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd)
+{
+	UCHAR secure_password[SHA1_SIZE];
+	SESSION *s;
+	SOCK *sock;
+	PACK *p;
+	RPC_WINVER ver;
+	// 接続
+	s = NewRpcSessionEx2(cedar, o, err, client_name, hWnd);
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	// ソケット取得
+	sock = s->Connection->FirstSock;
+
+	// 接続メソッド作成
+	p = NewPack();
+
+	PackAddClientVersion(p, s->Connection);
+
+	PackAddStr(p, "method", "admin");
+
+	// クライアント Windows バージョン
+	GetWinVer(&ver);
+	OutRpcWinVer(p, &ver);
+
+	// セキュアパスワード
+	SecurePassword(secure_password, hashed_password, s->Connection->Random);
+
+	PackAddData(p, "secure_password", secure_password, sizeof(secure_password));
+
+	// HUB 名
+	if (hubname != NULL)
+	{
+		PackAddStr(p, "hubname", hubname);
+	}
+
+	if (HttpClientSend(sock, p) == false)
+	{
+		// 切断
+		FreePack(p);
+		ReleaseSession(s);
+		*err = ERR_DISCONNECTED;
+		return NULL;
+	}
+
+	FreePack(p);
+
+	p = HttpClientRecv(sock);
+	if (p == NULL)
+	{
+		// 切断
+		ReleaseSession(s);
+		*err = ERR_DISCONNECTED;
+		return NULL;
+	}
+
+	if (GetErrorFromPack(p) != 0)
+	{
+		// エラー
+		ReleaseSession(s);
+		*err = GetErrorFromPack(p);
+		FreePack(p);
+		return NULL;
+	}
+
+	FreePack(p);
+
+	return s;
+}
+
+// 管理用コネクション接続
+RPC *AdminConnect(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err)
+{
+	return AdminConnectEx(cedar, o, hubname, hashed_password, err, NULL);
+}
+RPC *AdminConnectEx(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name)
+{
+	return AdminConnectEx2(cedar, o, hubname, hashed_password, err, client_name, NULL);
+}
+RPC *AdminConnectEx2(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd)
+{
+	SESSION *s;
+	SOCK *sock;
+	RPC *rpc;
+	// 引数チェック
+	if (cedar == NULL || o == NULL || hashed_password == NULL || err == NULL)
+	{
+		return NULL;
+	}
+
+	if (client_name == NULL)
+	{
+		client_name = CEDAR_MANAGER_STR;
+	}
+
+	s = AdminConnectMain(cedar, o, hubname, hashed_password, err, client_name, hWnd);
+
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	sock = s->Connection->FirstSock;
+
+	// RPC 開始
+	rpc = StartRpcClient(sock, s);
+
+	rpc->IsVpnServer = true;
+	Copy(&rpc->VpnServerClientOption, o, sizeof(CLIENT_OPTION));
+	StrCpy(rpc->VpnServerHubName, sizeof(rpc->VpnServerHubName), hubname);
+	Copy(rpc->VpnServerHashedPassword, hashed_password, SHA1_SIZE);
+	StrCpy(rpc->VpnServerClientName, sizeof(rpc->VpnServerClientName), client_name);
+
+	// タイムアウト設定
+	SetTimeout(sock, INFINITE);
+
+	return rpc;
+}
+
+// 再接続
+UINT AdminReconnect(RPC *rpc)
+{
+	SESSION *s;
+	SOCK *sock;
+	CEDAR *cedar;
+	UINT err;
+	// 引数チェック
+	if (rpc == NULL || rpc->IsVpnServer == false)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	s = (SESSION *)rpc->Param;
+	cedar = s->Cedar;
+	AddRef(cedar->ref);
+
+	sock = rpc->Sock;
+	Disconnect(sock);
+	ReleaseSock(sock);
+	ReleaseSession(s);
+	rpc->Param = NULL;
+
+	rpc->Sock = NULL;
+
+	s = AdminConnectMain(cedar, &rpc->VpnServerClientOption,
+		rpc->VpnServerHubName,
+		rpc->VpnServerHashedPassword,
+		&err,
+		rpc->VpnServerClientName, NULL);
+
+	ReleaseCedar(cedar);
+
+	if (s == NULL)
+	{
+		return err;
+	}
+
+	rpc->Param = s;
+	rpc->Sock = s->Connection->FirstSock;
+	AddRef(rpc->Sock->ref);
+
+	return ERR_NO_ERROR;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Admin.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Admin.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Admin.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1410 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Admin.h
+// Admin.c のヘッダ
+
+#ifndef	ADMIN_H
+#define	ADMIN_H
+
+// Windows のバージョン
+struct RPC_WINVER
+{
+	bool IsWindows;
+	bool IsNT;
+	bool IsServer;
+	bool IsBeta;
+	UINT VerMajor;
+	UINT VerMinor;
+	UINT Build;
+	UINT ServicePack;
+	char Title[128];
+};
+
+// サーバー側構造体
+struct ADMIN
+{
+	SERVER *Server;				// サーバー
+	bool ServerAdmin;			// サーバー Administrator
+	char *HubName;				// 管理することができる HUB 名
+	RPC *Rpc;					// RPC
+	LIST *LogFileList;			// アクセス可能なログファイルリスト
+	UINT ClientBuild;			// クライアントのビルド番号
+	RPC_WINVER ClientWinVer;	// クライアントの Windows のバージョン
+};
+
+// テスト
+struct RPC_TEST
+{
+	UINT IntValue;
+	char StrValue[1024];
+};
+
+// サーバー情報 *
+struct RPC_SERVER_INFO
+{
+	char ServerProductName[128];		// サーバー製品名
+	char ServerVersionString[128];		// サーバーバージョン文字列
+	char ServerBuildInfoString[128];	// サーバービルド情報文字列
+	UINT ServerVerInt;					// サーバーバージョン整数値
+	UINT ServerBuildInt;				// サーバービルド番号整数値
+	char ServerHostName[MAX_HOST_NAME_LEN + 1];	// サーバーホスト名
+	UINT ServerType;					// サーバーの種類
+	OS_INFO OsInfo;						// OS 情報
+};
+
+// サーバー状態
+struct RPC_SERVER_STATUS
+{
+	UINT ServerType;					// サーバーの種類
+	UINT NumTcpConnections;				// 合計 TCP コネクション数
+	UINT NumTcpConnectionsLocal;		// ローカル TCP コネクション数
+	UINT NumTcpConnectionsRemote;		// リモート TCP コネクション数
+	UINT NumHubTotal;					// 合計 HUB 数
+	UINT NumHubStandalone;				// スタンドアロン HUB 数
+	UINT NumHubStatic;					// スタティック HUB 数
+	UINT NumHubDynamic;					// ダイナミック HUB 数
+	UINT NumSessionsTotal;				// 合計セッション数
+	UINT NumSessionsLocal;				// ローカルセッション数 (コントローラのみ)
+	UINT NumSessionsRemote;				// リモートセッション数 (コントローラ以外)
+	UINT NumMacTables;					// MAC テーブル数
+	UINT NumIpTables;					// IP テーブル数
+	UINT NumUsers;						// ユーザー数
+	UINT NumGroups;						// グループ数
+	UINT AssignedBridgeLicenses;		// 割り当て済みブリッジライセンス数
+	UINT AssignedClientLicenses;		// 割り当て済みクライアントライセンス数
+	UINT AssignedBridgeLicensesTotal;	// 割り当て済みブリッジライセンス数 (クラスタ全体)
+	UINT AssignedClientLicensesTotal;	// 割り当て済みクライアントライセンス数 (クラスタ全体)
+	TRAFFIC Traffic;					// トラフィック情報
+	UINT64 CurrentTime;					// 現在時刻
+	UINT64 CurrentTick;					// 現在 Tick
+	UINT64 StartTime;					// 起動時刻
+	MEMINFO MemInfo;					// メモリ情報
+};
+
+// リスナー
+struct RPC_LISTENER
+{
+	UINT Port;							// ポート番号
+	bool Enable;						// 有効状態
+};
+
+// リスナーのリスト*
+struct RPC_LISTENER_LIST
+{
+	UINT NumPort;						// ポート数
+	UINT *Ports;						// ポート一覧
+	bool *Enables;						// 有効状態
+	bool *Errors;						// エラー発生
+};
+
+// 文字列*
+struct RPC_STR
+{
+	char *String;						// 文字列
+};
+
+// 整数
+struct RPC_INT
+{
+	UINT IntValue;						// 整数
+};
+
+// パスワードの設定
+struct RPC_SET_PASSWORD
+{
+	UCHAR HashedPassword[SHA1_SIZE];	// ハッシュされたパスワード
+};
+
+// サーバーファーム設定*
+struct RPC_FARM
+{
+	UINT ServerType;					// サーバーの種類
+	UINT NumPort;						// 公開ポート数
+	UINT *Ports;						// 公開ポート一覧
+	UINT PublicIp;						// 公開 IP
+	char ControllerName[MAX_HOST_NAME_LEN + 1];	// コントローラ名
+	UINT ControllerPort;				// コントローラポート
+	UCHAR MemberPassword[SHA1_SIZE];	// メンバパスワード
+	UINT Weight;						// 性能基準比
+	bool ControllerOnly;				// コントローラ機能のみ
+};
+
+// ファームメンバごとの HUB アイテム
+struct RPC_FARM_HUB
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	bool DynamicHub;					// ダイナミック HUB
+};
+
+// サーバーファームメンバ情報取得*
+struct RPC_FARM_INFO
+{
+	UINT Id;							// ID
+	bool Controller;					// コントローラ
+	UINT64 ConnectedTime;				// 接続時刻
+	UINT Ip;							// IP アドレス
+	char Hostname[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	UINT Point;							// ポイント
+	UINT NumPort;						// ポート数
+	UINT *Ports;						// ポート
+	X *ServerCert;						// サーバー証明書
+	UINT NumFarmHub;					// ファーム HUB 数
+	RPC_FARM_HUB *FarmHubs;				// ファーム HUB
+	UINT NumSessions;					// セッション数
+	UINT NumTcpConnections;				// TCP コネクション数
+	UINT Weight;						// 性能基準比
+};
+
+// サーバーファームメンバ列挙項目
+struct RPC_ENUM_FARM_ITEM
+{
+	UINT Id;							// ID
+	bool Controller;					// コントローラ
+	UINT64 ConnectedTime;				// 接続時刻
+	UINT Ip;							// IP アドレス
+	char Hostname[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	UINT Point;							// ポイント
+	UINT NumSessions;					// セッション数
+	UINT NumTcpConnections;				// TCP コネクション数
+	UINT NumHubs;						// HUB 数
+	UINT AssignedClientLicense;			// 割り当て済みクライアントライセンス数
+	UINT AssignedBridgeLicense;			// 割り当て済みブリッジライセンス数
+};
+
+// サーバーファームメンバ列挙*
+struct RPC_ENUM_FARM
+{
+	UINT NumFarm;						// ファーム数
+	RPC_ENUM_FARM_ITEM *Farms;			// ファーム一覧
+};
+
+// コントローラへの接続状態
+struct RPC_FARM_CONNECTION_STATUS
+{
+	UINT Ip;							// IP アドレス
+	UINT Port;							// ポート番号
+	bool Online;						// オンライン状態
+	UINT LastError;						// 最終エラー
+	UINT64 StartedTime;					// 接続開始時刻
+	UINT64 FirstConnectedTime;			// 最初の接続時刻
+	UINT64 CurrentConnectedTime;		// 今回の接続時刻
+	UINT NumTry;						// 試行回数
+	UINT NumConnected;					// 接続回数
+	UINT NumFailed;						// 接続失敗回数
+};
+
+// キーペア
+struct RPC_KEY_PAIR
+{
+	X *Cert;							// 証明書
+	K *Key;								// 秘密鍵
+};
+
+// HUB オプション
+struct RPC_HUB_OPTION
+{
+	UINT MaxSession;					// 最大セッション数
+	bool NoEnum;						// 列挙しない
+};
+
+// Radius サーバーオプション
+struct RPC_RADIUS
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	char RadiusServerName[MAX_HOST_NAME_LEN + 1];	// Radius サーバー名
+	UINT RadiusPort;					// Radius ポート番号
+	char RadiusSecret[MAX_PASSWORD_LEN + 1];	// 秘密鍵
+	UINT RadiusRetryInterval;			// Radius 再試行間隔
+};
+
+// HUB の指定
+struct RPC_HUB
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+};
+
+// HUB の作成
+struct RPC_CREATE_HUB
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	UCHAR HashedPassword[SHA1_SIZE];	// 管理用パスワード
+	UCHAR SecurePassword[SHA1_SIZE];	// Administrator パスワード
+	bool Online;						// オンラインフラグ
+	RPC_HUB_OPTION HubOption;			// HUB オプション
+	UINT HubType;						// HUB の種類
+};
+
+// HUB の列挙項目
+struct RPC_ENUM_HUB_ITEM
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	bool Online;						// オンライン
+	UINT HubType;						// HUB の種類
+	UINT NumUsers;						// ユーザー数
+	UINT NumGroups;						// グループ数
+	UINT NumSessions;					// セッション数
+	UINT NumMacTables;					// MAC テーブル数
+	UINT NumIpTables;					// IP テーブル数
+	UINT64 LastCommTime;				// 最終通信日時
+	UINT64 LastLoginTime;				// 最終ログイン日時
+	UINT64 CreatedTime;					// 作成日時
+	UINT NumLogin;						// ログイン回数
+};
+
+// HUB の列挙*
+struct RPC_ENUM_HUB
+{
+	UINT NumHub;						// HUB 数
+	RPC_ENUM_HUB_ITEM *Hubs;			// HUB
+};
+
+// HUB の削除
+struct RPC_DELETE_HUB
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+};
+
+// コネクション列挙項目
+struct RPC_ENUM_CONNECTION_ITEM
+{
+	char Name[MAX_SIZE];				// コネクション名
+	char Hostname[MAX_SIZE];			// ホスト名
+	UINT Ip;							// IP アドレス
+	UINT Port;							// ポート番号
+	UINT64 ConnectedTime;				// 接続された時刻
+	UINT Type;							// 種類
+};
+
+// コネクション列挙
+struct RPC_ENUM_CONNECTION
+{
+	UINT NumConnection;					// コネクション数
+	RPC_ENUM_CONNECTION_ITEM *Connections;	// コネクション一覧
+};
+
+// コネクション切断
+struct RPC_DISCONNECT_CONNECTION
+{
+	char Name[MAX_SIZE];				// コネクション名
+};
+
+// コネクション情報
+struct RPC_CONNECTION_INFO
+{
+	char Name[MAX_SIZE];				// コネクション名
+	UINT Type;							// 種類
+	char Hostname[MAX_SIZE];			// ホスト名
+	UINT Ip;							// IP アドレス
+	UINT Port;							// ポート番号
+	UINT64 ConnectedTime;				// 接続された時刻
+	char ServerStr[MAX_SERVER_STR_LEN + 1];	// サーバー文字列
+	UINT ServerVer;						// サーバーバージョン
+	UINT ServerBuild;					// サーバービルド番号
+	char ClientStr[MAX_CLIENT_STR_LEN + 1];	// クライアント文字列
+	UINT ClientVer;						// クライアントバージョン
+	UINT ClientBuild;					// クライアントビルド番号
+};
+
+// HUB をオンラインまたはオフラインにする
+struct RPC_SET_HUB_ONLINE
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	bool Online;						// オンライン・オフラインフラグ
+};
+
+// HUB 状態の取得
+struct RPC_HUB_STATUS
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	bool Online;						// オンライン
+	UINT HubType;						// HUB の種類
+	UINT NumSessions;					// セッション数
+	UINT NumSessionsClient;				// セッション数 (クライアント)
+	UINT NumSessionsBridge;				// セッション数 (ブリッジ)
+	UINT NumAccessLists;				// アクセスリスト数
+	UINT NumUsers;						// ユーザー数
+	UINT NumGroups;						// グループ数
+	UINT NumMacTables;					// MAC テーブル数
+	UINT NumIpTables;					// IP テーブル数
+	TRAFFIC Traffic;					// トラフィック
+	bool SecureNATEnabled;				// SecureNAT が有効かどうか
+	UINT64 LastCommTime;				// 最終通信日時
+	UINT64 LastLoginTime;				// 最終ログイン日時
+	UINT64 CreatedTime;					// 作成日時
+	UINT NumLogin;						// ログイン回数
+};
+
+// HUB ログ設定
+struct RPC_HUB_LOG
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	HUB_LOG LogSetting;					// ログ設定
+};
+
+// HUB への CA 追加*
+struct RPC_HUB_ADD_CA
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	X *Cert;							// 証明書
+};
+
+// HUB の CA 列挙項目
+struct RPC_HUB_ENUM_CA_ITEM
+{
+	UINT Key;								// 証明書キー
+	wchar_t SubjectName[MAX_SIZE];			// 発行先
+	wchar_t IssuerName[MAX_SIZE];			// 発行者
+	UINT64 Expires;							// 有効期限
+};
+
+// HUB の CA 列挙*
+struct RPC_HUB_ENUM_CA
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	UINT NumCa;								// CA 数
+	RPC_HUB_ENUM_CA_ITEM *Ca;				// CA
+};
+
+// HUB の CA の取得*
+struct RPC_HUB_GET_CA
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	UINT Key;							// 証明書キー
+	X *Cert;							// 証明書
+};
+
+// HUB の CA の削除
+struct RPC_HUB_DELETE_CA
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	UINT Key;							// 削除する証明書キー
+};
+
+// リンクの作成・設定*
+struct RPC_CREATE_LINK
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	bool Online;						// オンラインフラグ
+	CLIENT_OPTION *ClientOption;		// クライアントオプション
+	CLIENT_AUTH *ClientAuth;			// クライアント認証データ
+	POLICY Policy;						// ポリシー
+	bool CheckServerCert;				// サーバー証明書を検証する
+	X *ServerCert;						// サーバー証明書
+};
+
+// リンクの列挙項目
+struct RPC_ENUM_LINK_ITEM
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+	bool Online;									// オンラインフラグ
+	bool Connected;									// 接続完了フラグ
+	UINT LastError;									// 最後に発生したエラー
+	UINT64 ConnectedTime;							// 接続完了時刻
+	char Hostname[MAX_HOST_NAME_LEN + 1];			// ホスト名
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+};
+
+// リンクの列挙*
+struct RPC_ENUM_LINK
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT NumLink;									// リンク数
+	RPC_ENUM_LINK_ITEM *Links;						// リンク一覧
+};
+
+// リンク状態の取得*
+struct RPC_LINK_STATUS
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+	RPC_CLIENT_GET_CONNECTION_STATUS Status;		// ステータス
+};
+
+// リンクの指定
+struct RPC_LINK
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+};
+
+// リンクの名前変更
+struct RPC_RENAME_LINK
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	wchar_t OldAccountName[MAX_ACCOUNT_NAME_LEN + 1];	// 古いアカウント名
+	wchar_t NewAccountName[MAX_ACCOUNT_NAME_LEN + 1];	// 新しいアカウント名
+};
+
+// アクセスリストの列挙*
+struct RPC_ENUM_ACCESS_LIST
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT NumAccess;									// アクセスリスト数
+	ACCESS *Accesses;								// アクセスリスト
+};
+
+// アクセスリストの追加
+struct RPC_ADD_ACCESS
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	ACCESS Access;									// アクセスリスト
+};
+
+// アクセスリストの削除
+struct RPC_DELETE_ACCESS
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT Id;										// ID
+};
+
+// ユーザーの作成・設定・取得*
+struct RPC_SET_USER
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	char Name[MAX_USERNAME_LEN + 1];				// ユーザー名
+	char GroupName[MAX_USERNAME_LEN + 1];			// グループ名
+	wchar_t Realname[MAX_SIZE];						// 本名
+	wchar_t Note[MAX_SIZE];							// メモ
+	UINT64 CreatedTime;								// 作成日時
+	UINT64 UpdatedTime;								// 更新日時
+	UINT64 ExpireTime;								// 有効期限
+	UINT AuthType;									// 認証方法
+	void *AuthData;									// 認証データ
+	UINT NumLogin;									// ログイン回数
+	TRAFFIC Traffic;								// トラフィックデータ
+	POLICY *Policy;									// ポリシー
+};
+
+// ユーザーの列挙項目
+struct RPC_ENUM_USER_ITEM
+{
+	char Name[MAX_USERNAME_LEN + 1];				// ユーザー名
+	char GroupName[MAX_USERNAME_LEN + 1];			// グループ名
+	wchar_t Realname[MAX_SIZE];						// 本名
+	wchar_t Note[MAX_SIZE];							// メモ
+	UINT AuthType;									// 認証方法
+	UINT NumLogin;									// ログイン回数
+	UINT64 LastLoginTime;							// 最終ログイン日時
+	bool DenyAccess;								// アクセス拒否
+};
+
+// ユーザーの列挙
+struct RPC_ENUM_USER
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT NumUser;									// ユーザー数
+	RPC_ENUM_USER_ITEM *Users;						// ユーザー
+};
+
+// グループの作成・設定・取得*
+struct RPC_SET_GROUP
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	char Name[MAX_USERNAME_LEN + 1];				// ユーザー名
+	wchar_t Realname[MAX_SIZE];						// 本名
+	wchar_t Note[MAX_SIZE];							// メモ
+	TRAFFIC Traffic;								// トラフィックデータ
+	POLICY *Policy;									// ポリシー
+};
+
+// グループの列挙項目
+struct RPC_ENUM_GROUP_ITEM
+{
+	char Name[MAX_USERNAME_LEN + 1];				// ユーザー名
+	wchar_t Realname[MAX_SIZE];						// 本名
+	wchar_t Note[MAX_SIZE];							// メモ
+	UINT NumUsers;									// ユーザー数
+	bool DenyAccess;								// アクセス拒否
+};
+
+// グループの列挙
+struct RPC_ENUM_GROUP
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT NumGroup;									// グループ数
+	RPC_ENUM_GROUP_ITEM *Groups;					// グループ
+};
+
+// ユーザーまたはグループの削除
+struct RPC_DELETE_USER
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	char Name[MAX_USERNAME_LEN + 1];				// ユーザー名またはグループ名
+};
+
+// セッションの列挙項目
+struct RPC_ENUM_SESSION_ITEM
+{
+	char Name[MAX_SESSION_NAME_LEN + 1];			// セッション名
+	bool RemoteSession;								// リモートセッション
+	char RemoteHostname[MAX_HOST_NAME_LEN + 1];		// リモートサーバー名
+	char Username[MAX_USERNAME_LEN + 1];			// ユーザー名
+	UINT Ip;										// IP アドレス (IPv4)
+	char Hostname[MAX_HOST_NAME_LEN	+ 1];			// ホスト名
+	UINT MaxNumTcp;									// TCP コネクション数最大
+	UINT CurrentNumTcp;								// TCP コネクション数現在
+	UINT64 PacketSize;								// パケットサイズ
+	UINT64 PacketNum;								// パケット数
+	bool LinkMode;									// リンクモード
+	bool SecureNATMode;								// SecureNAT モード
+	bool BridgeMode;								// ブリッジモード
+	bool Layer3Mode;								// レイヤ 3 モード
+	bool Client_BridgeMode;							// クライアントがブリッジモード
+	bool Client_MonitorMode;						// クライアントがモニタリングモード
+	UINT VLanId;									// VLAN ID
+	UCHAR UniqueId[16];								// Unique ID
+};
+
+// セッションの切断
+struct RPC_DELETE_SESSION
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	char Name[MAX_SESSION_NAME_LEN + 1];			// セッション名
+};
+
+// MAC テーブルの列挙項目
+struct RPC_ENUM_MAC_TABLE_ITEM
+{
+	UINT Key;										// キー
+	char SessionName[MAX_SESSION_NAME_LEN + 1];		// セッション名
+	UCHAR MacAddress[6];							// MAC アドレス
+	UCHAR Padding[2];
+	UINT64 CreatedTime;								// 作成日時
+	UINT64 UpdatedTime;								// 更新日時
+	bool RemoteItem;								// リモートアイテム
+	char RemoteHostname[MAX_HOST_NAME_LEN + 1];		// リモートホスト名
+	UINT VlanId;									// VLAN ID
+};
+
+// MAC テーブルの列挙
+struct RPC_ENUM_MAC_TABLE
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT NumMacTable;								// テーブル数
+	RPC_ENUM_MAC_TABLE_ITEM *MacTables;				// MAC テーブル
+};
+
+// IP テーブルの列挙項目
+struct RPC_ENUM_IP_TABLE_ITEM
+{
+	UINT Key;										// キー
+	char SessionName[MAX_SESSION_NAME_LEN + 1];		// セッション名
+	UINT Ip;										// IP アドレス
+	IP IpV6;										// IPv6 アドレス
+	bool DhcpAllocated;								// DHCP によって割り当て済み
+	UINT64 CreatedTime;								// 作成日時
+	UINT64 UpdatedTime;								// 更新日時
+	bool RemoteItem;								// リモートアイテム
+	char RemoteHostname[MAX_HOST_NAME_LEN + 1];		// リモートホスト名
+};
+
+// IP テーブルの列挙
+struct RPC_ENUM_IP_TABLE
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT NumIpTable;								// テーブル数
+	RPC_ENUM_IP_TABLE_ITEM *IpTables;				// MAC テーブル
+};
+
+// テーブルの削除
+struct RPC_DELETE_TABLE
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT Key;										// キー
+};
+
+// KEEP 設定
+struct RPC_KEEP
+{
+	bool UseKeepConnect;					// インターネットへの接続を維持
+	char KeepConnectHost[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	UINT KeepConnectPort;					// ポート番号
+	UINT KeepConnectProtocol;				// プロトコル
+	UINT KeepConnectInterval;				// 間隔
+};
+
+// Ethernet 列挙アイテム
+struct RPC_ENUM_ETH_ITEM
+{
+	char DeviceName[MAX_SIZE];				// デバイス名
+	wchar_t NetworkConnectionName[MAX_SIZE];// ネットワーク接続名
+};
+
+// Ethernet 列挙
+struct RPC_ENUM_ETH
+{
+	UINT NumItem;							// アイテム数
+	RPC_ENUM_ETH_ITEM *Items;				// アイテム
+};
+
+// ブリッジ項目
+struct RPC_LOCALBRIDGE
+{
+	char DeviceName[MAX_SIZE];				// デバイス名
+	char HubName[MAX_HUBNAME_LEN + 1];		// HUB 名
+	bool Online;							// オンラインフラグ
+	bool Active;							// 動作フラグ
+	bool TapMode;							// tap モード
+};
+
+// ブリッジ列挙
+struct RPC_ENUM_LOCALBRIDGE
+{
+	UINT NumItem;							// アイテム数
+	RPC_LOCALBRIDGE *Items;					// アイテム
+};
+
+// ブリッジサポート情報
+struct RPC_BRIDGE_SUPPORT
+{
+	bool IsBridgeSupportedOs;				// ブリッジがサポートされている OS か
+	bool IsWinPcapNeeded;					// WinPcap が必要とされているか
+};
+
+// config 操作
+struct RPC_CONFIG
+{
+	char FileName[MAX_PATH];				// ファイル名
+	char *FileData;							// ファイルデータ
+};
+
+// 管理オプションリスト
+struct RPC_ADMIN_OPTION
+{
+	char HubName[MAX_HUBNAME_LEN + 1];		// 仮想 HUB 名
+	UINT NumItem;							// 個数
+	ADMIN_OPTION *Items;					// データ
+};
+
+// Layer-3 スイッチ
+struct RPC_L3SW
+{
+	char Name[MAX_HUBNAME_LEN + 1];			// L3 スイッチ名
+};
+
+// Layer-3 スイッチ列挙
+struct RPC_ENUM_L3SW_ITEM
+{
+	char Name[MAX_HUBNAME_LEN + 1];			// 名前
+	UINT NumInterfaces;						// インターフェイス数
+	UINT NumTables;							// ルーティングテーブル数
+	bool Active;							// 動作中
+	bool Online;							// オンライン
+};
+struct RPC_ENUM_L3SW
+{
+	UINT NumItem;
+	RPC_ENUM_L3SW_ITEM *Items;
+};
+
+// Layer-3 インターフェイス
+struct RPC_L3IF
+{
+	char Name[MAX_HUBNAME_LEN + 1];			// L3 スイッチ名
+	char HubName[MAX_HUBNAME_LEN + 1];		// 仮想 HUB 名
+	UINT IpAddress;							// IP アドレス
+	UINT SubnetMask;						// サブネットマスク
+};
+
+// Layer-3 インターフェイス列挙
+struct RPC_ENUM_L3IF
+{
+	char Name[MAX_HUBNAME_LEN + 1];			// L3 スイッチ名
+	UINT NumItem;
+	RPC_L3IF *Items;
+};
+
+// ルーティングテーブル
+struct RPC_L3TABLE
+{
+	char Name[MAX_HUBNAME_LEN + 1];			// L3 スイッチ名
+	UINT NetworkAddress;					// ネットワークアドレス
+	UINT SubnetMask;						// サブネットマスク
+	UINT GatewayAddress;					// ゲートウェイアドレス
+	UINT Metric;							// メトリック
+};
+
+// ルーティングテーブル列挙
+struct RPC_ENUM_L3TABLE
+{
+	char Name[MAX_HUBNAME_LEN + 1];			// L3 スイッチ名
+	UINT NumItem;
+	RPC_L3TABLE *Items;
+};
+
+// CRL エントリ
+struct RPC_CRL
+{
+	char HubName[MAX_HUBNAME_LEN + 1];		// HUB 名
+	UINT Key;								// キー
+	CRL *Crl;								// CRL 本体
+};
+
+// CRL 列挙
+struct RPC_ENUM_CRL_ITEM
+{
+	UINT Key;								// キー
+	wchar_t CrlInfo[MAX_SIZE];				// 情報
+};
+struct RPC_ENUM_CRL
+{
+	char HubName[MAX_HUBNAME_LEN + 1];		// HUB 名
+	UINT NumItem;							// アイテム数
+	RPC_ENUM_CRL_ITEM *Items;				// リスト
+};
+
+// AC リスト
+struct RPC_AC_LIST
+{
+	char HubName[MAX_HUBNAME_LEN + 1];		// HUB 名
+	LIST *o;								// リスト本体
+};
+
+// ログファイル列挙
+struct RPC_ENUM_LOG_FILE_ITEM
+{
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	char FilePath[MAX_PATH];				// ファイルパス
+	UINT FileSize;							// ファイルサイズ
+	UINT64 UpdatedTime;						// 更新日時
+};
+struct RPC_ENUM_LOG_FILE
+{
+	UINT NumItem;							// アイテム数
+	RPC_ENUM_LOG_FILE_ITEM *Items;			// リスト
+};
+
+// ログファイル読み込み
+struct RPC_READ_LOG_FILE
+{
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	char FilePath[MAX_PATH];				// ファイルパス
+	UINT Offset;							// オフセット
+	BUF *Buffer;							// バッファ
+};
+
+// ダウンロード情報
+struct DOWNLOAD_PROGRESS
+{
+	void *Param;							// ユーザー定義データ
+	UINT TotalSize;							// 合計ファイルサイズ
+	UINT CurrentSize;						// 読み込みが完了したサイズ
+	UINT ProgressPercent;					// 完了パーセント
+};
+
+// ライセンスキーの列挙
+struct RPC_ENUM_LICENSE_KEY_ITEM
+{
+	UINT Id;								// ID
+	char LicenseKey[LICENSE_KEYSTR_LEN + 1];	// ライセンスキー
+	char LicenseId[LICENSE_LICENSEID_STR_LEN + 1];	// ライセンス ID
+	char LicenseName[LICENSE_MAX_PRODUCT_NAME_LEN + 1];	// ライセンス名
+	UINT64 Expires;							// 有効期限
+	UINT Status;							// 状況
+	UINT ProductId;							// 製品 ID
+	UINT64 SystemId;						// システム ID
+	UINT SerialId;							// シリアル ID
+};
+struct RPC_ENUM_LICENSE_KEY
+{
+	UINT NumItem;							// アイテム数
+	RPC_ENUM_LICENSE_KEY_ITEM *Items;		// リスト
+};
+
+// サーバーのライセンスの状態
+struct RPC_LICENSE_STATUS
+{
+	UINT EditionId;							// エディション ID
+	char EditionStr[LICENSE_MAX_PRODUCT_NAME_LEN + 1];	// エディション名
+	UINT64 SystemId;						// システム ID
+	UINT64 SystemExpires;					// システム有効期限
+	UINT NumClientConnectLicense;			// クライアント同時接続可能数
+	UINT NumBridgeConnectLicense;			// ブリッジ同時接続可能数
+
+	// v3.0
+	bool NeedSubscription;					// サブスクリプション制度が有効かどうか
+	UINT64 SubscriptionExpires;				// サブスクリプション有効期限
+	bool IsSubscriptionExpired;				// サブスクリプション有効期限が切れているかどうか
+	UINT NumUserCreationLicense;			// ユーザー作成可能数
+	bool AllowEnterpriseFunction;			// エンタープライズ機能の動作
+	UINT64 ReleaseDate;						// リリース日付
+};
+
+// 物理 LAN カードの VLAN 対応状況の列挙
+struct RPC_ENUM_ETH_VLAN_ITEM
+{
+	char DeviceName[MAX_SIZE];				// デバイス名
+	char Guid[MAX_SIZE];					// GUID
+	char DeviceInstanceId[MAX_SIZE];		// デバイスインスタンス ID
+	char DriverName[MAX_SIZE];				// ドライバファイル名
+	char DriverType[MAX_SIZE];				// ドライバの種類
+	bool Support;							// サポートしているかどうか
+	bool Enabled;							// 有効化されているかどうか
+};
+struct RPC_ENUM_ETH_VLAN
+{
+	UINT NumItem;							// アイテム数
+	RPC_ENUM_ETH_VLAN_ITEM *Items;			// リスト
+};
+
+// メッセージ
+struct RPC_MSG
+{
+	char HubName[MAX_HUBNAME_LEN + 1];		// HUB 名
+	wchar_t *Msg;							// メッセージ
+};
+
+
+// 関数プロトタイプ
+UINT AdminAccept(CONNECTION *c, PACK *p);
+void HashAdminPassword(void *hash, char *password);
+SESSION *AdminConnectMain(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd);
+RPC *AdminConnect(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err);
+RPC *AdminConnectEx(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name);
+RPC *AdminConnectEx2(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd);
+void AdminDisconnect(RPC *rpc);
+UINT AdminReconnect(RPC *rpc);
+UINT AdminCheckPassword(CEDAR *c, void *random, void *secure_password, char *hubname);
+PACK *AdminDispatch(RPC *rpc, char *name, PACK *p);
+PACK *AdminCall(RPC *rpc, char *function_name, PACK *p);
+void SiEnumLocalSession(SERVER *s, char *hubname, RPC_ENUM_SESSION *t);
+void CopyOsInfo(OS_INFO *dst, OS_INFO *info);
+CAPSLIST *ScGetCapsEx(RPC *rpc);
+UINT SiEnumMacTable(SERVER *s, char *hubname, RPC_ENUM_MAC_TABLE *t);
+UINT SiEnumIpTable(SERVER *s, char *hubname, RPC_ENUM_IP_TABLE *t);
+void SiEnumLocalLogFileList(SERVER *s, char *hubname, RPC_ENUM_LOG_FILE *t);
+void SiReadLocalLogFile(SERVER *s, char *filepath, UINT offset, RPC_READ_LOG_FILE *t);
+typedef bool (DOWNLOAD_PROC)(DOWNLOAD_PROGRESS *progress);
+BUF *DownloadFileFromServer(RPC *r, char *server_name, char *filepath, UINT total_size, DOWNLOAD_PROC *proc, void *param);
+bool CheckAdminSourceAddress(SOCK *sock, char *hubname);
+void SiEnumSessionMain(SERVER *s, RPC_ENUM_SESSION *t);
+
+UINT StTest(ADMIN *a, RPC_TEST *t);
+UINT StGetServerInfo(ADMIN *a, RPC_SERVER_INFO *t);
+UINT StGetServerStatus(ADMIN *a, RPC_SERVER_STATUS *t);
+UINT StCreateListener(ADMIN *a, RPC_LISTENER *t);
+UINT StEnumListener(ADMIN *a, RPC_LISTENER_LIST *t);
+UINT StDeleteListener(ADMIN *a, RPC_LISTENER *t);
+UINT StEnableListener(ADMIN *a, RPC_LISTENER *t);
+UINT StSetServerPassword(ADMIN *a, RPC_SET_PASSWORD *t);
+UINT StSetFarmSetting(ADMIN *a, RPC_FARM *t);
+UINT StGetFarmSetting(ADMIN *a, RPC_FARM *t);
+UINT StGetFarmInfo(ADMIN *a, RPC_FARM_INFO *t);
+UINT StEnumFarmMember(ADMIN *a, RPC_ENUM_FARM *t);
+UINT StGetFarmConnectionStatus(ADMIN *a, RPC_FARM_CONNECTION_STATUS *t);
+UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t);
+UINT StGetServerCert(ADMIN *a, RPC_KEY_PAIR *t);
+UINT StGetServerCipher(ADMIN *a, RPC_STR *t);
+UINT StSetServerCipher(ADMIN *a, RPC_STR *t);
+UINT StCreateHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StSetHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StGetHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StEnumHub(ADMIN *a, RPC_ENUM_HUB *t);
+UINT StDeleteHub(ADMIN *a, RPC_DELETE_HUB *t);
+UINT StGetHubRadius(ADMIN *a, RPC_RADIUS *t);
+UINT StSetHubRadius(ADMIN *a, RPC_RADIUS *t);
+UINT StEnumConnection(ADMIN *a, RPC_ENUM_CONNECTION *t);
+UINT StDisconnectConnection(ADMIN *a, RPC_DISCONNECT_CONNECTION *t);
+UINT StGetConnectionInfo(ADMIN *a, RPC_CONNECTION_INFO *t);
+UINT StSetHubOnline(ADMIN *a, RPC_SET_HUB_ONLINE *t);
+UINT StGetHubStatus(ADMIN *a, RPC_HUB_STATUS *t);
+UINT StSetHubLog(ADMIN *a, RPC_HUB_LOG *t);
+UINT StGetHubLog(ADMIN *a, RPC_HUB_LOG *t);
+UINT StAddCa(ADMIN *a, RPC_HUB_ADD_CA *t);
+UINT StEnumCa(ADMIN *a, RPC_HUB_ENUM_CA *t);
+UINT StGetCa(ADMIN *a, RPC_HUB_GET_CA *t);
+UINT StDeleteCa(ADMIN *a, RPC_HUB_DELETE_CA *t);
+UINT StCreateLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StEnumLink(ADMIN *a, RPC_ENUM_LINK *t);
+UINT StGetLinkStatus(ADMIN *a, RPC_LINK_STATUS *t);
+UINT StSetLinkOnline(ADMIN *a, RPC_LINK *t);
+UINT StSetLinkOffline(ADMIN *a, RPC_LINK *t);
+UINT StDeleteLink(ADMIN *a, RPC_LINK *t);
+UINT StRenameLink(ADMIN *a, RPC_RENAME_LINK *t);
+UINT StAddAccess(ADMIN *a, RPC_ADD_ACCESS *t);
+UINT StDeleteAccess(ADMIN *a, RPC_DELETE_ACCESS *t);
+UINT StEnumAccess(ADMIN *a, RPC_ENUM_ACCESS_LIST *t);
+UINT StCreateUser(ADMIN *a, RPC_SET_USER *t);
+UINT StSetUser(ADMIN *a, RPC_SET_USER *t);
+UINT StGetUser(ADMIN *a, RPC_SET_USER *t);
+UINT StDeleteUser(ADMIN *a, RPC_DELETE_USER *t);
+UINT StEnumUser(ADMIN *a, RPC_ENUM_USER *t);
+UINT StCreateGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StSetGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StGetGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StDeleteGroup(ADMIN *a, RPC_DELETE_USER *t);
+UINT StEnumGroup(ADMIN *a, RPC_ENUM_GROUP *t);
+UINT StEnumSession(ADMIN *a, RPC_ENUM_SESSION *t);
+UINT StGetSessionStatus(ADMIN *a, RPC_SESSION_STATUS *t);
+UINT StDeleteSession(ADMIN *a, RPC_DELETE_SESSION *t);
+UINT StEnumMacTable(ADMIN *a, RPC_ENUM_MAC_TABLE *t);
+UINT StDeleteMacTable(ADMIN *a, RPC_DELETE_TABLE *t);
+UINT StEnumIpTable(ADMIN *a, RPC_ENUM_IP_TABLE *t);
+UINT StDeleteIpTable(ADMIN *a, RPC_DELETE_TABLE *t);
+UINT StGetLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StSetLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StSetAccessList(ADMIN *a, RPC_ENUM_ACCESS_LIST *t);
+UINT StSetKeep(ADMIN *a, RPC_KEEP *t);
+UINT StGetKeep(ADMIN *a, RPC_KEEP *t);
+UINT StEnableSecureNAT(ADMIN *a, RPC_HUB *t);
+UINT StDisableSecureNAT(ADMIN *a, RPC_HUB *t);
+UINT StSetSecureNATOption(ADMIN *a, VH_OPTION *t);
+UINT StGetSecureNATOption(ADMIN *a, VH_OPTION *t);
+UINT StEnumNAT(ADMIN *a, RPC_ENUM_NAT *t);
+UINT StEnumDHCP(ADMIN *a, RPC_ENUM_DHCP *t);
+UINT StGetSecureNATStatus(ADMIN *a, RPC_NAT_STATUS *t);
+UINT StEnumEthernet(ADMIN *a, RPC_ENUM_ETH *t);
+UINT StAddLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t);
+UINT StDeleteLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t);
+UINT StEnumLocalBridge(ADMIN *a, RPC_ENUM_LOCALBRIDGE *t);
+UINT StGetBridgeSupport(ADMIN *a, RPC_BRIDGE_SUPPORT *t);
+UINT StRebootServer(ADMIN *a, RPC_TEST *t);
+UINT StGetCaps(ADMIN *a, CAPSLIST *t);
+UINT StGetConfig(ADMIN *a, RPC_CONFIG *t);
+UINT StSetConfig(ADMIN *a, RPC_CONFIG *t);
+UINT StGetDefaultHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StGetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StSetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StGetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StSetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StAddL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StDelL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StEnumL3Switch(ADMIN *a, RPC_ENUM_L3SW *t);
+UINT StStartL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StStopL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StAddL3If(ADMIN *a, RPC_L3IF *t);
+UINT StDelL3If(ADMIN *a, RPC_L3IF *t);
+UINT StEnumL3If(ADMIN *a, RPC_ENUM_L3IF *t);
+UINT StAddL3Table(ADMIN *a, RPC_L3TABLE *t);
+UINT StDelL3Table(ADMIN *a, RPC_L3TABLE *t);
+UINT StEnumL3Table(ADMIN *a, RPC_ENUM_L3TABLE *t);
+UINT StEnumCrl(ADMIN *a, RPC_ENUM_CRL *t);
+UINT StAddCrl(ADMIN *a, RPC_CRL *t);
+UINT StDelCrl(ADMIN *a, RPC_CRL *t);
+UINT StGetCrl(ADMIN *a, RPC_CRL *t);
+UINT StSetCrl(ADMIN *a, RPC_CRL *t);
+UINT StSetAcList(ADMIN *a, RPC_AC_LIST *t);
+UINT StGetAcList(ADMIN *a, RPC_AC_LIST *t);
+UINT StEnumLogFile(ADMIN *a, RPC_ENUM_LOG_FILE *t);
+UINT StReadLogFile(ADMIN *a, RPC_READ_LOG_FILE *t);
+UINT StAddLicenseKey(ADMIN *a, RPC_TEST *t);
+UINT StDelLicenseKey(ADMIN *a, RPC_TEST *t);
+UINT StEnumLicenseKey(ADMIN *a, RPC_ENUM_LICENSE_KEY *t);
+UINT StGetLicenseStatus(ADMIN *a, RPC_LICENSE_STATUS *t);
+UINT StSetSysLog(ADMIN *a, SYSLOG_SETTING *t);
+UINT StGetSysLog(ADMIN *a, SYSLOG_SETTING *t);
+UINT StEnumEthVLan(ADMIN *a, RPC_ENUM_ETH_VLAN *t);
+UINT StSetEnableEthVLan(ADMIN *a, RPC_TEST *t);
+UINT StSetHubMsg(ADMIN *a, RPC_MSG *t);
+UINT StGetHubMsg(ADMIN *a, RPC_MSG *t);
+UINT StCrash(ADMIN *a, RPC_TEST *t);
+UINT StGetAdminMsg(ADMIN *a, RPC_MSG *t);
+UINT StFlush(ADMIN *a, RPC_TEST *t);
+UINT StDebug(ADMIN *a, RPC_TEST *t);
+
+UINT ScTest(RPC *r, RPC_TEST *t);
+UINT ScGetServerInfo(RPC *r, RPC_SERVER_INFO *t);
+UINT ScGetServerStatus(RPC *r, RPC_SERVER_STATUS *t);
+UINT ScCreateListener(RPC *r, RPC_LISTENER *t);
+UINT ScEnumListener(RPC *r, RPC_LISTENER_LIST *t);
+UINT ScDeleteListener(RPC *r, RPC_LISTENER *t);
+UINT ScEnableListener(RPC *r, RPC_LISTENER *t);
+UINT ScSetServerPassword(RPC *r, RPC_SET_PASSWORD *t);
+UINT ScSetFarmSetting(RPC *r, RPC_FARM *t);
+UINT ScGetFarmSetting(RPC *r, RPC_FARM *t);
+UINT ScGetFarmInfo(RPC *r, RPC_FARM_INFO *t);
+UINT ScEnumFarmMember(RPC *r, RPC_ENUM_FARM *t);
+UINT ScGetFarmConnectionStatus(RPC *r, RPC_FARM_CONNECTION_STATUS *t);
+UINT ScSetServerCert(RPC *r, RPC_KEY_PAIR *t);
+UINT ScGetServerCert(RPC *r, RPC_KEY_PAIR *t);
+UINT ScGetServerCipher(RPC *r, RPC_STR *t);
+UINT ScSetServerCipher(RPC *r, RPC_STR *t);
+UINT ScCreateHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScSetHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScGetHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScEnumHub(RPC *r, RPC_ENUM_HUB *t);
+UINT ScDeleteHub(RPC *r, RPC_DELETE_HUB *t);
+UINT ScGetHubRadius(RPC *r, RPC_RADIUS *t);
+UINT ScSetHubRadius(RPC *r, RPC_RADIUS *t);
+UINT ScEnumConnection(RPC *r, RPC_ENUM_CONNECTION *t);
+UINT ScDisconnectConnection(RPC *r, RPC_DISCONNECT_CONNECTION *t);
+UINT ScGetConnectionInfo(RPC *r, RPC_CONNECTION_INFO *t);
+UINT ScSetHubOnline(RPC *r, RPC_SET_HUB_ONLINE *t);
+UINT ScGetHubStatus(RPC *r, RPC_HUB_STATUS *t);
+UINT ScSetHubLog(RPC *r, RPC_HUB_LOG *t);
+UINT ScGetHubLog(RPC *r, RPC_HUB_LOG *t);
+UINT ScAddCa(RPC *r, RPC_HUB_ADD_CA *t);
+UINT ScEnumCa(RPC *r, RPC_HUB_ENUM_CA *t);
+UINT ScGetCa(RPC *r, RPC_HUB_GET_CA *t);
+UINT ScDeleteCa(RPC *r, RPC_HUB_DELETE_CA *t);
+UINT ScCreateLink(RPC *r, RPC_CREATE_LINK *t);
+UINT ScEnumLink(RPC *r, RPC_ENUM_LINK *t);
+UINT ScGetLinkStatus(RPC *r, RPC_LINK_STATUS *t);
+UINT ScSetLinkOnline(RPC *r, RPC_LINK *t);
+UINT ScSetLinkOffline(RPC *r, RPC_LINK *t);
+UINT ScDeleteLink(RPC *r, RPC_LINK *t);
+UINT ScRenameLink(RPC *r, RPC_RENAME_LINK *t);
+UINT ScAddAccess(RPC *r, RPC_ADD_ACCESS *t);
+UINT ScDeleteAccess(RPC *r, RPC_DELETE_ACCESS *t);
+UINT ScEnumAccess(RPC *r, RPC_ENUM_ACCESS_LIST *t);
+UINT ScCreateUser(RPC *r, RPC_SET_USER *t);
+UINT ScSetUser(RPC *r, RPC_SET_USER *t);
+UINT ScGetUser(RPC *r, RPC_SET_USER *t);
+UINT ScDeleteUser(RPC *r, RPC_DELETE_USER *t);
+UINT ScEnumUser(RPC *r, RPC_ENUM_USER *t);
+UINT ScCreateGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScSetGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScGetGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScDeleteGroup(RPC *r, RPC_DELETE_USER *t);
+UINT ScEnumGroup(RPC *r, RPC_ENUM_GROUP *t);
+UINT ScEnumSession(RPC *r, RPC_ENUM_SESSION *t);
+UINT ScGetSessionStatus(RPC *r, RPC_SESSION_STATUS *t);
+UINT ScDeleteSession(RPC *r, RPC_DELETE_SESSION *t);
+UINT ScEnumMacTable(RPC *r, RPC_ENUM_MAC_TABLE *t);
+UINT ScDeleteMacTable(RPC *r, RPC_DELETE_TABLE *t);
+UINT ScEnumIpTable(RPC *r, RPC_ENUM_IP_TABLE *t);
+UINT ScDeleteIpTable(RPC *r, RPC_DELETE_TABLE *t);
+UINT ScGetLink(RPC *a, RPC_CREATE_LINK *t);
+UINT ScSetLink(RPC *a, RPC_CREATE_LINK *t);
+UINT ScSetAccessList(RPC *r, RPC_ENUM_ACCESS_LIST *t);
+UINT ScSetKeep(RPC *r, RPC_KEEP *t);
+UINT ScGetKeep(RPC *r, RPC_KEEP *t);
+UINT ScEnableSecureNAT(RPC *r, RPC_HUB *t);
+UINT ScDisableSecureNAT(RPC *r, RPC_HUB *t);
+UINT ScSetSecureNATOption(RPC *r, VH_OPTION *t);
+UINT ScGetSecureNATOption(RPC *r, VH_OPTION *t);
+UINT ScEnumNAT(RPC *r, RPC_ENUM_NAT *t);
+UINT ScEnumDHCP(RPC *r, RPC_ENUM_DHCP *t);
+UINT ScGetSecureNATStatus(RPC *r, RPC_NAT_STATUS *t);
+UINT ScEnumEthernet(RPC *r, RPC_ENUM_ETH *t);
+UINT ScAddLocalBridge(RPC *r, RPC_LOCALBRIDGE *t);
+UINT ScDeleteLocalBridge(RPC *r, RPC_LOCALBRIDGE *t);
+UINT ScEnumLocalBridge(RPC *r, RPC_ENUM_LOCALBRIDGE *t);
+UINT ScGetBridgeSupport(RPC *r, RPC_BRIDGE_SUPPORT *t);
+UINT ScRebootServer(RPC *r, RPC_TEST *t);
+UINT ScGetCaps(RPC *r, CAPSLIST *t);
+UINT ScGetConfig(RPC *r, RPC_CONFIG *t);
+UINT ScSetConfig(RPC *r, RPC_CONFIG *t);
+UINT ScGetDefaultHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScGetHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScSetHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScGetHubExtOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScSetHubExtOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScAddL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScDelL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScEnumL3Switch(RPC *r, RPC_ENUM_L3SW *t);
+UINT ScStartL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScStopL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScAddL3If(RPC *r, RPC_L3IF *t);
+UINT ScDelL3If(RPC *r, RPC_L3IF *t);
+UINT ScEnumL3If(RPC *r, RPC_ENUM_L3IF *t);
+UINT ScAddL3Table(RPC *r, RPC_L3TABLE *t);
+UINT ScDelL3Table(RPC *r, RPC_L3TABLE *t);
+UINT ScEnumL3Table(RPC *r, RPC_ENUM_L3TABLE *t);
+UINT ScEnumCrl(RPC *r, RPC_ENUM_CRL *t);
+UINT ScAddCrl(RPC *r, RPC_CRL *t);
+UINT ScDelCrl(RPC *r, RPC_CRL *t);
+UINT ScGetCrl(RPC *r, RPC_CRL *t);
+UINT ScSetCrl(RPC *r, RPC_CRL *t);
+UINT ScSetAcList(RPC *r, RPC_AC_LIST *t);
+UINT ScGetAcList(RPC *r, RPC_AC_LIST *t);
+UINT ScEnumLogFile(RPC *r, RPC_ENUM_LOG_FILE *t);
+UINT ScReadLogFile(RPC *r, RPC_READ_LOG_FILE *t);
+UINT ScAddLicenseKey(RPC *r, RPC_TEST *t);
+UINT ScDelLicenseKey(RPC *r, RPC_TEST *t);
+UINT ScEnumLicenseKey(RPC *r, RPC_ENUM_LICENSE_KEY *t);
+UINT ScGetLicenseStatus(RPC *r, RPC_LICENSE_STATUS *t);
+UINT ScSetSysLog(RPC *r, SYSLOG_SETTING *t);
+UINT ScGetSysLog(RPC *r, SYSLOG_SETTING *t);
+UINT ScEnumEthVLan(RPC *r, RPC_ENUM_ETH_VLAN *t);
+UINT ScSetEnableEthVLan(RPC *r, RPC_TEST *t);
+UINT ScSetHubMsg(RPC *r, RPC_MSG *t);
+UINT ScGetHubMsg(RPC *r, RPC_MSG *t);
+UINT ScCrash(RPC *r, RPC_TEST *t);
+UINT ScGetAdminMsg(RPC *r, RPC_MSG *t);
+UINT ScFlush(RPC *r, RPC_TEST *t);
+UINT ScDebug(RPC *r, RPC_TEST *t);
+
+void InRpcTest(RPC_TEST *t, PACK *p);
+void OutRpcTest(PACK *p, RPC_TEST *t);
+void FreeRpcTest(RPC_TEST *t);
+void InRpcServerInfo(RPC_SERVER_INFO *t, PACK *p);
+void OutRpcServerInfo(PACK *p, RPC_SERVER_INFO *t);
+void FreeRpcServerInfo(RPC_SERVER_INFO *t);
+void InRpcServerStatus(RPC_SERVER_STATUS *t, PACK *p);
+void OutRpcServerStatus(PACK *p, RPC_SERVER_STATUS *t);
+void InRpcListener(RPC_LISTENER *t, PACK *p);
+void OutRpcListener(PACK *p, RPC_LISTENER *t);
+void InRpcListenerList(RPC_LISTENER_LIST *t, PACK *p);
+void OutRpcListenerList(PACK *p, RPC_LISTENER_LIST *t);
+void FreeRpcListenerList(RPC_LISTENER_LIST *t);
+void InRpcStr(RPC_STR *t, PACK *p);
+void OutRpcStr(PACK *p, RPC_STR *t);
+void FreeRpcStr(RPC_STR *t);
+void InRpcSetPassword(RPC_SET_PASSWORD *t, PACK *p);
+void OutRpcSetPassword(PACK *p, RPC_SET_PASSWORD *t);
+void InRpcFarm(RPC_FARM *t, PACK *p);
+void OutRpcFarm(PACK *p, RPC_FARM *t);
+void FreeRpcFarm(RPC_FARM *t);
+void InRpcFarmHub(RPC_FARM_HUB *t, PACK *p);
+void OutRpcFarmHub(PACK *p, RPC_FARM_HUB *t);
+void InRpcFarmInfo(RPC_FARM_INFO *t, PACK *p);
+void OutRpcFarmInfo(PACK *p, RPC_FARM_INFO *t);
+void FreeRpcFarmInfo(RPC_FARM_INFO *t);
+void InRpcEnumFarm(RPC_ENUM_FARM *t, PACK *p);
+void OutRpcEnumFarm(PACK *p, RPC_ENUM_FARM *t);
+void FreeRpcEnumFarm(RPC_ENUM_FARM *t);
+void InRpcFarmConnectionStatus(RPC_FARM_CONNECTION_STATUS *t, PACK *p);
+void OutRpcFarmConnectionStatus(PACK *p, RPC_FARM_CONNECTION_STATUS *t);
+void InRpcHubOption(RPC_HUB_OPTION *t, PACK *p);
+void OutRpcHubOption(PACK *p, RPC_HUB_OPTION *t);
+void InRpcRadius(RPC_RADIUS *t, PACK *p);
+void OutRpcRadius(PACK *p, RPC_RADIUS *t);
+void InRpcHub(RPC_HUB *t, PACK *p);
+void OutRpcHub(PACK *p, RPC_HUB *t);
+void InRpcCreateHub(RPC_CREATE_HUB *t, PACK *p);
+void OutRpcCreateHub(PACK *p, RPC_CREATE_HUB *t);
+void InRpcEnumHub(RPC_ENUM_HUB *t, PACK *p);
+void OutRpcEnumHub(PACK *p, RPC_ENUM_HUB *t);
+void FreeRpcEnumHub(RPC_ENUM_HUB *t);
+void InRpcDeleteHub(RPC_DELETE_HUB *t, PACK *p);
+void OutRpcDeleteHub(PACK *p, RPC_DELETE_HUB *t);
+void InRpcEnumConnection(RPC_ENUM_CONNECTION *t, PACK *p);
+void OutRpcEnumConnection(PACK *p, RPC_ENUM_CONNECTION *t);
+void FreeRpcEnumConnetion(RPC_ENUM_CONNECTION *t);
+void InRpcDisconnectConnection(RPC_DISCONNECT_CONNECTION *t, PACK *p);
+void OutRpcDisconnectConnection(PACK *p, RPC_DISCONNECT_CONNECTION *t);
+void InRpcConnectionInfo(RPC_CONNECTION_INFO *t, PACK *p);
+void OutRpcConnectionInfo(PACK *p, RPC_CONNECTION_INFO *t);
+void InRpcSetHubOnline(RPC_SET_HUB_ONLINE *t, PACK *p);
+void OutRpcSetHubOnline(PACK *p, RPC_SET_HUB_ONLINE *t);
+void InRpcHubStatus(RPC_HUB_STATUS *t, PACK *p);
+void OutRpcHubStatus(PACK *p, RPC_HUB_STATUS *t);
+void InRpcHubLog(RPC_HUB_LOG *t, PACK *p);
+void OutRpcHubLog(PACK *p, RPC_HUB_LOG *t);
+void InRpcHubAddCa(RPC_HUB_ADD_CA *t, PACK *p);
+void OutRpcHubAddCa(PACK *p, RPC_HUB_ADD_CA *t);
+void FreeRpcHubAddCa(RPC_HUB_ADD_CA *t);
+void InRpcHubEnumCa(RPC_HUB_ENUM_CA *t, PACK *p);
+void OutRpcHubEnumCa(PACK *p, RPC_HUB_ENUM_CA *t);
+void FreeRpcHubEnumCa(RPC_HUB_ENUM_CA *t);
+void InRpcHubGetCa(RPC_HUB_GET_CA *t, PACK *p);
+void OutRpcHubGetCa(PACK *p, RPC_HUB_GET_CA *t);
+void FreeRpcHubGetCa(RPC_HUB_GET_CA *t);
+void InRpcHubDeleteCa(RPC_HUB_DELETE_CA *t, PACK *p);
+void OutRpcHubDeleteCa(PACK *p, RPC_HUB_DELETE_CA *t);
+void InRpcCreateLink(RPC_CREATE_LINK *t, PACK *p);
+void OutRpcCreateLink(PACK *p, RPC_CREATE_LINK *t);
+void FreeRpcCreateLink(RPC_CREATE_LINK *t);
+void InRpcEnumLink(RPC_ENUM_LINK *t, PACK *p);
+void OutRpcEnumLink(PACK *p, RPC_ENUM_LINK *t);
+void FreeRpcEnumLink(RPC_ENUM_LINK *t);
+void InRpcLinkStatus(RPC_LINK_STATUS *t, PACK *p);
+void OutRpcLinkStatus(PACK *p, RPC_LINK_STATUS *t);
+void FreeRpcLinkStatus(RPC_LINK_STATUS *t);
+void InRpcLink(RPC_LINK *t, PACK *p);
+void OutRpcLink(PACK *p, RPC_LINK *t);
+void InRpcAccessEx(ACCESS *a, PACK *p, UINT index);
+void InRpcAccess(ACCESS *a, PACK *p);
+void OutRpcAccessEx(PACK *p, ACCESS *a, UINT index, UINT total);
+void OutRpcAccess(PACK *p, ACCESS *a);
+void InRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a, PACK *p);
+void OutRpcEnumAccessList(PACK *p, RPC_ENUM_ACCESS_LIST *a);
+void FreeRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a);
+void *InRpcAuthData(PACK *p, UINT *authtype);
+void OutRpcAuthData(PACK *p, void *authdata, UINT authtype);
+void FreeRpcAuthData(void *authdata, UINT authtype);
+void InRpcSetUser(RPC_SET_USER *t, PACK *p);
+void OutRpcSetUser(PACK *p, RPC_SET_USER *t);
+void FreeRpcSetUser(RPC_SET_USER *t);
+void InRpcEnumUser(RPC_ENUM_USER *t, PACK *p);
+void OutRpcEnumUser(PACK *p, RPC_ENUM_USER *t);
+void FreeRpcEnumUser(RPC_ENUM_USER *t);
+void InRpcSetGroup(RPC_SET_GROUP *t, PACK *p);
+void OutRpcSetGroup(PACK *p, RPC_SET_GROUP *t);
+void InRpcEnumGroup(RPC_ENUM_GROUP *t, PACK *p);
+void OutRpcEnumGroup(PACK *p, RPC_ENUM_GROUP *t);
+void FreeRpcEnumGroup(RPC_ENUM_GROUP *t);
+void InRpcDeleteUser(RPC_DELETE_USER *t, PACK *p);
+void OutRpcDeleteUser(PACK *p, RPC_DELETE_USER *t);
+void InRpcEnumSession(RPC_ENUM_SESSION *t, PACK *p);
+void OutRpcEnumSession(PACK *p, RPC_ENUM_SESSION *t);
+void FreeRpcEnumSession(RPC_ENUM_SESSION *t);
+void InRpcNodeInfo(NODE_INFO *t, PACK *p);
+void OutRpcNodeInfo(PACK *p, NODE_INFO *t);
+void InRpcSessionStatus(RPC_SESSION_STATUS *t, PACK *p);
+void OutRpcSessionStatus(PACK *p, RPC_SESSION_STATUS *t);
+void FreeRpcSessionStatus(RPC_SESSION_STATUS *t);
+void InRpcDeleteSession(RPC_DELETE_SESSION *t, PACK *p);
+void OutRpcDeleteSession(PACK *p, RPC_DELETE_SESSION *t);
+void InRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t, PACK *p);
+void OutRpcEnumMacTable(PACK *p, RPC_ENUM_MAC_TABLE *t);
+void FreeRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t);
+void InRpcEnumIpTable(RPC_ENUM_IP_TABLE *t, PACK *p);
+void OutRpcEnumIpTable(PACK *p, RPC_ENUM_IP_TABLE *t);
+void FreeRpcEnumIpTable(RPC_ENUM_IP_TABLE *t);
+void InRpcDeleteTable(RPC_DELETE_TABLE *t, PACK *p);
+void OutRpcDeleteTable(PACK *p, RPC_DELETE_TABLE *t);
+void InRpcMemInfo(MEMINFO *t, PACK *p);
+void OutRpcMemInfo(PACK *p, MEMINFO *t);
+void InRpcKeyPair(RPC_KEY_PAIR *t, PACK *p);
+void OutRpcKeyPair(PACK *p, RPC_KEY_PAIR *t);
+void FreeRpcKeyPair(RPC_KEY_PAIR *t);
+void InRpcAddAccess(RPC_ADD_ACCESS *t, PACK *p);
+void OutRpcAddAccess(PACK *p, RPC_ADD_ACCESS *t);
+void InRpcDeleteAccess(RPC_DELETE_ACCESS *t, PACK *p);
+void OutRpcDeleteAccess(PACK *p, RPC_DELETE_ACCESS *t);
+void FreeRpcSetGroup(RPC_SET_GROUP *t);
+void AdjoinRpcEnumSession(RPC_ENUM_SESSION *dest, RPC_ENUM_SESSION *src);
+void AdjoinRpcEnumMacTable(RPC_ENUM_MAC_TABLE *dest, RPC_ENUM_MAC_TABLE *src);
+void AdjoinRpcEnumIpTable(RPC_ENUM_IP_TABLE *dest, RPC_ENUM_IP_TABLE *src);
+void InRpcKeep(RPC_KEEP *t, PACK *p);
+void OutRpcKeep(PACK *p, RPC_KEEP *t);
+void InRpcOsInfo(OS_INFO *t, PACK *p);
+void OutRpcOsInfo(PACK *p, OS_INFO *t);
+void FreeRpcOsInfo(OS_INFO *t);
+void InRpcEnumEth(RPC_ENUM_ETH *t, PACK *p);
+void OutRpcEnumEth(PACK *p, RPC_ENUM_ETH *t);
+void FreeRpcEnumEth(RPC_ENUM_ETH *t);
+void InRpcLocalBridge(RPC_LOCALBRIDGE *t, PACK *p);
+void OutRpcLocalBridge(PACK *p, RPC_LOCALBRIDGE *t);
+void InRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t, PACK *p);
+void OutRpcEnumLocalBridge(PACK *p, RPC_ENUM_LOCALBRIDGE *t);
+void FreeRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t);
+void InRpcBridgeSupport(RPC_BRIDGE_SUPPORT *t, PACK *p);
+void OutRpcBridgeSupport(PACK *p, RPC_BRIDGE_SUPPORT *t);
+void InRpcConfig(RPC_CONFIG *t, PACK *p);
+void OutRpcConfig(PACK *p, RPC_CONFIG *t);
+void FreeRpcConfig(RPC_CONFIG *t);
+void InRpcAdminOption(RPC_ADMIN_OPTION *t, PACK *p);
+void OutRpcAdminOption(PACK *p, RPC_ADMIN_OPTION *t);
+void FreeRpcAdminOption(RPC_ADMIN_OPTION *t);
+void InRpcEnumL3Table(RPC_ENUM_L3TABLE *t, PACK *p);
+void OutRpcEnumL3Table(PACK *p, RPC_ENUM_L3TABLE *t);
+void FreeRpcEnumL3Table(RPC_ENUM_L3TABLE *t);
+void InRpcL3Table(RPC_L3TABLE *t, PACK *p);
+void OutRpcL3Table(PACK *p, RPC_L3TABLE *t);
+void InRpcEnumL3If(RPC_ENUM_L3IF *t, PACK *p);
+void OutRpcEnumL3If(PACK *p, RPC_ENUM_L3IF *t);
+void FreeRpcEnumL3If(RPC_ENUM_L3IF *t);
+void InRpcL3If(RPC_L3IF *t, PACK *p);
+void OutRpcL3If(PACK *p, RPC_L3IF *t);
+void InRpcL3Sw(RPC_L3SW *t, PACK *p);
+void OutRpcL3Sw(PACK *p, RPC_L3SW *t);
+void InRpcEnumL3Sw(RPC_ENUM_L3SW *t, PACK *p);
+void OutRpcEnumL3Sw(PACK *p, RPC_ENUM_L3SW *t);
+void FreeRpcEnumL3Sw(RPC_ENUM_L3SW *t);
+void InRpcCrl(RPC_CRL *t, PACK *p);
+void OutRpcCrl(PACK *p, RPC_CRL *t);
+void FreeRpcCrl(RPC_CRL *t);
+void InRpcEnumCrl(RPC_ENUM_CRL *t, PACK *p);
+void OutRpcEnumCrl(PACK *p, RPC_ENUM_CRL *t);
+void FreeRpcEnumCrl(RPC_ENUM_CRL *t);
+void InRpcInt(RPC_INT *t, PACK *p);
+void OutRpcInt(PACK *p, RPC_INT *t);
+void InRpcAcList(RPC_AC_LIST *t, PACK *p);
+void OutRpcAcList(PACK *p, RPC_AC_LIST *t);
+void FreeRpcAcList(RPC_AC_LIST *t);
+void InRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, PACK *p);
+void OutRpcEnumLogFile(PACK *p, RPC_ENUM_LOG_FILE *t);
+void FreeRpcEnumLogFile(RPC_ENUM_LOG_FILE *t);
+void AdjoinRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, RPC_ENUM_LOG_FILE *src);
+void InRpcReadLogFile(RPC_READ_LOG_FILE *t, PACK *p);
+void OutRpcReadLogFile(PACK *p, RPC_READ_LOG_FILE *t);
+void FreeRpcReadLogFile(RPC_READ_LOG_FILE *t);
+void InRpcRenameLink(RPC_RENAME_LINK *t, PACK *p);
+void OutRpcRenameLink(PACK *p, RPC_RENAME_LINK *t);
+void InRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t, PACK *p);
+void OutRpcEnumLicenseKey(PACK *p, RPC_ENUM_LICENSE_KEY *t);
+void FreeRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t);
+void InRpcLicenseStatus(RPC_LICENSE_STATUS *t, PACK *p);
+void OutRpcLicenseStatus(PACK *p, RPC_LICENSE_STATUS *t);
+void InRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t, PACK *p);
+void OutRpcEnumEthVLan(PACK *p, RPC_ENUM_ETH_VLAN *t);
+void FreeRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t);
+void InRpcMsg(RPC_MSG *t, PACK *p);
+void OutRpcMsg(PACK *p, RPC_MSG *t);
+void FreeRpcMsg(RPC_MSG *t);
+void InRpcWinVer(RPC_WINVER *t, PACK *p);
+void OutRpcWinVer(PACK *p, RPC_WINVER *t);
+
+
+
+#endif	// ADMIN_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Bridge.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Bridge.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Bridge.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,513 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Bridge.c
+// Ethernet ブリッジプログラム
+
+#define	BRIDGE_C
+
+#ifdef	WIN32
+#define	OS_WIN32
+#endif
+
+#ifdef	OS_WIN32
+
+// Win32 用
+#include "BridgeWin32.c"
+
+#else
+
+// Unix 用
+#include "BridgeUnix.c"
+
+#endif	// OS_WIN32
+
+// 現在の Ethernet デバイス一覧をハッシュする
+UINT GetEthDeviceHash()
+{
+#ifdef	OS_UNIX
+	// UNIX 版
+	UINT num;
+	UINT i;
+	char tmp[4096];
+	UCHAR hash[SHA1_SIZE];
+	TOKEN_LIST *t = GetEthList();
+
+	num = t->NumTokens;
+	tmp[0] = 0;
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		StrCat(tmp, sizeof(tmp), t->Token[i]);
+	}
+	FreeToken(t);
+
+	Hash(hash, tmp, StrLen(tmp), true);
+
+	Copy(&num, hash, sizeof(UINT));
+
+	return num;
+#else	// OS_UNIX
+	// Win32 版
+	UINT ret = 0;
+	MS_ADAPTER_LIST *a = MsCreateAdapterListEx(true);
+	UINT num;
+	UINT i;
+	char tmp[4096];
+	UCHAR hash[SHA1_SIZE];
+
+	tmp[0] = 0;
+	if (a != NULL)
+	{
+		for (i = 0;i < a->Num;i++)
+		{
+			StrCat(tmp, sizeof(tmp), a->Adapters[i]->Title);
+		}
+	}
+	MsFreeAdapterList(a);
+
+	Hash(hash, tmp, StrLen(tmp), true);
+
+	Copy(&num, hash, sizeof(UINT));
+
+	return num;
+#endif	// OS_UNIU
+}
+
+// WinPcap が必要かどうか取得する
+bool IsNeedWinPcap()
+{
+	if (IsBridgeSupported() == false)
+	{
+		// Windows 以外
+		return false;
+	}
+	else
+	{
+		// Windows
+		if (IsEthSupported())
+		{
+			// すでに Ethernet デバイスへのアクセスに成功している
+			return false;
+		}
+		else
+		{
+			// Ethernet デバイスへのアクセスに失敗している
+			return true;
+		}
+	}
+}
+
+// 現在の OS でブリッジがサポートされているかどうか取得する
+bool IsBridgeSupported()
+{
+	UINT type = GetOsInfo()->OsType;
+
+	if (OS_IS_WINDOWS(type))
+	{
+		return true;
+	}
+	else
+	{
+		return IsEthSupported();
+	}
+}
+
+// ローカルブリッジの削除
+bool DeleteLocalBridge(CEDAR *c, char *hubname, char *devicename)
+{
+	bool ret = false;
+	// 引数チェック
+	if (c == NULL || hubname == NULL || devicename == NULL)
+	{
+		return false;
+	}
+
+	LockList(c->HubList);
+	{
+		LockList(c->LocalBridgeList);
+		{
+			UINT i;
+
+			for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+			{
+				LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+
+				if (StrCmpi(br->HubName, hubname) == 0)
+				{
+					if (StrCmpi(br->DeviceName, devicename) == 0)
+					{
+						if (br->Bridge != NULL)
+						{
+							BrFreeBridge(br->Bridge);
+							br->Bridge = NULL;
+						}
+
+						Delete(c->LocalBridgeList, br);
+						Free(br);
+
+						ret = true;
+						break;
+					}
+				}
+			}
+		}
+		UnlockList(c->LocalBridgeList);
+	}
+	UnlockList(c->HubList);
+
+	return ret;
+}
+
+// ローカルブリッジの追加
+void AddLocalBridge(CEDAR *c, char *hubname, char *devicename, bool local, bool monitor, bool tapmode, char *tapaddr, bool fullbcast)
+{
+	UINT i;
+	HUB *h = NULL;
+	LOCALBRIDGE *br = NULL;
+	// 引数チェック
+	if (c == NULL || hubname == NULL || devicename == NULL)
+	{
+		return;
+	}
+
+	if (OS_IS_UNIX(GetOsInfo()->OsType) == false)
+	{
+		tapmode = false;
+	}
+
+	LockList(c->HubList);
+	{
+		LockList(c->LocalBridgeList);
+		{
+			bool exists = false;
+
+			// 全く同一のブリッジ設定が無いかどうか調べる
+			for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+			{
+				LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+				if (StrCmpi(br->DeviceName, devicename) == 0)
+				{
+					if (StrCmpi(br->HubName, hubname) == 0)
+					{
+						if (br->TapMode == tapmode)
+						{
+							exists = true;
+						}
+					}
+				}
+			}
+
+			if (exists == false)
+			{
+				// 設定を追加する
+				br = ZeroMalloc(sizeof(LOCALBRIDGE));
+				StrCpy(br->HubName, sizeof(br->HubName), hubname);
+				StrCpy(br->DeviceName, sizeof(br->DeviceName), devicename);
+				br->Bridge = NULL;
+				br->Local = local;
+				br->TapMode = tapmode;
+				br->FullBroadcast = fullbcast;
+				br->Monitor = monitor;
+				if (br->TapMode)
+				{
+					if (tapaddr != NULL && IsZero(tapaddr, 6) == false)
+					{
+						Copy(br->TapMacAddress, tapaddr, 6);
+					}
+					else
+					{
+						GenMacAddress(br->TapMacAddress);
+					}
+				}
+
+				Add(c->LocalBridgeList, br);
+
+				// HUB を検索する
+				for (i = 0;i < LIST_NUM(c->HubList);i++)
+				{
+					HUB *hub = LIST_DATA(c->HubList, i);
+					if (StrCmpi(hub->Name, br->HubName) == 0)
+					{
+						h = hub;
+						AddRef(h->ref);
+						break;
+					}
+				}
+			}
+		}
+		UnlockList(c->LocalBridgeList);
+	}
+	UnlockList(c->HubList);
+
+	// 早速ブリッジを開始する
+	if (h != NULL && br != NULL && h->Type != HUB_TYPE_FARM_DYNAMIC)
+	{
+		Lock(h->lock_online);
+		{
+			if (h->Offline == false)
+			{
+				LockList(c->LocalBridgeList);
+				{
+					if (IsInList(c->LocalBridgeList, br))
+					{
+						if (br->Bridge == NULL)
+						{
+							br->Bridge = BrNewBridge(h, br->DeviceName, NULL, br->Local, br->Monitor, br->TapMode, br->TapMacAddress, br->FullBroadcast);
+						}
+					}
+				}
+				UnlockList(c->LocalBridgeList);
+			}
+		}
+		Unlock(h->lock_online);
+	}
+
+	ReleaseHub(h);
+}
+
+// ローカルブリッジリストの初期化
+void InitLocalBridgeList(CEDAR *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->LocalBridgeList = NewList(NULL);
+}
+
+// ローカルブリッジリストの解放
+void FreeLocalBridgeList(CEDAR *c)
+{
+	UINT i;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+	{
+		LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+		Free(br);
+	}
+
+	ReleaseList(c->LocalBridgeList);
+	c->LocalBridgeList = NULL;
+}
+
+// ブリッジ用スレッド
+void BrBridgeThread(THREAD *thread, void *param)
+{
+	BRIDGE *b;
+	CONNECTION *c;
+	SESSION *s;
+	HUB *h;
+	char name[MAX_SIZE];
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	b = (BRIDGE *)param;
+
+	// コネクションの作成
+	c = NewServerConnection(b->Cedar, NULL, thread);
+	c->Protocol = CONNECTION_HUB_BRIDGE;
+
+	// セッションの作成
+	s = NewServerSession(b->Cedar, c, b->Hub, BRIDGE_USER_NAME, b->Policy);
+	HLog(b->Hub, "LH_START_BRIDGE", b->Name, s->Name);
+	StrCpy(name, sizeof(name), b->Name);
+	h = b->Hub;
+	AddRef(h->ref);
+	s->BridgeMode = true;
+	s->Bridge = b;
+	c->Session = s;
+	ReleaseConnection(c);
+
+	// ユーザー名
+	s->Username = CopyStr(BRIDGE_USER_NAME_PRINT);
+
+	b->Session = s;
+	AddRef(s->ref);
+
+	// 初期化完了を通知
+	NoticeThreadInit(thread);
+
+	// セッションのメイン関数
+	Debug("Bridge %s Start.\n", b->Name);
+	SessionMain(s);
+	Debug("Bridge %s Stop.\n", b->Name);
+
+	HLog(h, "LH_STOP_BRIDGE", name);
+
+	ReleaseHub(h);
+
+	ReleaseSession(s);
+}
+
+// ブリッジの解放
+void BrFreeBridge(BRIDGE *b)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	// セッション停止
+	StopSession(b->Session);
+	ReleaseSession(b->Session);
+	Free(b->Name);
+
+	Free(b);
+}
+
+// 新しいブリッジの作成
+BRIDGE *BrNewBridge(HUB *h, char *name, POLICY *p, bool local, bool monitor, bool tapmode, char *tapaddr, bool fullbcast)
+{
+	BRIDGE *b;
+	POLICY *policy;
+	THREAD *t;
+	// 引数チェック
+	if (h == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	if (p == NULL)
+	{
+		policy = ClonePolicy(GetDefaultPolicy());
+	}
+	else
+	{
+		policy = ClonePolicy(p);
+	}
+
+	policy->CheckMac = true;
+
+#ifdef	UNIX_LINUX
+	policy->CheckMac = false;
+#endif	// UNIX_LINUX
+
+	policy->NoBroadcastLimiter = true;
+
+	b = ZeroMalloc(sizeof(BRIDGE));
+	b->Cedar = h->Cedar;
+	b->Hub = h;
+	b->Name = CopyStr(name);
+	b->Policy = policy;
+	b->Local = local;
+	b->Monitor = monitor;
+	b->TapMode = tapmode;
+	b->FullBroadcast = fullbcast;
+
+	if (b->TapMode)
+	{
+		if (tapaddr != NULL && IsZero(tapaddr, 6) == false)
+		{
+			Copy(b->TapMacAddress, tapaddr, 6);
+		}
+		else
+		{
+			GenMacAddress(b->TapMacAddress);
+		}
+	}
+
+	if (monitor)
+	{
+		// モニタリングモード
+		policy->MonitorPort = true;
+	}
+
+	if (b->FullBroadcast)
+	{
+		// ブロードキャストを制限しない
+		policy->NoBroadcastLimiter = true;
+	}
+
+	// スレッド作成
+	t = NewThread(BrBridgeThread, b);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+
+	return b;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Bridge.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Bridge.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Bridge.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,144 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Bridge.h
+// Bridge.c のヘッダ
+
+#ifndef	BRIDGE_H
+#define	BRIDGE_H
+
+#ifdef	OS_WIN32
+
+// Win32 用
+#include <Cedar/BridgeWin32.h>
+
+#else
+
+// Unix 用
+#include <Cedar/BridgeUnix.h>
+
+#endif	// OS_WIN32
+
+// ブリッジ
+struct BRIDGE
+{
+	bool Active;			// 状態
+	CEDAR *Cedar;			// Cedar
+	HUB *Hub;				// HUB
+	SESSION *Session;		// セッション
+	POLICY *Policy;			// ポリシー
+	ETH *Eth;				// Ethernet
+	char *Name;				// デバイス名
+	UINT64 LastBridgeTry;	// 最後にブリッジを試行した時刻
+	bool Local;				// ローカルモード
+	bool Monitor;			// モニタモード
+	bool TapMode;			// tap モード
+	bool FullBroadcast;		// フルブロードキャスト
+	UCHAR TapMacAddress[6];	// tap の MAC アドレス
+	UINT LastNumDevice;		// デバイス個数 (最後にチェックした数)
+	UINT64 LastNumDeviceCheck;	// 最後にデバイスの個数をチェックした時刻
+	UINT64 LastChangeMtuError;	// 最後に MTU の変更エラーを記録した時刻
+};
+
+// ローカルブリッジ
+struct LOCALBRIDGE
+{
+	char HubName[MAX_HUBNAME_LEN + 1];			// 仮想 HUB 名
+	char DeviceName[MAX_SIZE];					// デバイス名
+	bool Local;									// ローカルモード
+	bool Monitor;								// モニタモード
+	bool TapMode;								// tap モード
+	bool FullBroadcast;							// フルブロードキャストモード
+	UCHAR TapMacAddress[6];						// tap の MAC アドレス
+	BRIDGE *Bridge;								// ブリッジ
+};
+
+BRIDGE *BrNewBridge(HUB *h, char *name, POLICY *p, bool local, bool monitor, bool tapmode, char *tapaddr, bool fullbcast);
+void BrBridgeThread(THREAD *thread, void *param);
+void BrFreeBridge(BRIDGE *b);
+void InitLocalBridgeList(CEDAR *c);
+void FreeLocalBridgeList(CEDAR *c);
+void AddLocalBridge(CEDAR *c, char *hubname, char *devicename, bool local, bool monitor, bool tapmode, char *tapaddr, bool fullbcast);
+bool DeleteLocalBridge(CEDAR *c, char *hubname, char *devicename);
+bool IsBridgeSupported();
+bool IsNeedWinPcap();
+UINT GetEthDeviceHash();
+
+#endif	// BRIDGE_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeUnix.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeUnix.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeUnix.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1800 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// BridgeUnix.c
+// Ethernet ブリッジプログラム (UNIX 版)
+//#define	BRIDGE_C
+//#define	UNIX_LINUX
+
+#ifdef	BRIDGE_C
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+#ifdef UNIX_SOLARIS
+#include <sys/sockio.h>
+#endif
+
+#ifdef BRIDGE_PCAP
+#include <pcap.h>
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#endif // BRIDGE_BPF
+
+// 初期化
+void InitEth()
+{
+}
+
+// 解放
+void FreeEth()
+{
+}
+
+// Unix のデバイスの説明文字列の取得がサポートされているかどうか取得
+bool EthIsInterfaceDescriptionSupportedUnix()
+{
+	bool ret = false;
+	DIRLIST *d = EnumDir("/etc/sysconfig/networking/devices/");
+
+	if (d == NULL)
+	{
+		return false;
+	}
+
+	if (d->NumFiles >= 1)
+	{
+		ret = true;
+	}
+
+	FreeDir(d);
+
+	return ret;
+}
+
+// Unix のデバイスの説明文字列を取得
+bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size)
+{
+	char tmp[MAX_SIZE];
+	bool ret = false;
+	BUF *b;
+	// 引数チェック
+	if (name == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(str, size, name);
+
+	Format(tmp, sizeof(tmp), "/etc/sysconfig/networking/devices/ifcfg-%s", name);
+
+	b = ReadDump(tmp);
+	if (b != NULL)
+	{
+		char *line = CfgReadNextLine(b);
+
+		if (IsEmptyStr(line) == false)
+		{
+			if (StartWith(line, "#"))
+			{
+				char tmp[MAX_SIZE];
+
+				StrCpy(tmp, sizeof(tmp), line + 1);
+
+				Trim(tmp);
+				tmp[60] = 0;
+
+				StrCpy(str, size, tmp);
+
+				ret = true;
+			}
+		}
+
+		Free(line);
+
+		FreeBuf(b);
+	}
+
+	return ret;
+}
+
+// Raw ソケットを開く
+int UnixEthOpenRawSocket()
+{
+#ifdef	UNIX_LINUX
+	int s;
+
+	s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (s < 0)
+	{
+		return INVALID_SOCKET;
+	}
+	else
+	{
+		return s;
+	}
+#else	// UNIX_LINUX
+	return -1;
+#endif	// UNIX_LINUX
+}
+
+// Ethernet 操作がサポートされているかどうか
+bool IsEthSupported()
+{
+	bool ret = false;
+
+#if		defined(UNIX_LINUX)
+	ret = IsEthSupportedLinux();
+#elif	defined(UNIX_SOLARIS)
+	ret = IsEthSupportedSolaris();
+#elif	defined(BRIDGE_PCAP)
+	ret = true;
+#elif	defined(BRIDGE_BPF)
+	ret = true;
+#endif
+	return ret;
+}
+
+#ifdef	UNIX_LINUX
+bool IsEthSupportedLinux()
+{
+	int s;
+
+	// Raw ソケットを開いてみる
+	s = UnixEthOpenRawSocket();
+	if (s == INVALID_SOCKET)
+	{
+		// 失敗
+		return false;
+	}
+
+	// 成功
+	closesocket(s);
+
+	return true;
+}
+#endif	// UNIX_LINUX
+
+#ifdef	UNIX_SOLARIS
+bool IsEthSupportedSolaris()
+{
+	return true;
+}
+#endif	// UNIX_SOLARIS
+
+#ifdef	UNIX_SOLARIS
+// アダプタ一覧を取得 (Solaris)
+TOKEN_LIST *GetEthListSolaris()
+{
+	TOKEN_LIST *t;
+	int i, s;
+	LIST *o;
+
+
+	o = NewListFast(CompareStr);
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s != INVALID_SOCKET)
+	{
+		struct lifnum lifn;
+		lifn.lifn_family = AF_INET;
+		lifn.lifn_flags = 0;
+		if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) >= 0)
+		{
+			struct lifconf lifc;
+			struct lifreq *buf;
+			UINT numifs;
+			UINT bufsize;
+			
+			numifs = lifn.lifn_count;
+			Debug("NumIFs:%d\n",numifs);
+			bufsize = numifs * sizeof(struct lifreq);
+			buf = Malloc(bufsize);
+
+			lifc.lifc_family = AF_INET;
+			lifc.lifc_flags = 0;
+			lifc.lifc_len = bufsize;
+			lifc.lifc_buf = (char*) buf;
+			if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) >= 0)
+			{
+				for (i = 0; i<numifs; i++)
+				{
+					if(StartWith(buf[i].lifr_name, "lo") == false){
+						Add(o, CopyStr(buf[i].lifr_name));
+					}
+				}
+			}
+			Free(buf);
+		}
+		closesocket(s);
+	}
+
+	Sort(o);
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		char *name = LIST_DATA(o, i);
+		t->Token[i] = name;
+	}
+
+	ReleaseList(o);
+
+	return t;
+}
+#endif	// UNIX_SOLARIS
+
+#ifdef	UNIX_LINUX
+// アダプタ一覧を取得 (Linux)
+TOKEN_LIST *GetEthListLinux()
+{
+	struct ifreq ifr;
+	TOKEN_LIST *t;
+	UINT i, n;
+	int s;
+	LIST *o;
+	char name[MAX_SIZE];
+
+	o = NewListFast(CompareStr);
+
+	s = UnixEthOpenRawSocket();
+	if (s != INVALID_SOCKET)
+	{
+		n = 0;
+		for (i = 0;;i++)
+		{
+			Zero(&ifr, sizeof(ifr));
+			ifr.ifr_ifindex = i;
+
+			if (ioctl(s, SIOCGIFNAME, &ifr) >= 0)
+			{
+				n = 0;
+				StrCpy(name, sizeof(name), ifr.ifr_name);
+
+				Zero(&ifr, sizeof(ifr));
+				StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+				if (ioctl(s, SIOCGIFHWADDR, &ifr) >= 0)
+				{
+					UINT type = ifr.ifr_hwaddr.sa_family;
+					if (type == 1 || type == 2 || type == 6 || type == 800 || type == 801)
+					{
+						if (IsInListStr(o, name) == false)
+						{
+							if (StartWith(name, "tap_") == false)
+							{
+								Add(o, CopyStr(name));
+							}
+						}
+					}
+				}
+			}
+			else
+			{
+				n++;
+				if (n >= 64)
+				{
+					break;
+				}
+			}
+		}
+		closesocket(s);
+	}
+
+	Sort(o);
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		char *name = LIST_DATA(o, i);
+		t->Token[i] = name;
+	}
+
+	ReleaseList(o);
+
+	return t;
+}
+#endif	// UNIX_LINUX
+
+#ifdef BRIDGE_PCAP
+// アダプタ一覧を取得 (Pcap)
+TOKEN_LIST *GetEthListPcap()
+{
+	pcap_if_t *alldevs;
+	char errbuf[PCAP_ERRBUF_SIZE];
+	LIST *o;
+	TOKEN_LIST *t;
+	int i;
+
+	o = NewListFast(CompareStr);
+
+	if( pcap_findalldevs(&alldevs,errbuf) != -1)
+	{
+		pcap_if_t *dev = alldevs;
+		while(dev != NULL)
+		{
+			pcap_t *p;
+			// デバイスを開いてみないとデバイスの種類が分からない？
+			p = pcap_open_live(dev->name, 0, false, 0, errbuf);
+			if(p != NULL)
+			{
+				int datalink = pcap_datalink(p);
+	//			Debug("type:%s\n",pcap_datalink_val_to_name(datalink));
+				pcap_close(p);
+				if(datalink == DLT_EN10MB){
+					// イーサネットデバイスのみ列挙する
+					Add(o, CopyStr(dev->name));
+				}
+			}
+			dev = dev->next;
+		}
+		pcap_freealldevs(alldevs);
+	}
+	
+	Sort(o);
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+	ReleaseList(o);
+	return t;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+// アダプタ一覧を取得 (BPF)
+TOKEN_LIST *GetEthListBpf()
+{
+	struct ifaddrs *ifadrs;
+	struct sockaddr_dl *sockadr;
+	LIST *o;
+	TOKEN_LIST *t;
+	int i;
+
+	o = NewListFast(CompareStr);
+
+	// ネットワークデバイスの一覧を取得
+	if(getifaddrs( &ifadrs ) == 0)
+	{
+		struct ifaddrs *ifadr = ifadrs;
+		while(ifadr)
+		{
+			sockadr = (struct sockaddr_dl*)ifadr->ifa_addr;
+			if(sockadr->sdl_family == AF_LINK && sockadr->sdl_type == IFT_ETHER)
+			{
+				// Ethernet デバイスか？
+				if(!IsInListStr(o,ifadr->ifa_name))
+				{
+					// 既存でなければ追加（複数のMACアドレスを持つインターフェースへの対策）
+					Add(o, CopyStr(ifadr->ifa_name));
+				}
+			}
+			ifadr = ifadr -> ifa_next;
+		}
+		freeifaddrs(ifadrs);
+	}
+
+	Sort(o);
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+	ReleaseList(o);
+	return t;
+}
+#endif // BRIDGE_BPF
+
+// アダプタ一覧を取得
+TOKEN_LIST *GetEthList()
+{
+	TOKEN_LIST *t = NULL;
+
+#if	defined(UNIX_LINUX)
+	t = GetEthListLinux();
+#elif	defined(UNIX_SOLARIS)
+	t = GetEthListSolaris();
+#elif	defined(BRIDGE_PCAP)
+	t = GetEthListPcap();
+#elif	defined(BRIDGE_BPF)
+	t = GetEthListBpf();
+#endif
+
+	return t;
+}
+
+#ifdef	UNIX_LINUX
+// アダプタを開く (Linux)
+ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)
+{
+	ETH *e;
+	struct ifreq ifr;
+	struct sockaddr_ll addr;
+	int s;
+	int index;
+	CANCEL *c;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	if (tapmode)
+	{
+#ifndef	NO_VLAN
+		// tap モードの場合
+		VLAN *v = NewTap(name, tapaddr);
+		if (v == NULL)
+		{
+			return NULL;
+		}
+
+		e = ZeroMalloc(sizeof(ETH));
+		e->Name = CopyStr(name);
+		e->Title = CopyStr(name);
+		e->Cancel = VLanGetCancel(v);
+		e->IfIndex = 0;
+		e->Socket = INVALID_SOCKET;
+		e->Tap = v;
+
+		return e;
+#else	// NO_VLAN
+		return NULL;
+#endif	// NO_VLAN
+	}
+
+	s = UnixEthOpenRawSocket();
+	if (s == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+
+	Zero(&ifr, sizeof(ifr));
+	StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+
+	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
+	{
+		closesocket(s);
+		return NULL;
+	}
+
+	index = ifr.ifr_ifindex;
+
+	Zero(&addr, sizeof(addr));
+	addr.sll_family = PF_PACKET;
+	addr.sll_protocol = htons(ETH_P_ALL);
+	addr.sll_ifindex = index;
+
+	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+	{
+		closesocket(s);
+		return NULL;
+	}
+
+	if (local == false)
+	{
+		// プロミスキャスモードに設定する
+		Zero(&ifr, sizeof(ifr));
+		StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+		if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
+		{
+			// 失敗
+			closesocket(s);
+			return NULL;
+		}
+
+		ifr.ifr_flags |= IFF_PROMISC;
+
+		if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
+		{
+			// 失敗
+			closesocket(s);
+			return NULL;
+		}
+	}
+
+	e = ZeroMalloc(sizeof(ETH));
+	e->Name = CopyStr(name);
+	e->Title = CopyStr(name);
+	e->IfIndex = index;
+	e->Socket = s;
+
+	c = NewCancel();
+	UnixDeletePipe(c->pipe_read, c->pipe_write);
+	c->pipe_read = c->pipe_write = -1;
+
+	UnixSetSocketNonBlockingMode(s, true);
+
+	c->SpecialFlag = true;
+	c->pipe_read = s;
+
+	e->Cancel = c;
+
+	// MTU の取得
+	e->InitialMtu = EthGetMtu(e);
+
+	return e;
+}
+#endif	// UNIX_LINUX
+
+// MTU の値を取得
+UINT EthGetMtu(ETH *e)
+{
+#if	defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	UINT ret = 0;
+#ifdef	UNIX_SOLARIS
+	struct lifreq ifr;
+#else	// UNIX_SOLARIS
+	struct ifreq ifr;
+#endif	// UNIX_SOLARIS
+	int s;
+	// 引数チェック
+	if (e == NULL || e->Tap != NULL)
+	{
+		return 0;
+	}
+
+	if (e->CurrentMtu != 0)
+	{
+		return e->CurrentMtu;
+	}
+
+#if	defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	s = e->SocketBsdIf;
+#else	// defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	s = e->Socket;
+#endif	// defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+
+	Zero(&ifr, sizeof(ifr));
+
+#ifdef	UNIX_SOLARIS
+	StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);
+#else	// UNIX_SOLARIS
+	StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);
+#endif	// UNIX_SOLARIS
+
+#ifdef	UNIX_SOLARIS
+	if (ioctl(s, SIOCGLIFMTU, &ifr) < 0)
+	{
+		// 失敗
+		return 0;
+	}
+#else	// UNIX_SOLARIS
+	if (ioctl(s, SIOCGIFMTU, &ifr) < 0)
+	{
+		// 失敗
+		return 0;
+	}
+#endif	// UNIX_SOLARIS
+
+#ifdef	UNIX_SOLARIS
+	ret = ifr.lifr_mtu + 14;
+#else	// UNIX_SOLARIS
+	ret = ifr.ifr_mtu + 14;
+#endif	// UNIX_SOLARIS
+
+	e->CurrentMtu = ret;
+
+	Debug("%s: GetMtu: %u\n", e->Name, ret);
+
+	return ret;
+#else	// defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	return 0;
+#endif	// defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+// MTU の値を設定
+bool EthSetMtu(ETH *e, UINT mtu)
+{
+#if	defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	UINT ret = 0;
+#ifdef	UNIX_SOLARIS
+	struct lifreq ifr;
+#else	// UNIX_SOLARIS
+	struct ifreq ifr;
+#endif	// UNIX_SOLARIS
+	int s;
+	// 引数チェック
+	if (e == NULL || e->Tap != NULL || (mtu > 1 && mtu < 1514))
+	{
+		return false;
+	}
+	if (mtu == 0 && e->InitialMtu == 0)
+	{
+		return false;
+	}
+
+	if (mtu == 0)
+	{
+		// mtu == 0 の場合は MTU の値を元に戻す
+		mtu = e->InitialMtu;
+	}
+
+#if	defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	s = e->SocketBsdIf;
+#else	// defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	s = e->Socket;
+#endif	// defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+
+	if (e->CurrentMtu == mtu)
+	{
+		// 変更の必要なし
+		return true;
+	}
+
+	Zero(&ifr, sizeof(ifr));
+
+#ifdef	UNIX_SOLARIS
+	StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);
+	ifr.lifr_mtu = mtu - 14;
+#else	// UNIX_SOLARIS
+	StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);
+	ifr.ifr_mtu = mtu - 14;
+#endif	// UNIX_SOLARIS
+
+#ifdef	UNIX_SOLARIS
+	if (ioctl(s, SIOCSLIFMTU, &ifr) < 0)
+	{
+		// 失敗
+		return false;
+	}
+#else	// UNIX_SOLARIS
+	if (ioctl(s, SIOCSIFMTU, &ifr) < 0)
+	{
+		// 失敗
+		return false;
+	}
+#endif	// UNIX_SOLARIS
+
+	e->CurrentMtu = mtu;
+
+	Debug("%s: SetMtu: %u\n", e->Name, mtu);
+
+	return true;
+#else	// defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	return false;
+#endif	// defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+// MTU の値の変更がサポートされているかどうか取得
+bool EthIsChangeMtuSupported(ETH *e)
+{
+#if	defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	// 引数チェック
+	if (e == NULL || e->Tap != NULL)
+	{
+		return false;
+	}
+
+	return true;
+#else	// defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+	return false;
+#endif	// defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+#ifdef	UNIX_SOLARIS
+// アダプタを開く (Solaris)
+ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr)
+{
+	char devname[MAX_SIZE];
+	UINT devid;
+	int fd;
+	ETH *e;
+	CANCEL *c;
+	struct strioctl sioc;
+
+	// 引数チェック
+	if (name == NULL || tapmode != false)
+	{
+		return NULL;
+	}
+
+	// デバイス名を解析
+	if (ParseUnixEthDeviceName(devname, sizeof(devname), &devid, name) == false)
+	{
+		return NULL;
+	}
+
+	// デバイスを開く
+	fd = open(devname, O_RDWR);
+	if (fd == -1)
+	{
+		// 失敗
+		return NULL;
+	}
+
+	// デバイスにアタッチする
+	if (DlipAttatchRequest(fd, devid) == false)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	// 確認
+	if (DlipReceiveAck(fd) == false)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	// SAPにバインドする
+	if (DlipBindRequest(fd) == false)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	// 確認
+	if (DlipReceiveAck(fd) == false)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	// SAPに関わらず受信するモードにセットする
+	if (DlipPromiscuous(fd, DL_PROMISC_SAP) == false)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	// 確認
+	if (DlipReceiveAck(fd) == false)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	// 自分の送信するパケットも受信するモードにセットする
+	if (DlipPromiscuous(fd, DL_PROMISC_PHYS) == false)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	// 確認
+	if (DlipReceiveAck(fd) == false)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	// Raw モードに設定
+	sioc.ic_cmd = DLIOCRAW;
+	sioc.ic_timout = -1;
+	sioc.ic_len = 0;
+	sioc.ic_dp = NULL;
+	if (ioctl(fd, I_STR, &sioc) < 0)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	if (ioctl(fd, I_FLUSH, FLUSHR) < 0)
+	{
+		// 失敗
+		close(fd);
+		return NULL;
+	}
+
+	e = ZeroMalloc(sizeof(ETH));
+	e->Name = CopyStr(name);
+	e->Title = CopyStr(name);
+
+	c = NewCancel();
+	UnixDeletePipe(c->pipe_read, c->pipe_write);
+	c->pipe_read = c->pipe_write = -1;
+
+	c->SpecialFlag = true;
+	c->pipe_read = fd;
+
+	e->Cancel = c;
+
+	e->IfIndex = -1;
+	e->Socket = fd;
+
+	UnixSetSocketNonBlockingMode(fd, true);
+
+	// 操作用 I/F の取得
+	e->SocketBsdIf = socket(AF_INET, SOCK_DGRAM, 0);
+
+	// MTU の取得
+	e->InitialMtu = EthGetMtu(e);
+
+	return e;
+}
+
+// プロミスキャスモードにセットする
+bool DlipPromiscuous(int fd, UINT level)
+{
+	dl_promiscon_req_t req;
+	struct strbuf ctl;
+	int flags;
+	// 引数チェック
+	if (fd == -1)
+	{
+		return false;
+	}
+
+	Zero(&req, sizeof(req));
+	req.dl_primitive = DL_PROMISCON_REQ;
+	req.dl_level = level;
+
+	Zero(&ctl, sizeof(ctl));
+	ctl.maxlen = 0;
+	ctl.len = sizeof(req);
+	ctl.buf = (char *)&req;
+
+	flags = 0;
+
+	if (putmsg(fd, &ctl, NULL, flags) < 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// SAPにバインドする
+bool DlipBindRequest(int fd)
+{
+	dl_bind_req_t	req;
+	struct strbuf ctl;
+
+	if (fd == -1)
+	{
+		return false;
+	}
+
+	Zero(&req, sizeof(req));
+	req.dl_primitive = DL_BIND_REQ;
+	req.dl_service_mode = DL_CLDLS;
+	req.dl_sap = 0;
+
+	Zero(&ctl, sizeof(ctl));
+	ctl.maxlen = 0;
+	ctl.len = sizeof(req);
+	ctl.buf = (char *)&req;
+
+	if (putmsg(fd, &ctl, NULL, 0) < 0)
+	{
+		return false;
+	}
+	return true;
+}
+
+// デバイスにアタッチする
+bool DlipAttatchRequest(int fd, UINT devid)
+{
+	dl_attach_req_t req;
+	struct strbuf ctl;
+	int flags;
+	// 引数チェック
+	if (fd == -1)
+	{
+		return false;
+	}
+
+	Zero(&req, sizeof(req));
+	req.dl_primitive = DL_ATTACH_REQ;
+	req.dl_ppa = devid;
+
+	Zero(&ctl, sizeof(ctl));
+	ctl.maxlen = 0;
+	ctl.len = sizeof(req);
+	ctl.buf = (char *)&req;
+
+	flags = 0;
+
+	if (putmsg(fd, &ctl, NULL, flags) < 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 確認応答を受信する
+bool DlipReceiveAck(int fd)
+{
+	union DL_primitives *dlp;
+	struct strbuf ctl;
+	int flags = 0;
+	char *buf;
+	// 引数チェック
+	if (fd == -1)
+	{
+		return false;
+	}
+
+	buf = MallocFast(SOLARIS_MAXDLBUF);
+
+	Zero(&ctl, sizeof(ctl));
+	ctl.maxlen = SOLARIS_MAXDLBUF;
+	ctl.len = 0;
+	ctl.buf = buf;
+
+	if (getmsg(fd, &ctl, NULL, &flags) < 0)
+	{
+		return false;
+	}
+
+	dlp = (union DL_primitives *)ctl.buf;
+	if (dlp->dl_primitive != (UINT)DL_OK_ACK && dlp->dl_primitive != (UINT)DL_BIND_ACK)
+	{
+		Free(buf);
+		return false;
+	}
+
+	Free(buf);
+
+	return true;
+}
+
+#endif	// UNIX_SOLARIS
+
+// UNIX のデバイス名文字列をデバイス名と番号に分ける
+bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, UINT *dst_devid, char *src_name)
+{
+	UINT len, i, j;
+
+	// 引数チェック
+	if (dst_devname == NULL || dst_devid == NULL || src_name == NULL)
+	{
+		return false;
+	}
+
+	len = strlen(src_name);
+	// 文字列長チェック
+	if(len == 0)
+	{
+		return false;
+	}
+
+	for (i = len-1; i+1 != 0; i--)
+	{
+		// 末尾からたどって最初に数字でない文字を検出
+		if (src_name[i] < '0' || '9' < src_name[i])
+		{
+			// 最後の文字が数字でなければエラー
+			if(src_name[i+1]==0)
+			{
+				return false;
+			}
+			*dst_devid = ToInt(src_name + i + 1);
+			StrCpy(dst_devname, dst_devname_size, "/dev/");
+			for (j = 0; j<i+1 && j<dst_devname_size-6; j++)
+			{
+				dst_devname[j+5] = src_name[j];
+			}
+			dst_devname[j+5]=0;
+			return true;
+		}
+	}
+	// 全て数字ならエラー
+	return false;
+}
+
+#if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP)
+// キャプチャしたパケットデータ構造体の初期化
+struct CAPTUREBLOCK *NewCaptureBlock(UCHAR *data, UINT size){
+	struct CAPTUREBLOCK *block = Malloc(sizeof(struct CAPTUREBLOCK));
+	block->Buf = data;
+	block->Size = size;
+	return block;
+}
+
+// キャプチャしたパケットデータ構造体の開放
+void FreeCaptureBlock(struct CAPTUREBLOCK *block){
+	Free(block);
+}
+#endif // BRIDGE_BPF || BRIDGE_PCAP
+
+#ifdef	BRIDGE_PCAP
+// パケット到着のコールバック関数
+void PcapHandler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
+{
+	ETH *e = (ETH*) user;
+	struct CAPTUREBLOCK *block;
+	UCHAR *data;
+	
+	data = Malloc(h->caplen);
+	Copy(data, bytes, h->caplen);
+	block = NewCaptureBlock(data, h->caplen);
+	LockQueue(e->Queue);
+	// キューのサイズが限界を超えたらパケットを破棄する。
+	if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE){
+		InsertQueue(e->Queue, block);
+		e->QueueSize += h->caplen;
+	}
+	UnlockQueue(e->Queue);
+	Cancel(e->Cancel);
+	return;
+}
+
+
+// Pcap でのパケットキャプチャの中継用スレッド
+void PcapThread(THREAD *thread, void *param)
+{
+	ETH *e = (ETH*)param;
+	pcap_t *p = e->Pcap;
+	int ret;
+
+	// 初期化完了を通知
+	NoticeThreadInit(thread);
+
+	// 帰り値 -1:エラー -2:外部からの終了
+	ret = pcap_loop(p, -1, PcapHandler, (u_char*) e);
+	if(ret == -1){
+		e->Socket = INVALID_SOCKET;
+		pcap_perror(p, "capture");
+	}
+	return;
+}
+
+
+// アダプタを開く (Pcap)
+ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr)
+{
+	char errbuf[PCAP_ERRBUF_SIZE];
+	ETH *e;
+	pcap_t *p;
+	CANCEL *c;
+
+	// 引数チェック
+	if (name == NULL || tapmode != false)
+	{
+		return NULL;
+	}
+	
+	// エラーメッセージバッファの初期化
+	errbuf[0] = 0;
+
+	// キャプチャデバイスを開く
+	p = pcap_open_live(name, 65535, (local == false), 1, errbuf);
+	if(p==NULL)
+	{
+		return NULL;
+	}
+
+	// ノンブロックモードに設定
+	// BSD系OSでは、BPFのselectが正常に動作しないのでブロックさせないとビジーループになる
+	/*
+	if(pcap_setnonblock(p, true, errbuf) == -1)
+	{
+		Debug("pcap_setnonblock:%s\n",errbuf);
+		pcap_close(p);
+		return NULL;
+	}
+	*/
+	
+	e = ZeroMalloc(sizeof(ETH));
+	e->Name = CopyStr(name);
+	e->Title = CopyStr(name);
+	e->Queue = NewQueue();
+	e->QueueSize = 0;
+	e->Cancel = NewCancel();
+	e->IfIndex = -1;
+	e->Socket = pcap_get_selectable_fd(p);
+	e->Pcap = p;
+	
+	e->CaptureThread = NewThread(PcapThread, e);
+	WaitThreadInit(e->CaptureThread);
+
+	return e;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+// BPF でのパケットキャプチャの中継用スレッド
+void BpfThread(THREAD *thread, void *param)
+{
+	ETH *e = (ETH*)param;
+	int fd = e->Socket;
+	int len;
+	int rest;	// バッファ中の残りバイト数
+	UCHAR *next;	//バッファ中の次のパケットの先頭
+	struct CAPTUREBLOCK *block;	// キューに追加するデータ
+	UCHAR *data;
+	struct bpf_hdr *hdr;
+
+	// バッファを確保
+	UCHAR *buf = Malloc(e->BufSize);
+	
+	// 初期化完了を通知
+	NoticeThreadInit(thread);
+
+	while(1){
+		// ループの脱出判定
+		if(e->Socket == INVALID_SOCKET){
+			break;
+		}
+		
+		rest = read(fd, buf, e->BufSize);
+		if(rest < 0 && errno != EAGAIN){
+			// エラー
+			close(fd);
+			e->Socket = INVALID_SOCKET;
+			Free(buf);
+			Cancel(e->Cancel);
+			return;
+		}
+		next = buf;
+		LockQueue(e->Queue);
+		while(rest>0){
+			// パケットの切り出し
+			hdr = (struct bpf_hdr*)next;
+
+			// Queue中のパケットサイズが限界を超えたらパケットを破棄する
+			if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE){
+				data = Malloc(hdr->bh_caplen);
+				Copy(data, next+(hdr->bh_hdrlen), hdr->bh_caplen);
+				block = NewCaptureBlock(data, hdr->bh_caplen);
+				InsertQueue(e->Queue, block);
+				e->QueueSize += hdr->bh_caplen;
+			}
+
+			// 次のパケットの頭出し
+			rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+			next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+		}
+		UnlockQueue(e->Queue);
+		Cancel(e->Cancel);
+	}
+	Free(buf);
+	Cancel(e->Cancel);
+	return;
+}
+#endif // BRIDGE_BPF_THREAD
+
+// アダプタを開く (BPF)
+ETH *OpenEthBpf(char *name, bool local, bool tapmode, char *tapaddr)
+{
+	ETH *e;
+	CANCEL *c;
+	char devname[MAX_SIZE];
+	int n = 0;
+	int fd;
+	int ret;
+	UINT bufsize;
+	struct ifreq ifr;
+	struct timeval to;
+	
+	// 未使用の bpf デバイスを探して開く
+	do{
+		Format(devname, sizeof(devname), "/dev/bpf%d", n++);
+		fd = open (devname, O_RDWR);
+		if(fd<0){
+			perror("open");
+		}
+	}while(fd < 0 && errno == EBUSY);
+	
+	// 開くことが出来るbpfデバイスが無ければエラー
+	if(fd < 0){
+		Debug("BPF: No minor number are free.\n");
+		return NULL;
+	}
+	
+	// バッファサイズを拡大
+	n = 524288; // なんとなく(libpcapでは32768だった)
+	while(true){
+		// バッファサイズを指定
+		ioctl(fd, BIOCSBLEN, &n);
+
+		// ネットワークをバインド
+		StrCpy(ifr.ifr_name, IFNAMSIZ, name);
+		ret = ioctl(fd, BIOCSETIF, &ifr);
+		if(ret < 0){
+			if(ret == ENOBUFS && n>1500){
+				// バッファサイズが不適切
+				// サイズを半分にしてリトライ
+				// バッファサイズ1500バイト以下でエラーになるのは何かおかしい
+				n /= 2;
+				continue;
+			}
+			Debug("bpf: binding network failed.\n");
+			close(fd);
+			return NULL;
+		}else{
+			break;
+		}
+	}
+	bufsize = n;
+
+	// プロミスキャスモードに設定
+	if(local == false){
+		if (ioctl(fd, BIOCPROMISC, NULL) < 0){
+			printf("bpf: promisc mode failed.\n");
+			close(fd);
+			return NULL;
+		}
+	}
+
+	
+	// 即時モードに設定（パケットを受信するとタイムアウトを待たず、すぐにreadがreturnする）
+	n = 1;
+	if (ioctl(fd, BIOCIMMEDIATE, &n) < 0){
+		Debug("BPF: non-block mode failed.\n");
+		close(fd);
+		return NULL;
+	}
+
+	// 自分が送信するパケットも受信する
+	n = 1;
+	if (ioctl(fd, BIOCGSEESENT, &n) < 0){
+		Debug("BPF: see sent mode failed.\n");
+		close(fd);
+		return NULL;
+	}
+
+
+	// ヘッダ完全モード（送信するパケットのヘッダも自分で生成する）
+	n = 1;
+	if (ioctl(fd, BIOCSHDRCMPLT, &n) < 0){
+		Debug("BPF: Header complete mode failed.\n");
+		close(fd);
+		return NULL;
+	}
+	
+	// read のタイムアウト時間を設定（1秒）
+	to.tv_sec = 1;
+	to.tv_usec = 0;
+	if (ioctl(fd, BIOCSRTIMEOUT, &to) < 0){
+		Debug("BPF: Read timeout setting failed.\n");
+		close(fd);
+		return NULL;
+	}
+	
+	e = ZeroMalloc(sizeof(ETH));
+	e->Name = CopyStr(name);
+	e->Title = CopyStr(name);
+	e->IfIndex = -1;
+	e->Socket = fd;
+	e->BufSize = bufsize;
+
+#ifdef BRIDGE_BPF_THREAD
+	e->Queue = NewQueue();
+	e->QueueSize = 0;
+	e->Cancel = NewCancel();
+
+	// キャプチャ用スレッドの開始
+	e->CaptureThread = NewThread(BpfThread, e);
+	WaitThreadInit(e->CaptureThread);
+
+#else // BRIDGE_BPF_THREAD
+	c = NewCancel();
+	UnixDeletePipe(c->pipe_read, c->pipe_write);
+	c->pipe_read = c->pipe_write = -1;
+	c->SpecialFlag = true;
+	c->pipe_read = fd;
+	e->Cancel = c;
+	e->Buffer = Malloc(bufsize);
+	e->Next = e->Buffer;
+	e->Rest = 0;
+
+	// ノンブロッキングモードに設定
+	UnixSetSocketNonBlockingMode(fd, true);
+#endif // BRIDGE_BPF_THREAD
+
+	// FreeBSD 用インターフェイス操作用ソケットを作成
+	e->SocketBsdIf = socket(AF_LOCAL, SOCK_DGRAM, 0);
+
+	// MTU の取得
+	e->InitialMtu = EthGetMtu(e);
+
+	return e;
+}
+#endif // BRIDGE_BPF
+
+// アダプタを開く
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)
+{
+	ETH *ret = NULL;
+
+#if		defined(UNIX_LINUX)
+	ret = OpenEthLinux(name, local, tapmode, tapaddr);
+#elif	defined(UNIX_SOLARIS)
+	ret = OpenEthSolaris(name, local, tapmode, tapaddr);
+#elif	defined(BRIDGE_PCAP)
+	ret = OpenEthPcap(name, local, tapmode, tapaddr);
+#elif	defined(BRIDGE_BPF)
+	ret = OpenEthBpf(name, local, tapmode, tapaddr);
+#endif
+
+	return ret;
+}
+
+typedef struct UNIXTHREAD
+{
+	pthread_t thread;
+	bool finished;
+} UNIXTHREAD;
+
+// アダプタを閉じる
+void CloseEth(ETH *e)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	if (e->Tap != NULL)
+	{
+#ifndef	NO_VLAN
+		FreeTap(e->Tap);
+#endif	// NO_VLAN
+	}
+
+#ifdef BRIDGE_PCAP
+	{
+		struct CAPTUREBLOCK *block;
+		pcap_breakloop(e->Pcap);
+		WaitThread(e->CaptureThread, INFINITE);
+		ReleaseThread(e->CaptureThread);
+		pcap_close(e->Pcap);
+		while (block = GetNext(e->Queue)){
+			Free(block->Buf);
+			FreeCaptureBlock(block);
+		}
+		ReleaseQueue(e->Queue);
+	}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+	{
+		struct CAPTUREBLOCK *block;
+		int fd = e->Socket;
+		e->Socket = INVALID_SOCKET;
+		WaitThread(e->CaptureThread, INFINITE);
+		ReleaseThread(e->CaptureThread);
+		e->Socket = fd; // 後でcloseするために復帰
+		while (block = GetNext(e->Queue)){
+			Free(block->Buf);
+			FreeCaptureBlock(block);
+		}
+		ReleaseQueue(e->Queue);
+	}
+#else // BRIDGE_BPF_THREAD
+	Free(e->Buffer);
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+	ReleaseCancel(e->Cancel);
+	Free(e->Name);
+	Free(e->Title);
+
+	// MTU の値を元に戻す
+	EthSetMtu(e, 0);
+
+	if (e->Socket != INVALID_SOCKET)
+	{
+#if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP) || defined(UNIX_SOLARIS)
+		close(e->Socket);
+#else // BRIDGE_PCAP
+		closesocket(e->Socket);
+#endif // BRIDGE_PCAP
+#if defined(BRIDGE_BPF) || defined(UNIX_SOLARIS)
+		if (e->SocketBsdIf != INVALID_SOCKET)
+		{
+			close(e->SocketBsdIf);
+		}
+#endif	// BRIDGE_BPF || UNIX_SOLARIS
+	}
+
+	Free(e);
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *EthGetCancel(ETH *e)
+{
+	CANCEL *c;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return NULL;
+	}
+
+	c = e->Cancel;
+	AddRef(c->ref);
+
+	return c;
+}
+
+// パケットの読み込み
+UINT EthGetPacket(ETH *e, void **data)
+{
+	UINT ret = 0;
+
+#if		defined(UNIX_LINUX)
+	ret = EthGetPacketLinux(e, data);
+#elif	defined(UNIX_SOLARIS)
+	ret = EthGetPacketSolaris(e, data);
+#elif	defined(BRIDGE_PCAP)
+	ret = EthGetPacketPcap(e, data);
+#elif	defined(BRIDGE_BPF)
+	ret = EthGetPacketBpf(e, data);
+#endif
+
+	return ret;
+}
+
+#ifdef	UNIX_LINUX
+UINT EthGetPacketLinux(ETH *e, void **data)
+{
+	int s, ret;
+	UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
+	// 引数チェック
+	if (e == NULL || data == NULL)
+	{
+		return INFINITE;
+	}
+
+	if (e->Tap != NULL)
+	{
+#ifndef	NO_VLAN
+		// tap モード
+		void *buf;
+		UINT size;
+
+		if (VLanGetNextPacket(e->Tap, &buf, &size) == false)
+		{
+			return INFINITE;
+		}
+
+		*data = buf;
+		return size;
+#else	// NO_VLAN
+		return INFINITE;
+#endif
+	}
+
+	s = e->Socket;
+
+	if (s == INVALID_SOCKET)
+	{
+		return INFINITE;
+	}
+
+	// 読み込み
+	ret = read(s, tmp, sizeof(tmp));
+	if (ret == 0 || (ret == -1 && errno == EAGAIN))
+	{
+		// パケット無し
+		*data = NULL;
+		return 0;
+	}
+	else if (ret == -1 || ret > sizeof(tmp))
+	{
+		// エラー
+		*data = NULL;
+		e->Socket = INVALID_SOCKET;
+		return INFINITE;
+	}
+	else
+	{
+		// パケット読み込み成功
+		*data = MallocFast(ret);
+		Copy(*data, tmp, ret);
+		return ret;
+	}
+
+	return 0;
+}
+#endif	// UNIX_LINUX
+
+#ifdef	UNIX_SOLARIS
+UINT EthGetPacketSolaris(ETH *e, void **data)
+{
+	UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
+	struct strbuf buf;
+	int s;
+	int flags = 0;
+	int ret;
+	// 引数チェック
+	if (e == NULL || data == NULL)
+	{
+		return INFINITE;
+	}
+
+	s = e->Socket;
+	if (s == INVALID_SOCKET)
+	{
+		return INFINITE;
+	}
+
+	Zero(&buf, sizeof(buf));
+	buf.buf = tmp;
+	buf.maxlen = sizeof(tmp);
+
+	ret = getmsg(s, NULL, &buf, &flags);
+
+	if (ret < 0 || ret > sizeof(tmp))
+	{
+		if (errno == EAGAIN)
+		{
+			// パケット無し
+			*data = NULL;
+			return 0;
+		}
+		// エラー
+		*data = NULL;
+		return INFINITE;
+	}
+
+	ret = buf.len;
+
+	*data = MallocFast(ret);
+	Copy(*data, tmp, ret);
+	return ret;
+}
+#endif	// UNIX_SOLARIS
+
+#ifdef	BRIDGE_PCAP
+UINT EthGetPacketPcap(ETH *e, void **data)
+{
+	struct CAPTUREBLOCK *block;
+	UINT size;
+	
+	LockQueue(e->Queue);
+	block = GetNext(e->Queue);
+	if(block != NULL){
+		e->QueueSize -= block->Size;
+	}
+	UnlockQueue(e->Queue);
+	
+	if(block == NULL){
+		*data = NULL;
+		if(e->Socket == INVALID_SOCKET){
+			return INFINITE;
+		}
+		return 0;
+	}
+	
+	*data = block->Buf;
+	size = block->Size;
+	FreeCaptureBlock(block);
+	
+	return size;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef	BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+UINT EthGetPacketBpf(ETH *e, void **data)
+{
+	struct CAPTUREBLOCK *block;
+	UINT size;
+	
+	LockQueue(e->Queue);
+	block = GetNext(e->Queue);
+	if(block != NULL){
+		e->QueueSize -= block->Size;
+	}
+	UnlockQueue(e->Queue);
+	
+	if(block == NULL){
+		*data = NULL;
+		if(e->Socket == INVALID_SOCKET){
+			return INFINITE;
+		}
+		return 0;
+	}
+	
+	*data = block->Buf;
+	size = block->Size;
+	FreeCaptureBlock(block);
+	
+	return size;
+}
+#else // BRIDGE_BPF_THREAD
+UINT EthGetPacketBpf(ETH *e, void **data)
+{
+	struct bpf_hdr *hdr;
+	
+	if(e->Rest<=0){
+		e->Rest = read(e->Socket, e->Buffer, e->BufSize);
+		if(e->Rest < 0){
+			*data = NULL;
+			if(errno != EAGAIN){
+				// エラー
+				return INFINITE;
+			}
+			// データなし
+			return 0;
+		}
+		e->Next = e->Buffer;
+	}
+	// パケットの切り出し
+	hdr = (struct bpf_hdr*)e->Next;
+	*data = Malloc(hdr->bh_caplen);
+	Copy(*data, e->Next+(hdr->bh_hdrlen), hdr->bh_caplen);
+
+	// 次のパケットの頭出し
+	e->Rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+	e->Next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+	
+	return hdr->bh_caplen;
+}
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+
+// 複数のパケットの書き込み
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || num == 0 || datas == NULL || sizes == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < num;i++)
+	{
+		EthPutPacket(e, datas[i], sizes[i]);
+	}
+}
+
+// パケットの書き込み
+void EthPutPacket(ETH *e, void *data, UINT size)
+{
+	int s, ret;
+	// 引数チェック
+	if (e == NULL || data == NULL)
+	{
+		return;
+	}
+	if (size < 14 || size > MAX_PACKET_SIZE)
+	{
+		Free(data);
+		return;
+	}
+
+	if (e->Tap != NULL)
+	{
+#ifndef	NO_VLAN
+		// tap モード
+		VLanPutPacket(e->Tap, data, size);
+#endif	// NO_VLAN
+		return;
+	}
+
+	s = e->Socket;
+
+	if (s == INVALID_SOCKET)
+	{
+		Free(data);
+		return;
+	}
+
+	// 書き込み
+#ifdef BRIDGE_PCAP
+	ret = pcap_inject(e->Pcap, data, size);
+	if( ret == -1 ){
+#ifdef _DEBUG
+		pcap_perror(e->Pcap, "inject");
+#endif // _DEBUG
+		Debug("EthPutPacket: ret:%d size:%d\n", ret, size);
+	}
+#else // BRIDGE_PCAP
+	ret = write(s, data, size);
+	if (ret<0)
+	{
+		Debug("EthPutPacket: ret:%d errno:%d  size:%d\n", ret, errno, size);
+	}
+#endif //BRIDGE_PCAP
+	
+	Free(data);
+}
+
+#endif	// BRIDGE_C
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeUnix.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeUnix.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeUnix.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,183 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// BridgeUnix.h
+// BridgeUnix.c のヘッダ
+
+#ifndef	BRIDGEUNIX_H
+#define	BRIDGEUNIX_H
+
+// マクロ
+#ifndef SOL_PACKET
+#define	SOL_PACKET	263
+#endif
+#ifndef ifr_newname
+#define ifr_newname     ifr_ifru.ifru_slave
+#endif
+
+// 定数
+#define	UNIX_ETH_TMP_BUFFER_SIZE		(2000)
+#define	SOLARIS_MAXDLBUF				(32768)
+#define BRIDGE_MAX_QUEUE_SIZE			(4096*1500)
+
+// ETH 構造体
+struct ETH
+{
+	char *Name;					// アダプタ名
+	char *Title;				// アダプタタイトル
+	CANCEL *Cancel;				// キャンセルオブジェクト
+	int IfIndex;				// インデックス
+	int Socket;					// ソケット
+	UINT InitialMtu;			// 初期の MTU 値
+	UINT CurrentMtu;			// 現在の MTU 値
+	int SocketBsdIf;			// BSD インターフェイス操作用ソケット
+
+#ifdef BRIDGE_PCAP
+	void *Pcap;					// Pcap 記述子
+	QUEUE *Queue;				// 中継スレッド用のキュー
+	UINT QueueSize;				// Queue 中のバイト数
+	THREAD *CaptureThread;			// Pcap 中継用スレッド
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+	UINT BufSize;				// BPF を read するときのバッファサイズ（これ以外だとエラー）
+#ifdef BRIDGE_BPF_THREAD
+	QUEUE *Queue;				// 中継スレッド用のキュー
+	UINT QueueSize;				// Queue 中のバイト数
+	THREAD *CaptureThread;			// BPF 中継用スレッド
+#else // BRIDGE_BPF_THREAD
+	UCHAR *Buffer;				// BPF を read するときのバッファ
+	UCHAR *Next;
+	int Rest;
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+	VLAN *Tap;					// tap
+};
+
+#if defined( BRIDGE_BPF ) || defined( BRIDGE_PCAP )
+struct CAPTUREBLOCK{
+	UINT Size;
+	UCHAR *Buf;
+};
+#endif // BRIDGE_BPF
+
+
+// 関数プロトタイプ
+void InitEth();
+void FreeEth();
+bool IsEthSupported();
+bool IsEthSupportedLinux();
+bool IsEthSupportedSolaris();
+bool IsEthSupportedPcap();
+TOKEN_LIST *GetEthList();
+TOKEN_LIST *GetEthListLinux();
+TOKEN_LIST *GetEthListSolaris();
+TOKEN_LIST *GetEthListPcap();
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr);
+bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, UINT *dst_devid, char *src_name);
+void CloseEth(ETH *e);
+CANCEL *EthGetCancel(ETH *e);
+UINT EthGetPacket(ETH *e, void **data);
+UINT EthGetPacketLinux(ETH *e, void **data);
+UINT EthGetPacketSolaris(ETH *e, void **data);
+UINT EthGetPacketPcap(ETH *e, void **data);
+UINT EthGetPacketBpf(ETH *e, void **data);
+void EthPutPacket(ETH *e, void *data, UINT size);
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes);
+UINT EthGetMtu(ETH *e);
+bool EthSetMtu(ETH *e, UINT mtu);
+bool EthIsChangeMtuSupported(ETH *e);
+bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size);
+bool EthIsInterfaceDescriptionSupportedUnix();
+
+#ifdef	UNIX_SOLARIS
+// Solaris 用関数プロトタイプ
+bool DlipAttatchRequest(int fd, UINT devid);
+bool DlipReceiveAck(int fd);
+bool DlipPromiscuous(int fd, UINT level);
+bool DlipBindRequest(int fd);
+#endif	// OS_SOLARIS
+
+int UnixEthOpenRawSocket();
+
+#endif	// BRIDGEUNIX_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeWin32.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeWin32.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeWin32.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1694 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// BridgeWin32.c
+// Ethernet ブリッジプログラム (Win32 版)
+
+#ifdef	BRIDGE_C
+
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Packet32.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+
+static WP *wp = NULL;
+static LIST *eth_list = NULL;
+
+static LOCK *eth_list_lock = NULL;
+static bool is_sep_mode = false;
+
+#define	LOAD_DLL_ADDR(name)				\
+	{									\
+		void *addr = GetProcAddress(h, #name);	\
+		Copy(&wp->name, &addr, sizeof(void *));	\
+	}
+
+// リスト比較
+int CmpRpcEnumEthVLan(void *p1, void *p2)
+{
+	RPC_ENUM_ETH_VLAN_ITEM *v1, *v2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	v1 = *((RPC_ENUM_ETH_VLAN_ITEM **)p1);
+	v2 = *((RPC_ENUM_ETH_VLAN_ITEM **)p2);
+	if (v1 == NULL || v2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(v1->DeviceName, v2->DeviceName);
+}
+
+// MTU の取得 (Windows では非サポート)
+UINT EthGetMtu(ETH *e)
+{
+	return 0;
+}
+
+// MTU の設定 (Windows では非サポート)
+bool EthSetMtu(ETH *e, UINT mtu)
+{
+	return false;
+}
+
+// MTU の設定がサポートされているかどうか取得 (Windows では非サポート)
+bool EthIsChangeMtuSupported(ETH *e)
+{
+	return false;
+}
+
+// デバイスの VLAN 有効化状態を設定
+bool SetVLanEnableStatus(char *title, bool enable)
+{
+	RPC_ENUM_ETH_VLAN t;
+	RPC_ENUM_ETH_VLAN_ITEM *e;
+	bool ret = false;
+	char key[MAX_SIZE];
+	char tcpkey[MAX_SIZE];
+	char short_key[MAX_SIZE];
+	// 引数チェック
+	if (title == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	if (EnumEthVLanWin32(&t) == false)
+	{
+		return false;
+	}
+
+	e = FindEthVLanItem(&t, title);
+
+	if (e != NULL)
+	{
+		if (GetClassRegKeyWin32(key, sizeof(key), short_key, sizeof(short_key), e->Guid))
+		{
+			if (StrCmpi(e->DriverType, "Intel") == 0)
+			{
+				if (enable)
+				{
+					MsRegWriteStr(REG_LOCAL_MACHINE, key, "VlanFiltering", "0");
+					MsRegWriteStr(REG_LOCAL_MACHINE, key, "TaggingMode", "0");
+					MsRegWriteInt(REG_LOCAL_MACHINE, key, "MonitorMode", 1);
+					MsRegWriteInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled", 1);
+				}
+				else
+				{
+					if (MsRegReadInt(REG_LOCAL_MACHINE, key, "TaggingMode") == 0)
+					{
+						MsRegDeleteValue(REG_LOCAL_MACHINE, key, "TaggingMode");
+					}
+
+					if (MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorMode") == 1)
+					{
+						MsRegDeleteValue(REG_LOCAL_MACHINE, key, "MonitorMode");
+					}
+
+					if (MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled") == 1)
+					{
+						MsRegDeleteValue(REG_LOCAL_MACHINE, key, "MonitorModeEnabled");
+					}
+				}
+
+				ret = true;
+			}
+			else if (StrCmpi(e->DriverType, "Broadcom") == 0)
+			{
+				if (enable)
+				{
+					MsRegWriteStr(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket", "1");
+				}
+				else
+				{
+					MsRegDeleteValue(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket");
+				}
+
+				ret = true;
+			}
+			else if (StrCmpi(e->DriverType, "Marvell") == 0)
+			{
+				if (enable)
+				{
+					MsRegWriteInt(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip", 1);
+				}
+				else
+				{
+					MsRegDeleteValue(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip");
+				}
+
+				ret = true;
+			}
+
+			Format(tcpkey, sizeof(tcpkey),
+				"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
+				e->Guid);
+
+			if (enable)
+			{
+				if (MsRegIsValue(REG_LOCAL_MACHINE, tcpkey, "MTU") == false)
+				{
+					MsRegWriteInt(REG_LOCAL_MACHINE, tcpkey, "MTU", 1500);
+				}
+			}
+			else
+			{
+				UINT mtu = MsRegReadInt(REG_LOCAL_MACHINE, tcpkey, "MTU");
+				if (mtu == 1500)
+				{
+					MsRegDeleteValue(REG_LOCAL_MACHINE, tcpkey, "MTU");
+				}
+			}
+		}
+	}
+
+	FreeRpcEnumEthVLan(&t);
+
+	return ret;
+}
+
+// デバイスを検索
+RPC_ENUM_ETH_VLAN_ITEM *FindEthVLanItem(RPC_ENUM_ETH_VLAN *t, char *name)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		if (StrCmpi(t->Items[i].DeviceName, name) == 0)
+		{
+			return &t->Items[i];
+		}
+	}
+
+	return NULL;
+}
+
+// デバイスの VLAN 有効化状態を取得
+void GetVLanEnableStatus(RPC_ENUM_ETH_VLAN_ITEM *e)
+{
+	char key[MAX_SIZE];
+	char short_key[MAX_SIZE];
+	char tcpkey[MAX_SIZE];
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	e->Enabled = false;
+
+	if (e->Support == false)
+	{
+		return;
+	}
+
+	if (GetClassRegKeyWin32(key, sizeof(key), short_key, sizeof(short_key), e->Guid) == false)
+	{
+		return;
+	}
+
+	Format(tcpkey, sizeof(tcpkey),
+		"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
+		e->Guid);
+
+	if (StrCmpi(e->DriverType, "Intel") == 0)
+	{
+		char *VlanFiltering = MsRegReadStr(REG_LOCAL_MACHINE, key, "VlanFiltering");
+		UINT MonitorMode = MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorMode");
+		UINT MonitorModeEnabled = MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled");
+		char *TaggingMode = MsRegReadStr(REG_LOCAL_MACHINE, key, "TaggingMode");
+
+		if (StrCmpi(VlanFiltering, "0") == 0 &&
+			MonitorMode == 1 &&
+			MonitorModeEnabled == 1 &&
+			StrCmpi(TaggingMode, "0") == 0)
+		{
+			e->Enabled = true;
+		}
+
+		Free(VlanFiltering);
+		Free(TaggingMode);
+	}
+	else if (StrCmpi(e->DriverType, "Broadcom") == 0)
+	{
+		char *PreserveVlanInfoInRxPacket = MsRegReadStr(REG_LOCAL_MACHINE,
+			key, "PreserveVlanInfoInRxPacket");
+
+		if (StrCmpi(PreserveVlanInfoInRxPacket, "1") == 0)
+		{
+			e->Enabled = true;
+		}
+
+		Free(PreserveVlanInfoInRxPacket);
+	}
+	else if (StrCmpi(e->DriverType, "Marvell") == 0)
+	{
+		DWORD SkDisableVlanStrip = MsRegReadInt(REG_LOCAL_MACHINE,
+			key, "SkDisableVlanStrip");
+
+		if (SkDisableVlanStrip == 1)
+		{
+			e->Enabled = true;
+		}
+	}
+
+	if (MsRegIsValue(REG_LOCAL_MACHINE, tcpkey, "MTU") == false)
+	{
+		e->Enabled = false;
+	}
+}
+
+// デバイスの VLAN サポート状態を取得
+void GetVLanSupportStatus(RPC_ENUM_ETH_VLAN_ITEM *e)
+{
+	BUF *b;
+	char filename[MAX_SIZE];
+	void *wow;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	wow = MsDisableWow64FileSystemRedirection();
+
+	// ドライバファイルを読み込む
+	CombinePath(filename, sizeof(filename), MsGetSystem32Dir(), "drivers");
+	CombinePath(filename, sizeof(filename), filename, e->DriverName);
+
+	b = ReadDump(filename);
+
+	if (b != NULL)
+	{
+		char intel1[] = "VlanFiltering";
+		char intel2[] = "V\0l\0a\0n\0F\0i\0l\0t\0e\0r\0i\0n\0g";
+		char intel3[] = "MonitorMode";
+		char intel4[] = "M\0o\0n\0i\0t\0o\0r\0M\0o\0d\0e";
+		char intel5[] = "TaggingMode";
+		char intel6[] = "T\0a\0g\0g\0i\0n\0g\0M\0o\0d\0e";
+		char broadcom1[] = "PreserveVlanInfoInRxPacket";
+		char broadcom2[] = "P\0r\0e\0s\0e\0r\0v\0e\0V\0l\0a\0n\0I\0n\0f\0o\0I\0n\0R\0x\0P\0a\0c\0k\0e\0t";
+		char marvell1[] = "SkDisableVlanStrip";
+		char marvell2[] = "S\0k\0D\0i\0s\0a\0b\0l\0e\0V\0l\0a\0n\0S\0t\0r\0i\0p";
+		char *driver_type = "";
+
+		if (SearchBin(b->Buf, 0, b->Size, intel1, sizeof(intel1)) != INFINITE
+			|| SearchBin(b->Buf, 0, b->Size, intel2, sizeof(intel2)) != INFINITE
+			|| SearchBin(b->Buf, 0, b->Size, intel3, sizeof(intel3)) != INFINITE
+			|| SearchBin(b->Buf, 0, b->Size, intel4, sizeof(intel4)) != INFINITE
+			|| SearchBin(b->Buf, 0, b->Size, intel5, sizeof(intel5)) != INFINITE
+			|| SearchBin(b->Buf, 0, b->Size, intel6, sizeof(intel6)) != INFINITE)
+		{
+			driver_type = "Intel";
+		}
+		else if (SearchBin(b->Buf, 0, b->Size, broadcom1, sizeof(broadcom1)) != INFINITE
+			|| SearchBin(b->Buf, 0, b->Size, broadcom2, sizeof(broadcom2)) != INFINITE)
+		{
+			driver_type = "Broadcom";
+		}
+		else if (SearchBin(b->Buf, 0, b->Size, marvell1, sizeof(marvell1)) != INFINITE
+			|| SearchBin(b->Buf, 0, b->Size, marvell2, sizeof(marvell2)) != INFINITE)
+		{
+			driver_type = "Marvell";
+		}
+
+		if (IsEmptyStr(driver_type) == false)
+		{
+			StrCpy(e->DriverType, sizeof(e->DriverType), driver_type);
+			e->Support = true;
+		}
+
+		FreeBuf(b);
+	}
+
+	MsRestoreWow64FileSystemRedirection(wow);
+}
+
+// short_key からデバイスのインスタンス ID を取得する
+char *SearchDeviceInstanceIdFromShortKey(char *short_key)
+{
+	char *ret = NULL;
+	TOKEN_LIST *t1;
+	// 引数チェック
+	if (short_key == NULL)
+	{
+		return NULL;
+	}
+
+	t1 = MsRegEnumKey(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum");
+
+	if (t1 != NULL)
+	{
+		TOKEN_LIST *t2;
+		char tmp[MAX_SIZE];
+		UINT i;
+
+		for (i = 0;i < t1->NumTokens;i++)
+		{
+			Format(tmp, sizeof(tmp), "SYSTEM\\CurrentControlSet\\Enum\\%s", t1->Token[i]);
+
+			t2 = MsRegEnumKey(REG_LOCAL_MACHINE, tmp);
+
+			if (t2 != NULL)
+			{
+				TOKEN_LIST *t3;
+				UINT i;
+
+				for (i = 0;i < t2->NumTokens;i++)
+				{
+					char tmp2[MAX_SIZE];
+
+					Format(tmp2, sizeof(tmp2), "%s\\%s", tmp, t2->Token[i]);
+
+					t3 = MsRegEnumKey(REG_LOCAL_MACHINE, tmp2);
+
+					if (t3 != NULL)
+					{
+						UINT i;
+
+						for (i = 0;i < t3->NumTokens;i++)
+						{
+							char tmp3[MAX_SIZE];
+							char *s;
+
+							Format(tmp3, sizeof(tmp3), "%s\\%s", tmp2, t3->Token[i]);
+
+							s = MsRegReadStr(REG_LOCAL_MACHINE, tmp3, "Driver");
+
+							if (s != NULL)
+							{
+								if (StrCmpi(s, short_key) == 0)
+								{
+									if (ret != NULL)
+									{
+										Free(ret);
+									}
+
+									ret = CopyStr(tmp3 + StrLen("SYSTEM\\CurrentControlSet\\Enum\\"));
+								}
+
+								Free(s);
+							}
+						}
+
+						FreeToken(t3);
+					}
+				}
+
+				FreeToken(t2);
+			}
+		}
+
+		FreeToken(t1);
+	}
+
+	return ret;
+}
+
+// 物理 LAN カードの VLAN 対応状況の列挙
+bool EnumEthVLanWin32(RPC_ENUM_ETH_VLAN *t)
+{
+	UINT i;
+	LIST *o;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+	if (MsIsWin2000OrGreater() == false)
+	{
+		return false;
+	}
+
+	if (IsEthSupported() == false)
+	{
+		return false;
+	}
+
+	// アダプタ一覧の取得
+	Lock(eth_list_lock);
+
+	InitEthAdaptersList();
+
+	o = NewListFast(CmpRpcEnumEthVLan);
+
+	for (i = 0;i < LIST_NUM(eth_list);i++)
+	{
+		WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+		if (IsEmptyStr(a->Guid) == false)
+		{
+			char class_key[MAX_SIZE];
+			char short_key[MAX_SIZE];
+
+			if (GetClassRegKeyWin32(class_key, sizeof(class_key),
+				short_key, sizeof(short_key), a->Guid))
+			{
+				char *device_instance_id = MsRegReadStr(REG_LOCAL_MACHINE, class_key, "DeviceInstanceID");
+
+				if (IsEmptyStr(device_instance_id))
+				{
+					Free(device_instance_id);
+					device_instance_id = SearchDeviceInstanceIdFromShortKey(short_key);
+				}
+
+				if (IsEmptyStr(device_instance_id) == false)
+				{
+					char device_key[MAX_SIZE];
+					char *service_name;
+
+					Format(device_key, sizeof(device_key), "SYSTEM\\CurrentControlSet\\Enum\\%s",
+						device_instance_id);
+
+					service_name = MsRegReadStr(REG_LOCAL_MACHINE, device_key, "Service");
+					if (IsEmptyStr(service_name) == false)
+					{
+						char service_key[MAX_SIZE];
+						char *sys;
+
+						Format(service_key, sizeof(service_key),
+							"SYSTEM\\CurrentControlSet\\services\\%s",
+							service_name);
+
+						sys = MsRegReadStr(REG_LOCAL_MACHINE, service_key, "ImagePath");
+
+						if (IsEmptyStr(sys) == false)
+						{
+							char sysname[MAX_PATH];
+
+							GetFileNameFromFilePath(sysname, sizeof(sysname), sys);
+
+							Trim(sysname);
+
+							if (EndWith(sysname, ".sys"))
+							{
+								// デバイス発見
+								RPC_ENUM_ETH_VLAN_ITEM *e = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM));
+
+								StrCpy(e->DeviceName, sizeof(e->DeviceName), a->Title);
+								StrCpy(e->Guid, sizeof(e->Guid), a->Guid);
+								StrCpy(e->DeviceInstanceId, sizeof(e->DeviceInstanceId), device_instance_id);
+								StrCpy(e->DriverName, sizeof(e->DriverName), sysname);
+
+								// デバイスの VLAN サポート状態を取得
+								GetVLanSupportStatus(e);
+
+								// 有効化状態を取得
+								GetVLanEnableStatus(e);
+
+								Insert(o, e);
+							}
+						}
+
+						Free(sys);
+					}
+
+					Free(service_name);
+				}
+
+				Free(device_instance_id);
+			}
+		}
+	}
+
+	t->NumItem = LIST_NUM(o);
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM) * i);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		RPC_ENUM_ETH_VLAN_ITEM *e = LIST_DATA(o, i);
+
+		Copy(&t->Items[i], e, sizeof(RPC_ENUM_ETH_VLAN_ITEM));
+
+		Free(e);
+	}
+
+	ReleaseList(o);
+
+	Unlock(eth_list_lock);
+
+	return true;
+}
+
+// GUID からネットワーククラスデータのレジストリキーを取得
+bool GetClassRegKeyWin32(char *key, UINT key_size, char *short_key, UINT short_key_size, char *guid)
+{
+	TOKEN_LIST *t;
+	bool ret = false;
+	UINT i;
+	// 引数チェック
+	if (key == NULL || short_key == NULL || guid == NULL)
+	{
+		return false;
+	}
+
+	t = MsRegEnumKey(REG_LOCAL_MACHINE,
+		"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}");
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char keyname[MAX_SIZE];
+		char *value;
+
+		Format(keyname, sizeof(keyname),
+			"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
+			t->Token[i]);
+
+		value = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "NetCfgInstanceId");
+
+		if (StrCmpi(value, guid) == 0)
+		{
+			ret = true;
+
+			StrCpy(key, key_size, keyname);
+
+			Format(short_key, short_key_size, "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
+				t->Token[i]);
+		}
+
+		Free(value);
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// 複数のパケットを書き込む
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)
+{
+	UINT i, total_size;
+	UCHAR *buf;
+	UINT write_pointer;
+	// 引数チェック
+	if (e == NULL || num == 0 || datas == NULL || sizes == NULL)
+	{
+		return;
+	}
+
+	if (IsWin32BridgeWithSep() == false)
+	{
+		// 古い WinPcap にはバグがあり、2 個以上の CPU が搭載されている場合に
+		// ロックが不十分なところがあってカーネル内でクラッシュすることが
+		// 頻繁にあった。そこで 1 個目の CPU でしか動作しないように工夫していた
+		if (e->LastSetSingleCpu == 0 || (e->LastSetSingleCpu + 10000) <= Tick64())
+		{
+			e->LastSetSingleCpu = Tick64();
+			MsSetThreadSingleCpu();
+		}
+	}
+
+	// 必要なデータサイズの計算
+	total_size = 0;
+	for (i = 0;i < num;i++)
+	{
+		void *data = datas[i];
+		UINT size = sizes[i];
+		if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE)
+		{
+			total_size += size + sizeof(struct dump_bpf_hdr);
+		}
+	}
+
+	// 適当やな
+	buf = MallocFast(total_size * 100 / 75 + 1600);
+
+	write_pointer = 0;
+	// キューに入れる
+	for (i = 0;i < num;i++)
+	{
+		void *data = datas[i];
+		UINT size = sizes[i];
+		if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE)
+		{
+			struct dump_bpf_hdr *h;
+
+			h = (struct dump_bpf_hdr *)(buf + write_pointer);
+			Zero(h, sizeof(struct dump_bpf_hdr));
+			h->caplen = h->len = size;
+			write_pointer += sizeof(struct dump_bpf_hdr);
+			Copy(buf + write_pointer, data, size);
+			write_pointer += size;
+
+			PROBE_DATA2("EthPutPackets", data, size);
+		}
+		// 元のメモリは解放する
+		Free(data);
+	}
+
+	// 送信
+	if (total_size != 0)
+	{
+		wp->PacketSendPackets(e->Adapter, buf, total_size, true);
+	}
+
+	Free(buf);
+}
+
+// パケットを書き込む
+void EthPutPacket(ETH *e, void *data, UINT size)
+{
+	// 引数チェック
+	if (e == NULL || data == NULL || size == 0)
+	{
+		return;
+	}
+	if (size < 14 || size > MAX_PACKET_SIZE)
+	{
+		Free(data);
+		return;
+	}
+
+	if (IsWin32BridgeWithSep() == false)
+	{
+		if (e->LastSetSingleCpu == 0 || (e->LastSetSingleCpu + 10000) <= Tick64())
+		{
+			e->LastSetSingleCpu = Tick64();
+			MsSetThreadSingleCpu();
+		}
+	}
+
+	wp->PacketInitPacket(e->PutPacket, data, size);
+	wp->PacketSendPacket(e->Adapter, e->PutPacket, false);
+
+	Free(data);
+}
+
+// 次のパケットを読み込む
+UINT EthGetPacket(ETH *e, void **data)
+{
+	BLOCK *b;
+	bool flag = false;
+	// 引数チェック
+	if (e == NULL || data == NULL)
+	{
+		return INFINITE;
+	}
+
+RETRY:
+	// まずキューにパケットがたまっているかどうか見てみる
+	b = GetNext(e->PacketQueue);
+	if (b != NULL)
+	{
+		UINT size;
+		size = b->Size;
+		*data = b->Buf;
+		Free(b);
+
+		if (e->PacketQueue->num_item == 0)
+		{
+			e->Empty = true;
+		}
+
+		return size;
+	}
+
+	if (e->Empty)
+	{
+		e->Empty = false;
+		return 0;
+	}
+
+	if (flag == false)
+	{
+		// 次のパケットの取得を試みる
+		PROBE_STR("EthGetPacket: PacketInitPacket");
+		wp->PacketInitPacket(e->Packet, e->Buffer, e->BufferSize);
+		PROBE_STR("EthGetPacket: PacketReceivePacket");
+		if (wp->PacketReceivePacket(e->Adapter, e->Packet, false) == false)
+		{
+			// 失敗
+			return INFINITE;
+		}
+		else
+		{
+			UCHAR *buf;
+			UINT total;
+			UINT offset;
+
+			buf = (UCHAR *)e->Packet->Buffer;
+			total = e->Packet->ulBytesReceived;
+			offset = 0;
+
+			while (offset < total)
+			{
+				struct bpf_hdr *header;
+				UINT packet_size;
+				UCHAR *packet_data;
+
+				header = (struct bpf_hdr *)(buf + offset);
+				packet_size = header->bh_caplen;
+				offset += header->bh_hdrlen;
+				packet_data = buf + offset;
+				offset = Packet_WORDALIGN(offset + packet_size);
+
+				if (packet_size >= 14)
+				{
+					UCHAR *tmp;
+					BLOCK *b;
+
+					PROBE_DATA2("EthGetPacket: NewBlock", packet_data, packet_size);
+					
+					tmp = MallocFast(packet_size);
+
+					Copy(tmp, packet_data, packet_size);
+					b = NewBlock(tmp, packet_size, 0);
+					InsertQueue(e->PacketQueue, b);
+				}
+			}
+
+			flag = true;
+			goto RETRY;
+		}
+	}
+
+	// これ以上パケットを取得できない
+	return 0;
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *EthGetCancel(ETH *e)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return NULL;
+	}
+
+	AddRef(e->Cancel->ref);
+
+	return e->Cancel;
+}
+
+// アダプタを閉じる
+void CloseEth(ETH *e)
+{
+	BLOCK *b;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	ReleaseCancel(e->Cancel);
+
+	wp->PacketCloseAdapter(e->Adapter);
+	wp->PacketFreePacket(e->Packet);
+	wp->PacketFreePacket(e->PutPacket);
+
+	while (b = GetNext(e->PacketQueue))
+	{
+		FreeBlock(b);
+	}
+	ReleaseQueue(e->PacketQueue);
+
+	Free(e->Name);
+	Free(e->Title);
+	Free(e->Buffer);
+
+	Free(e);
+}
+
+// アダプタを開く
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)
+{
+	ETH *ret;
+	void *p;
+
+	p = MsDisableWow64FileSystemRedirection();
+
+	ret = OpenEthInternal(name, local, tapmode, tapaddr);
+
+	MsRestoreWow64FileSystemRedirection(p);
+
+	return ret;
+}
+ETH *OpenEthInternal(char *name, bool local, bool tapmode, char *tapaddr)
+{
+	WP_ADAPTER *t, tt;
+	ETH *e;
+	ADAPTER *a;
+	HANDLE h;
+	CANCEL *c;
+	// 引数チェック
+	if (name == NULL || IsEthSupported() == false)
+	{
+		return NULL;
+	}
+
+	if (tapmode)
+	{
+		// Win32 では tap はサポートしていない
+		return NULL;
+	}
+
+	Lock(eth_list_lock);
+
+	InitEthAdaptersList();
+
+	Zero(&tt, sizeof(tt));
+	StrCpy(tt.Title, sizeof(tt.Title), name);
+
+	t = Search(eth_list, &tt);
+	if (t == NULL)
+	{
+		Unlock(eth_list_lock);
+		return NULL;
+	}
+
+	a = wp->PacketOpenAdapter(t->Name);
+	if (a == NULL)
+	{
+		Unlock(eth_list_lock);
+		return NULL;
+	}
+
+	if (IsWin32BridgeWithSep() == false)
+	{
+		MsSetThreadSingleCpu();
+	}
+
+	e = ZeroMalloc(sizeof(ETH));
+	e->Name = CopyStr(t->Name);
+	e->Title = CopyStr(t->Title);
+
+	e->Adapter = a;
+
+	wp->PacketSetBuff(e->Adapter, BRIDGE_WIN32_ETH_BUFFER);
+	wp->PacketSetHwFilter(e->Adapter, local ? 0x0080 : 0x0020);
+	wp->PacketSetMode(e->Adapter, PACKET_MODE_CAPT);
+	wp->PacketSetReadTimeout(e->Adapter, -1);
+	wp->PacketSetNumWrites(e->Adapter, 1);
+
+	if (wp->PacketSetLoopbackBehavior != NULL)
+	{
+		if (GET_KETA(GetOsType(), 100) >= 3)
+		{
+			// Windows XP, Server 2003 以降
+			bool ret = wp->PacketSetLoopbackBehavior(e->Adapter, 1);
+			Debug("*** PacketSetLoopbackBehavior: %u\n", ret);
+
+			e->LoopbackBlock = ret;
+		}
+	}
+
+	h = wp->PacketGetReadEvent(e->Adapter);
+
+	c = NewCancelSpecial(h);
+	e->Cancel = c;
+
+	e->Buffer = Malloc(BRIDGE_WIN32_ETH_BUFFER);
+	e->BufferSize = BRIDGE_WIN32_ETH_BUFFER;
+	e->Packet = wp->PacketAllocatePacket();
+
+	e->PutPacket = wp->PacketAllocatePacket();
+
+	e->PacketQueue = NewQueue();
+
+	Unlock(eth_list_lock);
+
+	return e;
+}
+
+// Ethernet アダプタリストの取得
+TOKEN_LIST *GetEthList()
+{
+	TOKEN_LIST *ret;
+	UINT i;
+
+	if (IsEthSupported() == false)
+	{
+		return NULL;
+	}
+
+	Lock(eth_list_lock);
+
+	InitEthAdaptersList();
+
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->NumTokens = LIST_NUM(eth_list);
+	ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+	for (i = 0;i < ret->NumTokens;i++)
+	{
+		WP_ADAPTER *a = LIST_DATA(eth_list, i);
+		ret->Token[i] = CopyStr(a->Title);
+	}
+
+	Unlock(eth_list_lock);
+
+	return ret;
+}
+
+// WP_ADAPTER の名前比較
+int CompareWpAdapter(void *p1, void *p2)
+{
+	int i;
+	WP_ADAPTER *a1, *a2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	a1 = *(WP_ADAPTER **)p1;
+	a2 = *(WP_ADAPTER **)p2;
+	if (a1 == NULL || a2 == NULL)
+	{
+		return 0;
+	}
+	i = StrCmpi(a1->Title, a2->Title);
+	return i;
+}
+
+// Ethernet アダプタリストの取得
+LIST *GetEthAdapterList()
+{
+	void *p;
+	LIST *o;
+
+	p = MsDisableWow64FileSystemRedirection();
+
+	o = GetEthAdapterListInternal();
+
+	MsRestoreWow64FileSystemRedirection(p);
+
+	return o;
+}
+LIST *GetEthAdapterListInternal()
+{
+	LIST *o;
+	LIST *ret;
+	UINT size;
+	char *buf;
+	UINT i, j;
+	char *qos_tag = " (Microsoft's Packet Scheduler)";
+
+	o = NewListFast(CompareWpAdapter);
+
+	size = 200000;
+	buf = ZeroMalloc(size);
+
+	if (wp->PacketGetAdapterNames(buf, &size) == false)
+	{
+		Free(buf);
+		return o;
+	}
+
+	i = 0;
+
+	if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))
+	{
+		// Windows NT
+		if (size >= 2 && buf[0] != 0 && buf[1] != 0)
+		{
+			goto ANSI_STR;
+		}
+
+		while (true)
+		{
+			wchar_t tmp[MAX_SIZE];
+			WP_ADAPTER *a;
+			UniStrCpy(tmp, sizeof(tmp), L"");
+
+			if (*((wchar_t *)(&buf[i])) == 0)
+			{
+				i += sizeof(wchar_t);
+				break;
+			}
+
+			for (;*((wchar_t *)(&buf[i])) != 0;i += sizeof(wchar_t))
+			{
+				wchar_t str[2];
+				str[0] = *((wchar_t *)(&buf[i]));
+				str[1] = 0;
+				UniStrCat(tmp, sizeof(tmp), str);
+			}
+
+			i += sizeof(wchar_t);
+
+			a = ZeroMalloc(sizeof(WP_ADAPTER));
+			UniToStr(a->Name, sizeof(a->Name), tmp);
+
+			Add(o, a);
+		}
+	}
+	else
+	{
+		// Windows 9x
+ANSI_STR:
+		while (true)
+		{
+			char tmp[MAX_SIZE];
+			WP_ADAPTER *a;
+			StrCpy(tmp, sizeof(tmp), "");
+
+			if (*((char *)(&buf[i])) == 0)
+			{
+				i += sizeof(char);
+				break;
+			}
+
+			for (;*((char *)(&buf[i])) != 0;i += sizeof(char))
+			{
+				char str[2];
+				str[0] = *((char *)(&buf[i]));
+				str[1] = 0;
+				StrCat(tmp, sizeof(tmp), str);
+			}
+
+			i += sizeof(char);
+
+			a = ZeroMalloc(sizeof(WP_ADAPTER));
+			StrCpy(a->Name, sizeof(a->Name), tmp);
+
+			Add(o, a);
+		}
+	}
+
+	for (j = 0;j < LIST_NUM(o);j++)
+	{
+		WP_ADAPTER *a = LIST_DATA(o, j);
+
+		StrCpy(a->Title, sizeof(a->Title), &buf[i]);
+		i += StrSize(a->Title);
+
+		// Win9x で デバイスの説明が"Unknown"ならば1文字読み飛ばす。
+		if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+		{
+			if (StrCmp(a->Title, "Unknown") == 0)
+			{
+				if (buf[i] == 0)
+				{
+					i+=sizeof(char);
+				}
+			}
+		}
+
+		TrimCrlf(a->Title);
+		Trim(a->Title);
+		TrimCrlf(a->Title);
+		Trim(a->Title);
+
+		if (EndWith(a->Title, qos_tag))
+		{
+			a->Title[StrLen(a->Title) - StrLen(qos_tag)] = 0;
+			TrimCrlf(a->Title);
+			Trim(a->Title);
+			TrimCrlf(a->Title);
+			Trim(a->Title);
+		}
+	}
+
+	for (j = 0;j < LIST_NUM(o);j++)
+	{
+		// GUID の抽出
+		WP_ADAPTER *a = LIST_DATA(o, j);
+
+		StrCpy(a->Guid, sizeof(a->Guid), a->Name);
+		ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\SEP_", "");
+		ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\SEE_", "");
+		ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\NPF_", "");
+		ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\PCD_", "");
+	}
+
+	// ソート
+	Sort(o);
+
+	ret = NewListFast(CompareWpAdapter);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		WP_ADAPTER *a = LIST_DATA(o, i);
+		ADAPTER *ad;
+		bool ok = false;
+
+		if (SearchStrEx(a->Title, "ppp", 0, false) != INFINITE ||
+			SearchStrEx(a->Title, "wan", 0, false) != INFINITE ||
+			SearchStrEx(a->Title, "dialup", 0, false) != INFINITE ||
+			SearchStrEx(a->Title, "pptp", 0, false) != INFINITE ||
+			SearchStrEx(a->Title, "telepho", 0, false) != INFINITE ||
+			SearchStrEx(a->Title, "modem", 0, false) != INFINITE ||
+			SearchStrEx(a->Title, "ras", 0, false) != INFINITE)
+		{
+			Free(a);
+			continue;
+		}
+
+		ad = wp->PacketOpenAdapter(a->Name);
+		if (ad != NULL)
+		{
+			NetType type;
+			if (wp->PacketGetNetType(ad, &type))
+			{
+				if (type.LinkType == 0)
+				{
+					char tmp[MAX_SIZE];
+					UINT k;
+					// Ethernet のみ
+					StrCpy(tmp, sizeof(tmp), a->Title);
+
+					for (k = 0;;k++)
+					{
+						if (k == 0)
+						{
+							StrCpy(tmp, sizeof(tmp), a->Title);
+						}
+						else
+						{
+							Format(tmp, sizeof(tmp), "%s (%u)", a->Title, k + 1);
+						}
+
+						ok = true;
+						for (j = 0;j < LIST_NUM(ret);j++)
+						{
+							WP_ADAPTER *aa = LIST_DATA(ret, j);
+							if (StrCmpi(aa->Title, tmp) == 0)
+							{
+								ok = false;
+							}
+						}
+
+						if (ok)
+						{
+							break;
+						}
+					}
+
+					StrCpy(a->Title, sizeof(a->Title), tmp);
+					Add(ret, a);
+				}
+				else
+				{
+					Debug("%s: type = %u\n", a->Name, type.LinkType);
+				}
+			}
+			else
+			{
+				Debug("%s: PacketGetNetType() Failed.\n", a->Name);
+			}
+			wp->PacketCloseAdapter(ad);
+		}
+		else
+		{
+			Debug("%s: PacketOpenAdapter() Failed.\n", a->Name);
+		}
+
+		if (ok == false)
+		{
+			Free(a);
+		}
+	}
+
+	Free(buf);
+
+	Sort(ret);
+
+	ReleaseList(o);
+
+	return ret;
+}
+
+// Ethernet アダプタのリストの初期化
+void InitEthAdaptersList()
+{
+	if (eth_list != NULL)
+	{
+		FreeEthAdaptersList();
+		eth_list = NULL;
+	}
+	eth_list = GetEthAdapterList();
+}
+
+// Ethernet アダプタのリストの解放
+void FreeEthAdaptersList()
+{
+	UINT i;
+	if (eth_list == NULL)
+	{
+		return;
+	}
+	for (i = 0;i < LIST_NUM(eth_list);i++)
+	{
+		WP_ADAPTER *a = LIST_DATA(eth_list, i);
+		Free(a);
+	}
+	ReleaseList(eth_list);
+	eth_list = NULL;
+}
+
+// Ethernet がサポートされているかどうか
+bool IsEthSupported()
+{
+	if (wp == NULL)
+	{
+		return false;
+	}
+
+	return wp->Inited;
+}
+
+// 現在の OS で PCD ドライバがサポートされているか
+bool IsPcdSupported()
+{
+	UINT type;
+	OS_INFO *info = GetOsInfo();
+
+	type = info->OsType;
+
+	if (OS_IS_WINDOWS_NT(type) == false)
+	{
+		// Windows NT 以外はダメ
+		return false;
+	}
+
+	if (GET_KETA(type, 100) >= 2)
+	{
+		// Windows 2000 以降は良い
+		return true;
+	}
+
+	// Windows NT 4.0, Longhorn はダメ
+
+	return false;
+}
+
+// PCD ドライバのビルド番号を書き込む
+void SavePcdDriverBuild(UINT build)
+{
+	MsRegWriteInt(REG_LOCAL_MACHINE, BRIDGE_WIN32_PCD_REGKEY, BRIDGE_WIN32_PCD_BUILDVALUE,
+		build);
+}
+
+// PCD ドライバのビルド番号を読み込む
+UINT LoadPcdDriverBuild()
+{
+	return MsRegReadInt(REG_LOCAL_MACHINE, BRIDGE_WIN32_PCD_REGKEY, BRIDGE_WIN32_PCD_BUILDVALUE);
+}
+
+// PCD ドライバのインストールを試みる
+HINSTANCE InstallPcdDriver()
+{
+	HINSTANCE ret;
+	void *p = MsDisableWow64FileSystemRedirection();
+
+	ret = InstallPcdDriverInternal();
+
+	MsRestoreWow64FileSystemRedirection(p);
+
+	return ret;
+}
+HINSTANCE InstallPcdDriverInternal()
+{
+	char tmp[MAX_PATH];
+	bool install_driver = true;
+	HINSTANCE h;
+	char *dll_filename;
+
+	// まず sep.sys が system32\drivers ディレクトリにインストールされているかどうか確認する
+	Format(tmp, sizeof(tmp), "%s\\drivers\\sep.sys", MsGetSystem32Dir());
+
+	if (IsFileExists(tmp))
+	{
+		// ドライバが存在している場合は、次にレジストリからビルド番号を取得する
+		if (LoadPcdDriverBuild() >= CEDAR_BUILD)
+		{
+			// すでに最新版のドライバがインストールされている
+			install_driver = false;
+		}
+	}
+
+	if (install_driver)
+	{
+		char *src_filename = BRIDGE_WIN32_PCD_SYS;
+		// ドライバのインストールをする必要がある場合
+		// まず Admin かどうかチェックする
+		if (MsIsAdmin() == false)
+		{
+			// Admin で無い場合はドライバのインストールは不能である
+			return NULL;
+		}
+
+		if (MsIsX64())
+		{
+			src_filename = BRIDGE_WIN32_PCD_SYS_X64;
+		}
+
+		if (MsIsIA64())
+		{
+			src_filename = BRIDGE_WIN32_PCD_SYS_IA64;
+		}
+
+		// sep.sys をコピーする
+		if (FileCopy(src_filename, tmp) == false)
+		{
+			return NULL;
+		}
+
+		// ビルド番号を書き込む
+		SavePcdDriverBuild(CEDAR_BUILD);
+	}
+
+	dll_filename = BRIDGE_WIN32_PCD_DLL;
+
+	if (Is64())
+	{
+		if (MsIsX64())
+		{
+			dll_filename = BRIDGE_WIN32_PCD_DLL_X64;
+		}
+		else if (MsIsIA64())
+		{
+			dll_filename = BRIDGE_WIN32_PCD_DLL_IA64;
+		}
+	}
+
+	// sep.dll を読み込んで初期化してみる
+	h = MsLoadLibrary(dll_filename);
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	return h;
+}
+
+// Ethernet の初期化
+void InitEth()
+{
+	HINSTANCE h;
+	if (wp != NULL)
+	{
+		// 初期化済み
+		return;
+	}
+
+	eth_list_lock = NewLock();
+
+	wp = ZeroMalloc(sizeof(WP));
+
+	is_sep_mode = false;
+
+	if (IsPcdSupported())
+	{
+		// PCD がサポートされている OS である
+		h = InstallPcdDriver();
+		if (h != NULL)
+		{
+			// PCD を使って初期化を試みる
+			if (InitWpWithLoadLibrary(wp, h) == false)
+			{
+				Debug("InitEth: SEP Failed.\n");
+				FreeLibrary(h);
+			}
+			else
+			{
+				Debug("InitEth: SEP Loaded.\n");
+				is_sep_mode = true;
+			}
+		}
+	}
+
+	if (wp->Inited == false)
+	{
+		// WinPcap の Packet.dll を使って初期化を試みる
+		h = LoadLibrary(BRIDGE_WIN32_PACKET_DLL);
+		if (h != NULL)
+		{
+			if (InitWpWithLoadLibrary(wp, h) == false)
+			{
+				Debug("InitEth: Packet.dll Failed.\n");
+				FreeLibrary(h);
+			}
+			else
+			{
+				Debug("InitEth: Packet.dll Loaded.\n");
+			}
+		}
+	}
+}
+
+// sep.sys を用いてブリッジを行っているかどうかを取得
+bool IsWin32BridgeWithSep()
+{
+	return is_sep_mode;
+}
+
+// WP 構造体を DLL で初期化する
+bool InitWpWithLoadLibrary(WP *wp, HINSTANCE h)
+{
+	TOKEN_LIST *o;
+	// 引数チェック
+	if (wp == NULL || h == NULL)
+	{
+		return false;
+	}
+	wp->Inited = true;
+	wp->hPacketDll = h;
+
+	LOAD_DLL_ADDR(PacketGetVersion);
+	LOAD_DLL_ADDR(PacketGetDriverVersion);
+	LOAD_DLL_ADDR(PacketSetMinToCopy);
+	LOAD_DLL_ADDR(PacketSetNumWrites);
+	LOAD_DLL_ADDR(PacketSetMode);
+	LOAD_DLL_ADDR(PacketSetReadTimeout);
+	LOAD_DLL_ADDR(PacketSetBpf);
+	LOAD_DLL_ADDR(PacketSetSnapLen);
+	LOAD_DLL_ADDR(PacketGetStats);
+	LOAD_DLL_ADDR(PacketGetStatsEx);
+	LOAD_DLL_ADDR(PacketSetBuff);
+	LOAD_DLL_ADDR(PacketGetNetType);
+	LOAD_DLL_ADDR(PacketOpenAdapter);
+	LOAD_DLL_ADDR(PacketSendPacket);
+	LOAD_DLL_ADDR(PacketSendPackets);
+	LOAD_DLL_ADDR(PacketAllocatePacket);
+	LOAD_DLL_ADDR(PacketInitPacket);
+	LOAD_DLL_ADDR(PacketFreePacket);
+	LOAD_DLL_ADDR(PacketReceivePacket);
+	LOAD_DLL_ADDR(PacketSetHwFilter);
+	LOAD_DLL_ADDR(PacketGetAdapterNames);
+	LOAD_DLL_ADDR(PacketGetNetInfoEx);
+	LOAD_DLL_ADDR(PacketRequest);
+	LOAD_DLL_ADDR(PacketGetReadEvent);
+	LOAD_DLL_ADDR(PacketSetDumpName);
+	LOAD_DLL_ADDR(PacketSetDumpLimits);
+	LOAD_DLL_ADDR(PacketSetDumpLimits);
+	LOAD_DLL_ADDR(PacketIsDumpEnded);
+	LOAD_DLL_ADDR(PacketStopDriver);
+	LOAD_DLL_ADDR(PacketCloseAdapter);
+	LOAD_DLL_ADDR(PacketSetLoopbackBehavior);
+
+	if (wp->PacketSetMinToCopy == NULL ||
+		wp->PacketSetNumWrites == NULL ||
+		wp->PacketSetMode == NULL ||
+		wp->PacketSetReadTimeout == NULL ||
+		wp->PacketSetBuff == NULL ||
+		wp->PacketGetNetType == NULL ||
+		wp->PacketOpenAdapter == NULL ||
+		wp->PacketSendPacket == NULL ||
+		wp->PacketSendPackets == NULL ||
+		wp->PacketAllocatePacket == NULL ||
+		wp->PacketInitPacket == NULL ||
+		wp->PacketFreePacket == NULL ||
+		wp->PacketReceivePacket == NULL ||
+		wp->PacketSetHwFilter == NULL ||
+		wp->PacketGetAdapterNames == NULL ||
+		wp->PacketGetNetInfoEx == NULL ||
+		wp->PacketCloseAdapter == NULL)
+	{
+RELEASE:
+		wp->Inited = false;
+		wp->hPacketDll = NULL;
+
+		return false;
+	}
+
+	o = GetEthList();
+	if (o == NULL || o->NumTokens == 0)
+	{
+		FreeToken(o);
+		goto RELEASE;
+	}
+
+	FreeToken(o);
+
+	return true;
+}
+
+// Ethernet の解放
+void FreeEth()
+{
+	if (wp == NULL)
+	{
+		// 初期化されていない
+		return;
+	}
+
+	// アダプタリストの解放
+	FreeEthAdaptersList();
+
+	if (wp->Inited)
+	{
+		// DLL 解放
+		FreeLibrary(wp->hPacketDll);
+	}
+
+	Free(wp);
+	wp = NULL;
+
+	DeleteLock(eth_list_lock);
+	eth_list_lock = NULL;
+}
+
+// Ethernet デバイスに対応するネットワーク接続名を取得する
+void GetEthNetworkConnectionName(wchar_t *dst, UINT size, char *device_name)
+{
+	WP_ADAPTER *t, tt;
+	char *tmp = NULL, guid[MAX_SIZE];
+	wchar_t *ncname = NULL;
+
+	UniStrCpy(dst, size, L"");
+
+	// 引数チェック
+	if (device_name == NULL || IsEthSupported() == false || 
+		IsNt() == false || MsIsWin2000OrGreater() == false)
+	{
+		return;
+	}
+
+	Lock(eth_list_lock);
+
+	InitEthAdaptersList();
+
+	Zero(&tt, sizeof(tt));
+	StrCpy(tt.Title, sizeof(tt.Title), device_name);
+
+	t = Search(eth_list, &tt);
+	if (t == NULL)
+	{
+		Unlock(eth_list_lock);
+		return;
+	}
+
+	tmp = Malloc(sizeof(t->Name));
+	StrCpy(tmp, sizeof(t->Name), t->Name);
+	Unlock(eth_list_lock);
+
+	ReplaceStr(guid, sizeof(guid), tmp, "\\Device\\SEP_", "");
+	Free(tmp);
+
+	ReplaceStr(guid, sizeof(guid), guid, "\\Device\\SEE_", "");
+	ReplaceStr(guid, sizeof(guid), guid, "\\Device\\NPF_", "");
+	ReplaceStr(guid, sizeof(guid), guid, "\\Device\\PCD_", "");
+
+	if(guid == NULL)
+	{
+		return;
+	}
+
+	ncname = MsGetNetworkConnectionName(guid);
+	if(ncname != NULL)
+	{
+		UniStrCpy(dst, size, ncname);
+	}
+	Free(ncname);
+}
+
+#endif	// BRIDGE_C
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeWin32.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeWin32.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/BridgeWin32.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,210 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// BridgeWin32.h
+// BridgeWin32.c のヘッダ
+
+#ifndef	BRIDGEWIN32_H
+#define	BRIDGEWIN32_H
+
+#define	BRIDGE_WIN32_PACKET_DLL		"Packet.dll"
+#define	BRIDGE_WIN32_PCD_DLL		"|sep.dll"
+#define	BRIDGE_WIN32_PCD_SYS		"|sep.sys"
+#define	BRIDGE_WIN32_PCD_DLL_X64	"|sep_x64.dll"
+#define	BRIDGE_WIN32_PCD_SYS_X64	"|sep_x64.sys"
+#define	BRIDGE_WIN32_PCD_DLL_IA64	"|sep_ia64.dll"
+#define	BRIDGE_WIN32_PCD_SYS_IA64	"|sep_ia64.sys"
+#define	BRIDGE_WIN32_PCD_REGKEY		"SYSTEM\\CurrentControlSet\\services\\SEP"
+#define	BRIDGE_WIN32_PCD_BUILDVALUE	"CurrentInstalledBuild"
+
+#define	BRIDGE_WIN32_ETH_BUFFER		(1048576)
+
+
+typedef void *HANDLE;
+
+#ifdef	BRIDGE_C
+
+// 内部向け関数ヘッダ (BridgeWin32.c 用)
+typedef struct WP
+{
+	bool Inited;
+	HINSTANCE hPacketDll;
+	PCHAR (*PacketGetVersion)();
+	PCHAR (*PacketGetDriverVersion)();
+	BOOLEAN (*PacketSetMinToCopy)(LPADAPTER AdapterObject,int nbytes);
+	BOOLEAN (*PacketSetNumWrites)(LPADAPTER AdapterObject,int nwrites);
+	BOOLEAN (*PacketSetMode)(LPADAPTER AdapterObject,int mode);
+	BOOLEAN (*PacketSetReadTimeout)(LPADAPTER AdapterObject,int timeout);
+	BOOLEAN (*PacketSetBpf)(LPADAPTER AdapterObject,struct bpf_program *fp);
+	INT (*PacketSetSnapLen)(LPADAPTER AdapterObject,int snaplen);
+	BOOLEAN (*PacketGetStats)(LPADAPTER AdapterObject,struct bpf_stat *s);
+	BOOLEAN (*PacketGetStatsEx)(LPADAPTER AdapterObject,struct bpf_stat *s);
+	BOOLEAN (*PacketSetBuff)(LPADAPTER AdapterObject,int dim);
+	BOOLEAN (*PacketGetNetType)(LPADAPTER AdapterObject,NetType *type);
+	LPADAPTER (*PacketOpenAdapter)(PCHAR AdapterName);
+	BOOLEAN (*PacketSendPacket)(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync);
+	INT (*PacketSendPackets)(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync);
+	LPPACKET (*PacketAllocatePacket)(void);
+	VOID (*PacketInitPacket)(LPPACKET lpPacket,PVOID  Buffer,UINT  Length);
+	VOID (*PacketFreePacket)(LPPACKET lpPacket);
+	BOOLEAN (*PacketReceivePacket)(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync);
+	BOOLEAN (*PacketSetHwFilter)(LPADAPTER AdapterObject,ULONG Filter);
+	BOOLEAN (*PacketGetAdapterNames)(PTSTR pStr,PULONG  BufferSize);
+	BOOLEAN (*PacketGetNetInfoEx)(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries);
+	BOOLEAN (*PacketRequest)(LPADAPTER  AdapterObject,BOOLEAN Set,PPACKET_OID_DATA  OidData);
+	HANDLE (*PacketGetReadEvent)(LPADAPTER AdapterObject);
+	BOOLEAN (*PacketSetDumpName)(LPADAPTER AdapterObject, void *name, int len);
+	BOOLEAN (*PacketSetDumpLimits)(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks);
+	BOOLEAN (*PacketIsDumpEnded)(LPADAPTER AdapterObject, BOOLEAN sync);
+	BOOL (*PacketStopDriver)();
+	VOID (*PacketCloseAdapter)(LPADAPTER lpAdapter);
+	BOOLEAN (*PacketSetLoopbackBehavior)(LPADAPTER AdapterObject, UINT LoopbackBehavior);
+} WP;
+
+// アダプタリスト
+typedef struct WP_ADAPTER
+{
+	char Name[MAX_SIZE];
+	char Title[MAX_SIZE];
+	char Guid[MAX_SIZE];
+} WP_ADAPTER;
+
+// 内部向け関数プロトタイプ
+void InitEthAdaptersList();
+void FreeEthAdaptersList();
+int CompareWpAdapter(void *p1, void *p2);
+LIST *GetEthAdapterList();
+LIST *GetEthAdapterListInternal();
+bool InitWpWithLoadLibrary(WP *wp, HINSTANCE h);
+bool IsPcdSupported();
+HINSTANCE InstallPcdDriver();
+HINSTANCE InstallPcdDriverInternal();
+UINT LoadPcdDriverBuild();
+void SavePcdDriverBuild(UINT build);
+
+#endif	// BRIDGE_C
+
+typedef struct _ADAPTER ADAPTER;
+typedef struct _PACKET PACKET;
+
+// ETH 構造体
+struct ETH
+{
+	char *Name;					// アダプタ名
+	char *Title;				// アダプタタイトル
+	ADAPTER *Adapter;			// アダプタ
+	CANCEL *Cancel;				// キャンセルオブジェクト
+	UCHAR *Buffer;				// バッファ
+	UINT BufferSize;			// バッファサイズ
+	PACKET *Packet;				// パケット
+	PACKET *PutPacket;			// 書き込みパケット
+	QUEUE *PacketQueue;			// パケットキュー
+	UINT64 LastSetSingleCpu;	// 最後にシングル CPU に設定した日時
+	bool LoopbackBlock;			// ループバックパケットを遮断するかどうか
+	bool Empty;					// 空である
+};
+
+// 関数プロトタイプ
+void InitEth();
+void FreeEth();
+bool IsEthSupported();
+TOKEN_LIST *GetEthList();
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthInternal(char *name, bool local, bool tapmode, char *tapaddr);
+void CloseEth(ETH *e);
+CANCEL *EthGetCancel(ETH *e);
+UINT EthGetPacket(ETH *e, void **data);
+void EthPutPacket(ETH *e, void *data, UINT size);
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes);
+void GetEthNetworkConnectionName(wchar_t *dst, UINT size, char *device_name);
+bool IsWin32BridgeWithSep();
+UINT EthGetMtu(ETH *e);
+bool EthSetMtu(ETH *e, UINT mtu);
+bool EthIsChangeMtuSupported(ETH *e);
+
+bool EnumEthVLanWin32(RPC_ENUM_ETH_VLAN *t);
+bool GetClassRegKeyWin32(char *key, UINT key_size, char *short_key, UINT short_key_size, char *guid);
+int CmpRpcEnumEthVLan(void *p1, void *p2);
+void GetVLanSupportStatus(RPC_ENUM_ETH_VLAN_ITEM *e);
+void GetVLanEnableStatus(RPC_ENUM_ETH_VLAN_ITEM *e);
+bool SetVLanEnableStatus(char *title, bool enable);
+RPC_ENUM_ETH_VLAN_ITEM *FindEthVLanItem(RPC_ENUM_ETH_VLAN *t, char *name);
+char *SearchDeviceInstanceIdFromShortKey(char *short_key);
+
+#endif	// BRIDGEWIN32_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CM.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CM.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CM.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,12153 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// CM.c
+// Win32 用 SoftEther UT-VPN クライアント接続マネージャ
+
+
+#ifdef	WIN32
+
+#define	CM_C
+#define	SM_C
+#define	MICROSOFT_C
+
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <Iphlpapi.h>
+#include <tlhelp32.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <setupapi.h>
+#include <regstr.h>
+#include <process.h>
+#include <psapi.h>
+#include <wtsapi32.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "../PenCore/resource.h"
+
+// IE のレジストリ文字列からプロキシサーバーの設定を取得する
+bool CmGetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	bool ret = false;
+	// 引数チェック
+	if (name == NULL || port == NULL || str == NULL || server_type == NULL)
+	{
+		return false;
+	}
+
+	t = ParseToken(str, ";");
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *s = t->Token[i];
+		UINT i;
+
+		Trim(s);
+
+		i = SearchStrEx(s, "=", 0, false);
+		if (i != INFINITE)
+		{
+			char tmp[MAX_PATH];
+
+			StrCpy(name, name_size, s);
+			name[i] = 0;
+
+			if (StrCmpi(name, server_type) == 0)
+			{
+				char *host;
+				StrCpy(tmp, sizeof(tmp), s + i + 1);
+
+				if (ParseHostPort(tmp, &host, port, 0))
+				{
+					StrCpy(name, name_size, host);
+					Free(host);
+
+					if (*port != 0)
+					{
+						ret = true;
+					}
+					break;
+				}
+			}
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+
+// 接続設定にプロキシ設定の内容を反映する
+void CmProxyDlgSet(HWND hWnd, CLIENT_OPTION *o, CM_INTERNET_SETTING *setting)
+{
+	// 引数チェック
+	if(hWnd == NULL || setting == NULL)
+	{
+		return;
+	}
+
+	// チェックをつける
+	Check(hWnd, R_DIRECT_TCP,	setting->ProxyType == PROXY_DIRECT);
+	Check(hWnd, R_HTTPS,		setting->ProxyType == PROXY_HTTP);
+	Check(hWnd, R_SOCKS,		setting->ProxyType == PROXY_SOCKS);
+
+	// Proxy 設定
+	if(setting->ProxyType != PROXY_DIRECT)
+	{
+		StrCpy(o->ProxyName, sizeof(setting->ProxyHostName), setting->ProxyHostName);
+		o->ProxyPort = setting->ProxyPort;
+	}
+}
+
+// IE のプロキシ設定を取得する
+void CmGetSystemInternetSetting(CM_INTERNET_SETTING *setting)
+{
+	bool use_proxy;
+	// 引数チェック
+	if (setting == NULL)
+	{
+		return;
+	}
+
+	Zero(setting, sizeof(CM_INTERNET_SETTING));
+
+	use_proxy = MsRegReadInt(REG_CURRENT_USER,
+		"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+		"ProxyEnable");
+
+	if (use_proxy)
+	{
+		char *str = MsRegReadStr(REG_CURRENT_USER,
+			"Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+			"ProxyServer");
+		if (str != NULL)
+		{
+			char name[MAX_HOST_NAME_LEN + 1];
+			UINT port;
+
+			if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+				&port, str, "https"))
+			{
+				setting->ProxyType = PROXY_HTTP;
+				StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+				setting->ProxyPort = port;
+			}
+			else if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+				&port, str, "http"))
+			{
+				setting->ProxyType = PROXY_HTTP;
+				StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+				setting->ProxyPort = port;
+			}
+			else if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+				&port, str, "socks"))
+			{
+				setting->ProxyType = PROXY_SOCKS;
+				StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+				setting->ProxyPort = port;
+			}
+			else
+			{
+				if (SearchStrEx(str, "=", 0, false) == INFINITE)
+				{
+					char *host;
+					UINT port;
+					if (ParseHostPort(str, &host, &port, 0))
+					{
+						if (port != 0)
+						{
+							setting->ProxyType = PROXY_HTTP;
+							StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), host);
+							setting->ProxyPort = port;
+						}
+						Free(host);
+					}
+				}
+			}
+
+			Free(str);
+		}
+	}
+}
+
+// 経由するプロキシ設定で、IE の設定を使用する
+void CmProxyDlgUseForIE(HWND hWnd, CLIENT_OPTION *o)
+{
+	CM_INTERNET_SETTING s;
+
+	// 引数チェック
+	if(hWnd == NULL)
+	{
+		return;
+	}
+
+	Zero(&s, sizeof(s));
+	CmGetSystemInternetSetting(&s);
+	
+	CmProxyDlgSet(hWnd, o, &s);
+}
+
+// スマートカード認証画面のビットマップ ID を決定する
+UINT CmGetSecureBitmapId(char *dest_hostname)
+{
+	// 引数チェック
+	if (dest_hostname == NULL)
+	{
+		return 0;
+	}
+
+	return 0;
+}
+
+// UAC のウインドウをアクティブにする
+void CmSetUacWindowActive()
+{
+	HWND hWnd;
+
+	if (MsIsVista() == false)
+	{
+		return;
+	}
+	
+	hWnd = FindWindowA("$$$Secure UAP Dummy Window Class For Interim Dialog", NULL);
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SwitchToThisWindow(hWnd, true);
+}
+
+// UAC ヘルパースレッド
+void CmUacHelperThread(THREAD *thread, void *param)
+{
+	CM_UAC_HELPER *c = (CM_UAC_HELPER *)param;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	while (c->Halt == false)
+	{
+		CmSetUacWindowActive();
+
+		Wait(c->HaltEvent, 200);
+	}
+}
+
+// UAC ヘルパーの開始
+void *CmStartUacHelper()
+{
+	CM_UAC_HELPER *c = ZeroMalloc(sizeof(CM_UAC_HELPER));
+
+	c->HaltEvent = NewEvent();
+	c->Thread = NewThread(CmUacHelperThread, c);
+
+	return (void *)c;
+}
+
+// UAC ヘルパーの終了
+void CmStopUacHelper(void *p)
+{
+	CM_UAC_HELPER *c = (CM_UAC_HELPER *)p;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->Halt = true;
+	Set(c->HaltEvent);
+	WaitThread(c->Thread, INFINITE);
+	ReleaseEvent(c->HaltEvent);
+	ReleaseThread(c->Thread);
+
+	Free(c);
+}
+
+// 簡易接続マネージャのコマンド呼び出し
+void CmEasyDlgOnCommand(HWND hWnd, CM_EASY_DLG *d, WPARAM wParam, LPARAM lParam)
+{
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	switch (wParam)
+	{
+	case B_MODE:
+		Command(hWnd, CMD_CM_SETTING);
+		return;
+
+	case B_STATUS:
+		Command(hWnd, CMD_STATUS);
+		return;
+
+	case IDCANCEL:
+		Close(hWnd);
+		return;
+	}
+
+	if (wParam == CMD_CONNECT)
+	{
+		cm->ConnectStartedFlag = false;
+	}
+
+	CmMainWindowOnCommandEx(hWnd, wParam, lParam, true);
+
+	if (wParam == CMD_CONNECT && cm->ConnectStartedFlag)
+	{
+		// 接続を開始することに成功したらウインドウを閉じる
+		Close(hWnd);
+	}
+}
+
+// 簡易接続マネージャのキーボード押下
+void CmEasyDlgOnKey(HWND hWnd, CM_EASY_DLG *d, bool ctrl, bool alt, UINT key)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 単一キー
+	switch (key)
+	{
+	case VK_RETURN:
+		Command(hWnd, IDOK);
+		break;
+	case VK_DELETE:
+		// 削除
+		if (IsFocus(hWnd, L_ACCOUNT))
+		{
+			// アカウントリストに関する操作
+			Command(hWnd, CMD_DELETE);
+		}
+		else
+		{
+			// 仮想 LAN カードリストに関する操作
+			Command(hWnd, CMD_DELETE_VLAN);
+		}
+		break;
+	case VK_F2:
+		// 名前変更
+		Command(hWnd, CMD_RENAME);
+		break;
+	case VK_F5:
+		// 状態更新
+		Command(hWnd, CMD_REFRESH);
+		break;
+	}
+
+	if (alt)
+	{
+		switch (key)
+		{
+		case 'Q':
+			// 閉じる
+			Command(hWnd, CMD_QUIT);
+			break;
+		}
+	}
+
+	if (ctrl)
+	{
+		switch (key)
+		{
+		case 'G':
+			// スマートカードマネージャ
+			Command(hWnd, CMD_SECURE_MANAGER);
+			break;
+		case 'S':
+			// 状態の表示
+			Command(hWnd, CMD_STATUS);
+			break;
+		case 'I':
+			// すべての接続を切断
+			Command(hWnd, CMD_DISCONNECT_ALL);
+			break;
+		case 'D':
+			// 切断
+			Command(hWnd, CMD_DISCONNECT);
+			break;
+		case 'N':
+			// 接続設定の新規作成
+			Command(hWnd, CMD_NEW);
+			break;
+		case 'C':
+			// コピーの作成
+			Command(hWnd, CMD_CLONE);
+			break;
+		case 'T':
+			// スタートアップ接続に設定
+			Command(hWnd, CMD_STARTUP);
+			break;
+		case 'A':
+			// すべて選択
+			Command(hWnd, CMD_SELECT_ALL);
+			break;
+		case 'L':
+			// 新規仮想 LAN カードの作成
+			Command(hWnd, CMD_NEW_VLAN);
+			break;
+		case 'P':
+			// パスワードの設定
+			Command(hWnd, CMD_PASSWORD);
+			break;
+		case 'O':
+			// オプション設定
+			Command(hWnd, CMD_TRAFFIC);
+			break;
+		case 'R':
+			// 証明書管理
+			Command(hWnd, CMD_TRUST);
+			break;
+		case 'Q':
+			// スループット
+			Command(hWnd, CMD_TRAFFIC);
+			break;
+		}
+	}
+}
+
+// 簡易接続マネージャのリストビューに対する操作
+void CmEasyDlgOnNotify(HWND hWnd, CM_EASY_DLG *d, NMHDR *n)
+{
+	NMLVDISPINFOW *disp_info;
+	NMLVKEYDOWN *key;
+
+	// 引数チェック
+	if (hWnd == NULL || n == NULL)
+	{
+		return;
+	}
+
+	switch (n->idFrom)
+	{
+	case L_ACCOUNT:
+		switch (n->code)
+		{
+		case LVN_ITEMCHANGED:
+			CmEasyDlgUpdate(hWnd, d);
+			break;
+		case NM_DBLCLK:
+			// ダブルクリック
+			Command(hWnd, CMD_EASY_DBLCLICK);
+			break;
+		case NM_RCLICK:
+			// 右クリック
+			CmAccountListRightClick(hWnd);
+			break;
+		case LVN_ENDLABELEDITW:
+			// 名前の変更
+			disp_info = (NMLVDISPINFOW *)n;
+			if (disp_info->item.pszText != NULL)
+			{
+				wchar_t *new_name = disp_info->item.pszText;
+				wchar_t *old_name = LvGetStr(hWnd, L_ACCOUNT, disp_info->item.iItem, 0);
+
+				if (old_name != NULL)
+				{
+					if (UniStrCmp(new_name, old_name) != 0 && UniIsEmptyStr(new_name) == false)
+					{
+						RPC_RENAME_ACCOUNT a;
+						Zero(&a, sizeof(a));
+						UniStrCpy(a.OldName, sizeof(a.OldName), old_name);
+						UniStrCpy(a.NewName, sizeof(a.NewName), new_name);
+						if (CALL(hWnd, CcRenameAccount(cm->Client, &a)))
+						{
+							LvSetItem(hWnd, L_ACCOUNT, disp_info->item.iItem, 0, new_name);
+						}
+					}
+
+					Free(old_name);
+				}
+			}
+			break;
+		case LVN_KEYDOWN:
+			// キー押下
+			key = (NMLVKEYDOWN *)n;
+			if (key != NULL)
+			{
+				bool ctrl, alt;
+				UINT code = key->wVKey;
+				ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+				alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+				CmEasyDlgOnKey(hWnd, d, ctrl, alt, code);
+			}
+			break;
+		}
+		break;
+	}
+}
+
+// 簡易接続マネージャに対して更新通知を送信する
+void CmRefreshEasy()
+{
+	if (cm->hEasyWnd == NULL)
+	{
+		return;
+	}
+
+	SendMessage(cm->hEasyWnd, WM_CM_EASY_REFRESH, 0, 0);
+}
+
+// 簡易接続マネージャ初期化
+void CmEasyDlgInit(HWND hWnd, CM_EASY_DLG *d)
+{
+	HFONT hFontForList;
+	HFONT hFontButton;
+	HFONT hFontTitle;
+	HFONT hFontInfo;
+	HFONT hFontOther;
+	UINT i, num, num2, j;
+	bool b = false;
+	char *font_name = NULL;
+	bool font_bold = true;
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_VPN);
+
+	// ウインドウハンドル登録
+	cm->hEasyWnd = hWnd;
+
+	// 中央に表示
+	Center(hWnd);
+
+	// アカウントリストの更新
+	CmInitAccountListEx(hWnd, true);
+
+	// リストのフォント設定
+	if (cm->VistaStyle)
+	{
+		if (_GETLANG() == 0)
+		{
+			font_name = "Meiryo";
+			font_bold = false;
+		}
+		else if (_GETLANG() == 2)
+		{
+			font_name = "Microsoft YaHei";
+			font_bold = false;
+		}
+	}
+
+	hFontForList = GetFont(font_name, 14, font_bold, false, false, false);
+	hFontButton = GetFont(font_name, 13, font_bold, false, false, false);
+	hFontTitle = GetFont(font_name, 14, font_bold, false, false, false);
+	hFontInfo = GetFont(font_name, 11, font_bold, false, false, false);
+	hFontOther = GetDialogDefaultFont();
+
+	if (cm->VistaStyle)
+	{
+		hFontOther = GetMeiryoFont();
+	}
+
+	SetFont(hWnd, L_ACCOUNT, hFontForList);
+	SetFont(hWnd, IDOK, hFontButton);
+	SetFont(hWnd, S_TITLE, hFontTitle);
+	SetFont(hWnd, S_INFO, hFontInfo);
+	SetFont(hWnd, B_MODE, hFontOther);
+	SetFont(hWnd, IDCANCEL, hFontOther);
+
+	CmEasyDlgRefresh(hWnd, d);
+
+	num = LvNum(hWnd, L_ACCOUNT);
+	num2 = 0;
+	j = 0;
+	for (i = 0;i < num;i++)
+	{
+		wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+		if (str != NULL)
+		{
+			if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+			{
+				num2++;
+				j = i;
+			}
+			Free(str);
+		}
+	}
+
+	if (num2 == 1)
+	{
+		LvSelect(hWnd, L_ACCOUNT, j);
+		b = true;
+	}
+
+	if (b == false)
+	{
+		if (UniIsEmptyStr(cm->EasyLastSelectedAccountName) == false)
+		{
+			i = LvSearchStr(hWnd, L_ACCOUNT, 0, cm->EasyLastSelectedAccountName);
+			if (i != INFINITE)
+			{
+				LvSelect(hWnd, L_ACCOUNT, i);
+				b = true;
+			}
+		}
+	}
+
+	if (b == false)
+	{
+		if (LvNum(hWnd, L_ACCOUNT) != 0)
+		{
+			LvSelect(hWnd, L_ACCOUNT, 0);
+		}
+	}
+
+	Focus(hWnd, L_ACCOUNT);
+
+	CmEasyDlgUpdate(hWnd, d);
+}
+
+// 簡易接続マネージャコントロール更新
+void CmEasyDlgUpdate(HWND hWnd, CM_EASY_DLG *d)
+{
+	bool ok = true;
+	bool show_status = false;
+	wchar_t *button_str = _UU("CM_EASY_CONNECT_BUTTON_1");
+	wchar_t *info_str = _UU("CM_EASY_INFO_1");
+	wchar_t *title_str = _UU("CM_EASY_TITLE");
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSingleSelected(hWnd, L_ACCOUNT) == false)
+	{
+		ok = false;
+	}
+
+	if (ok)
+	{
+		UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+		wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+		info_str = _UU("CM_EASY_INFO_2");
+
+		if (str != NULL)
+		{
+			if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+			{
+				button_str = _UU("CM_EASY_CONNECT_BUTTON_2");
+				show_status = true;
+				info_str = _UU("CM_EASY_INFO_3");
+
+				if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0)
+				{
+					title_str = _UU("CM_EASY_CONNECTED");
+				}
+				else
+				{
+					title_str = _UU("CM_EASY_CONNECTING");
+				}
+			}
+			Free(str);
+		}
+	}
+
+	SetShow(hWnd, B_STATUS, show_status);
+
+	SetText(hWnd, IDOK, button_str);
+	SetText(hWnd, S_INFO, info_str);
+	SetText(hWnd, S_TITLE, title_str);
+
+	SetShow(hWnd, IDOK, ok);
+}
+
+// 簡易接続マネージャ内容更新
+void CmEasyDlgRefresh(HWND hWnd, CM_EASY_DLG *d)
+{
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	// アカウントリスト更新
+	CmRefreshAccountListEx(hWnd, true);
+
+	CmEasyDlgUpdate(hWnd, d);
+}
+
+// 簡易接続マネージャのダイアログプロシージャ
+UINT CmEasyDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CM_EASY_DLG *d = (CM_EASY_DLG *)param;
+	NMHDR *n;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmEasyDlgInit(hWnd, d);
+		SetTimer(hWnd, 1, 10, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			SetForegroundWindow(hWnd);
+			SetActiveWindow(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CM_EASY_REFRESH:
+		CmEasyDlgRefresh(hWnd, d);
+		break;
+
+	case WM_COMMAND:
+		CmEasyDlgOnCommand(hWnd, d, wParam, lParam);
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		CmEasyDlgOnNotify(hWnd, d, n);
+		break;
+
+	case WM_CLOSE:
+		i = LvGetSelected(hWnd, L_ACCOUNT);
+		if (i != INFINITE)
+		{
+			wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+			if (s != NULL)
+			{
+				UniStrCpy(cm->EasyLastSelectedAccountName, sizeof(cm->EasyLastSelectedAccountName),
+					s);
+				Free(s);
+			}
+		}
+		else
+		{
+			Zero(cm->EasyLastSelectedAccountName, sizeof(cm->EasyLastSelectedAccountName));
+		}
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 簡易接続マネージャのウインドウを表示する (遅延タイマで呼び出される)
+void CmMainWindowOnShowEasy(HWND hWnd)
+{
+	CM_EASY_DLG d;
+
+	Zero(&d, sizeof(d));
+
+	if (cm->CmSetting.EasyMode == false)
+	{
+		// 簡易モードではない
+		return;
+	}
+
+	if (cm->hEasyWnd != NULL)
+	{
+		// すでに表示されている
+		SetForegroundWindow(cm->hEasyWnd);
+		SetActiveWindow(cm->hEasyWnd);
+		return;
+	}
+
+	Dialog(NULL, D_CM_EASY, CmEasyDlg, &d);
+
+	cm->hEasyWnd = NULL;
+}
+
+// 簡易接続マネージャのウインドウを表示する
+void CmShowEasy()
+{
+	SetTimer(cm->hMainWnd, 4, 2, NULL);
+}
+
+// 簡易接続マネージャのウインドウを閉じる
+void CmCloseEasy()
+{
+	if (cm->hEasyWnd == NULL)
+	{
+		return;
+	}
+
+	SendMessage(cm->hEasyWnd, WM_CLOSE, 0, 0);
+}
+
+// トレイアイコンのクリック等のメッセージ処理
+void CmMainWindowOnTrayClicked(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+	bool easymode = cm->CmSetting.EasyMode;
+
+	switch (wParam)
+	{
+	case 1:
+		switch (lParam)
+		{
+		case WM_LBUTTONDOWN:
+		case WM_RBUTTONDOWN:
+			// クリック
+			if (easymode == false)
+			{
+				if (IsEnable(hWnd, 0))
+				{
+					CmShowTrayMenu(hWnd);
+				}
+				else
+				{
+					CmShowOrHideWindow(hWnd);
+				}
+			}
+			else
+			{
+				if (cm->hEasyWnd == NULL || IsEnable(cm->hEasyWnd, 0))
+				{
+					CmShowTrayMenu(hWnd);
+				}
+				else
+				{
+					//CmShowOrHideWindow(hWnd);
+				}
+			}
+			break;
+		case WM_LBUTTONDBLCLK:
+		case WM_RBUTTONDBLCLK:
+			// ダブルクリック
+			if (easymode == false)
+			{
+				if (IsEnable(hWnd, 0))
+				{
+					CmShowOrHideWindow(hWnd);
+				}
+			}
+			else
+			{
+				if (cm->hEasyWnd == NULL)
+				{
+					CmShowEasy();
+				}
+				else
+				{
+					SetForegroundWindow(cm->hEasyWnd);
+					SetActiveWindow(cm->hEasyWnd);
+				}
+			}
+			break;
+		}
+		break;
+	}
+}
+
+// 動作モードの設定の適用
+void CmApplyCmSetting()
+{
+	CM_SETTING a;
+	bool changed = false;
+
+	if (cm->CmSettingSupported == false)
+	{
+		return;
+	}
+
+	// 現在の vpnclient の設定を取得する
+	Zero(&a, sizeof(a));
+	CcGetCmSetting(cm->Client, &a);
+
+	// 以前の CM_SETTING と比較して変化点があるか調べる
+	if (cm->CmSetting.EasyMode != a.EasyMode)
+	{
+		changed = true;
+	}
+	if (cm->CmSetting.LockMode != a.LockMode)
+	{
+		changed = true;
+	}
+
+	Copy(&cm->CmSetting, &a, sizeof(CM_SETTING));
+
+	if (changed == false)
+	{
+		return;
+	}
+
+	if (cm->StartupFinished)
+	{
+		if (IsShow(cm->hMainWnd, 0) && cm->CmSetting.EasyMode)
+		{
+			// メインウインドウが表示されていれば閉じる
+			Hide(cm->hMainWnd, 0);
+		}
+		else
+		{
+			if (cm->CmSetting.EasyMode == false && IsShow(cm->hMainWnd, 0) == false)
+			{
+				// 通常モードに復帰した際は、メインウインドウを復元する
+				if (IsZero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement)) == false)
+				{
+					cm->FakeWindowPlacement.flags = cm->FakeWindowPlacement.flags & ~SW_MINIMIZE;
+					SetWindowPlacement(cm->hMainWnd, &cm->FakeWindowPlacement);
+					Zero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement));
+					Hide(cm->hMainWnd, 0);
+				}
+				CmShowOrHideWindow(cm->hMainWnd);
+			}
+		}
+
+		Command(cm->hMainWnd, CMD_REFRESH);
+	}
+
+	if (cm->CmSetting.EasyMode)
+	{
+		if (cm->StartupFinished == false && cm->StartupMode)
+		{
+			// /startup の場合は表示しない
+		}
+		else
+		{
+			CmShowEasy();
+		}
+	}
+	else
+	{
+		CmCloseEasy();
+	}
+}
+
+// 動作モード変更ダイアログ初期化
+void CmSettingDlgInit(HWND hWnd, CM_SETTING_DLG *d)
+{
+	CM_SETTING a;
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	// 現在の vpnclient の設定を取得する
+	Zero(&a, sizeof(a));
+	CcGetCmSetting(cm->Client, &a);
+
+	Check(hWnd, R_EASY, a.EasyMode);
+	Check(hWnd, R_NORMAL, a.EasyMode == false);
+
+	if (a.EasyMode == false)
+	{
+		Focus(hWnd, R_NORMAL);
+	}
+	else
+	{
+		Focus(hWnd, R_EASY);
+	}
+
+	Check(hWnd, R_LOCK, a.LockMode);
+
+	SetEnable(hWnd, R_EASY, cm->CmEasyModeSupported);
+
+	if (a.LockMode)
+	{
+		if (IsZero(a.HashedPassword, sizeof(a.HashedPassword)) == false)
+		{
+			// パスワードが設定されている
+			SetText(hWnd, S_PASSWORD1, _UU("CM_SETTING_PASSWORD"));
+			Hide(hWnd, S_PASSWORD3);
+			Hide(hWnd, E_PASSWORD2);
+
+			d->CheckPassword = true;
+			Copy(d->HashedPassword, a.HashedPassword, sizeof(d->HashedPassword));
+		}
+	}
+
+	CmSettingDlgUpdate(hWnd, d);
+}
+
+// 動作モード変更ダイアログ更新
+void CmSettingDlgUpdate(HWND hWnd, CM_SETTING_DLG *d)
+{
+	bool ok = true;
+	char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+	GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+
+	if (d->CheckPassword == false)
+	{
+		if (IsChecked(hWnd, R_LOCK))
+		{
+			if (StrCmp(tmp1, tmp2) != 0)
+			{
+				ok = false;
+			}
+		}
+	}
+	else
+	{
+		bool password_ok = false;
+		UCHAR hash[SHA1_SIZE];
+
+		Hash(hash, tmp1, StrLen(tmp1), true);
+		if (Cmp(hash, d->HashedPassword, sizeof(hash)) == 0)
+		{
+			password_ok = true;
+		}
+
+		if (password_ok == false)
+		{
+			Check(hWnd, R_LOCK, true);
+			Disable(hWnd, R_LOCK);
+		}
+		else
+		{
+			Enable(hWnd, R_LOCK);
+		}
+	}
+
+	SetEnable(hWnd, S_PASSWORD1, IsChecked(hWnd, R_LOCK));
+	SetEnable(hWnd, S_PASSWORD2, IsChecked(hWnd, R_LOCK));
+	SetEnable(hWnd, S_PASSWORD3, IsChecked(hWnd, R_LOCK));
+	SetEnable(hWnd, E_PASSWORD1, IsChecked(hWnd, R_LOCK));
+	SetEnable(hWnd, E_PASSWORD2, IsChecked(hWnd, R_LOCK));
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// 動作モード変更ダイアログ OK
+void CmSettingDlgOnOk(HWND hWnd, CM_SETTING_DLG *d)
+{
+	CM_SETTING a;
+	char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+	GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+
+	Zero(&a, sizeof(a));
+
+	a.EasyMode = IsChecked(hWnd, R_EASY);
+	a.LockMode = IsChecked(hWnd, R_LOCK);
+
+	if (a.LockMode)
+	{
+		if (d->CheckPassword && IsEnable(hWnd, R_LOCK) == false)
+		{
+			Copy(a.HashedPassword, d->HashedPassword, sizeof(a.HashedPassword));
+		}
+		else
+		{
+			if (StrLen(tmp1) >= 1)
+			{
+				Hash(a.HashedPassword, tmp1, StrLen(tmp1), true);
+			}
+		}
+	}
+
+	CcSetCmSetting(cm->Client, &a);
+
+	EndDialog(hWnd, true);
+}
+
+// 動作モード変更ダイアログ
+UINT CmSettingDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CM_SETTING_DLG *d = (CM_SETTING_DLG *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmSettingDlgInit(hWnd, d);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_EASY:
+		case R_NORMAL:
+		case R_LOCK:
+		case E_PASSWORD1:
+		case E_PASSWORD2:
+		case IDOK:
+		case IDCANCEL:
+			CmSettingDlgUpdate(hWnd, d);
+			break;
+		}
+		switch (wParam)
+		{
+		case IDOK:
+			CmSettingDlgOnOk(hWnd, d);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case R_LOCK:
+			if (IsChecked(hWnd, R_LOCK))
+			{
+				if (IsEmpty(hWnd, E_PASSWORD1))
+				{
+					Focus(hWnd, E_PASSWORD1);
+				}
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 動作モード変更
+bool CmSetting(HWND hWnd)
+{
+	CM_SETTING_DLG d;
+
+	Zero(&d, sizeof(d));
+
+	return Dialog(hWnd, D_CM_SETTING, CmSettingDlg, &d);
+}
+
+// UI Helper の起動の試行スレッド
+void CmTryToExecUiHelperThread(THREAD *thread, void *param)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	bool first_flag = true;
+
+	while (cm->TryExecUiHelperHalt == false && cm->WindowsShutdowning == false)
+	{
+		if (first_flag == false)
+		{
+			// 初回以外は少し待つ
+			Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL * 2);
+
+			if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+			{
+				break;
+			}
+		}
+		first_flag = false;
+
+		if (cm->TryExecUiHelperHalt == false && cm->WindowsShutdowning == false)
+		{
+			if (cm->TryExecUiHelperProcessHandle == NULL)
+			{
+				CmTryToExecUiHelper();
+			}
+		}
+
+		if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+		{
+			break;
+		}
+
+		if (cm->TryExecUiHelperProcessHandle == NULL)
+		{
+			Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL);
+		}
+		else
+		{
+			HANDLE handles[2];
+			handles[0] = cm->TryExecUiHelperProcessHandle;
+			handles[1] = (HANDLE)cm->TryExecUiHelperHaltEvent->pData;
+			WaitForMultipleObjects(2, handles, false, CM_TRY_EXEC_UI_HELPER_INTERVAL);
+
+			if (WaitForSingleObject(cm->TryExecUiHelperProcessHandle, 0) != WAIT_TIMEOUT)
+			{
+				CloseHandle(cm->TryExecUiHelperProcessHandle);
+				cm->TryExecUiHelperProcessHandle = NULL;
+				if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+				{
+					break;
+				}
+				Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL * 2);
+			}
+		}
+	}
+}
+
+// UI Helper 終了
+void CmFreeTryToExecUiHelper()
+{
+	cm->TryExecUiHelperHalt = true;
+	Set(cm->TryExecUiHelperHaltEvent);
+
+	WaitThread(cm->TryExecUiHelperThread, INFINITE);
+
+	ReleaseThread(cm->TryExecUiHelperThread);
+	cm->TryExecUiHelperThread = NULL;
+
+	ReleaseEvent(cm->TryExecUiHelperHaltEvent);
+	cm->TryExecUiHelperHaltEvent = NULL;
+
+	cm->TryExecUiHelperHalt = false;
+	cm->TryExecUiHelperProcessHandle = NULL;
+}
+
+// UI Helper 起動初期化
+void CmInitTryToExecUiHelper()
+{
+	cm->TryExecUiHelperProcessHandle = NULL;
+	cm->TryExecUiHelperHalt = false;
+	cm->TryExecUiHelperHaltEvent = NewEvent();
+	cm->TryExecUiHelperThread = NewThread(CmTryToExecUiHelperThread, NULL);
+}
+
+// UI Helper の起動
+void *CmExecUiHelperMain()
+{
+	HANDLE h;
+	wchar_t tmp[MAX_SIZE];
+
+	UniFormat(tmp, sizeof(tmp), L"%s\\%S", MsGetExeDirNameW(), CiGetVpnClientExeFileName());
+
+	// 起動
+	h = Win32RunExW(tmp, SVC_ARG_UIHELP_W, false);
+
+	return (void *)h;
+}
+
+// UI Helper の起動の試行
+void CmTryToExecUiHelper()
+{
+	HANDLE h;
+	// 既に起動していないかどうかチェックする
+	if (CnCheckAlreadyExists(false))
+	{
+		// 既に起動している
+		return;
+	}
+
+	h = (HANDLE)CmExecUiHelperMain();
+
+	if (h != NULL)
+	{
+		cm->TryExecUiHelperProcessHandle = h;
+	}
+}
+
+// ダイアログ初期化
+void CmTrafficResultDlgInit(HWND hWnd, TT_RESULT *res)
+{
+	LVB *ct;
+	wchar_t tmp[MAX_SIZE];
+	wchar_t tmp1[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || res == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_SWITCH);
+
+	SetFont(hWnd, L_STATUS, GetFont(_SS("DEFAULT_FONT_2"), 10, false, false, false, false));
+
+	LvInit(hWnd, L_STATUS);
+	LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_STATUS, 0, _UU("TTC_RES_COLUMN_1"), 100);
+	LvInsertColumn(hWnd, L_STATUS, 1, _UU("TTC_RES_COLUMN_2"), 100);
+	LvInsertColumn(hWnd, L_STATUS, 2, _UU("TTC_RES_COLUMN_3"), 100);
+
+	ct = LvInsertStart();
+
+	// 測定に使用した時間
+	GetSpanStrMilli(str, sizeof(str), res->Span);
+	StrToUni(tmp, sizeof(tmp), str);
+	LvInsertAdd(ct, ICO_DATETIME, NULL, 3, _UU("TTC_RES_SPAN"), tmp, L"");
+
+	// Ethernet フレーム用にデータ補正
+	LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_ETHER"), res->Raw ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+	// ダウンロード方向の通信データ量
+	ToStr3(str, sizeof(str), res->NumBytesDownload);
+	UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+	ToStrByte1000(str, sizeof(str), res->NumBytesDownload);
+	StrToUni(tmp2, sizeof(tmp2), str);
+	LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_DOWNLOAD"), tmp1, tmp2);
+
+	// アップロード方向の通信データ量
+	ToStr3(str, sizeof(str), res->NumBytesUpload);
+	UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+	ToStrByte1000(str, sizeof(str), res->NumBytesUpload);
+	StrToUni(tmp2, sizeof(tmp2), str);
+	LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_UPLOAD"), tmp1, tmp2);
+
+	// 合計通信データ量
+	ToStr3(str, sizeof(str), res->NumBytesTotal);
+	UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+	ToStrByte1000(str, sizeof(str), res->NumBytesTotal);
+	StrToUni(tmp2, sizeof(tmp2), str);
+	LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_TOTAL"), tmp1, tmp2);
+
+	// 中継機器入出力合計スループット算出
+	LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_DOUBLE"), (res->Double == false) ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+	// ダウンロード方向の平均スループット
+	ToStr3(str, sizeof(str), res->BpsDownload);
+	UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+	ToStrByte1000(str, sizeof(str), res->BpsDownload);
+	ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+	StrToUni(tmp2, sizeof(tmp2), str);
+	LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_DOWNLOAD"), tmp1, tmp2);
+
+	// アップロード方向の平均スループット
+	ToStr3(str, sizeof(str), res->BpsUpload);
+	UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+	ToStrByte1000(str, sizeof(str), res->BpsUpload);
+	ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+	StrToUni(tmp2, sizeof(tmp2), str);
+	LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_UPLOAD"), tmp1, tmp2);
+
+	// 合計平均スループット
+	ToStr3(str, sizeof(str), res->BpsTotal);
+	UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+	ToStrByte1000(str, sizeof(str), res->BpsTotal);
+	ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+	StrToUni(tmp2, sizeof(tmp2), str);
+	LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_TOTAL"), tmp1, tmp2);
+
+	LvInsertEnd(ct, hWnd, L_STATUS);
+
+	LvAutoSize(hWnd, L_STATUS);
+}
+
+// トラフィック測定結果の表示ダイアログプロシージャ
+UINT CmTrafficResultDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	TT_RESULT *r = (TT_RESULT *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmTrafficResultDlgInit(hWnd, r);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// トラフィック測定結果の表示
+void CmTrafficResult(HWND hWnd, TT_RESULT *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_CM_TRAFFIC_RESULT, CmTrafficResultDlg, r);
+}
+
+// クライアントの終了を待機するスレッド
+void CmTrafficRunDlgClientWaitThread(THREAD *t, void *param)
+{
+	CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+	TT_RESULT result;
+	UINT ret;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	Zero(&result, sizeof(result));
+	ret = FreeTtc(d->Ttc, &result);
+	d->Ttc = NULL;
+
+	d->RetCode = ret;
+	Copy(&d->Result, &result, sizeof(TT_RESULT));
+
+	PostMessage(d->hWnd, WM_APP + 66, 0, 0);
+}
+
+// 文字列の追記
+void CmTrafficRunDlgAddStr(HWND hWnd, wchar_t *str)
+{
+	wchar_t *tmp;
+	UINT tmp_size;
+
+	tmp_size = UniStrSize(str) + 32;
+	tmp = Malloc(tmp_size);
+	UniStrCpy(tmp, tmp_size, str);
+	if (UniEndWith(str, L"\n") == false)
+	{
+		UniStrCat(tmp, tmp_size, L"\n");
+	}
+
+	UniReplaceStrEx(tmp, tmp_size, tmp, L"\r\n", L"\n", false);
+	UniReplaceStrEx(tmp, tmp_size, tmp, L"\n", L"\r\n", false);
+
+	if (MsIsNt())
+	{
+		SendMsg(hWnd, E_EDIT, EM_SETSEL, 0x7fffffff, 0x7fffffff);
+		SendMsg(hWnd, E_EDIT, EM_REPLACESEL, false, (LPARAM)tmp);
+	}
+	else
+	{
+		char *s = CopyUniToStr(tmp);
+		UINT len;
+
+		len = GetWindowTextLength(DlgItem(hWnd, E_EDIT));
+		SendMsg(hWnd, E_EDIT, EM_SETSEL, 0x7fffffff, 0x7fffffff);
+		SendMsg(hWnd, E_EDIT, EM_SETSEL, len, len);
+		SendMsg(hWnd, E_EDIT, EM_REPLACESEL, false, (LPARAM)s);
+		Free(s);
+	}
+
+	Free(tmp);
+}
+
+// 文字列の表示
+void CmTrafficRunDlgPrintProc(void *param, wchar_t *str)
+{
+	CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+	HWND hWnd;
+	// 引数チェック
+	if (param == NULL || str == NULL)
+	{
+		return;
+	}
+
+	hWnd = d->hWnd;
+
+	PostMessage(hWnd, WM_APP + 64, 0, (LPARAM)UniCopyStr(str));
+}
+
+// 測定プログラムの停止用スレッド
+void CmTrafficRunDlgHaltThread(THREAD *t, void *param)
+{
+	CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	if (d->Setting->ServerMode)
+	{
+		// サーバーを停止
+		d->RetCode = FreeTts(d->Tts);
+
+		PostMessage(d->hWnd, WM_APP + 65, 0, 0);
+	}
+}
+
+// 測定プログラムを停止する
+void CmTrafficRunDlgHalt(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	if (d->Started == false)
+	{
+		return;
+	}
+
+	if (d->Setting->ServerMode)
+	{
+		if (d->HaltThread == NULL)
+		{
+			Disable(hWnd, IDCANCEL);
+			d->HaltThread = NewThread(CmTrafficRunDlgHaltThread, d);
+		}
+	}
+	else
+	{
+		if (d->ClientEndWaitThread != NULL)
+		{
+			StopTtc(d->Ttc);
+		}
+		else
+		{
+			EndDialog(hWnd, 0);
+		}
+	}
+}
+
+// トラフィック測定の動作を開始する
+void CmTrafficRunDlgStart(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	if (d->Setting->ServerMode)
+	{
+		// 測定サーバーを開始
+		d->Tts = NewTts(d->Setting->Port, d, CmTrafficRunDlgPrintProc);
+	}
+	else
+	{
+		// 測定クライアントを開始
+		d->Ttc = NewTtc(d->Setting->Host, d->Setting->Port,
+			d->Setting->NumTcp, d->Setting->Type, d->Setting->Span * 1000ULL,
+			d->Setting->Double, d->Setting->Raw, CmTrafficRunDlgPrintProc, d);
+
+		d->ClientEndWaitThread = NewThread(CmTrafficRunDlgClientWaitThread, d);
+	}
+
+	d->Started = true;
+}
+
+// トラフィック測定実行ダイアログ初期化
+void CmTrafficRunDlgInit(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return;
+	}
+
+	d->hWnd = hWnd;
+
+	SetIcon(hWnd, 0, ICO_SWITCH);
+	DlgFont(hWnd, S_INFO, 11, false);
+	SetFont(hWnd, E_EDIT, GetFont(_SS("DEFAULT_FONT_2"), 0, false, false,
+		false, false));
+
+	Focus(hWnd, IDCANCEL);
+}
+
+// トラフィック測定実行ダイアログプロシージャ
+UINT CmTrafficRunDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+	wchar_t *s;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmTrafficRunDlgInit(hWnd, d);
+
+		SetTimer(hWnd, 1, 10, NULL);
+		break;
+
+	case WM_APP + 64:
+		// 文字列追加
+		s = (wchar_t *)lParam;
+		if (s != NULL)
+		{
+			CmTrafficRunDlgAddStr(hWnd, s);
+			Free(s);
+		}
+		break;
+
+	case WM_APP + 65:
+		// 停止完了
+		if (d->HaltThread != NULL)
+		{
+			WaitThread(d->HaltThread, INFINITE);
+			ReleaseThread(d->HaltThread);
+			d->HaltThread = NULL;
+			EndDialog(hWnd, 0);
+		}
+		break;
+
+	case WM_APP + 66:
+		// 結果表示
+		if (d->RetCode == ERR_NO_ERROR)
+		{
+			CmTrafficResult(hWnd, &d->Result);
+		}
+
+		if (d->ClientEndWaitThread != NULL)
+		{
+			WaitThread(d->ClientEndWaitThread, INFINITE);
+			ReleaseThread(d->ClientEndWaitThread);
+			d->ClientEndWaitThread = NULL;
+		}
+
+		if (d->CloseDialogAfter)
+		{
+			EndDialog(hWnd, 0);
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			CmTrafficRunDlgStart(hWnd, d);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		d->CloseDialogAfter = true;
+		CmTrafficRunDlgHalt(hWnd, d);
+		return 1;
+	}
+
+	return 0;
+}
+
+// トラフィック測定を実行する
+void CmExecTraffic(HWND hWnd, CM_TRAFFIC *t)
+{
+	CM_TRAFFIC_DLG d;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Zero(&d, sizeof(d));
+	d.Setting = t;
+	d.ResultShowEvent = NewEvent();
+
+	MsSetThreadPriorityHigh();
+	Dialog(hWnd, D_CM_TRAFFIC_RUN, CmTrafficRunDlg, &d);
+	MsRestoreThreadPriority();
+
+	ReleaseEvent(d.ResultShowEvent);
+}
+
+// レジストリに設定を書き込む
+void CmTrafficSaveToReg(CM_TRAFFIC *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "ServerMode", t->ServerMode ? 1 : 0);
+	MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Double", t->Double ? 1 : 0);
+	MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Raw", t->Raw ? 1 : 0);
+	MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Port", t->Port);
+	MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "NumTcp", t->NumTcp);
+	MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Type", t->Type);
+	MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Span", t->Span);
+	MsRegWriteStr(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Host", t->Host);
+}
+
+// レジストリから設定を読み込む
+bool CmTrafficLoadFromReg(CM_TRAFFIC *t)
+{
+	char *s;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	Zero(t, sizeof(CM_TRAFFIC));
+
+	if (MsRegIsKey(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY) == false)
+	{
+		return false;
+	}
+
+	t->Double = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Double") == 0 ? false : true;
+	t->Raw = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Raw") == 0 ? false : true;
+	t->Port = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Port");
+	if (t->Port == 0)
+	{
+		t->Port = TRAFFIC_DEFAULT_PORT;
+	}
+
+	s = MsRegReadStr(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Host");
+
+	if (IsEmptyStr(s) == false)
+	{
+		Trim(s);
+		StrCpy(t->Host, sizeof(t->Host), s);
+	}
+
+	Free(s);
+
+	t->NumTcp = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "NumTcp");
+	t->NumTcp = MAKESURE(t->NumTcp, 1, TRAFFIC_NUMTCP_MAX);
+	t->Type = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Type");
+
+	if (t->Type != TRAFFIC_TYPE_DOWNLOAD && t->Type != TRAFFIC_TYPE_UPLOAD &&
+		t->Type != TRAFFIC_TYPE_FULL)
+	{
+		t->Type = TRAFFIC_TYPE_FULL;
+	}
+
+	t->Span = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Span");
+	if (t->Span == 0)
+	{
+		t->Span = TRAFFIC_SPAN_DEFAULT;
+	}
+
+	t->ServerMode = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "ServerMode") == 0 ? false : true;
+
+	return true;
+}
+
+// デフォルトの設定を取得する
+void CmTrafficGetDefaultSetting(CM_TRAFFIC *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(CM_TRAFFIC));
+
+	t->Double = false;
+	t->Raw = false;
+	t->Port = TRAFFIC_DEFAULT_PORT;
+	t->NumTcp = TRAFFIC_NUMTCP_DEFAULT;
+	t->Type = TRAFFIC_TYPE_FULL;
+	t->Span = TRAFFIC_SPAN_DEFAULT;
+	t->ServerMode = false;
+}
+
+// 通信スループット測定ツールダイアログ初期化
+void CmTrafficDlgInit(HWND hWnd)
+{
+	CM_TRAFFIC t;
+	LIST *c1, *c2;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	DlgFont(hWnd, S_8, 9, true);
+	DlgFont(hWnd, S_3, 9, true);
+
+	Zero(&t, sizeof(t));
+	if (CmTrafficLoadFromReg(&t) == false)
+	{
+		CmTrafficGetDefaultSetting(&t);
+	}
+
+	// 設定をダイアログに書き出す
+	Check(hWnd, R_SERVER, t.ServerMode);
+	Check(hWnd, R_CLIENT, t.ServerMode == false);
+
+	c1 = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "HostCandidate");
+	if (c1 != NULL)
+	{
+		UINT i;
+
+		CbReset(hWnd, C_HOST);
+
+		for (i = 0;i < LIST_NUM(c1);i++)
+		{
+			CANDIDATE *c = LIST_DATA(c1, i);
+
+			CbAddStr(hWnd, C_HOST, c->Str, 0);
+		}
+
+		FreeCandidateList(c1);
+	}
+
+	if (CbNum(hWnd, C_HOST) == 0)
+	{
+		CbAddStr(hWnd, C_HOST, L"speed.softether.com", 0);
+	}
+
+	if (IsEmptyStr(t.Host) == false)
+	{
+		SetTextA(hWnd, C_HOST, t.Host);
+	}
+
+	c2 = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "PortCandidate");
+	if (c2 != NULL)
+	{
+		UINT i;
+
+		if (t.Port != 0)
+		{
+			wchar_t tmp[32];
+
+			UniToStru(tmp, t.Port);
+
+			AddCandidate(c2, tmp, 0);
+		}
+
+		CbReset(hWnd, C_PORT);
+
+		for (i = 0;i < LIST_NUM(c2);i++)
+		{
+			CANDIDATE *c = LIST_DATA(c2, i);
+
+			CbAddStr(hWnd, C_PORT, c->Str, 0);
+		}
+
+		FreeCandidateList(c2);
+	}
+
+	CbReset(hWnd, C_NUM);
+
+	for (i = 1;i <= TRAFFIC_NUMTCP_MAX;i++)
+	{
+		wchar_t tmp[32];
+
+		UniToStru(tmp, i);
+
+		CbAddStr(hWnd, C_NUM, tmp, i);
+	}
+
+	CbSelect(hWnd, C_NUM, t.NumTcp);
+
+	Check(hWnd, R_DOWNLOAD, t.Type == TRAFFIC_TYPE_DOWNLOAD);
+	Check(hWnd, R_UPLOAD, t.Type == TRAFFIC_TYPE_UPLOAD);
+	Check(hWnd, R_FULL, t.Type == TRAFFIC_TYPE_FULL);
+
+	Check(hWnd, R_ETHERNET, t.Raw ? false : true);
+	Check(hWnd, R_DOUBLE, t.Double);
+
+	SetIntEx(hWnd, E_SPAN, t.Span);
+
+	CmTrafficDlgUpdate(hWnd);
+}
+
+// ダイアログの内容を構造体に入れる
+void CmTrafficDlgToStruct(HWND hWnd, CM_TRAFFIC *t)
+{
+	// 引数チェック
+	if (hWnd == NULL || t == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(CM_TRAFFIC));
+	t->ServerMode = IsChecked(hWnd, R_SERVER);
+	GetTxtA(hWnd, C_HOST, t->Host, sizeof(t->Host));
+	Trim(t->Host);
+
+	t->Port = GetInt(hWnd, C_PORT);
+	t->NumTcp = CbGetSelect(hWnd, C_NUM);
+	t->Span = GetInt(hWnd, E_SPAN);
+	t->Raw = IsChecked(hWnd, R_ETHERNET) ? false : true;
+	t->Double = IsChecked(hWnd, R_DOUBLE);
+
+	if (IsChecked(hWnd, R_DOWNLOAD))
+	{
+		t->Type = TRAFFIC_TYPE_DOWNLOAD;
+	}
+	else if (IsChecked(hWnd, R_UPLOAD))
+	{
+		t->Type = TRAFFIC_TYPE_UPLOAD;
+	}
+	else
+	{
+		t->Type = TRAFFIC_TYPE_FULL;
+	}
+}
+
+// 通信スループット測定ツールダイアログ更新
+bool CmTrafficDlgUpdate(HWND hWnd)
+{
+	CM_TRAFFIC t;
+	bool ok = true;
+	bool client_only;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	CmTrafficDlgToStruct(hWnd, &t);
+
+	client_only = t.ServerMode ? false : true;
+
+	SetEnable(hWnd, C_HOST, client_only);
+	SetEnable(hWnd, S_5, client_only);
+	SetEnable(hWnd, S_8, client_only);
+	SetEnable(hWnd, S_9, client_only);
+	SetEnable(hWnd, R_DOWNLOAD, client_only);
+	SetEnable(hWnd, R_UPLOAD, client_only);
+	SetEnable(hWnd, R_FULL, client_only);
+	SetEnable(hWnd, S_10, client_only);
+	SetEnable(hWnd, S_11, client_only);
+	SetEnable(hWnd, C_NUM, client_only);
+	SetEnable(hWnd, S_14, client_only);
+	SetEnable(hWnd, S_12, client_only);
+	SetEnable(hWnd, E_SPAN, client_only);
+	SetEnable(hWnd, S_13, client_only);
+	SetEnable(hWnd, R_ETHERNET, client_only);
+	SetEnable(hWnd, R_DOUBLE, client_only);
+
+	if (t.Port == 0 || t.Port >= 65536)
+	{
+		ok = false;
+	}
+
+	if (t.ServerMode == false)
+	{
+		if (IsEmptyStr(t.Host))
+		{
+			ok = false;
+		}
+
+		if (t.NumTcp == 0 || t.NumTcp >= 33)
+		{
+			ok = false;
+		}
+
+		if (t.Span == 0)
+		{
+			ok = false;
+		}
+
+		if (t.Type == TRAFFIC_TYPE_FULL && ((t.NumTcp % 2) != 0))
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+
+	return ok;
+}
+
+// 通信スループット測定ツールダイアログ OK ボタン
+void CmTrafficDlgOnOk(HWND hWnd)
+{
+	CM_TRAFFIC t;
+	LIST *c;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 基本データの取得
+	CmTrafficDlgToStruct(hWnd, &t);
+
+	// レジストリに保存
+	CmTrafficSaveToReg(&t);
+
+	// サーバー名候補の取得と保存
+	if (IsEmptyStr(t.Host) == false)
+	{
+		c = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "HostCandidate");
+		if (c != NULL)
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			StrToUni(tmp, sizeof(tmp), t.Host);
+			AddCandidate(c, tmp, 0);
+
+			WriteCandidateToReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, c, "HostCandidate");
+
+			FreeCandidateList(c);
+		}
+	}
+
+	if (t.Port != 0 && t.Port <= 65536)
+	{
+		// ポート番号候補の取得と保存
+		c = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "PortCandidate");
+		if (c != NULL)
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			UniToStru(tmp, t.Port);
+			AddCandidate(c, tmp, 0);
+
+			WriteCandidateToReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, c, "PortCandidate");
+
+			FreeCandidateList(c);
+		}
+	}
+
+	// 実行
+	CmExecTraffic(hWnd, &t);
+
+	// ダイアログを更新
+	CmTrafficDlgInit(hWnd);
+}
+
+// 通信スループット測定ツールダイアログプロシージャ
+UINT CmTrafficDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetIcon(hWnd, 0, ICO_SWITCH);
+		CmTrafficDlgInit(hWnd);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_SERVER:
+		case R_CLIENT:
+		case C_HOST:
+		case C_PORT:
+		case R_DOWNLOAD:
+		case R_UPLOAD:
+		case R_FULL:
+		case C_NUM:
+		case E_SPAN:
+		case R_ETHERNET:
+		case R_DOUBLE:
+			CmTrafficDlgUpdate(hWnd);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			CmTrafficDlgOnOk(hWnd);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// 通信スループット測定ツール
+void CmTraffic(HWND hWnd)
+{
+	Dialog(hWnd, D_CM_TRAFFIC, CmTrafficDlgProc, NULL);
+}
+
+// 古いスタートアップファイルがあれば削除する
+void CmDeleteOldStartupTrayFile()
+{
+	char tmp[MAX_SIZE];
+	char *tag = _SS("CM_JAPANESE_ONLY_OLD_STARTUP");
+	if (IsEmptyStr(tag))
+	{
+		return;
+	}
+
+	Format(tmp, sizeof(tmp), tag, MsGetCommonStartupDir());
+
+	FileDelete(tmp);
+}
+
+// PKCS ライセンス確認ダイアログ
+UINT CmPkcsEulaDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UINT id;
+	SECURE_DEVICE *dev;
+	char *name;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		id = (UINT)param;
+		dev = GetSecureDevice(id);
+		if (dev == NULL)
+		{
+			EndDialog(hWnd, 0);
+			return 0;
+		}
+
+		name = dev->ModuleName;
+
+		FormatText(hWnd, S_INFO_1, name);
+		FormatText(hWnd, S_INFO_2, name, name);
+		FormatText(hWnd, S_INFO_3, name);
+
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			EndDialog(hWnd, 1);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// PKCS の DLL の EULA に同意しているかどうかの確認画面
+bool CmCheckPkcsEula(HWND hWnd, UINT id)
+{
+	return (Dialog(hWnd, D_CM_PKCSEULA, CmPkcsEulaDlg, (void *)id) == 0) ? false : true;
+}
+
+// コントロール更新
+void CmSecurePinDlgUpdate(HWND hWnd)
+{
+	char *tmp1, *tmp2, *tmp3;
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	tmp1 = GetTextA(hWnd, E_PIN1);
+	tmp2 = GetTextA(hWnd, E_PIN2);
+	tmp3 = GetTextA(hWnd, E_PIN3);
+	if (IsEmptyStr(tmp1))
+	{
+		ok = false;
+	}
+	if (IsEmptyStr(tmp2))
+	{
+		ok = false;
+	}
+	if (IsEmptyStr(tmp3))
+	{
+		ok = false;
+	}
+	if (StrCmp(tmp2, tmp3) != 0)
+	{
+		ok = false;
+	}
+	Free(tmp1);
+	Free(tmp2);
+	Free(tmp3);
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// PIN コード変更ダイアログ
+UINT CmSecurePinDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UINT id = (UINT)param;
+	char *src, *dst;
+	SECURE *s;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmSecurePinDlgUpdate(hWnd);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_PIN1:
+		case E_PIN2:
+		case E_PIN3:
+			CmSecurePinDlgUpdate(hWnd);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			src = GetTextA(hWnd, E_PIN1);
+			dst = GetTextA(hWnd, E_PIN3);
+
+			Disable(hWnd, IDOK);
+			Disable(hWnd, IDCANCEL);
+
+			s = OpenSec(id);
+			if (s == NULL)
+			{
+				if (GetSecureDevice(id) != NULL)
+				{
+					MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+						GetSecureDevice(id)->DeviceName);
+				}
+				else
+				{
+					MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+						"Unknown");
+				}
+			}
+			else
+			{
+				if (OpenSecSession(s, 0) == false)
+				{
+					if (GetSecureDevice(id) != NULL)
+					{
+						MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+							GetSecureDevice(id)->DeviceName);
+					}
+					else
+					{
+						MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+							"Unknown");
+					}
+				}
+				else
+				{
+					if (LoginSec(s, src) == false)
+					{
+						MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_CURRENT_BAD"));
+						FocusEx(hWnd, E_PIN1);
+					}
+					else
+					{
+						if (ChangePin(s, src, dst) == false)
+						{
+							MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_CHANGE_FAILED"));
+							FocusEx(hWnd, E_PIN1);
+						}
+						else
+						{
+							// PIN コードのキャッシュの消去
+							cached_pin_code_expires = 0;
+							cached_pin_code[0] = 0;
+							MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_PIN_OK"));
+							EndDialog(hWnd, true);
+						}
+
+						LogoutSec(s);
+					}
+
+					CloseSecSession(s);
+				}
+				CloseSec(s);
+			}
+
+			Enable(hWnd, IDOK);
+			Enable(hWnd, IDCANCEL);
+
+			Free(src);
+			Free(dst);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// PIN コードの変更
+void CmSecurePin(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL || id == 0 || CheckSecureDeviceId(id) == false)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_CM_SECURE_PIN, CmSecurePinDlg, (void *)id);
+}
+
+// オブジェクト種類選択ダイアログ
+UINT CmSecureTypeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UINT type;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		type = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DefaultImportType");
+		Check(hWnd, R_DATA, type == SEC_DATA);
+		Check(hWnd, R_CERT, type == SEC_X);
+		Check(hWnd, R_KEY, type == SEC_K);
+		goto UPDATE_CONTROL;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			type = SEC_DATA;
+			if (IsChecked(hWnd, R_CERT))
+			{
+				type = SEC_X;
+			}
+			else if (IsChecked(hWnd, R_KEY))
+			{
+				type = SEC_K;
+			}
+
+			MsRegWriteInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DefaultImportType", type);
+
+			EndDialog(hWnd, type);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		case R_CERT:
+		case R_KEY:
+		case R_DATA:
+UPDATE_CONTROL:
+			SetEnable(hWnd, IDOK, IsChecked(hWnd, R_CERT) || 
+				IsChecked(hWnd, R_KEY) || 
+				IsChecked(hWnd, R_DATA));
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, INFINITE);
+		break;
+	}
+
+	return 0;
+}
+
+// オブジェクト種類選択
+UINT CmSecureType(HWND hWnd)
+{
+	return Dialog(hWnd, D_CM_SECURE_TYPE, CmSecureTypeDlg, NULL);
+}
+
+// ダイアログ初期化
+void CmSecureManagerDlgInit(HWND hWnd, UINT id)
+{
+	SECURE_DEVICE *dev;
+	// 引数チェック
+	if (hWnd == NULL || id == 0)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_SECURE);
+
+	dev = GetSecureDevice(id);
+	if (dev != NULL)
+	{
+		FormatText(hWnd, S_INFO, dev->DeviceName);
+	}
+
+	SetFont(hWnd, B_BOLD, Font(0, true));
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SEC_MGR_COLUMN1"), 200);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SEC_MGR_COLUMN2"), 110);
+
+	CmSecureManagerDlgUpdate(hWnd, id);
+}
+
+// コントロール更新
+void CmSecureManagerDlgUpdate(HWND hWnd, UINT id)
+{
+	bool b = true;
+	bool read_only = IsJPKI(id);
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSingleSelected(hWnd, L_LIST) == false)
+	{
+		b = false;
+	}
+
+	SetEnable(hWnd, B_EXPORT, b && ((UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST)) != SEC_K));
+	SetEnable(hWnd, B_DELETE, b && (read_only == false));
+	SetEnable(hWnd, B_PIN, (read_only == false));
+	SetEnable(hWnd, B_IMPORT, (read_only == false));
+	SetEnable(hWnd, B_NEW_CERT, (read_only == false));
+}
+
+// 内容更新
+void CmSecureManagerDlgRefresh(HWND hWnd, UINT id)
+{
+	bool ret;
+	LIST *o;
+	WINUI_SECURE_BATCH batch[] =
+	{
+		{WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+	};
+	// 引数チェック
+	if (hWnd == NULL || id == 0)
+	{
+		return;
+	}
+
+	ret = SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0);
+
+	if (ret == false)
+	{
+		return;
+	}
+
+	o = batch[0].EnumList;
+	if (o != NULL)
+	{
+		CmSecureManagerDlgPrintList(hWnd, o);
+
+		FreeEnumSecObject(o);
+	}
+
+	// コントロール更新
+	CmSecureManagerDlgUpdate(hWnd, id);
+}
+
+// オブジェクト一覧の表示
+void CmSecureManagerDlgPrintList(HWND hWnd, LIST *o)
+{
+	CmSecureManagerDlgPrintListEx(hWnd, L_LIST, o, INFINITE);
+}
+void CmSecureManagerDlgPrintListEx(HWND hWnd, UINT id, LIST *o, UINT type)
+{
+	UINT i;
+	LVB *v;
+	// 引数チェック
+	if (hWnd == NULL || o == NULL)
+	{
+		return;
+	}
+
+	LvReset(hWnd, id);
+
+	v = LvInsertStart();
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		UINT icon = ICO_LOG2;
+		wchar_t tmp1[MAX_SIZE], *tmp2, *tmp3;
+		SEC_OBJ *obj = LIST_DATA(o, i);
+
+		if (type == INFINITE || obj->Type == type)
+		{
+			StrToUni(tmp1, sizeof(tmp1), obj->Name);
+			tmp2 = CmSecureObjTypeToStr(obj->Type);
+			tmp3 = obj->Private ? _UU("SEC_YES") : _UU("SEC_NO");
+
+			if (obj->Type == SEC_X)
+			{
+				icon = ICO_CERT;
+			}
+			else if (obj->Type == SEC_K || obj->Type == SEC_P)
+			{
+				icon = ICO_KEY;
+			}
+
+			LvInsertAdd(v, icon, (void *)obj->Type, 2, tmp1, tmp2);
+		}
+	}
+
+	LvInsertEnd(v, hWnd, id);
+}
+
+// オブジェクトの種類を文字列にする
+wchar_t *CmSecureObjTypeToStr(UINT type)
+{
+	wchar_t *ret = _UU("SEC_TYPE_DATA");
+
+	if (type == SEC_X)
+	{
+		ret = _UU("SEC_TYPE_CERT");
+	}
+	else if (type == SEC_K)
+	{
+		ret = _UU("SEC_TYPE_KEY");
+	}
+	else if (type == SEC_P)
+	{
+		ret = _UU("SEC_TYPE_PUB");
+	}
+
+	return ret;
+}
+
+// 新しい証明書を作成して書き込み
+void CmSecureManagerDlgNewCert(HWND hWnd, UINT id)
+{
+	X *x;
+	K *k;
+	char default_name[MAX_SIZE];
+	char *object_name;
+	bool ok = false;
+	WINUI_SECURE_BATCH batch[] =
+	{
+		{WINUI_SECURE_WRITE_CERT, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+		{WINUI_SECURE_WRITE_KEY, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+		{WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+	};
+	// 引数チェック
+	if (hWnd == NULL || id == 0)
+	{
+		return;
+	}
+
+	// 証明書の作成ダイアログ
+	if (SmCreateCert(hWnd, &x, &k, true, NULL) == false)
+	{
+		return;
+	}
+	// デフォルトの名前を生成する
+	GetPrintNameFromXA(default_name, sizeof(default_name), x);
+	ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+	object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+		_UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_CERT, false, false);
+
+	if (object_name != NULL)
+	{
+		// 書き込みと列挙
+		batch[0].InputX = x;
+		batch[0].Name = object_name;
+		batch[1].InputK = k;
+		batch[1].Name = object_name;
+
+		if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+		{
+			// 失敗
+		}
+		else
+		{
+			ok = true;
+		}
+
+		Free(object_name);
+	}
+
+	if (ok)
+	{
+		LIST *o = batch[2].EnumList;
+
+		CmSecureManagerDlgPrintList(hWnd, o);
+
+		FreeEnumSecObject(o);
+
+		MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_NEW_CERT_IMPORT_OK"));
+	}
+
+	FreeX(x);
+	FreeK(k);
+}
+
+// インポート
+void CmSecureManagerDlgImport(HWND hWnd, UINT id)
+{
+	UINT type;
+	char name[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	wchar_t *tmp;
+	wchar_t *filename;
+	BUF *b;
+	K *k;
+	bool ok = false;
+	X *x;
+	WINUI_SECURE_BATCH batch[] =
+	{
+		{WINUI_SECURE_WRITE_DATA, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+		{WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+	};
+	// 引数チェック
+	if (hWnd == NULL || id == 0)
+	{
+		return;
+	}
+
+	// オブジェクトの種類の選択
+	type = CmSecureType(hWnd);
+
+	switch (type)
+	{
+	case SEC_DATA:
+		// データ
+		tmp = OpenDlg(hWnd, _UU("DLG_ALL_FILES"), _UU("SEC_IMPORT_DATA"));
+		if (tmp == NULL)
+		{
+			return;
+		}
+
+		filename = CopyUniStr(tmp);
+		Free(tmp);
+
+		// ファイル読み込み
+		b = ReadDumpW(filename);
+		if (b == NULL)
+		{
+			// 読み込み失敗
+			MsgBox(hWnd, MB_ICONSTOP, _UU("SEC_READ_FAILED"));
+		}
+		else
+		{
+			if (b->Size > MAX_SEC_DATA_SIZE)
+			{
+				// ファイルサイズが大きすぎる
+				MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_DATA_TOO_BIG"), MAX_SEC_DATA_SIZE);
+			}
+			else
+			{
+				// デフォルトの名前を生成する
+				char default_name[MAX_SIZE];
+				wchar_t default_name_w[MAX_SIZE];
+				char *object_name;
+				GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), filename);
+				UniToStr(default_name, sizeof(default_name), default_name_w);
+				ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+				object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+					_UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_LOG2, false, false);
+
+				if (object_name != NULL)
+				{
+					// 書き込みと列挙
+					batch[0].InputData = b;
+					batch[0].Name = object_name;
+
+					if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+					{
+						// 失敗
+					}
+					else
+					{
+						ok = true;
+					}
+
+					Free(object_name);
+				}
+			}
+
+			FreeBuf(b);
+		}
+
+		Free(filename);
+		break;
+
+	case SEC_X:
+		// 証明書読み込み
+		if (CmLoadXExW(hWnd, &x, tmp2, sizeof(tmp2)))
+		{
+			// デフォルトの名前を生成する
+			char default_name[MAX_SIZE];
+			wchar_t default_name_w[MAX_PATH];
+			char *object_name;
+			GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), tmp2);
+			UniToStr(default_name, sizeof(default_name), default_name_w);
+			ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+			object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+				_UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_CERT, false, false);
+
+			if (object_name != NULL)
+			{
+				// 書き込みと列挙
+				batch[0].Type = WINUI_SECURE_WRITE_CERT;
+				batch[0].InputX = x;
+				batch[0].Name = object_name;
+
+				if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+				{
+					// 失敗
+				}
+				else
+				{
+					ok = true;
+				}
+
+				Free(object_name);
+			}
+
+			FreeX(x);
+		}
+
+		break;
+
+	case SEC_K:
+		// 秘密鍵
+		if (CmLoadKExW(hWnd, &k, tmp2, sizeof(tmp2)))
+		{
+			// デフォルトの名前を生成する
+			char default_name[MAX_SIZE];
+			wchar_t default_name_w[MAX_PATH];
+			char *object_name;
+			GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), tmp2);
+			UniToStr(default_name, sizeof(default_name), default_name_w);
+			ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+			object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+				_UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_KEY, false, false);
+
+			if (object_name != NULL)
+			{
+				// 書き込みと列挙
+				batch[0].Type = WINUI_SECURE_WRITE_KEY;
+				batch[0].InputK = k;
+				batch[0].Name = object_name;
+
+				if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+				{
+					// 失敗
+				}
+				else
+				{
+					ok = true;
+				}
+
+				Free(object_name);
+			}
+
+			FreeK(k);
+		}
+		break;
+
+	default:
+		// 無効
+		return;
+	}
+
+	if (ok)
+	{
+		LIST *o = batch[1].EnumList;
+
+		CmSecureManagerDlgPrintList(hWnd, o);
+
+		FreeEnumSecObject(o);
+
+		MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_OBJECT_IMPORT_OK"));
+	}
+}
+
+// オブジェクトのエクスポート
+void CmSecureManagerDlgExport(HWND hWnd, UINT id)
+{
+	char name[MAX_SIZE];
+	UINT method = WINUI_SECURE_READ_DATA;
+	char *tmp;
+	UINT type;
+	wchar_t filename[MAX_PATH];
+	wchar_t *uni_tmp;
+	X *x;
+	BUF *b;
+	wchar_t default_name[128];
+	WINUI_SECURE_BATCH batch[] =
+	{
+		{WINUI_SECURE_READ_DATA, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+	};
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || id == 0)
+	{
+		return;
+	}
+
+	i = LvGetSelected(hWnd, L_LIST);
+	if (i == INFINITE)
+	{
+		return;
+	}
+
+	tmp = LvGetStrA(hWnd, L_LIST, i, 0);
+	StrCpy(name, sizeof(name), tmp);
+	Free(tmp);
+
+	type = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+	switch (type)
+	{
+	case SEC_X:
+		method = WINUI_SECURE_READ_CERT;
+		break;
+
+	default:
+		method = WINUI_SECURE_READ_DATA;
+		break;
+	}
+
+	batch[0].Type = method;
+
+	// スマートカードの操作を行う
+	if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+	{
+		return;
+	}
+
+	switch (type)
+	{
+	case SEC_X:
+		// 証明書
+		x = batch[0].OutputX;
+
+		CertDlg(hWnd, x, NULL, true);
+
+		FreeX(x);
+		break;
+
+	default:
+		// ファイル
+		b = batch[0].OutputData;
+		StrToUni(default_name, sizeof(default_name), name);
+		uni_tmp = SaveDlg(hWnd, _UU("DLG_ALL_FILES"), _UU("DLG_SAVE_FILE"), default_name, NULL);
+
+		if (uni_tmp != NULL)
+		{
+			UniStrCpy(filename, sizeof(filename), uni_tmp);
+
+			DumpBufW(b, filename);
+
+			Free(uni_tmp);
+
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_OBJECT_EXPORT_OK"));
+		}
+
+
+		FreeBuf(b);
+		break;
+	}
+}
+
+// オブジェクトの削除
+void CmSecureManagerDlgDelete(HWND hWnd, UINT id)
+{
+	char name[MAX_SIZE];
+	UINT method = WINUI_SECURE_DELETE_DATA;
+	char *tmp;
+	UINT type;
+	LIST *o;
+	WINUI_SECURE_BATCH batch[] =
+	{
+		{WINUI_SECURE_DELETE_OBJECT, name, false, NULL, NULL, NULL, NULL, NULL, NULL},
+		{WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+	};
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || id == 0)
+	{
+		return;
+	}
+
+	i = LvGetSelected(hWnd, L_LIST);
+	if (i == INFINITE)
+	{
+		return;
+	}
+
+	tmp = LvGetStrA(hWnd, L_LIST, i, 0);
+	StrCpy(name, sizeof(name), tmp);
+	Free(tmp);
+
+	type = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+	switch (type)
+	{
+	case SEC_X:
+		method = WINUI_SECURE_DELETE_CERT;
+		break;
+
+	case SEC_K:
+		method = WINUI_SECURE_DELETE_KEY;
+		break;
+
+	default:
+		method = WINUI_SECURE_DELETE_DATA;
+		break;
+	}
+
+	batch[0].Type = method;
+
+	if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+	{
+		return;
+	}
+
+	o = batch[1].EnumList;
+
+	CmSecureManagerDlgPrintList(hWnd, o);
+
+	FreeEnumSecObject(o);
+}
+
+static bool cm_secure_manager_no_new_cert = false;
+
+// スマートカードマネージャダイアログ
+UINT CmSecureManagerDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	UINT id = (UINT)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmSecureManagerDlgInit(hWnd, id);
+
+		if (cm_secure_manager_no_new_cert)
+		{
+			Hide(hWnd, B_NEW_CERT);
+		}
+
+		SetTimer(hWnd, 1, 1, NULL);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_REFRESH:
+			CmSecureManagerDlgRefresh(hWnd, id);
+			break;
+
+		case B_IMPORT:
+			CmSecureManagerDlgImport(hWnd, id);
+			break;
+
+		case B_EXPORT:
+			CmSecureManagerDlgExport(hWnd, id);
+			break;
+
+		case B_DELETE:
+			if (MsgBox(hWnd, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2,
+				_UU("SEC_DELETE_MSG")) == IDYES)
+			{
+				CmSecureManagerDlgDelete(hWnd, id);
+			}
+			break;
+
+		case B_NEW_CERT:
+			CmSecureManagerDlgNewCert(hWnd, id);
+			break;
+
+		case B_PIN:
+			CmSecurePin(hWnd, id);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			CmSecureManagerDlgRefresh(hWnd, id);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_LIST:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				CmSecureManagerDlgUpdate(hWnd, id);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// スマートカードマネージャ
+void CmSecureManager(HWND hWnd, UINT id)
+{
+	CmSecureManagerEx(hWnd, id, false);
+}
+void CmSecureManagerEx(HWND hWnd, UINT id, bool no_new_cert)
+{
+	// 引数チェック
+	if (hWnd == NULL || id == 0)
+	{
+		return;
+	}
+
+	// ID チェック
+	if (CheckSecureDeviceId(id) == false)
+	{
+		MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_INVALID_ID"));
+		return;
+	}
+
+	if (no_new_cert)
+	{
+		cm_secure_manager_no_new_cert = true;
+	}
+	else
+	{
+		cm_secure_manager_no_new_cert = false;
+	}
+
+	Dialog(hWnd, D_CM_SECURE_MANAGER, CmSecureManagerDlg, (void *)id);
+}
+
+// クライアント用スマートカードマネージャ
+void CmClientSecureManager(HWND hWnd)
+{
+	RPC_USE_SECURE t;
+	UINT id;
+
+	Zero(&t, sizeof(t));
+	CcGetUseSecure(cm->Client, &t);
+
+	id = t.DeviceId;
+
+	if (id == 0 || CheckSecureDeviceId(id) == false)
+	{
+		id = CmClientSelectSecure(hWnd);
+	}
+
+	if (id == 0)
+	{
+		return;
+	}
+
+	CmSecureManager(hWnd, id);
+}
+
+// ダイアログの初期化
+void CmSelectSecureDlgInit(HWND hWnd, UINT default_id)
+{
+	UINT i;
+	LIST *o;
+	LVB *v;
+
+	SetIcon(hWnd, 0, ICO_SECURE);
+
+	o = GetSecureDeviceList();
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SEC_COLUMN1"), 150);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SEC_COLUMN2"), 100);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SEC_COLUMN3"), 130);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SEC_COLUMN4"), 100);
+
+	v = LvInsertStart();
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t *tmp2;
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp4[MAX_SIZE];
+		SECURE_DEVICE *dev = LIST_DATA(o, i);
+
+		StrToUni(tmp1, sizeof(tmp1), dev->DeviceName);
+		tmp2 = (dev->Type == SECURE_IC_CARD) ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN");
+		StrToUni(tmp3, sizeof(tmp3), dev->Manufacturer);
+		StrToUni(tmp4, sizeof(tmp4), dev->ModuleName);
+
+		LvInsertAdd(v, ICO_SECURE, (void *)dev->Id, 4, tmp1, tmp2, tmp3, tmp4);
+	}
+
+	LvInsertEnd(v, hWnd, L_LIST);
+
+	if (default_id != 0)
+	{
+		LvSelect(hWnd, L_LIST, LvSearchParam(hWnd, L_LIST, (void *)default_id));
+	}
+
+	ReleaseList(o);
+
+	// コントロール更新
+	CmSelectSecureDlgUpdate(hWnd);
+}
+
+// ダイアログのコントロール更新
+void CmSelectSecureDlgUpdate(HWND hWnd)
+{
+	SetEnable(hWnd, IDOK, LvIsSingleSelected(hWnd, L_LIST));
+}
+
+// スマートカード選択ダイアログ
+UINT CmSelectSecureDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UINT default_id = (UINT)param;
+	NMHDR *n = NULL;
+	static UINT old_id;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		old_id = default_id;
+		CmSelectSecureDlgInit(hWnd, default_id);
+
+		if (LvNum(hWnd, L_LIST) == 0)
+		{
+			// 1 つもスマートカードが無い
+			SetTimer(hWnd, 1, 100, NULL);
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			Disable(hWnd, L_LIST);
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_NO_SECURE_DEVICE"));
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (IsEnable(hWnd, IDOK))
+			{
+				UINT i = LvGetSelected(hWnd, L_LIST);
+				if (i != INFINITE)
+				{
+					UINT id = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+					if (old_id != id)
+					{
+						if (CmCheckPkcsEula(hWnd, id) == false)
+						{
+							break;
+						}
+					}
+					EndDialog(hWnd, id);
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_LIST:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				CmSelectSecureDlgUpdate(hWnd);
+				break;
+			case NM_DBLCLK:
+				Command(hWnd, IDOK);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// 使用するスマートカードデバイスの選択
+UINT CmSelectSecure(HWND hWnd, UINT current_id)
+{
+	return Dialog(hWnd, D_CM_SELECT_SECURE, CmSelectSecureDlg, (void *)current_id);
+}
+
+// 使用するスマートカードデバイスの選択 (クライアント)
+UINT CmClientSelectSecure(HWND hWnd)
+{
+	UINT id;
+	RPC_USE_SECURE t;
+
+	if (cm->server_name != NULL)
+	{
+		MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("CM_SECURE_MUST_LOCAL"));
+		return 0;
+	}
+
+	Zero(&t, sizeof(t));
+	CcGetUseSecure(cm->Client, &t);
+
+	id = t.DeviceId;
+
+	id = CmSelectSecure(hWnd, id);
+	if (id != 0)
+	{
+		Zero(&t, sizeof(t));
+		t.DeviceId = id;
+
+		CALL(hWnd, CcUseSecure(cm->Client, &t));
+
+		SmWriteSelectSecureIdReg(id);
+	}
+
+	return id;
+}
+
+// ショートカット接続
+void CmConnectShortcut(UCHAR *key)
+{
+	UINT ret;
+	// 引数チェック
+	if (key == NULL)
+	{
+		return;
+	}
+
+	// 接続を試行する
+	ret = CcShortcut(key);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		if (ret == ERR_ACCOUNT_ACTIVE)
+		{
+			// 現在接続中なので、切断するかどうか問い合わせる
+			if (MsgBox(NULL, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_SHORTCUT_DISCONNECT")) == IDYES)
+			{
+				// 切断してみる
+				ret = CcShortcutDisconnect(key);
+
+				if (ret != ERR_NO_ERROR)
+				{
+					// エラー
+					MsgBox(NULL, MB_ICONEXCLAMATION, GetUniErrorStr(ret));
+				}
+			}
+		}
+		else
+		{
+			// その他のエラー
+			MsgBox(NULL, MB_ICONEXCLAMATION, GetUniErrorStr(ret));
+		}
+	}
+}
+
+// 音声ガイドを再生する
+void CmVoice(char *name)
+{
+	UINT i;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	if (cm->DisableVoice)
+	{
+		return;
+	}
+
+	for (i = 0;i < sizeof(cm_voice) / sizeof(CM_VOICE);i++)
+	{
+		if (cm_voice[i].voice_id == cm->VoiceId)
+		{
+			char tmp[MAX_SIZE];
+			Format(tmp, sizeof(tmp), "%s_%s.wav", cm_voice[i].perfix, name);
+			MsPlaySound(tmp);
+			return;
+		}
+	}
+}
+
+// パスワード変更画面更新
+void CmChangePasswordUpdate(HWND hWnd, CM_CHANGE_PASSWORD *p)
+{
+	bool ok = true;
+	char *s1, *s2;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (IsEmpty(hWnd, E_USERNAME))
+	{
+		ok = false;
+	}
+
+	s1 = GetTextA(hWnd, E_NEW_PASSWORD1);
+	s2 = GetTextA(hWnd, E_NEW_PASSWORD2);
+
+	if (StrCmp(s1, s2) != 0)
+	{
+		ok = false;
+	}
+
+	Free(s1);
+	Free(s2);
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// パスワード変更ダイアログプロシージャ
+UINT CmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CM_CHANGE_PASSWORD *p = (CM_CHANGE_PASSWORD *)param;
+	char username[MAX_USERNAME_LEN + 1];
+	char old_pass[MAX_PASSWORD_LEN + 1];
+	char new_pass[MAX_PASSWORD_LEN + 1];
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetTextA(hWnd, E_HUBNAME, p->HubName);
+		SetTextA(hWnd, E_USERNAME, p->Username);
+		FormatText(hWnd, S_TITLE, p->ClientOption->Hostname);
+
+		if (IsEmpty(hWnd, E_USERNAME))
+		{
+			FocusEx(hWnd, E_USERNAME);
+		}
+		else
+		{
+			FocusEx(hWnd, E_OLD_PASSWORD);
+		}
+
+		CmChangePasswordUpdate(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_USERNAME:
+		case E_OLD_PASSWORD:
+		case E_NEW_PASSWORD1:
+		case E_NEW_PASSWORD2:
+			CmChangePasswordUpdate(hWnd, p);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			GetTxtA(hWnd, E_USERNAME, username, sizeof(username));
+			GetTxtA(hWnd, E_OLD_PASSWORD, old_pass, sizeof(old_pass));
+			GetTxtA(hWnd, E_NEW_PASSWORD1, new_pass, sizeof(new_pass));
+
+			Disable(hWnd, E_USERNAME);
+			Disable(hWnd, E_OLD_PASSWORD);
+			Disable(hWnd, E_NEW_PASSWORD1);
+			Disable(hWnd, E_NEW_PASSWORD2);
+			Disable(hWnd, IDOK);
+			Disable(hWnd, IDCANCEL);
+
+			ret = ChangePassword(cm->Cedar, p->ClientOption, p->HubName, username, old_pass, new_pass);
+
+			if (ret == ERR_NO_ERROR)
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_CHANGED"));
+				EndDialog(hWnd, true);
+			}
+			else
+			{
+				MsgBox(hWnd, MB_ICONSTOP, _E(ret));
+				Enable(hWnd, E_USERNAME);
+				Enable(hWnd, E_OLD_PASSWORD);
+				Enable(hWnd, E_NEW_PASSWORD1);
+				Enable(hWnd, E_NEW_PASSWORD2);
+				Enable(hWnd, IDOK);
+				Enable(hWnd, IDCANCEL);
+
+				SetTextA(hWnd, E_OLD_PASSWORD, "");
+				SetTextA(hWnd, E_NEW_PASSWORD1, "");
+				SetTextA(hWnd, E_NEW_PASSWORD2, "");
+
+				Focus(hWnd, E_OLD_PASSWORD);
+			}
+
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		}
+
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// パスワード変更ダイアログ表示
+void CmChangePassword(HWND hWnd, CLIENT_OPTION *o, char *hubname, char *username)
+{
+	CM_CHANGE_PASSWORD p;
+	// 引数チェック
+	if (hWnd == NULL || o == NULL || hubname == NULL || username == NULL)
+	{
+		return;
+	}
+
+	Zero(&p, sizeof(p));
+	StrCpy(p.Username, sizeof(p.Username), username);
+	StrCpy(p.HubName, sizeof(p.HubName), hubname);
+	p.ClientOption = o;
+
+	CmVoice("password");
+
+	Dialog(hWnd, D_CM_CHANGE_PASSWORD, CmChangePasswordProc, &p);
+}
+
+// デスクトップ相違警告メッセージダイアログ初期化
+void CmDesktopDlgInit(HWND hWnd, wchar_t *account_name)
+{
+	wchar_t tmp[2048];
+	bool remote = false;
+	bool user_switching = false;
+	bool console_active = false;
+	wchar_t *console_user = NULL;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	FormatText(hWnd, 0, account_name);
+	FormatText(hWnd, S_TITLE, account_name);
+	DlgFont(hWnd, S_TITLE, 11, true);
+	DlgFont(hWnd, S_INFO, 11, true);
+	if (cm->server_name == NULL)
+	{
+		UniStrCpy(tmp, sizeof(tmp), _UU("CM_DESKTOP_LOCAL_PC"));
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_REMOTE_PC"), cm->server_name);
+	}
+	FormatText(hWnd, S_WARNING, tmp);
+
+	if (cm->server_name != NULL)
+	{
+		remote = true;
+	}
+	else
+	{
+		if (MsIsTerminalServiceInstalled())
+		{
+			user_switching = false;
+		}
+		else
+		{
+			user_switching = true;
+		}
+
+		console_user = MsGetSessionUserName(0);
+
+		if (console_user == NULL)
+		{
+			console_active = false;
+		}
+		else
+		{
+			console_active = true;
+		}
+	}
+
+	// MSG1
+	if (remote == false)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_1"),
+			user_switching ? _UU("CM_DESKTOP_MSG_LOCAL_SW") : _UU("CM_DESKTOP_MSG_LOCAL_TS"));
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_1"),
+			cm->server_name);
+	}
+	SetText(hWnd, S_MSG_1, tmp);
+
+	// MSG2
+	if (remote == false)
+	{
+		if (console_active)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_21"),
+				console_user, MsGetCurrentTerminalSessionId());
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_22"),
+				MsGetCurrentTerminalSessionId());
+		}
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_2"), cm->server_name);
+	}
+	SetText(hWnd, S_MSG_2, tmp);
+
+	// MSG3
+	if (remote == false)
+	{
+		if (console_active)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_31"),
+				console_user, account_name);
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_32"),
+				account_name);
+		}
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_3"), cm->server_name,
+			account_name);
+	}
+	SetText(hWnd, S_MSG_3, tmp);
+
+	if (console_user != NULL)
+	{
+		Free(console_user);
+	}
+}
+
+// デスクトップ相違警告メッセージダイアログ
+UINT CmDesktopDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	wchar_t *account_name = (wchar_t *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmDesktopDlgInit(hWnd, account_name);
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			EndDialog(hWnd, true);
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 必要であればデスクトップが異なる旨の警告メッセージを表示する
+bool CmWarningDesktop(HWND hWnd, wchar_t *account_name)
+{
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return false;
+	}
+
+	if (cm->Client->Unix)
+	{
+		//クライアントが UNIX の場合警告の必要は無い
+		return true;
+	}
+
+	if (/*MsIsTerminalServiceInstalled() || MsIsUserSwitchingInstalled() ||*/ (cm->server_name != NULL))
+	{
+		if (cm->server_name == NULL)
+		{
+			//if (MsGetCurrentTerminalSessionId() == 0)
+			{
+				// 警告の必要は無い
+				return true;
+			}
+		}
+		// 警告の必要がある
+		return Dialog(hWnd, D_CM_DESKTOP, CmDesktopDlgProc, account_name);
+	}
+	else
+	{
+		// 警告の必要は無い
+		return true;
+	}
+}
+
+// パスワード設定ダイアログ更新
+void CmPasswordRefresh(HWND hWnd)
+{
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, E_PASSWORD, IsChecked(hWnd, R_USE_PASSWORD));
+	SetEnable(hWnd, E_PASSWORD2, IsChecked(hWnd, R_USE_PASSWORD));
+	SetEnable(hWnd, IDC_STATIC1, IsChecked(hWnd, R_USE_PASSWORD));
+	SetEnable(hWnd, IDC_STATIC2, IsChecked(hWnd, R_USE_PASSWORD));
+	SetEnable(hWnd, R_REMOTE_ONLY, IsChecked(hWnd, R_USE_PASSWORD));
+
+	if (IsChecked(hWnd, R_USE_PASSWORD))
+	{
+		char tmp1[MAX_SIZE];
+		char tmp2[MAX_SIZE];
+		if (IsEmpty(hWnd, E_PASSWORD))
+		{
+			ok = false;
+		}
+		GetTxtA(hWnd, E_PASSWORD, tmp1, sizeof(tmp1));
+		GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+		if (StrCmp(tmp1, tmp2) != 0)
+		{
+			ok = false;
+		}
+		if (StrCmp(tmp1, HIDDEN_PASSWORD) == 0)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// パスワード設定プロシージャ
+UINT CmPasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	RPC_CLIENT_PASSWORD_SETTING c;
+	RPC_CLIENT_PASSWORD p;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// パスワード設定の取得
+		if (CALL(hWnd, CcGetPasswordSetting(cm->Client, &c)))
+		{
+			Check(hWnd, R_USE_PASSWORD, c.IsPasswordPresented);
+			if (c.IsPasswordPresented)
+			{
+				SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+				SetTextA(hWnd, E_PASSWORD2, HIDDEN_PASSWORD);
+				FocusEx(hWnd, E_PASSWORD);
+				Check(hWnd, R_REMOTE_ONLY, c.PasswordRemoteOnly);
+			}
+			else
+			{
+				Focus(hWnd, R_USE_PASSWORD);
+			}
+		}
+		CmPasswordRefresh(hWnd);
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case R_USE_PASSWORD:
+			if (IsChecked(hWnd, R_USE_PASSWORD))
+			{
+				FocusEx(hWnd, E_PASSWORD);
+			}
+			break;
+		case IDOK:
+			GetTxtA(hWnd, E_PASSWORD, tmp, sizeof(tmp));
+			Zero(&p, sizeof(p));
+			if (IsChecked(hWnd, R_USE_PASSWORD))
+			{
+				StrCpy(p.Password, sizeof(p.Password), tmp);
+				p.PasswordRemoteOnly = IsChecked(hWnd, R_REMOTE_ONLY);
+			}
+
+			if (CALL(hWnd, CcSetPassword(cm->Client, &p)))
+			{
+				if (StrLen(p.Password) > 0)
+				{
+					MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_SET"));
+				}
+				else
+				{
+					MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_REMOVE"));
+				}
+				EndDialog(hWnd, true);
+			}
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		switch (LOWORD(wParam))
+		{
+		case R_USE_PASSWORD:
+		case R_REMOTE_ONLY:
+		case E_PASSWORD:
+		case E_PASSWORD2:
+			CmPasswordRefresh(hWnd);
+			break;
+		}
+		switch (wParam)
+		{
+		case R_REMOTE_ONLY:
+		case R_USE_PASSWORD:
+			if (IsChecked(hWnd, R_USE_PASSWORD))
+			{
+				FocusEx(hWnd, E_PASSWORD);
+			}
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// パスワード設定
+void CmPassword(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_CM_PASSWORD, CmPasswordProc, NULL);
+}
+
+// CA ダイアログ更新
+void CmTrustDlgUpdate(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, B_EXPORT, LvIsSelected(hWnd, L_CERT));
+	SetEnable(hWnd, B_DELETE, LvIsSelected(hWnd, L_CERT) && cm->CmSetting.LockMode == false);
+	SetEnable(hWnd, IDOK, LvIsSelected(hWnd, L_CERT));
+	SetEnable(hWnd, B_IMPORT, cm->CmSetting.LockMode == false);
+}
+
+// 証明書リストの更新
+void CmTrustDlgRefresh(HWND hWnd)
+{
+	RPC_CLIENT_ENUM_CA c;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (CALL(hWnd, CcEnumCa(cm->Client, &c)))
+	{
+		UINT i;
+		LVB *b = LvInsertStart();
+		for (i = 0;i < c.NumItem;i++)
+		{
+			RPC_CLIENT_ENUM_CA_ITEM *cert = c.Items[i];
+			wchar_t tmp[MAX_SIZE];
+
+			GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(cert->Expires), NULL);
+			LvInsertAdd(b, ICO_CERT, (void *)cert->Key, 3,
+				cert->SubjectName, cert->IssuerName, tmp);
+		}
+		LvInsertEnd(b, hWnd, L_CERT);
+		CiFreeClientEnumCa(&c);
+	}
+
+	CmTrustDlgUpdate(hWnd);
+}
+
+// インポート
+void CmTrustImport(HWND hWnd)
+{
+	X *x;
+	RPC_CERT c;
+	if (CmLoadXFromFileOrSecureCard(hWnd, &x) == false)
+	{
+		return;
+	}
+
+	Zero(&c, sizeof(c));
+	c.x = x;
+
+	CALL(hWnd, CcAddCa(cm->Client, &c));
+	CmVoice("new_cert");
+
+	FreeX(c.x);
+	CmTrustDlgRefresh(hWnd);
+}
+
+// エクスポート
+void CmTrustExport(HWND hWnd)
+{
+	UINT key;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	key = (UINT)LvGetParam(hWnd, L_CERT, LvGetSelected(hWnd, L_CERT));
+	if (key != INFINITE)
+	{
+		RPC_GET_CA a;
+		Zero(&a, sizeof(a));
+		a.Key = key;
+
+		if (CALL(hWnd, CcGetCa(cm->Client, &a)))
+		{
+			wchar_t *name;
+			X *x = CloneX(a.x);
+			CiFreeGetCa(&a);
+
+			// 保存
+			name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), NULL, L".cer");
+			if (name != NULL)
+			{
+				wchar_t str[MAX_SIZE];
+				UniStrCpy(str, sizeof(str), name);
+				if (XToFileW(x, str, true))
+				{
+					MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_CERT_SAVE_OK"));
+				}
+				else
+				{
+					MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
+				}
+				Free(name);
+			}
+			FreeX(x);
+		}
+	}
+}
+
+// 表示
+void CmTrustView(HWND hWnd)
+{
+	UINT key;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	key = (UINT)LvGetParam(hWnd, L_CERT, LvGetSelected(hWnd, L_CERT));
+	if (key != INFINITE)
+	{
+		RPC_GET_CA a;
+		Zero(&a, sizeof(a));
+		a.Key = key;
+
+		if (CALL(hWnd, CcGetCa(cm->Client, &a)))
+		{
+			X *x = CloneX(a.x);
+			X *x_issuer;
+			CiFreeGetCa(&a);
+
+			x_issuer = CmGetIssuer(x);
+			CertDlg(hWnd, x, x_issuer, true);
+			FreeX(x);
+			FreeX(x_issuer);
+		}
+	}
+}
+
+// CA ダイアログプロシージャ
+UINT CmTrustDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	UINT index;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		LvInit(hWnd, L_CERT);
+		LvInsertColumn(hWnd, L_CERT, 0, _UU("CM_CERT_COLUMN_1"), 190);
+		LvInsertColumn(hWnd, L_CERT, 1, _UU("CM_CERT_COLUMN_2"), 190);
+		LvInsertColumn(hWnd, L_CERT, 2, _UU("CM_CERT_COLUMN_3"), 160);
+		CmTrustDlgRefresh(hWnd);
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_IMPORT:
+			CmTrustImport(hWnd);
+			break;
+		case B_EXPORT:
+			CmTrustExport(hWnd);
+			break;
+		case B_DELETE:
+			index = LvGetSelected(hWnd, L_CERT);
+			if (index != INFINITE)
+			{
+				UINT key = (UINT)LvGetParam(hWnd, L_CERT, index);
+				if (key != INFINITE)
+				{
+					if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_CERT_DELETE_MSG")) == IDYES)
+					{
+						RPC_CLIENT_DELETE_CA c;
+						Zero(&c, sizeof(c));
+						c.Key = key;
+						if (CALL(hWnd, CcDeleteCa(cm->Client, &c)))
+						{
+							CmTrustDlgRefresh(hWnd);
+						}
+					}
+				}
+			}
+			break;
+		case IDOK:
+			if (IsEnable(hWnd, IDOK))
+			{
+				CmTrustView(hWnd);
+			}
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_CERT:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				CmTrustDlgUpdate(hWnd);
+				break;
+			case NM_DBLCLK:
+				Command(hWnd, IDOK);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	LvSortHander(hWnd, msg, wParam, lParam, L_CERT);
+
+	return 0;
+}
+
+// CA ダイアログの表示
+void CmTrustDlg(HWND hWnd)
+{
+	Dialog(hWnd, D_CM_TRUST, CmTrustDlgProc, NULL);
+}
+
+// メインウインドウプロシージャ
+UINT CmMainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	static UINT taskbar_msg = 0;
+	COPYDATASTRUCT *cpy;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	if (taskbar_msg != 0 && msg == taskbar_msg)
+	{
+		// タスクバーが再生成された
+		if (cm->TrayInited)
+		{
+			MsRestoreIconOnTray();
+		}
+	}
+
+	// CmSetForegroundProcessToCnService();
+
+	switch (msg)
+	{
+	case WM_CM_SETTING_CHANGED_MESSAGE:
+		// CM_SETTING が変更された
+		CmApplyCmSetting();
+		break;
+	case WM_INITDIALOG:
+		CmMainWindowOnInit(hWnd);
+		taskbar_msg = RegisterWindowMessage("TaskbarCreated");
+		CmEndStartupMutex();
+		break;
+	case WM_SHOWWINDOW:
+LABEL_SPLASH:
+		if (cm->SplashHasBeenShown == false)
+		{
+			if ((msg == WM_SHOWWINDOW && wParam) || (msg != WM_SHOWWINDOW && IsShow(hWnd, 0)))
+			{
+				if (IsIconic(hWnd) == false)
+				{
+					SetTimer(hWnd, 5, 100, NULL);
+				}
+			}
+		}
+		break;
+	case WM_CM_SHOW:
+		// 別のプロセスから表示要求を受けた
+		if (cm->CmSetting.EasyMode == false)
+		{
+			ShowWindow(hWnd, SW_SHOWNORMAL);
+		}
+		else
+		{
+			if (cm->hEasyWnd == NULL)
+			{
+				CmShowEasy();
+			}
+			else
+			{
+				SetForegroundWindow(cm->hEasyWnd);
+				SetActiveWindow(cm->hEasyWnd);
+			}
+		}
+		break;
+	case WM_COMMAND:
+		CmMainWindowOnCommand(hWnd, wParam, lParam);
+		break;
+	case WM_SIZE:
+		CmMainWindowOnSize(hWnd);
+		goto LABEL_SPLASH;
+	case WM_CLOSE:
+		if (cm->CmSetting.EasyMode == false)
+		{
+			CmShowOrHideWindow(hWnd);
+		}
+		else
+		{
+			if (cm->hEasyWnd == NULL)
+			{
+				CmShowEasy();
+			}
+			else
+			{
+				SetForegroundWindow(cm->hEasyWnd);
+				SetActiveWindow(cm->hEasyWnd);
+			}
+		}
+		return 1;
+	case WM_INITMENUPOPUP:
+		if (HIWORD(lParam) == false)
+		{
+			CmMainWindowOnPopupMenu(hWnd, (HMENU)wParam, LOWORD(lParam));
+		}
+		break;
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		if (n->idFrom == L_ACCOUNT && (n->code == LVN_BEGINLABELEDITW || n->code == LVN_BEGINLABELEDITA))
+		{
+			wchar_t *tmp = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+			if (tmp != NULL)
+			{
+				if (UniStrCmpi(tmp, _UU("CM_NEW_ICON")) == 0 ||
+					UniStrCmpi(tmp, _UU("CM_ASP")) == 0)
+				{
+					SendMsg(hWnd, L_ACCOUNT, LVM_CANCELEDITLABEL, 0, 0);
+					Free(tmp);
+					return true;
+				}
+				Free(tmp);
+			}
+		}
+		CmMainWindowOnNotify(hWnd, (NMHDR *)lParam);
+		break;
+	case WM_CM_NOTIFY:
+		CmRefreshVLanList(hWnd);
+		CmRefreshAccountList(hWnd);
+		CmRefreshStatusBar(hWnd);
+		break;
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			CmSetForegroundProcessToCnService();
+			break;
+		case 2:
+			CmPollingTray(hWnd);
+			break;
+		case 3:
+			KillTimer(hWnd, 3);
+			Hide(hWnd, 0);
+			break;
+		case 4:
+			KillTimer(hWnd, 4);
+			CmMainWindowOnShowEasy(hWnd);
+			break;
+		case 5:
+			KillTimer(hWnd, 5);
+			if (cm->SplashHasBeenShown == false)
+			{
+				cm->SplashHasBeenShown = true;
+
+				ShowSplashEx(hWnd, "UT-VPN Client", 1300, CM_SPLASH_BORDER_COLOR);
+			}
+			break;
+		}
+		break;
+	case WM_CM_TRAY_MESSAGE:
+		// タスクトレイのアイコンからのメッセージ
+		CmMainWindowOnTrayClicked(hWnd, wParam, lParam);
+		break;
+	case WM_COPYDATA:
+		cpy = (COPYDATASTRUCT *)lParam;
+		if (cpy != NULL)
+		{
+			if (cpy->dwData == CM_IMPORT_FILENAME_MSG || cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE)
+			{
+				char *filename = (char *)cpy->lpData;
+
+				if (cm->CmSetting.LockMode == false || cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE)
+				{
+					wchar_t fullpath[MAX_PATH];
+
+					if (StrLen(filename) >= 2 && IsFileExists(filename))
+					{
+						StrToUni(fullpath, sizeof(fullpath), filename);
+					}
+					else
+					{
+						UniStrCpy(fullpath, sizeof(fullpath), (wchar_t *)filename);
+					}
+
+					CmImportAccountMainEx(cm->hEasyWnd ? cm->hEasyWnd : hWnd, fullpath, cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE);
+				}
+				else
+				{
+					MsgBox(cm->hEasyWnd ? cm->hEasyWnd : hWnd, MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_TOPMOST, _UU("CM_VPN_FILE_IMPORT_NG"));
+				}
+			}
+		}
+		break;
+	case WM_QUERYENDSESSION:
+		// Windows が終了しようとしている
+		cm->WindowsShutdowning = true;
+		CmSaveMainWindowPos(hWnd);
+		SleepThread(256);
+		break;
+	case WM_ENDSESSION:
+		// Windows が終了した
+		_exit(0);
+		break;
+	}
+
+	LvSortHander(hWnd, msg, wParam, lParam, L_ACCOUNT);
+	LvSortHander(hWnd, msg, wParam, lParam, L_VLAN);
+
+	return 0;
+}
+
+// 通知サービスをフォアグラウンドプロセスに指定する
+void CmSetForegroundProcessToCnService()
+{
+	if (cm->MenuPopuping)
+	{
+		return;
+	}
+	if (cm->server_name == NULL)
+	{
+		if (CnCheckAlreadyExists(false))
+		{
+			AllowFGWindow(MsRegReadInt(REG_CURRENT_USER,
+				CM_REG_KEY, "NotifyServerProcessId"));
+		}
+	}
+}
+
+// [最近の接続先] のサブメニューを表示する
+HMENU CmCreateRecentSubMenu(HWND hWnd, UINT start_id)
+{
+	HMENU h = NULL;
+	UINT i;
+	RPC_CLIENT_ENUM_ACCOUNT a;
+	LIST *o;
+	bool easy;
+
+	easy = cm->CmSetting.EasyMode;
+
+	Zero(&a, sizeof(a));
+
+	if (CcEnumAccount(cm->Client, &a) == ERR_NO_ERROR)
+	{
+		o = NewListFast(CiCompareClientAccountEnumItemByLastConnectDateTime);
+
+		for (i = 0;i < a.NumItem;i++)
+		{
+			RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = a.Items[i];
+
+			item->tmp1 = i;
+
+			if (item->LastConnectDateTime != 0)
+			{
+				Add(o, item);
+			}
+		}
+
+		Sort(o);
+
+		for (i = 0;i < MIN(LIST_NUM(o), CM_NUM_RECENT);i++)
+		{
+			RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = (RPC_CLIENT_ENUM_ACCOUNT_ITEM *)LIST_DATA(o, i);
+			wchar_t tmp[MAX_PATH];
+			wchar_t *account_name;
+			char *server_name;
+			char *hub_name;
+			UINT pos;
+
+			if (h == NULL)
+			{
+				h = CreatePopupMenu();
+			}
+
+			account_name = item->AccountName;
+			server_name = item->ServerName;
+			hub_name = item->HubName;
+
+			UniStrCpy(tmp, sizeof(tmp), account_name);
+
+			pos = LvSearchStr(hWnd, L_ACCOUNT, 0, account_name);
+			if (pos != INFINITE)
+			{
+				MsAppendMenu(h, MF_STRING, start_id + pos, tmp);
+			}
+		}
+
+		ReleaseList(o);
+
+		CiFreeClientEnumAccount(&a);
+	}
+
+	return h;
+}
+
+// タスクトレイの右クリックメニューのサブメニューを表示する
+HMENU CmCreateTraySubMenu(HWND hWnd, bool flag, UINT start_id)
+{
+	HMENU h = NULL;
+	UINT i, num;
+	bool easy;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	easy = cm->CmSetting.EasyMode;
+
+	num = LvNum(hWnd, L_ACCOUNT);
+
+	for (i = 0;i < num;i++)
+	{
+		wchar_t *status_str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+		if (status_str != NULL)
+		{
+			bool b = false;
+			bool is_account = false;
+
+			if (UniStrCmpi(status_str, _UU("CM_ACCOUNT_OFFLINE")) == 0)
+			{
+				if (flag == false)
+				{
+					b = true;
+				}
+
+				is_account = true;
+			}
+
+			if (UniStrCmpi(status_str, _UU("CM_ACCOUNT_ONLINE")) == 0 ||
+				UniStrCmpi(status_str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+			{
+				if (flag == true)
+				{
+					b = true;
+				}
+
+				is_account = true;
+			}
+
+			if (b)
+			{
+				wchar_t tmp[MAX_PATH];
+				wchar_t *account_name, *server_name;
+				wchar_t *hub_name;
+				if (h == NULL)
+				{
+					h = CreatePopupMenu();
+				}
+
+				account_name = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+				server_name = LvGetStr(hWnd, L_ACCOUNT, i, 2);
+				hub_name = LvGetStr(hWnd, L_ACCOUNT, i, 3);
+
+				if (easy == false)
+				{
+					UniFormat(tmp, sizeof(tmp), L"%s\t- %s [%s]", account_name, server_name, hub_name);
+				}
+				else
+				{
+					UniStrCpy(tmp, sizeof(tmp), account_name);
+				}
+
+				MsAppendMenu(h, MF_STRING, start_id + i, tmp);
+
+				Free(account_name);
+				Free(server_name);
+				Free(hub_name);
+			}
+
+			Free(status_str);
+		}
+	}
+
+	return h;
+}
+
+// タスクトレイの右クリックメニューを表示する
+void CmShowTrayMenu(HWND hWnd)
+{
+	HMENU h;
+	POINT p;
+	HMENU sub1, sub2, sub3, sub4;
+	bool locked;
+	bool easy;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	cm->MenuPopuping = true;
+
+	locked = cm->CmSetting.LockMode;
+	easy = cm->CmSetting.EasyMode;
+
+	// メニューを作成する
+	h = CreatePopupMenu();
+
+	// キャンセル
+	MsAppendMenu(h, MF_ENABLED | MF_STRING, 100007, _UU("CM_TRAY_MENU_CANCEL"));
+
+	// セパレータ
+	MsAppendMenu(h, MF_SEPARATOR, 10006, NULL);
+
+	if (locked == false && easy == false)
+	{
+		// 新しい接続設定の作成
+		MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_NEW, _UU("CM_TRAY_MENU_NEW"));
+
+		// セパレータ
+		MsAppendMenu(h, MF_SEPARATOR, 10005, NULL);
+	}
+
+	// 接続メニュー
+	sub1 = CmCreateTraySubMenu(hWnd, false, CM_TRAY_MENU_CONNECT_ID_START);
+	if (sub1 != NULL)
+	{
+		MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+			(UINT_PTR)sub1, _UU("CM_TRAY_MENU_CONNECT"));
+	}
+
+	// 切断メニュー
+	sub2 = CmCreateTraySubMenu(hWnd, true, CM_TRAY_MENU_DISCONNECT_ID_START);
+	if (sub2 != NULL)
+	{
+		MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+			(UINT_PTR)sub2, _UU("CM_TRAY_MENU_DISCONNECT"));
+	}
+
+	// ステータス表示メニュー
+	sub3 = CmCreateTraySubMenu(hWnd, true, CM_TRAY_MENU_STATUS_ID_START);
+	if (sub3 != NULL)
+	{
+		MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+			(UINT_PTR)sub3, _UU("CM_TRAY_MENU_STATUS"));
+	}
+
+	if (sub3 != NULL)
+	{
+		// すべての接続を切断
+		MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_DISCONNECT_ALL, _UU("CM_TRAY_MENU_DISCONNECT_ALL"));
+	}
+
+	if (sub1 != NULL || sub2 != NULL || sub3 != NULL)
+	{
+		// セパレータ
+		MsAppendMenu(h, MF_SEPARATOR, 10003, NULL);
+	}
+
+	// 最近接続した VPN サーバーに接続
+	sub4 = CmCreateRecentSubMenu(hWnd, CM_TRAY_MENU_RECENT_ID_START);
+	if (sub4 != NULL)
+	{
+		MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+			(UINT_PTR)sub4, _UU("CM_TRAY_MENU_RECENT"));
+		MsAppendMenu(h, MF_SEPARATOR, 10008, NULL);
+	}
+
+	if (locked == false && easy == false)
+	{
+		// 通信スループット測定
+		MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_TRAFFIC, _UU("CM_TRAY_MENU_TRAFFIC"));
+	}
+
+	if (easy == false)
+	{
+		// ネットワークデバイス状態
+		MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_NETIF, _UU("CM_TRAY_MENU_NETIF"));
+	}
+
+	// バージョン情報
+	MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_ABOUT, _UU("CM_TRAY_MENU_ABOUT"));
+
+	// セパレータ
+	MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+	// 動作モードの変更
+	MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_CM_SETTING, _UU("CM_TRAY_MENU_SETTING"));
+
+	// セパレータ
+	MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+	// アイコンを非表示
+	MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_TRAYICON, _UU("CM_MENU@CMD_TRAYICON"));
+
+	// セパレータ
+	MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+	// 表示または非表示
+	MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_EXIT,
+		IsHide(hWnd, 0) ? _UU("CM_TRAY_MENU_1_SHOW") : _UU("CM_TRAY_MENU_1_HIDE"));
+
+	// 終了
+	MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_QUIT, _UU("CM_TRAY_MENU_2_QUIT"));
+
+	// メニューを表示する
+	GetCursorPos(&p);
+
+	SetForegroundWindow(hWnd);
+	TrackPopupMenu(h, TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
+	PostMessage(hWnd, WM_NULL, 0, 0);
+
+	if (sub1 != NULL)
+	{
+		DestroyMenu(sub1);
+	}
+
+	if (sub2 != NULL)
+	{
+		DestroyMenu(sub2);
+	}
+
+	if (sub3 != NULL)
+	{
+		DestroyMenu(sub3);
+	}
+
+	DestroyMenu(h);
+
+	cm->MenuPopuping = false;
+}
+
+// メインウインドウを表示または隠す
+void CmShowOrHideWindow(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (IsHide(hWnd, 0))
+	{
+		Show(hWnd, 0);
+		if (IsIconic(hWnd))
+		{
+			ShowWindow(hWnd, SW_SHOWNORMAL);
+		}
+		SetForegroundWindow(hWnd);
+		SetActiveWindow(hWnd);
+	}
+	else
+	{
+		CmSaveMainWindowPos(hWnd);
+		Hide(hWnd, 0);
+
+		if (cm->TrayInited == false)
+		{
+			Command(hWnd, CMD_QUIT);
+			return;
+		}
+	}
+}
+
+// アカウントリストを右クリックした
+void CmAccountListRightClick(HWND hWnd)
+{
+	HMENU h;
+	HMENU parent;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// メニューをロード
+	h = LoadSubMenu(M_MAIN, 0, &parent);
+	if (h == NULL)
+	{
+		return;
+	}
+
+	InitMenuInternational(h, "CM_MENU");
+
+	// ショートカットキーを除去
+	RemoveShortcutKeyStrFromMenu(h);
+
+	// 終了メニューを削除
+	i = GetMenuItemPos(h, CMD_QUIT);
+	if (i != INFINITE)
+	{
+		DeleteMenuItem(h, i);
+		DeleteMenuItem(h, i - 1);
+		DeleteMenuItem(h, i - 2);
+		DeleteMenuItem(h, i - 3);
+	}
+
+	// 有効 / 無効の設定
+	CmMainWindowOnPopupMenu(hWnd, h, INFINITE);
+
+	if (h != NULL)
+	{
+		// 選択されているアカウントが接続中かどうか判別する
+		UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+		wchar_t *str;
+		bool is_connected = false;
+		if (i != INFINITE)
+		{
+			str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+			if (str != NULL)
+			{
+				if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+				{
+					// 接続中
+					is_connected = true;
+				}
+				Free(str);
+			}
+		}
+
+		if (i == INFINITE)
+		{
+			// 新規作成メニューを太字にする
+			SetMenuItemBold(h, GetMenuItemPos(h, CMD_NEW), true);
+		}
+		else
+		{
+			if (is_connected == false)
+			{
+				// 接続メニューを太字にする
+				SetMenuItemBold(h, GetMenuItemPos(h, CMD_CONNECT), true);
+			}
+			else
+			{
+				// 状況メニューを太字にする
+				SetMenuItemBold(h, GetMenuItemPos(h, CMD_STATUS), true);
+			}
+		}
+	}
+
+	// メニューを表示
+	PrintMenu(hWnd, h);
+
+	DestroyMenu(parent);
+}
+
+// 仮想 LAN カードリストを右クリックした
+void CmVLanListRightClick(HWND hWnd)
+{
+	HMENU h;
+	HMENU parent;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// メニューをロード
+	h = LoadSubMenu(M_MAIN, 3, &parent);
+	if (h == NULL)
+	{
+		return;
+	}
+
+	InitMenuInternational(h, "CM_MENU");
+
+	// ショートカットキーを除去
+	RemoveShortcutKeyStrFromMenu(h);
+
+	// 有効 / 無効の設定
+	CmMainWindowOnPopupMenu(hWnd, h, INFINITE);
+
+	if (h != NULL)
+	{
+		// 選択されているデバイスが有効かどうか調べる
+		UINT i = LvGetSelected(hWnd, L_VLAN);
+		wchar_t *str;
+		bool is_active = false;
+		if (i != INFINITE)
+		{
+			str = LvGetStr(hWnd, L_VLAN, i, 1);
+			if (str != NULL)
+			{
+				if (UniStrCmpi(str, _UU("CM_VLAN_ENABLED")) == 0)
+				{
+					// 有効
+					is_active = true;
+				}
+				Free(str);
+			}
+		}
+
+		if (i == INFINITE)
+		{
+			// 新規作成メニューを太字にする
+			SetMenuItemBold(h, GetMenuItemPos(h, CMD_NEW_VLAN), true);
+		}
+		else
+		{
+			if (is_active == false)
+			{
+				// 有効化メニューを太字にする
+				SetMenuItemBold(h, GetMenuItemPos(h, CMD_ENABLE_VLAN), true);
+			}
+			else
+			{
+				// Windows ネットワーク設定メニューを太字にする
+				SetMenuItemBold(h, GetMenuItemPos(h, CMD_WINNET), true);
+			}
+		}
+	}
+
+	// メニューを表示
+	PrintMenu(hWnd, h);
+
+	DestroyMenu(parent);
+}
+
+// メインウインドウへの通知
+void CmMainWindowOnNotify(HWND hWnd, NMHDR *n)
+{
+	bool item_vlan;
+	NMLVDISPINFOW *disp_info;
+	NMLVKEYDOWN *key;
+
+	// 引数チェック
+	if (hWnd == NULL || n == NULL)
+	{
+		return;
+	}
+
+	switch (n->idFrom)
+	{
+	case L_ACCOUNT:
+	case L_VLAN:
+		if (n->idFrom == L_ACCOUNT)
+		{
+			item_vlan = false;
+		}
+		else
+		{
+			item_vlan = true;
+		}
+
+		switch (n->code)
+		{
+		case NM_DBLCLK:
+			// ダブルクリック
+			CmOnKey(hWnd, false, false, VK_RETURN);
+			break;
+		case NM_RCLICK:
+			// 右クリック
+			if (item_vlan == false)
+			{
+				CmAccountListRightClick(hWnd);
+			}
+			else
+			{
+				CmVLanListRightClick(hWnd);
+			}
+			break;
+		case LVN_ENDLABELEDITW:
+			// 名前の変更
+			disp_info = (NMLVDISPINFOW *)n;
+			if (disp_info->item.pszText != NULL)
+			{
+				wchar_t *new_name = disp_info->item.pszText;
+				wchar_t *old_name = LvGetStr(hWnd, L_ACCOUNT, disp_info->item.iItem, 0);
+
+				if (old_name != NULL)
+				{
+					if (UniStrCmp(new_name, old_name) != 0 && UniIsEmptyStr(new_name) == false)
+					{
+						RPC_RENAME_ACCOUNT a;
+						Zero(&a, sizeof(a));
+						UniStrCpy(a.OldName, sizeof(a.OldName), old_name);
+						UniStrCpy(a.NewName, sizeof(a.NewName), new_name);
+						if (CALL(hWnd, CcRenameAccount(cm->Client, &a)))
+						{
+							LvSetItem(hWnd, L_ACCOUNT, disp_info->item.iItem, 0, new_name);
+						}
+					}
+
+					Free(old_name);
+				}
+			}
+			break;
+		case LVN_KEYDOWN:
+			// キー押下
+			key = (NMLVKEYDOWN *)n;
+			if (key != NULL)
+			{
+				bool ctrl, alt;
+				UINT code = key->wVKey;
+				ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+				alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+				CmOnKey(hWnd, ctrl, alt, code);
+			}
+			break;
+		}
+		break;
+	}
+}
+
+// キーボード押下
+void CmOnKey(HWND hWnd, bool ctrl, bool alt, UINT key)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 単一キー
+	switch (key)
+	{
+	case VK_RETURN:
+		Command(hWnd, IDOK);
+		break;
+	case VK_DELETE:
+		// 削除
+		if (IsFocus(hWnd, L_ACCOUNT))
+		{
+			// アカウントリストに関する操作
+			Command(hWnd, CMD_DELETE);
+		}
+		else
+		{
+			// 仮想 LAN カードリストに関する操作
+			Command(hWnd, CMD_DELETE_VLAN);
+		}
+		break;
+	case VK_F2:
+		// 名前変更
+		Command(hWnd, CMD_RENAME);
+		break;
+	case VK_F5:
+		// 状態更新
+		Command(hWnd, CMD_REFRESH);
+		break;
+	}
+
+	if (alt)
+	{
+		switch (key)
+		{
+		case 'Q':
+			// 閉じる
+			Command(hWnd, CMD_QUIT);
+			break;
+		}
+	}
+
+	if (ctrl)
+	{
+		switch (key)
+		{
+		case 'G':
+			// スマートカードマネージャ
+			Command(hWnd, CMD_SECURE_MANAGER);
+			break;
+		case 'S':
+			// 状態の表示
+			Command(hWnd, CMD_STATUS);
+			break;
+		case 'I':
+			// すべての接続を切断
+			Command(hWnd, CMD_DISCONNECT_ALL);
+			break;
+		case 'D':
+			// 切断
+			Command(hWnd, CMD_DISCONNECT);
+			break;
+		case 'N':
+			// 接続設定の新規作成
+			Command(hWnd, CMD_NEW);
+			break;
+		case 'C':
+			// コピーの作成
+			Command(hWnd, CMD_CLONE);
+			break;
+		case 'T':
+			// スタートアップ接続に設定
+			Command(hWnd, CMD_STARTUP);
+			break;
+		case 'A':
+			// すべて選択
+			Command(hWnd, CMD_SELECT_ALL);
+			break;
+		case 'L':
+			// 新規仮想 LAN カードの作成
+			Command(hWnd, CMD_NEW_VLAN);
+			break;
+		case 'E':
+			// 仮想 LAN カードの有効化
+			Command(hWnd, CMD_ENABLE_VLAN);
+			break;
+		case 'B':
+			// 仮想 LAN カードの無効化
+			Command(hWnd, CMD_DISABLE_VLAN);
+			break;
+		case 'U':
+			// ドライバの再インストール
+			Command(hWnd, CMD_REINSTALL);
+			break;
+		case 'W':
+			// Windows ネットワーク接続の設定
+			Command(hWnd, CMD_WINNET);
+			break;
+		case 'P':
+			// パスワードの設定
+			Command(hWnd, CMD_PASSWORD);
+			break;
+		case 'O':
+			// オプション設定
+			Command(hWnd, CMD_TRAFFIC);
+			break;
+		case 'R':
+			// 証明書管理
+			Command(hWnd, CMD_TRUST);
+			break;
+		case 'Q':
+			// スループット
+			Command(hWnd, CMD_TRAFFIC);
+			break;
+		}
+	}
+}
+
+// メインウインドウのコマンド
+void CmMainWindowOnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+	CmMainWindowOnCommandEx(hWnd, wParam, lParam, false);
+}
+void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
+{
+	wchar_t *tmp;
+	char *name;
+	UINT index;
+	UINT id;
+	bool ctrl, alt;
+	UINT flag = 0;
+	// 引数チェック
+	wchar_t *selected_name = NULL;
+	UINT starter_id = 0;
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+	alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+
+	if (wParam == IDOK)
+	{
+		tmp = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+		if (tmp != NULL)
+		{
+			if (UniStrCmpi(tmp, _UU("CM_NEW_ICON")) == 0)
+			{
+				Free(tmp);
+				Command(hWnd, CMD_NEW);
+				return;
+			}
+			if (UniStrCmpi(tmp, _UU("CM_ASP")) == 0)
+			{
+				Free(tmp);
+				ShellExecuteA(hWnd, "open", _SS("CM_ASP_URL"), NULL, NULL, SW_SHOW);
+				return;
+			}
+			Free(tmp);
+		}
+	}
+
+	if (CmIsEnabled(hWnd, (UINT)wParam) == false)
+	{
+		return;
+	}
+
+	if (CM_TRAY_IS_CONNECT_ID(wParam))
+	{
+		// 接続要求
+		starter_id = CM_TRAY_MENU_CONNECT_ID_START;
+		flag = 1;
+	}
+
+	if (CM_TRAY_IS_STATUS_ID(wParam))
+	{
+		// 情報表示要求
+		starter_id = CM_TRAY_MENU_STATUS_ID_START;
+		flag = 2;
+	}
+
+	if (CM_TRAY_IS_DISCONNECT_ID(wParam))
+	{
+		// 切断要求
+		starter_id = CM_TRAY_MENU_DISCONNECT_ID_START;
+		flag = 3;
+	}
+
+	if (CM_TRAY_IS_RECENT_ID(wParam))
+	{
+		// 最近の接続先
+		starter_id = CM_TRAY_MENU_RECENT_ID_START;
+		flag = 1;
+	}
+
+	if (starter_id != 0)
+	{
+		UINT num;
+
+		id = (UINT)wParam - starter_id;
+
+		num = LvNum(hWnd, L_ACCOUNT);
+
+		if (id < num)
+		{
+			selected_name = LvGetStr(hWnd, L_ACCOUNT, id, 0);
+
+			if (selected_name != NULL)
+			{
+				if (UniStrCmpi(selected_name, _UU("CM_NEW_ICON")) != 0 &&
+					UniStrCmpi(selected_name, _UU("CM_ASP")) != 0)
+				{
+					switch (flag)
+					{
+					case 1:
+						CmConnect(hWnd, selected_name);
+						break;
+
+					case 2:
+						CmStatus(hWnd, selected_name);
+						break;
+
+					case 3:
+						CmDisconnect(hWnd, selected_name);
+						break;
+					}
+				}
+			}
+
+			Free(selected_name);
+		}
+	}
+
+	switch (wParam)
+	{
+	case IDOK:
+	case CMD_EASY_DBLCLICK:
+		// 接続またはプロパティ
+		if (IsFocus(hWnd, L_ACCOUNT) || (hWnd == cm->hEasyWnd))
+		{
+			// アカウントリストに関する操作
+			if (alt == false)
+			{
+				UINT index = LvGetSelected(hWnd, L_ACCOUNT);
+				bool b = false;
+				if (index != INFINITE)
+				{
+					wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, index, 1);
+					if (s != NULL)
+					{
+						if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+						{
+							b = true;
+						}
+						Free(s);
+					}
+				}
+
+				if (b == false)
+				{
+					// 接続
+					Command(hWnd, CMD_CONNECT);
+				}
+				else
+				{
+					if (hWnd != cm->hEasyWnd || wParam == CMD_EASY_DBLCLICK)
+					{
+						// 状況表示
+						Command(hWnd, CMD_STATUS);
+					}
+					else
+					{
+						// 切断
+						Command(hWnd, CMD_DISCONNECT);
+					}
+				}
+			}
+			else
+			{
+				// プロパティ
+				Command(hWnd, CMD_PROPERTY);
+			}
+		}
+		else
+		{
+			// Windows ネットワーク接続の設定
+			Command(hWnd, CMD_WINNET);
+		}
+		break;
+	case CMD_CONNECT:
+		// 接続
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			CmConnect(hWnd, tmp);
+			Free(tmp);
+		}
+		break;
+	case CMD_STATUS:
+		// 状態の表示
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			CmStatus(hWnd, tmp);
+			Free(tmp);
+		}
+		break;
+	case CMD_DISCONNECT_ALL:
+		// すべての接続を切断する
+		CmDisconnectAll(hWnd);
+		break;
+	case CMD_DISCONNECT:
+		// 切断
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			CmDisconnect(hWnd, tmp);
+			Free(tmp);
+		}
+		break;
+	case CMD_NEW:
+		// 新規作成
+		CmNewAccount(hWnd);
+		break;
+	case CMD_CLONE:
+		// コピー
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			CmCopyAccount(hWnd, tmp);
+			Free(tmp);
+		}
+		break;
+	case CMD_SHORTCUT:
+		// ショートカット作成
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			CmSortcut(hWnd, tmp);
+			Free(tmp);
+		}
+		break;
+	case CMD_EXPORT_ACCOUNT:
+		// 設定のエクスポート
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			CmExportAccount(hWnd, tmp);
+			Free(tmp);
+		}
+		break;
+	case CMD_IMPORT_ACCOUNT:
+		// 設定のインポート
+		CmImportAccount(hWnd);
+		break;
+	case CMD_STARTUP:
+		// スタートアップ接続に設定
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			RPC_CLIENT_DELETE_ACCOUNT c;
+			Zero(&c, sizeof(c));
+			UniStrCpy(c.AccountName, sizeof(c.AccountName), tmp);
+			CALL(hWnd, CcSetStartupAccount(cm->Client, &c));
+			CmVoice("set_startup");
+			MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_SET_STARTUP"), tmp);
+			Free(tmp);
+		}
+		break;
+	case CMD_NOSTARTUP:
+		// スタートアップ接続を解除
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+				_UU("CM_REMOVE_STARTUP"), tmp) == IDYES)
+			{
+				RPC_CLIENT_DELETE_ACCOUNT c;
+				Zero(&c, sizeof(c));
+				UniStrCpy(c.AccountName, sizeof(c.AccountName), tmp);
+				CALL(hWnd, CcRemoveStartupAccount(cm->Client, &c));
+				CmVoice("remove_startup");
+			}
+			Free(tmp);
+		}
+		break;
+	case CMD_DELETE:
+		// 削除
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			CmDeleteAccount(hWnd, tmp);
+			Free(tmp);
+		}
+		break;
+	case CMD_RENAME:
+		// 名前の変更
+		Focus(hWnd, L_ACCOUNT);
+		LvRename(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT));
+		break;
+	case CMD_PROPERTY:
+		// プロパティ
+		tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+		if (tmp != NULL)
+		{
+			CmEditAccount(hWnd, tmp);
+			Free(tmp);
+		}
+		break;
+	case IDCANCEL:
+	case CMD_EXIT:
+		// 閉じる
+		Close(hWnd);
+		break;
+	case CMD_QUIT:
+		// 終了
+		CmMainWindowOnQuit(hWnd);
+		break;
+	case CMD_SELECT_ALL:
+		// すべて選択
+		LvSelectAll(hWnd, L_ACCOUNT);
+		LvSelectAll(hWnd, L_VLAN);
+		break;
+	case CMD_SWITCH_SELECT:
+		// 選択反転
+		LvSwitchSelect(hWnd, L_ACCOUNT);
+		LvSwitchSelect(hWnd, L_VLAN);
+		break;
+	case CMD_GRID:
+		// 罫線表示
+		cm->ShowGrid = !cm->ShowGrid;
+		CmRefreshVLanListEx(hWnd, true);
+		CmRefreshAccountListEx2(hWnd, false, true);
+		break;
+	case CMD_STATUSBAR:
+		// ステータスバー表示
+		if (cm->HideStatusBar == false)
+		{
+			cm->HideStatusBar = true;
+			Hide(hWnd, S_STATUSBAR);
+			CmMainWindowOnSize(hWnd);
+		}
+		else
+		{
+			cm->HideStatusBar = false;
+			Show(hWnd, S_STATUSBAR);
+			CmMainWindowOnSize(hWnd);
+		}
+		CmSaveMainWindowPos(hWnd);
+		break;
+	case CMD_VISTASTYLE:
+		cm->VistaStyle = !cm->VistaStyle;
+		CmRefreshEx(hWnd, true);
+		CmSaveMainWindowPos(hWnd);
+		break;
+	case CMD_TRAYICON:
+		// トレイアイコン表示
+		if (cm->HideTrayIcon == false)
+		{
+			cm->HideTrayIcon = true;
+			CmFreeTray(hWnd);
+
+			if (IsHide(hWnd, 0))
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_TRAY_ICON_RESTORE"));
+			}
+		}
+		else
+		{
+			cm->HideTrayIcon = false;
+			if (cm->server_name == NULL)
+			{
+				CmInitTray(hWnd);
+			}
+		}
+		break;
+	case CMD_SHOWPORT:
+		// ポート番号を表示
+		cm->ShowPort = !cm->ShowPort;
+		CmRefresh(hWnd);
+		break;
+	case CMD_ICON:
+		// アイコン表示
+		if (cm->IconView == false)
+		{
+			cm->IconView = true;
+			CmRefresh(hWnd);
+		}
+		break;
+	case CMD_DETAIL:
+		// 詳細表示
+		if (cm->IconView)
+		{
+			cm->IconView = false;
+			CmRefresh(hWnd);
+		}
+		break;
+	case CMD_REFRESH:
+		if (easy == false)
+		{
+			// 表示更新
+			LvReset(hWnd, L_ACCOUNT);
+			LvReset(hWnd, L_VLAN);
+			CmRefresh(hWnd);
+		}
+		break;
+	case CMD_NEW_VLAN:
+		// 仮想 LAN カード作成
+		name = CmNewVLanDlg(hWnd);
+		if (name != NULL)
+		{
+			wchar_t tmp[MAX_SIZE];
+			void *helper = NULL;
+			RPC_CLIENT_CREATE_VLAN c;
+			Zero(&c, sizeof(c));
+			StrCpy(c.DeviceName, sizeof(c.DeviceName), name);
+			if (MsIsNt() == false)
+			{
+				// ウインドウのタイトルを変更する
+				GetTxt(hWnd, 0, tmp, sizeof(tmp));
+				SetText(hWnd, 0, _UU("CM_VLAN_INSTALLING"));
+			}
+			// 最小化
+			if (MsIsVista() == false)
+			{
+				ShowWindow(hWnd, SW_SHOWMINIMIZED);
+			}
+
+			if (MsIsVista())
+			{
+				helper = CmStartUacHelper();
+			}
+
+			if (CALL(hWnd, CcCreateVLan(cm->Client, &c)))
+			{
+				CmVoice("new_vlan");
+			}
+
+			CmStopUacHelper(helper);
+
+			if (MsIsNt() == false)
+			{
+				// ウインドウのタイトルを戻す
+				SetText(hWnd, 0, tmp);
+			}
+			// 戻す
+			if (MsIsVista() == false)
+			{
+				ShowWindow(hWnd, SW_SHOWNORMAL);
+			}
+			Free(name);
+		}
+		break;
+	case CMD_DELETE_VLAN:
+		// 仮想 LAN カード削除
+		index = LvGetSelected(hWnd, L_VLAN);
+		if (index != INFINITE)
+		{
+			if (cm->Client->Win9x == false)
+			{
+				// Windows 2000 以降
+				wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+				if (s != NULL)
+				{
+					RPC_CLIENT_CREATE_VLAN c;
+					char str[MAX_SIZE];
+					CmVoice("delete_vlan_1");
+					if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_VLAN"), s) == IDYES)
+					{
+						Zero(&c, sizeof(c));
+						UniToStr(str, sizeof(str), s);
+						if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+						{
+							if (CALL(hWnd, CcDeleteVLan(cm->Client, &c)))
+							{
+								CmVoice("delete_vlan_2");
+							}
+						}
+					}
+					Free(s);
+				}
+			}
+			else
+			{
+				// Windows 9x
+				if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_9X_VLAN_UNINSTALL")) == IDYES)
+				{
+					Run("rundll32.exe", "shell32.dll,Control_RunDLL NETCPL.CPL",
+						false, false);
+				}
+			}
+		}
+		break;
+	case CMD_ENABLE_VLAN:
+		// 仮想 LAN カードの有効化
+		index = LvGetSelected(hWnd, L_VLAN);
+		if (index != INFINITE)
+		{
+			wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+			if (s != NULL)
+			{
+				RPC_CLIENT_CREATE_VLAN c;
+				char str[MAX_SIZE];
+				Zero(&c, sizeof(c));
+				UniToStr(str, sizeof(str), s);
+				if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+				{
+					CALL(hWnd, CcEnableVLan(cm->Client, &c));
+				}
+				Free(s);
+			}
+		}
+		break;
+	case CMD_DISABLE_VLAN:
+		// 仮想 LAN カードの無効化
+		index = LvGetSelected(hWnd, L_VLAN);
+		if (index != INFINITE)
+		{
+			wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+			if (s != NULL)
+			{
+				RPC_CLIENT_CREATE_VLAN c;
+				char str[MAX_SIZE];
+				Zero(&c, sizeof(c));
+				UniToStr(str, sizeof(str), s);
+				if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+				{
+					CALL(hWnd, CcDisableVLan(cm->Client, &c));
+				}
+				Free(s);
+			}
+		}
+		break;
+	case CMD_REINSTALL:
+		// 仮想 LAN カードの再インストール
+		index = LvGetSelected(hWnd, L_VLAN);
+		if (index != INFINITE)
+		{
+			wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+			if (s != NULL)
+			{
+				RPC_CLIENT_CREATE_VLAN c;
+				char str[MAX_SIZE];
+				Zero(&c, sizeof(c));
+				UniToStr(str, sizeof(str), s);
+				if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+				{
+					void *helper = NULL;
+
+					if (MsIsVista() == false)
+					{
+						ShowWindow(hWnd, SW_SHOWMINIMIZED);
+					}
+
+					if (MsIsVista())
+					{
+						helper = CmStartUacHelper();
+					}
+
+					CALL(hWnd, CcUpgradeVLan(cm->Client, &c));
+
+					CmStopUacHelper(helper);
+
+					if (MsIsVista() == false)
+					{
+						ShowWindow(hWnd, SW_SHOWNORMAL);
+					}
+				}
+				Free(s);
+			}
+		}
+		break;
+	case CMD_PASSWORD:
+		// パスワード設定
+		CmPassword(hWnd);
+		break;
+	case CMD_OPTION:
+		// オプション
+		CmConfigDlg(hWnd);
+		break;
+	case CMD_TRUST:
+		// 証明書管理
+		CmTrustDlg(hWnd);
+		break;
+	case CMD_ABOUT:
+		// バージョン情報
+		if (IsEnable(hWnd, 0))
+		{
+			ShowSplashEx(hWnd, "UT-VPN Client", 0, CM_SPLASH_BORDER_COLOR);
+		}
+		break;
+	case CMD_VOIDE_NONE:
+		cm->DisableVoice = true;
+		break;
+	case CMD_VOICE_NORMAL:
+		cm->DisableVoice = false;
+		cm->VoiceId = VOICE_SSK;
+		break;
+	case CMD_VOICE_ODD:
+		if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_EXT_VOICE_MSG")) == IDYES)
+		{
+			cm->DisableVoice = false;
+			cm->VoiceId = VOICE_AHO;
+		}
+		break;
+	case CMD_SECURE_MANAGER:
+		// スマートカードマネージャ
+		CmClientSecureManager(hWnd);
+		break;
+	case CMD_SECURE_SELECT:
+		// スマートカードの選択
+		CmClientSelectSecure(hWnd);
+		break;
+	case CMD_NETIF:
+		// ネットワークデバイスの状態
+		if (IsEnable(hWnd, 0))
+		{
+			UtSpeedMeterEx(hWnd);
+		}
+		break;
+	case CMD_TCPIP:
+		// TCP/IP 最適化ユーティリティ
+		if (IsEnable(hWnd, 0))
+		{
+			ShowTcpIpConfigUtil(hWnd, true);
+		}
+		break;
+	case CMD_MMCSS:
+		// Windows Vista 用最適化ユーティリティ
+		if (MsIsVista() == false)
+		{
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_4"));
+		}
+		else
+		{
+			if (MsIsAdmin() == false)
+			{
+				MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("VISTA_MMCSS_MSG_4"));
+			}
+			else
+			{
+				if (MsIsMMCSSNetworkThrottlingEnabled())
+				{
+					if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("VISTA_MMCSS_MSG")) == IDYES)
+					{
+						MsSetMMCSSNetworkThrottlingEnable(false);
+						MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_5"));
+					}
+				}
+				else
+				{
+					if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("VISTA_MMCSS_MSG_2")) == IDYES)
+					{
+						MsSetMMCSSNetworkThrottlingEnable(true);
+						MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_6"));
+					}
+				}
+			}
+		}
+		break;
+	case CMD_TRAFFIC:
+		// 通信トラフィック測定
+		if (IsEnable(hWnd, 0))
+		{
+			CmTraffic(hWnd);
+		}
+		break;
+	case CMD_CM_SETTING:
+		// 動作モード設定
+		if (IsEnable(hWnd, 0))
+		{
+			if (CmSetting(hWnd))
+			{
+				CmApplyCmSetting();
+			}
+		}
+		break;
+	case CMD_WINNET:
+		// Windows ネットワークの設定
+		ShowWindowsNetworkConnectionDialog();
+		break;
+	}
+}
+
+// オプション設定ダイアログ
+void CmConfigDlg(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_CM_CONFIG, CmConfigDlgProc, NULL);
+}
+
+// オプション設定ダイアログの初期化
+void CmConfigDlgInit(HWND hWnd)
+{
+	bool use_alpha;
+	UINT alpha_value;
+	UINT os;
+	CLIENT_CONFIG c;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	DlgFont(hWnd, S_WARNING, 10, true);
+	DlgFont(hWnd, S_INFO, 10, false);
+
+	Zero(&c, sizeof(c));
+	if (CALL(hWnd, CcGetClientConfig(cm->Client, &c)) == false)
+	{
+		EndDialog(hWnd, 0);
+		return;
+	}
+
+	Check(hWnd, R_ALLOW_REMOTE_CONFIG, c.AllowRemoteConfig);
+
+	Check(hWnd, R_USE_KEEP_CONNECT, c.UseKeepConnect);
+	SetTextA(hWnd, E_HOSTNAME, c.KeepConnectHost);
+	SetIntEx(hWnd, E_PORT, c.KeepConnectPort);
+	SetIntEx(hWnd, E_INTERVAL, c.KeepConnectInterval);
+
+	Check(hWnd, R_TCP, c.KeepConnectProtocol == CONNECTION_TCP);
+	Check(hWnd, R_UDP, c.KeepConnectProtocol == CONNECTION_UDP);
+
+	use_alpha = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha") == 0 ? false : true;
+	alpha_value = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue");
+	alpha_value = MAKESURE(alpha_value, 0, 100);
+
+	SetInt(hWnd, E_ALPHA_VALUE, alpha_value == 0 ? 50 : alpha_value);
+	Check(hWnd, R_ALPHA, use_alpha);
+
+	os = GetOsInfo()->OsType;
+	if (OS_IS_WINDOWS_NT(os) && GET_KETA(os, 100) >= 2)
+	{
+		Enable(hWnd, R_ALPHA);
+	}
+	else
+	{
+		Disable(hWnd, R_ALPHA);
+	}
+
+	CmConfigDlgRefresh(hWnd);
+}
+
+// オプション設定ダイアログの更新
+void CmConfigDlgRefresh(HWND hWnd)
+{
+	bool ok = true;
+	bool use_keep_connect;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	use_keep_connect = IsChecked(hWnd, R_USE_KEEP_CONNECT);
+	SetEnable(hWnd, S_HOSTNAME, use_keep_connect);
+	SetEnable(hWnd, S_PORT, use_keep_connect);
+	SetEnable(hWnd, S_INTERVAL, use_keep_connect);
+	SetEnable(hWnd, S_INTERVAL2, use_keep_connect);
+	SetEnable(hWnd, S_PROTOCOL, use_keep_connect);
+	SetEnable(hWnd, S_INFO, use_keep_connect);
+	SetEnable(hWnd, S_INFO2, use_keep_connect);
+	SetEnable(hWnd, E_HOSTNAME, use_keep_connect);
+	SetEnable(hWnd, E_PORT, use_keep_connect);
+	SetEnable(hWnd, E_INTERVAL, use_keep_connect);
+	SetEnable(hWnd, R_TCP, use_keep_connect);
+	SetEnable(hWnd, R_UDP, use_keep_connect);
+
+	SetEnable(hWnd, S_WARNING, IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG));
+
+	if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+	{
+		if (IsEmpty(hWnd, E_HOSTNAME))
+		{
+			ok = false;
+		}
+		if (IsChecked(hWnd, R_TCP) == false && IsChecked(hWnd, R_UDP) == false)
+		{
+			ok = false;
+		}
+		if (GetInt(hWnd, E_PORT) == 0 || GetInt(hWnd, E_PORT) >= 65536)
+		{
+			ok = false;
+		}
+		if (GetInt(hWnd, E_INTERVAL) == 0)
+		{
+			ok = false;
+		}
+	}
+
+	if (IsChecked(hWnd, R_ALPHA))
+	{
+		UINT i = GetInt(hWnd, E_ALPHA_VALUE);
+		if (i < 20 || i >= 100)
+		{
+			ok = false;
+		}
+		Enable(hWnd, E_ALPHA_VALUE);
+	}
+	else
+	{
+		Disable(hWnd, E_ALPHA_VALUE);
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// オプション設定ダイアログの設定保存
+void CmConfigDlgOnOk(HWND hWnd)
+{
+	CLIENT_CONFIG c;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	Zero(&c, sizeof(c));
+	c.AllowRemoteConfig = IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG);
+	c.UseKeepConnect = IsChecked(hWnd, R_USE_KEEP_CONNECT);
+	GetTxtA(hWnd, E_HOSTNAME, c.KeepConnectHost, sizeof(c.KeepConnectHost));
+	c.KeepConnectPort = GetInt(hWnd, E_PORT);
+	c.KeepConnectInterval = GetInt(hWnd, E_INTERVAL);
+	if (IsChecked(hWnd, R_TCP))
+	{
+		c.KeepConnectProtocol = CONNECTION_TCP;
+	}
+	else if (IsChecked(hWnd, R_UDP))
+	{
+		c.KeepConnectProtocol = CONNECTION_UDP;
+	}
+	else
+	{
+		return;
+	}
+
+	if (c.UseKeepConnect)
+	{
+		if (c.KeepConnectInterval < KEEP_INTERVAL_MIN || c.KeepConnectInterval > KEEP_INTERVAL_MAX)
+		{
+			MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_KEEP_INTERVAL_MSG"),
+				KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX);
+			FocusEx(hWnd, E_INTERVAL);
+			return;
+		}
+	}
+
+	if (CALL(hWnd, CcSetClientConfig(cm->Client, &c)) == false)
+	{
+		return;
+	}
+
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue", GetInt(hWnd, E_ALPHA_VALUE));
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha", IsChecked(hWnd, R_ALPHA));
+
+	EndDialog(hWnd, true);
+}
+
+// オプション設定ダイアログプロシージャ
+UINT CmConfigDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmConfigDlgInit(hWnd);
+		break;
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_ALLOW_REMOTE_CONFIG:
+		case R_USE_KEEP_CONNECT:
+		case E_HOSTNAME:
+		case E_PORT:
+		case E_INTERVAL:
+		case R_ALPHA:
+		case E_ALPHA_VALUE:
+			CmConfigDlgRefresh(hWnd);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			CmConfigDlgRefresh(hWnd);
+			CmConfigDlgOnOk(hWnd);
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		case R_ALLOW_REMOTE_CONFIG:
+			if (IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG) == false)
+			{
+				if (cm->server_name != NULL)
+				{
+					// 現在リモート接続している場合、リモート管理を無効にするように
+					// 選択すると警告を表示する
+					if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_YESNO, _UU("CM_REMOTE_WARNING"),
+						cm->server_name, cm->server_name) == IDNO)
+					{
+						Check(hWnd, R_ALLOW_REMOTE_CONFIG, true);
+					}
+				}
+			}
+			break;
+		case R_USE_KEEP_CONNECT:
+			if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+			{
+				FocusEx(hWnd, E_HOSTNAME);
+			}
+			break;
+		case R_ALPHA:
+			if (IsChecked(hWnd, R_ALPHA))
+			{
+				FocusEx(hWnd, E_ALPHA_VALUE);
+			}
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ショートカット作成
+void CmSortcut(HWND hWnd, wchar_t *account_name)
+{
+	wchar_t tmp[MAX_SIZE];
+	CM_ACCOUNT *a;
+	wchar_t *filename;
+	UCHAR key[SHA1_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+
+	// アカウント情報を取得
+	a = CmGetExistAccountObject(hWnd, account_name);
+	if (a == NULL)
+	{
+		return;
+	}
+
+	Copy(key, a->ShortcutKey, SHA1_SIZE);
+
+	if (IsZero(key, SHA1_SIZE))
+	{
+		MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_SHORTCUT_UNSUPPORTED"));
+	}
+	else
+	{
+		// ファイル名を決定
+		UniFormat(tmp, sizeof(tmp), L"%s.lnk", account_name);
+		UniSafeFileName(tmp);
+
+		filename = SaveDlg(hWnd, _UU("CM_SHORTCUT_FILE"),
+			_UU("CM_SHORTCUT_SAVE_TITLE"), tmp, L".uvpn");
+
+		if (filename != NULL)
+		{
+			char key_str[64];
+			wchar_t target[MAX_PATH];
+			wchar_t workdir[MAX_PATH];
+			wchar_t args[MAX_PATH];
+			wchar_t comment[MAX_SIZE];
+			wchar_t icon[MAX_PATH];
+
+			BinToStr(key_str, sizeof(key_str), key, SHA1_SIZE);
+
+			// ショートカットを作成
+			UniStrCpy(target, sizeof(target), MsGetExeFileNameW());
+			UniStrCpy(workdir, sizeof(workdir), MsGetExeDirNameW());
+			StrToUni(args, sizeof(args), key_str);
+			UniFormat(comment, sizeof(comment), _UU("CM_SHORTCUT_COMMENT"), account_name);
+			UniStrCpy(icon, sizeof(icon), MsGetExeFileNameW());
+
+			if (CreateLink(tmp, target, workdir, args, comment, icon, 1) == false)
+			{
+				MsgBox(hWnd, MB_ICONSTOP, _UU("CM_SHORTCUT_ERROR"));
+			}
+
+			Free(filename);
+		}
+	}
+
+	CmFreeAccountObject(hWnd, a);
+}
+
+// アカウントのエクスポート
+void CmExportAccount(HWND hWnd, wchar_t *account_name)
+{
+	wchar_t tmp[MAX_SIZE];
+	CM_ACCOUNT *a;
+	wchar_t *filename;
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+
+	// アカウント情報を取得
+	a = CmGetExistAccountObject(hWnd, account_name);
+	if (a == NULL)
+	{
+		return;
+	}
+
+	// ファイル名を決定
+	UniFormat(tmp, sizeof(tmp), L"%s.uvpn", account_name);
+	UniSafeFileName(tmp);
+
+	filename = SaveDlg(hWnd, _UU("CM_ACCOUNT_SETTING_FILE"),
+		_UU("CM_ACCOUNT_SAVE_TITLE"), tmp, L".uvpn");
+
+	if (filename != NULL)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT t;
+		BUF *b;
+		BUF *b2;
+		wchar_t tmp[MAX_SIZE];
+		UCHAR *buf;
+		UINT buf_size;
+		UCHAR bom[] = {0xef, 0xbb, 0xbf, };
+
+		Zero(&t, sizeof(t));
+		t.ClientOption = a->ClientOption;
+		t.ClientAuth = a->ClientAuth;
+		t.StartupAccount = a->Startup;
+		t.CheckServerCert = a->CheckServerCert;
+		t.ServerCert = a->ServerCert;
+		t.ClientOption->FromAdminPack = false;
+
+		b = CiAccountToCfg(&t);
+
+		UniStrCpy(tmp, sizeof(tmp), filename);
+		b2 = NewBuf();
+
+		WriteBuf(b2, bom, sizeof(bom));
+
+		// ヘッダ部分を付加する
+		buf_size = CalcUniToUtf8(_UU("CM_ACCOUNT_FILE_BANNER"));
+		buf = ZeroMalloc(buf_size + 32);
+		UniToUtf8(buf, buf_size, _UU("CM_ACCOUNT_FILE_BANNER"));
+
+		WriteBuf(b2, buf, StrLen((char *)buf));
+		WriteBuf(b2, b->Buf, b->Size);
+		SeekBuf(b2, 0, 0);
+
+		FreeBuf(b);
+
+		if (DumpBufW(b2, tmp) == false)
+		{
+			MsgBox(hWnd, MB_ICONSTOP, _UU("CM_FAILED_TO_SAVE_FILE"));
+		}
+
+		Free(filename);
+		FreeBuf(b2);
+		Free(buf);
+	}
+
+	CmFreeAccountObject(hWnd, a);
+}
+
+// アカウントのインポートメイン処理
+void CmImportAccountMain(HWND hWnd, wchar_t *filename)
+{
+	CmImportAccountMainEx(hWnd, filename, false);
+}
+void CmImportAccountMainEx(HWND hWnd, wchar_t *filename, bool overwrite)
+{
+	wchar_t name[MAX_SIZE];
+	wchar_t tmp[MAX_SIZE];
+	BUF *b;
+	RPC_CLIENT_CREATE_ACCOUNT *t;
+	// 引数チェック
+	if (hWnd == NULL || filename == NULL)
+	{
+		return;
+	}
+
+	UniStrCpy(tmp, sizeof(tmp), filename);
+
+	b = ReadDumpW(tmp);
+	if (b == NULL)
+	{
+		MsgBox(hWnd, MB_ICONSTOP, _UU("CM_FAILED_TO_OPEN_FILE"));
+		return;
+	}
+
+	t = CiCfgToAccount(b);
+	if (t == NULL)
+	{
+		FreeBuf(b);
+		MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("CM_ACCOUNT_PARSE_FAILED"));
+		return;
+	}
+
+	if (overwrite)
+	{
+		// すでに同一名が存在する場合は削除する
+		if (LvSearchStr(hWnd, L_ACCOUNT, 0, t->ClientOption->AccountName) != INFINITE)
+		{
+			RPC_CLIENT_DELETE_ACCOUNT d;
+			RPC_CLIENT_GET_ACCOUNT get;
+			HWND h = cm->hEasyWnd == NULL ? hWnd : cm->hEasyWnd;
+
+			Zero(&d, sizeof(d));
+			UniStrCpy(d.AccountName, sizeof(d.AccountName), t->ClientOption->AccountName);
+
+			Zero(&get, sizeof(get));
+			UniStrCpy(get.AccountName, sizeof(get.AccountName), t->ClientOption->AccountName);
+			if (CcGetAccount(cm->Client, &get) == ERR_NO_ERROR)
+			{
+				// すでに存在する同一名のアカウント情報を取得して
+				// クライアントオプションのうちいくつかの情報を継承する
+				if (get.ClientOption != NULL && get.ClientAuth != NULL)
+				{
+					CLIENT_OPTION *old_option = get.ClientOption;
+					CLIENT_AUTH *old_auth = get.ClientAuth;
+
+					// 接続パラメータの継承
+					t->ClientOption->ProxyType = old_option->ProxyType;
+					StrCpy(t->ClientOption->ProxyName, sizeof(t->ClientOption->ProxyName),
+						old_option->ProxyName);
+					t->ClientOption->ProxyPort = old_option->ProxyPort;
+					StrCpy(t->ClientOption->ProxyUsername, sizeof(t->ClientOption->ProxyUsername),
+						old_option->ProxyUsername);
+					StrCpy(t->ClientOption->ProxyPassword, sizeof(t->ClientOption->ProxyPassword),
+						old_option->ProxyPassword);
+					t->ClientOption->NumRetry = old_option->NumRetry;
+					t->ClientOption->RetryInterval = old_option->RetryInterval;
+					t->ClientOption->MaxConnection = old_option->MaxConnection;
+					t->ClientOption->UseEncrypt = old_option->UseEncrypt;
+					t->ClientOption->UseCompress = old_option->UseCompress;
+					t->ClientOption->HalfConnection = old_option->HalfConnection;
+					t->ClientOption->NoRoutingTracking = old_option->NoRoutingTracking;
+					StrCpy(t->ClientOption->DeviceName, sizeof(t->ClientOption->DeviceName),
+						old_option->DeviceName);
+					t->ClientOption->AdditionalConnectionInterval = old_option->AdditionalConnectionInterval;
+					t->ClientOption->ConnectionDisconnectSpan = old_option->ConnectionDisconnectSpan;
+					t->ClientOption->HideStatusWindow = old_option->HideStatusWindow;
+					t->ClientOption->RequireMonitorMode = old_option->RequireMonitorMode;
+					t->ClientOption->RequireBridgeRoutingMode = old_option->RequireBridgeRoutingMode;
+					t->ClientOption->DisableQoS = old_option->DisableQoS;
+					t->ClientOption->NoTls1 = old_option->NoTls1;
+
+					// 認証データの継承
+					CiFreeClientAuth(t->ClientAuth);
+					t->ClientAuth = CopyClientAuth(old_auth);
+
+					// その他の設定
+					t->StartupAccount = get.StartupAccount;
+					t->CheckServerCert = get.CheckServerCert;
+					if (t->ServerCert != NULL)
+					{
+						FreeX(t->ServerCert);
+					}
+					t->ServerCert = NULL;
+					if (get.ServerCert != NULL)
+					{
+						t->ServerCert = CloneX(get.ServerCert);
+					}
+					Copy(t->ShortcutKey, get.ShortcutKey, sizeof(t->ShortcutKey));
+				}
+
+				CiFreeClientGetAccount(&get);
+			}
+
+			if (CALL(h, CcDeleteAccount(cm->Client, &d)) == false)
+			{
+				CiFreeClientCreateAccount(t);
+				Free(t);
+				return;
+			}
+
+			CmRefreshAccountList(hWnd);
+		}
+	}
+
+	CmGenerateImportName(hWnd, name, sizeof(name), t->ClientOption->AccountName);
+	UniStrCpy(t->ClientOption->AccountName, sizeof(t->ClientOption->AccountName), name);
+
+	if (overwrite)
+	{
+		t->ClientOption->FromAdminPack = true;
+	}
+
+	CALL(hWnd, CcCreateAccount(cm->Client, t));
+
+	CiFreeClientCreateAccount(t);
+	Free(t);
+
+	FreeBuf(b);
+
+	if (overwrite)
+	{
+		// VPN 接続を開始する
+		CmConnect(hWnd, name);
+	}
+
+	//MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_IMPORT_MESSAGE"), filename, name);
+}
+
+// アカウントのインポート
+void CmImportAccount(HWND hWnd)
+{
+	wchar_t *filename;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// ファイルを開く
+	filename = OpenDlg(hWnd, _UU("CM_ACCOUNT_SETTING_FILE"), _UU("CM_ACCOUNT_OPEN_TITLE"));
+	if (filename == NULL)
+	{
+		return;
+	}
+
+	UniStrCpy(tmp, sizeof(tmp), filename);
+	Free(filename);
+
+	CmImportAccountMain(hWnd, tmp);
+}
+
+// アカウントのコピーの作成
+void CmCopyAccount(HWND hWnd, wchar_t *account_name)
+{
+	wchar_t tmp[MAX_SIZE];
+	CM_ACCOUNT *a;
+	RPC_CLIENT_CREATE_ACCOUNT c;
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+
+	CmGenerateCopyName(hWnd, tmp, sizeof(tmp), account_name);
+
+	// アカウント情報を取得
+	a = CmGetExistAccountObject(hWnd, account_name);
+	if (a == NULL)
+	{
+		return;
+	}
+
+	// アカウント名を変更
+	UniStrCpy(a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName), tmp);
+
+	// 書き込み
+	Zero(&c, sizeof(c));
+	c.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	Copy(c.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+	c.ClientAuth = CopyClientAuth(a->ClientAuth);
+	if (a->ServerCert)
+	{
+		c.ServerCert = CloneX(a->ServerCert);
+	}
+	c.CheckServerCert = a->CheckServerCert;
+	c.StartupAccount = false;		// スタートアップ属性はコピーしない
+
+	CALL(hWnd, CcCreateAccount(cm->Client, &c));
+	CiFreeClientCreateAccount(&c);
+
+	CmFreeAccountObject(hWnd, a);
+}
+
+// 仮想 LAN カード名ダイアログ更新
+void CmNewVLanDlgUpdate(HWND hWnd)
+{
+	bool ok = true;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	GetTxtA(hWnd, E_NAME, tmp, sizeof(tmp));
+	if (IsSafeStr(tmp) == false)
+	{
+		ok = false;
+	}
+	Trim(tmp);
+	if (StrLen(tmp) == 0)
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// 仮想 LAN カード名決定ダイアログプロシージャ
+UINT CmNewVLanDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	char *tmp = (char *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		LimitText(hWnd, E_NAME, cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN);
+		FormatText(hWnd, S_INFO, cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN);
+		CmNewVLanDlgUpdate(hWnd);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (cm->Client->Win9x)
+			{
+				// Windows 9x の場合、確認メッセージを出す
+				if (MsgBox(hWnd, MB_ICONQUESTION | MB_OKCANCEL, _UU("CM_9X_VLAN_INSTALL")) == IDCANCEL)
+				{
+					break;
+				}
+			}
+			GetTxtA(hWnd, E_NAME, tmp, (cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN) + 1);
+			Trim(tmp);
+			EndDialog(hWnd, true);
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		switch (LOWORD(wParam))
+		{
+		case E_NAME:
+			CmNewVLanDlgUpdate(hWnd);
+			break;
+
+		case R_USE_DISCONNECT:
+			if (IsChecked(hWnd, R_USE_DISCONNECT))
+			{
+				FocusEx(hWnd, E_DISCONNECT_SPAN);
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 新しい仮想 LAN カード名を決定するダイアログ
+char *CmNewVLanDlg(HWND hWnd)
+{
+	char tmp[MAX_DEVICE_NAME_LEN + 1];
+
+	if (Dialog(hWnd, D_CM_NEW_VLAN, CmNewVLanDlgProc, tmp) == false)
+	{
+		return NULL;
+	}
+
+	return CopyStr(tmp);
+}
+
+// 詳細設定ダイアログ更新
+void CmDetailDlgUpdate(HWND hWnd, CM_ACCOUNT *a)
+{
+	bool ok = true;
+	bool locked;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	locked = a->LockMode;
+
+	if (a->LinkMode || a->NatMode)
+	{
+		Disable(hWnd, R_NO_ROUTING);
+	}
+	else
+	{
+		if (cm->Client->Unix)
+		{
+			Disable(hWnd, R_NO_ROUTING);
+		}
+	}
+
+	SetEnable(hWnd, E_DISCONNECT_SPAN, IsChecked(hWnd, R_USE_DISCONNECT));
+
+	SetEnable(hWnd, IDOK, ok);
+
+	if (locked)
+	{
+		Disable(hWnd, C_NUM_TCP);
+		Disable(hWnd, S_STATIC5);
+		Disable(hWnd, S_STATIC8);
+		Disable(hWnd, E_INTERVAL);
+		Disable(hWnd, S_STATIC9);
+		Disable(hWnd, E_DISCONNECT_SPAN);
+		Disable(hWnd, S_STATIC10);
+		Disable(hWnd, S_STATIC11);
+		Disable(hWnd, R_USE_DISCONNECT);
+		Disable(hWnd, R_USE_HALF_CONNECTION);
+		Disable(hWnd, R_DISABLE_QOS);
+		Disable(hWnd, R_USE_ENCRYPT);
+		Disable(hWnd, R_USE_COMPRESS);
+		Disable(hWnd, R_BRIDGE);
+		Disable(hWnd, R_MONITOR);
+		Disable(hWnd, R_NO_ROUTING);
+	}
+}
+
+// 詳細設定ダイアログプロシージャ
+UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CM_ACCOUNT *a = (CM_ACCOUNT *)param;
+	UINT i;
+	UINT num;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// TCP コネクション本数
+		for (i = 1;i <= MAX_TCP_CONNECTION;i++)
+		{
+			UniFormat(tmp, sizeof(tmp), L"%u", i);
+			CbAddStr(hWnd, C_NUM_TCP, tmp, i);
+		}
+		CbSelect(hWnd, C_NUM_TCP, a->ClientOption->MaxConnection);
+
+		// コネクション確立間隔
+		SetInt(hWnd, E_INTERVAL, a->ClientOption->AdditionalConnectionInterval);
+
+		// 寿命
+		SetIntEx(hWnd, E_DISCONNECT_SPAN, a->ClientOption->ConnectionDisconnectSpan);
+		Check(hWnd, R_USE_DISCONNECT, a->ClientOption->ConnectionDisconnectSpan != 0);
+		Check(hWnd, R_USE_HALF_CONNECTION, a->ClientOption->HalfConnection);
+		Check(hWnd, R_USE_ENCRYPT, a->ClientOption->UseEncrypt);
+		Check(hWnd, R_USE_COMPRESS, a->ClientOption->UseCompress);
+		Check(hWnd, R_NO_ROUTING, a->ClientOption->NoRoutingTracking);
+		Check(hWnd, R_DISABLE_QOS, a->ClientOption->DisableQoS);
+
+		// 接続モードの選択
+		if (a->LinkMode == false)
+		{
+			Check(hWnd, R_BRIDGE, a->ClientOption->RequireBridgeRoutingMode);
+			Check(hWnd, R_MONITOR, a->ClientOption->RequireMonitorMode);
+		}
+		else
+		{
+			Check(hWnd, R_BRIDGE, true);
+			Check(hWnd, R_MONITOR, false);
+
+			SetText(hWnd, S_MODE, _UU("CM_DETAIL_MODE_LINK_STR"));
+			Disable(hWnd, R_BRIDGE);
+			Disable(hWnd, R_MONITOR);
+		}
+
+		CmDetailDlgUpdate(hWnd, a);
+		Focus(hWnd, IDOK);
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (IsChecked(hWnd, R_USE_DISCONNECT) && GetInt(hWnd, E_DISCONNECT_SPAN) == 0)
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_NO_DISCONNECT_SPAN"));
+				FocusEx(hWnd, E_DISCONNECT_SPAN);
+				break;
+			}
+			num = GetInt(hWnd, C_NUM_TCP);
+			if (num == 0)
+			{
+				break;
+			}
+			if (num == 1 && IsChecked(hWnd, R_USE_HALF_CONNECTION))
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_HALF_MSG"));
+				Focus(hWnd, C_NUM_TCP);
+				break;
+			}
+			if (GetInt(hWnd, E_INTERVAL) < 1)
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_TOO_SMALL_INTERVAL"));
+				Focus(hWnd, E_INTERVAL);
+				break;
+			}
+
+			a->ClientOption->MaxConnection = num;
+			a->ClientOption->AdditionalConnectionInterval = GetInt(hWnd, E_INTERVAL);
+			if (IsChecked(hWnd, R_USE_DISCONNECT) == false)
+			{
+				a->ClientOption->ConnectionDisconnectSpan = 0;
+			}
+			else
+			{
+				a->ClientOption->ConnectionDisconnectSpan = GetInt(hWnd, E_DISCONNECT_SPAN);
+			}
+			a->ClientOption->HalfConnection = IsChecked(hWnd, R_USE_HALF_CONNECTION);
+			a->ClientOption->UseEncrypt = IsChecked(hWnd, R_USE_ENCRYPT);
+			a->ClientOption->UseCompress = IsChecked(hWnd, R_USE_COMPRESS);
+			a->ClientOption->NoRoutingTracking = IsChecked(hWnd, R_NO_ROUTING);
+			a->ClientOption->DisableQoS = IsChecked(hWnd, R_DISABLE_QOS);
+
+			if (a->LinkMode)
+			{
+				a->ClientOption->RequireBridgeRoutingMode = true;
+				a->ClientOption->RequireMonitorMode = false;
+			}
+			else
+			{
+				a->ClientOption->RequireBridgeRoutingMode = IsChecked(hWnd, R_BRIDGE);
+				a->ClientOption->RequireMonitorMode = IsChecked(hWnd, R_MONITOR);
+			}
+
+			EndDialog(hWnd, true);
+
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		switch (LOWORD(wParam))
+		{
+		case C_NUM_TCP:
+		case E_INTERVAL:
+		case E_DISCONNECT_SPAN:
+		case R_USE_DISCONNECT:
+		case R_USE_HALF_CONNECTION:
+			CmDetailDlgUpdate(hWnd, a);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 詳細設定ダイアログ
+bool CmDetailDlg(HWND hWnd, CM_ACCOUNT *a)
+{
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	return Dialog(hWnd, D_CM_DETAIL, CmDetailDlgProc, a);
+}
+
+// アカウント編集ダイアログプロシージャ更新
+void CmEditAccountDlgUpdate(HWND hWnd, CM_ACCOUNT *a)
+{
+	bool ok = true;
+	char str[MAX_SIZE];
+	bool locked;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	locked = a->LockMode;
+
+	if (a->Inited == false)
+	{
+		return;
+	}
+
+	if (a->EditMode)
+	{
+		Disable(hWnd, E_ACCOUNT_NAME);
+	}
+
+	// 接続設定名
+	GetTxt(hWnd, E_ACCOUNT_NAME, a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName));
+	UniTrim(a->ClientOption->AccountName);
+
+	// ホスト名
+	GetTxtA(hWnd, E_HOSTNAME, a->ClientOption->Hostname, sizeof(a->ClientOption->Hostname));
+	Trim(a->ClientOption->Hostname);
+
+	// ポート番号
+	a->ClientOption->Port = GetInt(hWnd, C_PORT);
+
+	// HUB 名
+	GetTxtA(hWnd,C_HUBNAME, a->ClientOption->HubName, sizeof(a->ClientOption->HubName));
+
+	// プロキシの種類
+	a->ClientOption->ProxyType = PROXY_DIRECT;
+	if (IsChecked(hWnd, R_HTTPS))
+	{
+		a->ClientOption->ProxyType = PROXY_HTTP;
+	}
+	if (IsChecked(hWnd, R_SOCKS))
+	{
+		a->ClientOption->ProxyType = PROXY_SOCKS;
+	}
+
+	// サーバー証明書検証
+	a->CheckServerCert = IsChecked(hWnd, R_CHECK_CERT);
+
+	if (a->NatMode)
+	{
+		Disable(hWnd, R_CHECK_CERT);
+		Disable(hWnd, B_TRUST);
+	}
+
+	if (a->HideTrustCert)
+	{
+		Disable(hWnd, B_TRUST);
+	}
+
+	// デバイス名
+	StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), "");
+	if (LvIsSelected(hWnd, L_VLAN))
+	{
+		wchar_t *s = LvGetStr(hWnd, L_VLAN, LvGetSelected(hWnd, L_VLAN), 0);
+		if (s != NULL)
+		{
+			char str[MAX_SIZE];
+			UniToStr(str, sizeof(str), s);
+			CmPrintNameToVLanName(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), str);
+			Free(s);
+		}
+	}
+
+	// ユーザー認証
+	a->ClientAuth->AuthType = CbGetSelect(hWnd, C_TYPE);
+	GetTxtA(hWnd, E_USERNAME, a->ClientAuth->Username, sizeof(a->ClientAuth->Username));
+	Trim(a->ClientAuth->Username);
+	switch (a->ClientAuth->AuthType)
+	{
+	case CLIENT_AUTHTYPE_PASSWORD:
+		// パスワード認証
+		GetTxtA(hWnd, E_PASSWORD, str, sizeof(str));
+		if (StrCmp(str, HIDDEN_PASSWORD) != 0)
+		{
+			HashPassword(a->ClientAuth->HashedPassword, a->ClientAuth->Username, str);
+		}
+		break;
+	case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+		// 平文パスワード認証
+		GetTxtA(hWnd, E_PASSWORD, str, sizeof(str));
+		if (StrCmp(str, HIDDEN_PASSWORD) != 0)
+		{
+			StrCpy(a->ClientAuth->PlainPassword, sizeof(a->ClientAuth->PlainPassword), str);
+		}
+		break;
+	}
+
+	// 再接続オプション
+	if ((a->LinkMode || a->NatMode) || a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+	{
+		Disable(hWnd, R_RETRY);
+	}
+	else
+	{
+		Enable(hWnd, R_RETRY);
+	}
+
+	if (IsChecked(hWnd, R_RETRY) == false)
+	{
+		a->ClientOption->NumRetry = 0;
+	}
+	else
+	{
+		if (IsChecked(hWnd, R_INFINITE))
+		{
+			a->ClientOption->NumRetry = INFINITE;
+		}
+		else
+		{
+			a->ClientOption->NumRetry = GetInt(hWnd, E_RETRY_NUM);
+		}
+	}
+	a->ClientOption->RetryInterval = GetInt(hWnd, E_RETRY_SPAN);
+
+	a->ClientOption->NoTls1 = IsChecked(hWnd, R_NOTLS1);
+
+	// 情報判定
+	if (UniStrLen(a->ClientOption->AccountName) == 0 && a->NatMode == false)
+	{
+		ok = false;
+	}
+	if (StrLen(a->ClientOption->Hostname) == 0)
+	{
+		ok = false;
+	}
+	if (a->ClientOption->Port == 0 || a->ClientOption->Port >= 65536)
+	{
+		ok = false;
+	}
+	if (StrLen(a->ClientOption->HubName) == 0)
+	{
+		ok = false;
+	}
+	if (StrLen(a->ClientAuth->Username) == 0)
+	{
+		ok = false;
+	}
+	if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+	{
+		if (a->ClientAuth->ClientK == NULL || a->ClientAuth->ClientX == NULL)
+		{
+			ok = false;
+		}
+	}
+	if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+	{
+		if (IsEmptyStr(a->ClientAuth->SecurePrivateKeyName) || IsEmptyStr(a->ClientAuth->SecurePublicCertName))
+		{
+			ok = false;
+		}
+	}
+
+	// 表示更新
+	if (IsChecked(hWnd, R_RETRY) && IsEnable(hWnd, R_RETRY))
+	{
+		if (a->LinkMode == false && a->NatMode == false)
+		{
+			Enable(hWnd, R_INFINITE);
+			Enable(hWnd, E_RETRY_SPAN);
+			Enable(hWnd, S_RETRY_SPAN_1);
+			Enable(hWnd, S_RETRY_SPAN_2);
+		}
+		else
+		{
+			Disable(hWnd, R_INFINITE);
+			Disable(hWnd, E_RETRY_SPAN);
+			Disable(hWnd, S_RETRY_SPAN_1);
+			Disable(hWnd, S_RETRY_SPAN_2);
+		}
+		if (IsChecked(hWnd, R_INFINITE) == false)
+		{
+			Enable(hWnd, E_RETRY_NUM);
+			Enable(hWnd, S_RETRY_NUM_1);
+			Enable(hWnd, S_RETRY_NUM_2);
+			if (GetInt(hWnd, E_RETRY_NUM) == 0)
+			{
+				ok = false;
+			}
+		}
+		else
+		{
+			Disable(hWnd, E_RETRY_NUM);
+			Disable(hWnd, S_RETRY_NUM_1);
+			Disable(hWnd, S_RETRY_NUM_2);
+		}
+	}
+	else
+	{
+		Disable(hWnd, E_RETRY_NUM);
+		Disable(hWnd, E_RETRY_SPAN);
+		Disable(hWnd, R_INFINITE);
+		Disable(hWnd, S_RETRY_NUM_1);
+		Disable(hWnd, S_RETRY_NUM_2);
+		Disable(hWnd, S_RETRY_SPAN_1);
+		Disable(hWnd, S_RETRY_SPAN_2);
+	}
+
+	if (a->NatMode == false)
+	{
+		if (a->ServerCert == NULL)
+		{
+			SetText(hWnd, B_SERVER_CERT, _UU("CM_SERVER_CERT_1"));
+			Disable(hWnd, B_VIEW_SERVER_CERT);
+		}
+		else
+		{
+			SetText(hWnd, B_SERVER_CERT, _UU("CM_SERVER_CERT_2"));
+			Enable(hWnd, B_VIEW_SERVER_CERT);
+		}
+	}
+	else
+	{
+		Disable(hWnd, B_VIEW_SERVER_CERT);
+		Disable(hWnd, B_SERVER_CERT);
+	}
+
+	if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT || a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+	{
+		wchar_t tmp[MAX_SIZE * 2];
+		wchar_t issuer[MAX_SIZE];
+		wchar_t subject[MAX_SIZE];
+		wchar_t expires[MAX_SIZE];
+
+		SetIcon(hWnd, S_CERT, (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT) ? ICO_CERT : ICO_SECURE);
+
+		Hide(hWnd, S_PASSWORD);
+		Hide(hWnd, E_PASSWORD);
+		if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+		{
+			if (a->ClientAuth->ClientX != NULL)
+			{
+				Enable(hWnd, B_VIEW_CLIENT_CERT);
+				SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_CLIENT_CERT_2"));
+				GetPrintNameFromName(issuer, sizeof(issuer), a->ClientAuth->ClientX->issuer_name);
+				GetPrintNameFromName(subject, sizeof(subject), a->ClientAuth->ClientX->subject_name);
+				GetDateStrEx64(expires, sizeof(expires), SystemToLocal64(a->ClientAuth->ClientX->notAfter), NULL);
+				UniFormat(tmp, sizeof(tmp), _UU("CM_CERT_INFO"), subject, issuer, expires);
+			}
+			else
+			{
+				Disable(hWnd, B_VIEW_CLIENT_CERT);
+				SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_CLIENT_CERT_1"));
+				UniStrCpy(tmp, sizeof(tmp), _UU("CM_NO_CERT"));
+			}
+			SetText(hWnd, B_VIEW_CLIENT_CERT, _UU("CM_VIEW_CLIENT_CERT"));
+
+			Enable(hWnd, B_REGIST_CLIENT_CERT);
+		}
+		else
+		{
+			if (IsEmptyStr(a->ClientAuth->SecurePrivateKeyName) || IsEmptyStr(a->ClientAuth->SecurePublicCertName))
+			{
+				UniStrCpy(tmp, sizeof(tmp), _UU("CM_NO_SECURE"));
+			}
+			else
+			{
+				UniFormat(tmp, sizeof(tmp), _UU("CM_CERT_SECURE_INFO"),
+					a->ClientAuth->SecurePublicCertName, a->ClientAuth->SecurePrivateKeyName);
+			}
+
+			SetText(hWnd, B_VIEW_CLIENT_CERT, _UU("CM_SELECT_SECURE_DEVICE"));
+			SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_SELECT_CERT_INCARD"));
+			Enable(hWnd, B_VIEW_CLIENT_CERT);
+
+			if (SmGetCurrentSecureIdFromReg() == 0)
+			{
+				Disable(hWnd, B_REGIST_CLIENT_CERT);
+			}
+			else
+			{
+				Enable(hWnd, B_REGIST_CLIENT_CERT);
+			}
+		}
+		SetText(hWnd, S_CERT_INFO, tmp);
+		Show(hWnd, S_CERT);
+		Show(hWnd, S_CERT_INFO);
+		Show(hWnd, B_VIEW_CLIENT_CERT);
+		Show(hWnd, B_REGIST_CLIENT_CERT);
+	}
+	else
+	{
+		if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_ANONYMOUS)
+		{
+			Hide(hWnd, S_PASSWORD);
+			Hide(hWnd, E_PASSWORD);
+		}
+		else
+		{
+			Show(hWnd, S_PASSWORD);
+			Show(hWnd, E_PASSWORD);
+		}
+		Hide(hWnd, S_CERT);
+		Hide(hWnd, S_CERT_INFO);
+		Hide(hWnd, B_VIEW_CLIENT_CERT);
+		Hide(hWnd, B_REGIST_CLIENT_CERT);
+	}
+
+	if (a->ClientOption->ProxyType != PROXY_DIRECT)
+	{
+		Enable(hWnd, B_PROXY_CONFIG);
+		if (StrLen(a->ClientOption->ProxyName) == 0)
+		{
+			ok = false;
+		}
+		if (a->ClientOption->ProxyPort == 0)
+		{
+			ok = false;
+		}
+	}
+	else
+	{
+		Disable(hWnd, B_PROXY_CONFIG);
+	}
+
+	if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+	{
+		bool b = true;
+
+		if (ok == false)
+		{
+			b = false;
+		}
+
+		if (a->LinkMode == false && a->NatMode == false)
+		{
+			SetEnable(hWnd, B_CHANGE_PASSWORD, b);
+			SetEnable(hWnd, S_CHANGE_PASSWORD, b);
+			Show(hWnd, B_CHANGE_PASSWORD);
+			Show(hWnd, S_CHANGE_PASSWORD);
+		}
+		else
+		{
+			Hide(hWnd, B_CHANGE_PASSWORD);
+			Hide(hWnd, S_CHANGE_PASSWORD);
+		}
+	}
+	else
+	{
+		Hide(hWnd, B_CHANGE_PASSWORD);
+		Hide(hWnd, S_CHANGE_PASSWORD);
+	}
+
+	if ((StrLen(a->ClientOption->DeviceName) == 0) && (a->LinkMode == false && a->NatMode == false))
+	{
+		ok = false;
+	}
+
+	if (a->LinkMode || a->NatMode)
+	{
+		Disable(hWnd, L_VLAN);
+	}
+
+	if (a->EditMode == false)
+	{
+		char tmp[MAX_SIZE];
+		GetTxtA(hWnd, E_HOSTNAME, tmp, sizeof(tmp));
+		Trim(tmp);
+
+		if (StartWith(tmp, "127.") || (StrCmpi(tmp, "localhost") == 0))
+		{
+			if (a->Flag1 == false)
+			{
+				a->Flag1 = true;
+				a->ClientOption->UseEncrypt = a->ClientOption->UseCompress = false;
+				a->ClientOption->MaxConnection = 1;
+			}
+		}
+	}
+
+	a->ClientOption->HideStatusWindow = IsChecked(hWnd, R_HIDE);
+	a->ClientOption->HideNicInfoWindow = IsChecked(hWnd, R_HIDE2);
+
+	if (locked)
+	{
+		SetEnable(hWnd, E_HOSTNAME, false);
+		SetEnable(hWnd, C_PORT, false);
+		SetEnable(hWnd, C_HUBNAME, false);
+		SetEnable(hWnd, S_STATIC2, false);
+		SetEnable(hWnd, S_STATIC3, false);
+		SetEnable(hWnd, S_STATIC4, false);
+		SetEnable(hWnd, S_STATIC5, false);
+		SetEnable(hWnd, S_STATIC66, false);
+		SetEnable(hWnd, S_STATIC7, false);
+		SetEnable(hWnd, S_STATIC11, false);
+		SetEnable(hWnd, R_CHECK_CERT, false);
+		SetEnable(hWnd, B_TRUST, false);
+		SetEnable(hWnd, B_SERVER_CERT, false);
+		SetEnable(hWnd, B_VIEW_SERVER_CERT, false);
+		SetEnable(hWnd, R_RETRY, false);
+		SetEnable(hWnd, S_RETRY_NUM_1, false);
+		SetEnable(hWnd, E_RETRY_NUM, false);
+		SetEnable(hWnd, S_RETRY_NUM_2, false);
+		SetEnable(hWnd, S_RETRY_SPAN_1, false);
+		SetEnable(hWnd, E_RETRY_SPAN, false);
+		SetEnable(hWnd, S_RETRY_SPAN_2, false);
+		SetEnable(hWnd, R_INFINITE, false);
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// アカウント編集ダイアログ初期化
+void CmEditAccountDlgInit(HWND hWnd, CM_ACCOUNT *a)
+{
+	RPC_CLIENT_ENUM_VLAN v;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	if (a->LockMode)
+	{
+		SetText(hWnd, S_STATIC1, _UU("CM_EASY_ACCOUNT_WARNING"));
+	}
+
+	// 接続設定名
+	if (a->EditMode || a->NatMode)
+	{
+		Disable(hWnd, E_ACCOUNT_NAME);
+	}
+
+	if (a->NatMode || a->LinkMode)
+	{
+		Hide(hWnd, R_HIDE);
+		Hide(hWnd, R_HIDE2);
+	}
+
+	Check(hWnd, R_HIDE, a->ClientOption->HideStatusWindow);
+	Check(hWnd, R_HIDE2, a->ClientOption->HideNicInfoWindow);
+
+	if (a->NatMode)
+	{
+		Hide(hWnd, E_ACCOUNT_NAME);
+		Hide(hWnd, S_ACCOUNT_NAME);
+	}
+
+	if ((cm != NULL && cm->server_name != NULL) || a->LinkMode)
+	{
+		Hide(hWnd, B_IE);
+	}
+
+	SetText(hWnd, E_ACCOUNT_NAME, a->ClientOption->AccountName);
+
+	// ホスト名
+	SetTextA(hWnd, E_HOSTNAME, a->ClientOption->Hostname);
+	StrCpy(a->old_server_name, sizeof(a->old_server_name), a->ClientOption->Hostname);
+
+	// ポート番号
+	CbSetHeight(hWnd, C_PORT, 18);
+	CbAddStr(hWnd, C_PORT, _UU("CM_PORT_4"), 0);
+	CbAddStr(hWnd, C_PORT, _UU("CM_PORT_1"), 0);
+	CbAddStr(hWnd, C_PORT, _UU("CM_PORT_2"), 0);
+	CbAddStr(hWnd, C_PORT, _UU("CM_PORT_3"), 0);
+	SetInt(hWnd, C_PORT, a->ClientOption->Port);
+
+	// 仮想 HUB 名
+	CbSetHeight(hWnd, C_HUBNAME, 18);
+	SetTextA(hWnd, C_HUBNAME, a->ClientOption->HubName);
+
+	// プロキシの種類
+	Check(hWnd, R_DIRECT_TCP, a->ClientOption->ProxyType == PROXY_DIRECT);
+	Check(hWnd, R_HTTPS, a->ClientOption->ProxyType == PROXY_HTTP);
+	Check(hWnd, R_SOCKS, a->ClientOption->ProxyType == PROXY_SOCKS);
+
+	// サーバー証明書の検証
+	Check(hWnd, R_CHECK_CERT, a->CheckServerCert);
+
+	// LAN カード一覧
+	if (a->NatMode == false && a->LinkMode == false)
+	{
+		Zero(&v, sizeof(v));
+		CcEnumVLan(cm->Client, &v);
+		LvInit(hWnd, L_VLAN);
+		LvInsertColumn(hWnd, L_VLAN, 0, L"DeviceName", 345);
+		for (i = 0;i < v.NumItem;i++)
+		{
+			wchar_t tmp[MAX_SIZE];
+			char str[MAX_SIZE];
+			CmVLanNameToPrintName(str, sizeof(str), v.Items[i]->DeviceName);
+			StrToUni(tmp, sizeof(tmp), str);
+			LvInsert(hWnd, L_VLAN, ICO_NIC_ONLINE, NULL, 1, tmp);
+		}
+//		LvAutoSize(hWnd, L_VLAN);
+
+		if (v.NumItem == 1)
+		{
+			// 仮想 LAN カードが 1 枚だけのときはそれを最初から選択する
+			LvSelect(hWnd, L_VLAN, 0);
+		}
+
+		CiFreeClientEnumVLan(&v);
+	}
+
+	// LAN カードを選択する
+	if (StrLen(a->ClientOption->DeviceName) != 0)
+	{
+		char str[MAX_SIZE];
+		wchar_t tmp[MAX_SIZE];
+		UINT index;
+		CmVLanNameToPrintName(str, sizeof(str), a->ClientOption->DeviceName);
+		StrToUni(tmp, sizeof(tmp), str);
+		index = LvSearchStr(hWnd, L_VLAN, 0, tmp);
+		if (index != INFINITE)
+		{
+			LvSelect(hWnd, L_VLAN, index);
+		}
+	}
+
+	// 認証の種類
+	CbSetHeight(hWnd, C_TYPE, 18);
+	CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_0"), CLIENT_AUTHTYPE_ANONYMOUS);
+	CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_1"), CLIENT_AUTHTYPE_PASSWORD);
+	CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_2"), CLIENT_AUTHTYPE_PLAIN_PASSWORD);
+
+	if (a->HideClientCertAuth == false)
+	{
+		// HideClientCertAuth が true の場合は証明書認証は利用できない
+		CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_3"), CLIENT_AUTHTYPE_CERT);
+	}
+
+	if (a->HideSecureAuth == false)
+	{
+		// スマートカードを利用した認証
+		CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_4"), CLIENT_AUTHTYPE_SECURE);
+	}
+
+	// 認証の選択
+	CbSelect(hWnd, C_TYPE, a->ClientAuth->AuthType);
+
+	// ユーザー名
+	SetTextA(hWnd, E_USERNAME, a->ClientAuth->Username);
+
+	// パスワード
+	if (a->EditMode)
+	{
+		SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+	}
+
+	// 再接続回数
+	if (a->ClientOption->NumRetry == 0)
+	{
+		Check(hWnd, R_RETRY, false);
+	}
+	else
+	{
+		Check(hWnd, R_RETRY, true);
+		if (a->ClientOption->NumRetry == INFINITE)
+		{
+			Check(hWnd, R_INFINITE, true);
+		}
+		else
+		{
+			Check(hWnd, R_INFINITE, false);
+			SetInt(hWnd, E_RETRY_NUM, a->ClientOption->NumRetry);
+		}
+	}
+	SetIntEx(hWnd, E_RETRY_SPAN, a->ClientOption->RetryInterval);
+
+	Check(hWnd, R_NOTLS1, a->ClientOption->NoTls1);
+
+	// タイトル
+	if (a->NatMode == false)
+	{
+		if (a->EditMode == false)
+		{
+			SetText(hWnd, 0, _UU("CM_ACCOUNT_TITLE_1"));
+			FocusEx(hWnd, E_ACCOUNT_NAME);
+		}
+		else
+		{
+			SetText(hWnd, 0, _UU("CM_ACCOUNT_TITLE_2"));
+			FormatText(hWnd, 0, a->ClientOption->AccountName);
+			FocusEx(hWnd, E_HOSTNAME);
+		}
+	}
+	else
+	{
+		SetText(hWnd, 0, _UU("NM_ACCOUNT_TITLE"));
+		FocusEx(hWnd, E_HOSTNAME);
+	}
+
+	if (a->LinkMode || a->NatMode)
+	{
+		Hide(hWnd, L_VLAN);
+
+		if (a->NatMode == false)
+		{
+			SetText(hWnd, S_VLAN_GROUP, _UU("SM_LINK_POLICY_GROUP"));
+			Show(hWnd, S_POLICY_1);
+			Show(hWnd, S_POLICY_2);
+			Show(hWnd, B_POLICY);
+		}
+		else
+		{
+			Hide(hWnd, S_VLAN_GROUP);
+			Show(hWnd, S_ROUTER_LOGO);
+		}
+	}
+
+	// 表示更新
+	a->Inited = true;
+	CmEditAccountDlgUpdate(hWnd, a);
+}
+
+// アカウント編集ダイアログプロシージャ
+UINT CmEditAccountDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CM_ACCOUNT *a = (CM_ACCOUNT *)param;
+	NMHDR *n;
+	X *x;
+	K *k;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmEditAccountDlgInit(hWnd, a);
+		if (a->EditMode == false && a->LinkMode == false && a->NatMode == false)
+		{
+			SetTimer(hWnd, 1, 100, NULL);
+		}
+		break;
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			{
+				CM_INTERNET_SETTING s;
+
+				KillTimer(hWnd, 1);
+
+				Zero(&s, sizeof(s));
+				CmGetSystemInternetSetting(&s);
+
+				if (s.ProxyType != PROXY_DIRECT)
+				{
+					if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO,
+						_UU("CM_WOULDYOULOAD_IE_PROXY"),
+						s.ProxyHostName) == IDYES)
+					{
+						Command(hWnd, B_IE);
+					}
+				}
+			}
+			break;
+		}
+		break;
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_ACCOUNT_NAME:
+		case E_HOSTNAME:
+		case C_PORT:
+		case C_HUBNAME:
+		case R_DIRECT_TCP:
+		case R_HTTPS:
+		case R_SOCKS:
+		case R_CHECK_CERT:
+		case C_TYPE:
+		case E_USERNAME:
+		case E_PASSWORD:
+		case R_RETRY:
+		case E_RETRY_NUM:
+		case E_RETRY_SPAN:
+		case R_INFINITE:
+			CmEditAccountDlgUpdate(hWnd, a);
+			break;
+		}
+		switch (HIWORD(wParam))
+		{
+		case EN_KILLFOCUS:
+			switch (LOWORD(wParam))
+			{
+			case E_HOSTNAME:
+				CmEditAccountDlgStartEnumHub(hWnd, a);
+				break;
+			}
+			break;
+		case BN_KILLFOCUS:
+			switch (LOWORD(wParam))
+			{
+			case R_DIRECT_TCP:
+			case R_HTTPS:
+			case R_SOCKS:
+				CmEditAccountDlgStartEnumHub(hWnd, a);
+				break;
+			}
+			break;
+		case CBN_KILLFOCUS:
+			switch (LOWORD(wParam))
+			{
+			case C_PORT:
+				CmEditAccountDlgStartEnumHub(hWnd, a);
+				break;
+			}
+			break;
+		}
+		if (HIWORD(wParam) == 0)
+		{
+			CmEditAccountDlgUpdate(hWnd, a);
+		}
+		switch (wParam)
+		{
+		case B_POLICY:
+			// ポリシー
+			if (a->LinkMode || a->NatMode)
+			{
+				a->Policy.Access = true;
+				a->Policy.MonitorPort = false;
+				SmPolicyDlgEx2(hWnd, &a->Policy, _UU("SM_LINK_POLICY_CAPTION"), true, a->PolicyVer);
+				a->Policy.Access = true;
+				a->Policy.MonitorPort = false;
+			}
+			break;
+		case IDOK:
+			CmEditAccountDlgUpdate(hWnd, a);
+			CmEditAccountDlgOnOk(hWnd, a);
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		case B_PROXY_CONFIG:
+			// プロキシ設定
+			if (CmProxyDlg(hWnd, a->ClientOption))
+			{
+				UINT n = GetInt(hWnd, C_PORT);
+				if (a->ClientOption->ProxyType == PROXY_HTTP &&
+					n != 443)
+				{
+					// HTTP プロキシ経由の設定になっていて接続先が 443 番ポート
+					// 以外のポートである場合は警告を表示する
+					if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_HTTP_PROXY_WARNING"), n) == IDYES)
+					{
+						// ポート番号を 443 に変更する
+						SetText(hWnd, C_PORT, _UU("CM_PORT_2"));
+					}
+				}
+				CmEditAccountDlgStartEnumHub(hWnd, a);
+				CmEditAccountDlgUpdate(hWnd, a);
+			}
+			break;
+		case B_IE:
+			// IE の設定を使用する
+			if(cm->server_name == NULL)
+			{
+				CmProxyDlgUseForIE(hWnd, a->ClientOption);
+				CmEditAccountDlgUpdate(hWnd, a);
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PROXY_FROM_IE"));
+			}
+			break;
+		case B_TRUST:
+			// CA
+			if (a->LinkMode == false)
+			{
+				CmTrustDlg(hWnd);
+			}
+			else
+			{
+				SmCaDlg(hWnd, a->Hub);
+			}
+			break;
+		case B_SERVER_CERT:
+			// サーバー証明書登録 / 削除
+			if (a->ServerCert == NULL)
+			{
+				if (CmLoadXFromFileOrSecureCard(hWnd, &x))
+				{
+					a->ServerCert = x;
+					CmEditAccountDlgUpdate(hWnd, a);
+				}
+			}
+			else
+			{
+				if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_SERVER_CERT")) == IDYES)
+				{
+					FreeX(a->ServerCert);
+					a->ServerCert = NULL;
+					CmEditAccountDlgUpdate(hWnd, a);
+				}
+			}
+			break;
+		case B_VIEW_SERVER_CERT:
+			// サーバー証明書表示
+			if (a->ServerCert != NULL)
+			{
+				X *issuer = CmGetIssuer(a->ServerCert);
+				CertDlg(hWnd, a->ServerCert, issuer, true);
+				FreeX(issuer);
+			}
+			break;
+		case B_VIEW_CLIENT_CERT:
+			if (a->ClientAuth->AuthType != CLIENT_AUTHTYPE_SECURE)
+			{
+				// クライアント証明書表示
+				if (a->ClientAuth->ClientX != NULL)
+				{
+					X *issuer = CmGetIssuer(a->ClientAuth->ClientX);
+					CertDlg(hWnd, a->ClientAuth->ClientX, issuer, true);
+					FreeX(issuer);
+				}
+			}
+			else
+			{
+				UINT id;
+				// スマートカードの種類の選択
+				SmSelectSecureId(hWnd);
+				id = SmGetCurrentSecureIdFromReg();
+				if (id != 0)
+				{
+					if (cm->server_name == NULL)
+					{
+						RPC_USE_SECURE t;
+
+						Zero(&t, sizeof(t));
+						t.DeviceId = id;
+						CcUseSecure(cm->Client, &t);
+					}
+				}
+				CmEditAccountDlgUpdate(hWnd, a);
+			}
+			break;
+		case B_REGIST_CLIENT_CERT:
+			if (a->ClientAuth->AuthType != CLIENT_AUTHTYPE_SECURE)
+			{
+				// クライアント証明書登録 / 削除
+				if (a->ClientAuth->ClientX == NULL)
+				{
+					if (CmLoadXAndK(hWnd, &x, &k))
+					{
+						a->ClientAuth->ClientX = x;
+						a->ClientAuth->ClientK = k;
+						CmEditAccountDlgUpdate(hWnd, a);
+					}
+				}
+				else
+				{
+					if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_CLIENT_CERT")) == IDYES)
+					{
+						FreeX(a->ClientAuth->ClientX);
+						FreeK(a->ClientAuth->ClientK);
+						a->ClientAuth->ClientX = NULL;
+						a->ClientAuth->ClientK = NULL;
+						CmEditAccountDlgUpdate(hWnd, a);
+					}
+				}
+			}
+			else
+			{
+				char cert[MAX_SECURE_DEVICE_FILE_LEN + 1], priv[MAX_SECURE_DEVICE_FILE_LEN + 1];
+
+				// スマートカード内証明書の選択
+				if (SmSelectKeyPairEx(hWnd, cert, sizeof(cert), priv, sizeof(priv), CmGetSecureBitmapId(a->ClientOption->Hostname)))
+				{
+					StrCpy(a->ClientAuth->SecurePublicCertName, sizeof(a->ClientAuth->SecurePublicCertName), cert);
+					StrCpy(a->ClientAuth->SecurePrivateKeyName, sizeof(a->ClientAuth->SecurePrivateKeyName), priv);
+					CmEditAccountDlgUpdate(hWnd, a);
+				}
+			}
+			break;
+		case B_DETAIL:
+			// 高度な通信設定
+			if (CmDetailDlg(hWnd, a))
+			{
+				CmEditAccountDlgUpdate(hWnd, a);
+			}
+			break;
+		case B_CHANGE_PASSWORD:
+			// パスワードの変更
+			CmChangePassword(hWnd, a->ClientOption, a->ClientOption->HubName,
+				a->ClientAuth->Username);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_VLAN:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				CmEditAccountDlgUpdate(hWnd, a);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// プロキシサーバー設定更新
+void CmProxyDlgUpdate(HWND hWnd, CLIENT_OPTION *a)
+{
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	if (IsEmpty(hWnd, E_HOSTNAME))
+	{
+		ok = false;
+	}
+	if (GetInt(hWnd, C_PORT) == 0)
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// プロキシサーバー設定ダイアログc
+UINT CmProxyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CLIENT_OPTION *a = (CLIENT_OPTION *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetTextA(hWnd, E_HOSTNAME, a->ProxyName);
+		CbSetHeight(hWnd, C_PORT, 18);
+		CbAddStr(hWnd, C_PORT, L"8080", 0);
+		CbAddStr(hWnd, C_PORT, L"1080", 0);
+		CbAddStr(hWnd, C_PORT, L"80", 0);
+		CbAddStr(hWnd, C_PORT, L"3128", 0);
+		CbAddStr(hWnd, C_PORT, L"443", 0);
+		CbAddStr(hWnd, C_PORT, L"9821", 0);
+		CbAddStr(hWnd, C_PORT, L"9801", 0);
+		SetIntEx(hWnd, C_PORT, a->ProxyPort);
+		SetTextA(hWnd, E_USERNAME, a->ProxyUsername);
+		SetTextA(hWnd, E_PASSWORD, a->ProxyPassword);
+		if (a->ProxyPort == 0)
+		{
+			if (a->ProxyType == PROXY_HTTP)
+			{
+				SetInt(hWnd, C_PORT, 8080);
+			}
+			else
+			{
+				SetInt(hWnd, C_PORT, 1080);
+			}
+		}
+		CmProxyDlgUpdate(hWnd, a);
+		break;
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_HOSTNAME:
+		case C_PORT:
+		case E_USERNAME:
+		case E_PASSWORD:
+			CmProxyDlgUpdate(hWnd, a);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			GetTxtA(hWnd, E_HOSTNAME, a->ProxyName, sizeof(a->ProxyName));
+			GetTxtA(hWnd, E_USERNAME, a->ProxyUsername, sizeof(a->ProxyUsername));
+			GetTxtA(hWnd, E_PASSWORD, a->ProxyPassword, sizeof(a->ProxyPassword));
+			a->ProxyPort = GetInt(hWnd, C_PORT);
+			EndDialog(hWnd, true);
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// プロキシサーバー設定
+bool CmProxyDlg(HWND hWnd, CLIENT_OPTION *a)
+{
+	// 引数チェック
+	if (a == NULL)
+	{
+		return false;
+	}
+
+	return Dialog(hWnd, D_CM_PROXY, CmProxyDlgProc, a);
+}
+
+// 指定した証明書の署名者がわかれば取得する
+X *CmGetIssuer(X *x)
+{
+	RPC_GET_ISSUER a;
+	X *ret;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&a, sizeof(a));
+	a.x = CloneX(x);
+	if (CALLEX(cm->hMainWnd, CcGetIssuer(cm->Client, &a)) == 0)
+	{
+		ret = CloneX(a.issuer_x);
+	}
+	else
+	{
+		ret = NULL;
+	}
+
+	CiFreeGetIssuer(&a);
+
+	return ret;
+}
+
+// ダイアログ初期化
+void CmLoadXFromFileOrSecureCardDlgInit(HWND hWnd, CM_LOADX *p)
+{
+	UINT current;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	current = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "CertLoadSource");
+
+	Check(hWnd, R_FROM_FILE, current == 0);
+	Check(hWnd, R_FROM_SECURE, current != 0);
+
+	SetFont(hWnd, S_INFO, Font(0, true));
+
+	CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+}
+
+// ダイアログコントロール更新
+void CmLoadXFromFileOrSecureCardDlgUpdate(HWND hWnd, CM_LOADX *p)
+{
+	SECURE_DEVICE *dev;
+	wchar_t tmp[MAX_SIZE];
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	dev = GetSecureDevice(SmGetCurrentSecureIdFromReg());
+	if (dev == NULL)
+	{
+		UniStrCpy(tmp, sizeof(tmp), _UU("SEC_CURRENT_NO_DEVICE"));
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("SEC_CURRENT_DEVICE"), dev->DeviceName);
+	}
+
+	SetText(hWnd, S_INFO, tmp);
+
+	if (IsChecked(hWnd, R_FROM_SECURE))
+	{
+		if (dev == NULL)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+	SetEnable(hWnd, B_SELECT, IsChecked(hWnd, R_FROM_SECURE));
+	SetEnable(hWnd, S_CERT, IsChecked(hWnd, R_FROM_SECURE));
+	SetEnable(hWnd, S_FILE, IsChecked(hWnd, R_FROM_FILE));
+}
+
+// 証明書読み込み選択ダイアログプロシージャ
+UINT CmLoadXFromFileOrSecureCardDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CM_LOADX *p = (CM_LOADX *)param;
+	X *x;
+	UINT current;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CmLoadXFromFileOrSecureCardDlgInit(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			current = (IsChecked(hWnd, R_FROM_FILE)) ? 0 : 1;
+			MsRegWriteInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "CertLoadSource", current);
+
+			if (current == 0)
+			{
+				// ファイルから
+				if (CmLoadX(hWnd, &x))
+				{
+					p->x = x;
+					EndDialog(hWnd, true);
+				}
+			}
+			else
+			{
+				// スマートカードから
+				char name[MAX_SIZE];
+
+				// カード内の証明書名を選択
+				if (SmSelectKeyPair(hWnd, name, sizeof(name), NULL, 0))
+				{
+					// 読み込み
+					WINUI_SECURE_BATCH batch[] =
+					{
+						{WINUI_SECURE_READ_CERT, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+					};
+
+					// 読み込み実行
+					if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), SmGetCurrentSecureIdFromReg(), 0))
+					{
+						// 成功
+						p->x = batch[0].OutputX;
+						EndDialog(hWnd, true);
+					}
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case R_FROM_FILE:
+			CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+			break;
+
+		case R_FROM_SECURE:
+			CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+			break;
+
+		case B_SELECT:
+			SmSelectSecureId(hWnd);
+			CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 証明書をスマートカードかファイルから読み込む
+bool CmLoadXFromFileOrSecureCard(HWND hWnd, X **x)
+{
+	CM_LOADX p;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return false;
+	}
+
+	Zero(&p, sizeof(p));
+	if (Dialog(hWnd, D_CM_LOAD_X, CmLoadXFromFileOrSecureCardDlgProc, &p) == false)
+	{
+		return false;
+	}
+
+	*x = p.x;
+
+	return true;
+}
+
+// 証明書を読み込む
+bool CmLoadX(HWND hWnd, X **x)
+{
+	return CmLoadXEx(hWnd, x, NULL, 0);
+}
+bool CmLoadXEx(HWND hWnd, X **x, char *filename, UINT size)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	bool ret;
+
+	ret = CmLoadXExW(hWnd, x, filename_w, size);
+
+	Free(filename_w);
+
+	return ret;
+}
+bool CmLoadXExW(HWND hWnd, X **x, wchar_t *filename, UINT size)
+{
+	wchar_t *s;
+	bool is_p12;
+	wchar_t tmp[MAX_SIZE];
+	K *k;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return false;
+	}
+
+	// 証明書を読み込む
+	s = OpenDlg(hWnd, _UU("DLG_CERT_OR_P12_FILTER"), _UU("DLG_OPEN_CERT"));
+	if (s == NULL)
+	{
+		return false;
+	}
+	UniStrCpy(tmp, sizeof(tmp), s);
+	if (filename != NULL)
+	{
+		UniStrCpy(filename, size, tmp);
+	}
+	Free(s);
+	if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+	{
+		is_p12 = true;
+	}
+	else
+	{
+		is_p12 = false;
+	}
+
+	if (is_p12)
+	{
+		// PKCS#12 の処理
+		BUF *b = ReadDumpW(tmp);
+		P12 *p12;
+		if (b == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+			return false;
+		}
+		p12 = BufToP12(b);
+		if (p12 == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+			FreeBuf(b);
+			return false;
+		}
+		if (IsEncryptedP12(p12) == false)
+		{
+			if (ParseP12(p12, x, &k, NULL) == false)
+			{
+				MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+				FreeP12(p12);
+				FreeBuf(b);
+				return false;
+			}
+		}
+		else
+		{
+			char password[MAX_SIZE];
+			if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+			{
+				FreeP12(p12);
+				FreeBuf(b);
+				return false;
+			}
+			else
+			{
+				if (ParseP12(p12, x, &k, password) == false)
+				{
+					MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+					FreeP12(p12);
+					FreeBuf(b);
+					return false;
+				}
+			}
+		}
+		FreeP12(p12);
+		FreeBuf(b);
+		FreeK(k);
+		return true;
+	}
+	else
+	{
+		// X509 の処理
+		BUF *b = ReadDumpW(tmp);
+		X *x509;
+		if (b == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+			return false;
+		}
+
+		x509 = BufToX(b, IsBase64(b));
+		FreeBuf(b);
+		if (x509 == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_X509_W"), tmp);
+			return false;
+		}
+
+		*x = x509;
+		return true;
+	}
+}
+
+// 秘密鍵を読み込む
+bool CmLoadK(HWND hWnd, K **k)
+{
+	return CmLoadKEx(hWnd, k, NULL, 0);
+}
+bool CmLoadKEx(HWND hWnd, K **k, char *filename, UINT size)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	bool ret;
+
+	ret = CmLoadKExW(hWnd, k, filename_w, size);
+
+	Free(filename_w);
+
+	return ret;
+}
+bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size)
+{
+	wchar_t *s;
+	bool is_p12;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (k == NULL)
+	{
+		return false;
+	}
+
+	// 証明書を読み込む
+	s = OpenDlg(hWnd, _UU("DLG_KEY_OR_P12_FILTER"), _UU("DLG_OPEN_KEY"));
+	if (s == NULL)
+	{
+		return false;
+	}
+	UniStrCpy(tmp, sizeof(tmp), s);
+	Free(s);
+	if (filename != NULL)
+	{
+		UniStrCpy(filename, size, tmp);
+	}
+	if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+	{
+		is_p12 = true;
+	}
+	else
+	{
+		is_p12 = false;
+	}
+
+	if (is_p12)
+	{
+		// PKCS#12 の処理
+		BUF *b = ReadDumpW(tmp);
+		P12 *p12;
+		if (b == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+			return false;
+		}
+		p12 = BufToP12(b);
+		if (p12 == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+			FreeBuf(b);
+			return false;
+		}
+		if (IsEncryptedP12(p12) == false)
+		{
+			X *x;
+			if (ParseP12(p12, &x, k, NULL) == false)
+			{
+				MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+				FreeP12(p12);
+				FreeBuf(b);
+				return false;
+			}
+
+			FreeX(x);
+		}
+		else
+		{
+			char password[MAX_SIZE];
+			if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+			{
+				FreeP12(p12);
+				FreeBuf(b);
+				return false;
+			}
+			else
+			{
+				X *x;
+				if (ParseP12(p12, &x, k, password) == false)
+				{
+					MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+					FreeP12(p12);
+					FreeBuf(b);
+					return false;
+				}
+
+				FreeX(x);
+			}
+		}
+		FreeP12(p12);
+		FreeBuf(b);
+		return true;
+	}
+	else
+	{
+		// 秘密鍵の処理
+		BUF *b = ReadDumpW(tmp);
+		K *key;
+		if (b == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+			return false;
+		}
+
+		if (IsEncryptedK(b, true) == false)
+		{
+			key = BufToK(b, true, IsBase64(b), NULL);
+		}
+		else
+		{
+			char pass[MAX_SIZE];
+			if (PassphraseDlg(hWnd, pass, sizeof(pass), b, false) == false)
+			{
+				FreeBuf(b);
+				return false;
+			}
+			key = BufToK(b, true, IsBase64(b), pass);
+		}
+
+		if (key == NULL)
+		{
+			FreeBuf(b);
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_KEY_W"), tmp);
+			return false;
+		}
+
+		FreeBuf(b);
+		*k = key;
+		return true;
+	}
+}
+
+// 証明書と秘密鍵のセットを読み込む
+bool CmLoadXAndK(HWND hWnd, X **x, K **k)
+{
+	wchar_t *s;
+	bool is_p12;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (x == NULL || k == NULL)
+	{
+		return false;
+	}
+START_FIRST:
+
+	// 証明書を読み込む
+	s = OpenDlg(hWnd, _UU("DLG_CERT_OR_P12_FILTER"), _UU("DLG_OPEN_CERT"));
+	if (s == NULL)
+	{
+		return false;
+	}
+	UniStrCpy(tmp, sizeof(tmp), s);
+	Free(s);
+	if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+	{
+		is_p12 = true;
+	}
+	else
+	{
+		is_p12 = false;
+	}
+
+	if (is_p12)
+	{
+		// PKCS#12 の処理
+		BUF *b = ReadDumpW(tmp);
+		P12 *p12;
+		if (b == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+			return false;
+		}
+		p12 = BufToP12(b);
+		if (p12 == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+			FreeBuf(b);
+			return false;
+		}
+		if (IsEncryptedP12(p12) == false)
+		{
+			if (ParseP12(p12, x, k, NULL) == false)
+			{
+				MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+				FreeP12(p12);
+				FreeBuf(b);
+				return false;
+			}
+		}
+		else
+		{
+			char password[MAX_SIZE];
+			if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+			{
+				FreeP12(p12);
+				FreeBuf(b);
+				return false;
+			}
+			else
+			{
+				if (ParseP12(p12, x, k, password) == false)
+				{
+					MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+					FreeP12(p12);
+					FreeBuf(b);
+					return false;
+				}
+			}
+		}
+		if (CheckXandK(*x, *k) == false)
+		{
+			FreeX(*x);
+			FreeK(*k);
+			FreeP12(p12);
+			FreeBuf(b);
+			if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY)
+			{
+				goto START_FIRST;
+			}
+			return false;
+		}
+		FreeP12(p12);
+		FreeBuf(b);
+		return true;
+	}
+	else
+	{
+		// X509 の処理
+		BUF *b = ReadDumpW(tmp);
+		X *x509;
+		K *key;
+		if (b == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+			return false;
+		}
+
+		x509 = BufToX(b, IsBase64(b));
+		FreeBuf(b);
+		if (x509 == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_X509_W"), tmp);
+			return false;
+		}
+
+		// 秘密鍵を読み込む
+		s = OpenDlg(hWnd, _UU("DLG_KEY_FILTER"), _UU("DLG_OPEN_KEY_WITH_CERT"));
+		if (s == NULL)
+		{
+			FreeX(x509);
+			return false;
+		}
+		UniStrCpy(tmp, sizeof(tmp), s);
+		Free(s);
+
+		b = ReadDumpW(tmp);
+		if (b == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+			FreeX(x509);
+			return false;
+		}
+
+		if (IsEncryptedK(b, true) == false)
+		{
+			key = BufToK(b, true, IsBase64(b), NULL);
+		}
+		else
+		{
+			char pass[MAX_SIZE];
+			if (PassphraseDlg(hWnd, pass, sizeof(pass), b, false) == false)
+			{
+				FreeBuf(b);
+				FreeX(x509);
+				return false;
+			}
+			key = BufToK(b, true, IsBase64(b), pass);
+		}
+
+		if (key == NULL)
+		{
+			FreeBuf(b);
+			FreeX(x509);
+			MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_KEY_W"), tmp);
+			return false;
+		}
+
+		if (CheckXandK(x509, key) == false)
+		{
+			FreeBuf(b);
+			FreeX(x509);
+			FreeK(key);
+			if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY)
+			{
+				goto START_FIRST;
+			}
+			return false;
+		}
+
+		FreeBuf(b);
+		*x = x509;
+		*k = key;
+		return true;
+	}
+}
+
+// 仮想 HUB 列挙開始
+void CmEditAccountDlgStartEnumHub(HWND hWnd, CM_ACCOUNT *a)
+{
+	char server_name[MAX_HOST_NAME_LEN + 1];
+	UINT old_proxy_type;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	if (StrLen(a->ClientOption->Hostname) == 0)
+	{
+		return;
+	}
+	if (a->ClientOption->Port == 0)
+	{
+		return;
+	}
+	if (a->ClientOption->ProxyType != PROXY_DIRECT &&
+		(StrLen(a->ClientOption->ProxyName) == 0 ||
+		a->ClientOption->ProxyPort == 0))
+	{
+		return;
+	}
+
+	if (StrCmpi(server_name, a->old_server_name) == 0)
+	{
+		if (CbNum(hWnd, C_HUBNAME) != 0)
+		{
+			return;
+		}
+	}
+	else
+	{
+		StrCpy(a->old_server_name, sizeof(a->old_server_name), server_name);
+		CbReset(hWnd, C_HUBNAME);
+	}
+
+	old_proxy_type = a->ClientOption->ProxyType;
+
+	if (IsChecked(hWnd, R_DIRECT_TCP))
+	{
+		a->ClientOption->ProxyType = PROXY_DIRECT;
+	}
+	if (IsChecked(hWnd, R_HTTPS))
+	{
+		a->ClientOption->ProxyType = PROXY_HTTP;
+	}
+	if (IsChecked(hWnd, R_SOCKS))
+	{
+		a->ClientOption->ProxyType = PROXY_SOCKS;
+	}
+
+	CmEnumHubStart(hWnd, a->ClientOption);
+
+	a->ClientOption->ProxyType = old_proxy_type;
+}
+
+// [OK] ボタン
+void CmEditAccountDlgOnOk(HWND hWnd, CM_ACCOUNT *a)
+{
+	RPC_CLIENT_CREATE_ACCOUNT c;
+	bool b;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+	if (a->ClientOption->NumRetry != 0 && a->ClientOption->RetryInterval < 5)
+	{
+		MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_RETRY_INTERVAL_ERROR"));
+		FocusEx(hWnd, E_RETRY_SPAN);
+		return;
+	}
+
+	CmEditAccountDlgUpdate(hWnd, a);
+
+	if (a->LinkMode == false && a->NatMode == false)
+	{
+		// アカウントを保存
+		Zero(&c, sizeof(c));
+		c.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		Copy(c.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+		c.ClientAuth = CopyClientAuth(a->ClientAuth);
+		c.CheckServerCert = a->CheckServerCert;
+		if (a->ServerCert != NULL)
+		{
+			c.ServerCert = CloneX(a->ServerCert);
+		}
+		c.StartupAccount = a->Startup;
+
+		if (a->EditMode == false)
+		{
+			b = CALL(hWnd, CcCreateAccount(cm->Client, &c));
+		}
+		else
+		{
+			b = CALL(hWnd, CcSetAccount(cm->Client, &c));
+		}
+
+		CiFreeClientCreateAccount(&c);
+
+		// 現在このアカウントが動作中かどうかチェック
+		if (b)
+		{
+			RPC_CLIENT_GET_CONNECTION_STATUS st;
+			Zero(&st, sizeof(st));
+			UniStrCpy(st.AccountName, sizeof(st.AccountName), a->ClientOption->AccountName);
+			if (CALL(hWnd, CcGetAccountStatus(cm->Client, &st)))
+			{
+				if (st.Active)
+				{
+					MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_CURRENT_ACTIVE"),
+						st.AccountName);
+				}
+			}
+		}
+
+		if (b)
+		{
+			EndDialog(hWnd, true);
+		}
+	}
+	else
+	{
+		if (a->LinkMode)
+		{
+			// リンクモード
+			RPC_CREATE_LINK t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), a->Hub->HubName);
+			t.Online = a->OnlineFlag;
+			Copy(&t.Policy, &a->Policy, sizeof(POLICY));
+			t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+			Copy(t.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+			t.ClientAuth = CopyClientAuth(a->ClientAuth);
+			t.CheckServerCert = a->CheckServerCert;
+			t.ServerCert = CloneX(a->ServerCert);
+
+			// カスケード接続の設定を保存
+			if (a->EditMode)
+			{
+				if (CALL(hWnd, ScSetLink(a->Hub->Rpc, &t)))
+				{
+					if (a->OnlineFlag)
+					{
+						MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_LINK_SAVE_ONLINE"), a->ClientOption->AccountName);
+					}
+					EndDialog(hWnd, true);
+				}
+			}
+			else
+			{
+				if (CALL(hWnd, ScCreateLink(a->Hub->Rpc, &t)))
+				{
+					if (a->Link_ConnectNow)
+					{
+						RPC_LINK tt;
+
+						Zero(&tt, sizeof(tt));
+						UniStrCpy(tt.AccountName, sizeof(tt.AccountName), a->ClientOption->AccountName);
+						StrCpy(tt.HubName, sizeof(tt.HubName), a->Hub->HubName);
+
+						CALL(hWnd, ScSetLinkOnline(a->Hub->Rpc, &tt));
+					}
+					EndDialog(hWnd, true);
+				}
+			}
+
+			FreeRpcCreateLink(&t);
+		}
+		else
+		{
+			// NAT モード
+			RPC_CREATE_LINK t;
+			Zero(&t, sizeof(t));
+
+			t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+			Copy(t.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+			t.ClientAuth = CopyClientAuth(a->ClientAuth);
+
+			if (CALL(hWnd, NcSetClientConfig(a->Rpc, &t)))
+			{
+				EndDialog(hWnd, true);
+			}
+
+			FreeRpcCreateLink(&t);
+		}
+	}
+}
+
+// アカウント編集ダイアログの表示
+bool CmEditAccountDlg(HWND hWnd, CM_ACCOUNT *a)
+{
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	return Dialog(hWnd, D_CM_ACCOUNT, CmEditAccountDlgProc, a);
+}
+
+// アカウント編集
+void CmEditAccount(HWND hWnd, wchar_t *account_name)
+{
+	CM_ACCOUNT *a;
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+
+	a = CmGetExistAccountObject(hWnd, account_name);
+	if (a == NULL)
+	{
+		return;
+	}
+
+	CmVoice("input_config");
+	if (CmEditAccountDlg(hWnd, a))
+	{
+		CmVoice("set_config");
+	}
+
+	CmFreeAccountObject(hWnd, a);
+}
+
+// アカウント作成
+void CmNewAccount(HWND hWnd)
+{
+	CM_ACCOUNT *a;
+	RPC_CLIENT_ENUM_VLAN t;
+	UINT num_vlan = 0;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (IsEnable(hWnd, 0) == false)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CcEnumVLan(cm->Client, &t) == ERR_NO_ERROR)
+	{
+		num_vlan = t.NumItem;
+
+		CiFreeClientEnumVLan(&t);
+	}
+
+	if (num_vlan == 0)
+	{
+		if (MsgBox(hWnd, MB_ICONINFORMATION | MB_YESNO, _UU("CM_NO_VLAN")) == IDNO)
+		{
+			return;
+		}
+		else
+		{
+			if (cm->server_name == NULL)
+			{
+				Command(hWnd, CMD_NEW_VLAN);
+				return;
+			}
+			else
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_VLAN_REMOTE_ERROR"));
+			}
+			return;
+		}
+	}
+
+	a = CmCreateNewAccountObject(hWnd);
+	if (a == NULL)
+	{
+		return;
+	}
+
+	CmVoice("input_config");
+	if (CmEditAccountDlg(hWnd, a))
+	{
+		CmVoice("new_config");
+	}
+
+	CmFreeAccountObject(hWnd, a);
+}
+
+// アカウントオブジェクトの解放
+void CmFreeAccountObject(HWND hWnd, CM_ACCOUNT *a)
+{
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	Free(a->ClientOption);
+	CiFreeClientAuth(a->ClientAuth);
+	if (a->ServerCert != NULL)
+	{
+		FreeX(a->ServerCert);
+	}
+	Free(a);
+}
+
+// 既存のアカウントオブジェクトの取得
+CM_ACCOUNT *CmGetExistAccountObject(HWND hWnd, wchar_t *account_name)
+{
+	RPC_CLIENT_GET_ACCOUNT c;
+	CM_ACCOUNT *a;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&c, sizeof(c));
+	UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+	if (CALL(hWnd, CcGetAccount(cm->Client, &c)) == false)
+	{
+		return NULL;
+	}
+
+	a = ZeroMalloc(sizeof(CM_ACCOUNT));
+	a->EditMode = true;
+	a->CheckServerCert = c.CheckServerCert;
+	a->Startup = c.StartupAccount;
+	if (c.ServerCert != NULL)
+	{
+		a->ServerCert = CloneX(c.ServerCert);
+	}
+	a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	Copy(a->ClientOption, c.ClientOption, sizeof(CLIENT_OPTION));
+	a->ClientAuth = CopyClientAuth(c.ClientAuth);
+	Copy(a->ShortcutKey, c.ShortcutKey, SHA1_SIZE);
+	CiFreeClientGetAccount(&c);
+
+	a->LockMode = cm->CmSetting.LockMode;
+
+	return a;
+}
+
+// 新しいアカウントオブジェクトの作成
+CM_ACCOUNT *CmCreateNewAccountObject(HWND hWnd)
+{
+	CM_ACCOUNT *a;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	a = ZeroMalloc(sizeof(CM_ACCOUNT));
+	a->EditMode = false;
+	a->CheckServerCert = false;
+	a->Startup = false;
+	a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+
+	// クライアントオプションの初期化
+	CmGenerateNewAccountName(hWnd, a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName));
+	a->ClientOption->Port = 443;	// デフォルトポート番号
+	a->ClientOption->NumRetry = INFINITE;
+	a->ClientOption->RetryInterval = 15;
+	a->ClientOption->MaxConnection = 1;
+	a->ClientOption->HalfConnection = false;
+	a->ClientOption->UseEncrypt = true;
+	a->ClientOption->AdditionalConnectionInterval = 1;
+
+	if (cm->Client->Unix)
+	{
+		a->ClientOption->NoRoutingTracking = true;
+	}
+
+	a->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+	// パスワード認証
+	a->ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+
+	return a;
+}
+
+// インポート名の作成
+void CmGenerateImportName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name)
+{
+	UINT i;
+	// 引数チェック
+	if (name == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	for (i = 1;;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		if (i == 1)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_1"), old_name);
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_2"), old_name, i);
+		}
+
+		if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+		{
+			UniStrCpy(name, size, tmp);
+			return;
+		}
+	}
+}
+
+// コピー名の作成
+void CmGenerateCopyName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name)
+{
+	UINT i;
+	// 引数チェック
+	if (name == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	for (i = 1;;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		if (i == 1)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_COPY_NAME_1"), old_name);
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_COPY_NAME_2"), i, old_name);
+		}
+
+		if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+		{
+			UniStrCpy(name, size, tmp);
+			return;
+		}
+	}
+}
+
+// 新しいアカウント名の作成
+void CmGenerateNewAccountName(HWND hWnd, wchar_t *name, UINT size)
+{
+	UINT i;
+	// 引数チェック
+	if (name == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	for (i = 1;;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		if (i == 1)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_1"));
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_2"), i);
+		}
+
+		if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+		{
+			UniStrCpy(name, size, tmp);
+			return;
+		}
+	}
+}
+
+// ポリシー一覧を表示する
+void CmPolicyDlgPrint(HWND hWnd, CM_POLICY *p)
+{
+	CmPolicyDlgPrintEx(hWnd, p, false);
+}
+void CmPolicyDlgPrintEx(HWND hWnd, CM_POLICY *p, bool cascade_mode)
+{
+	CmPolicyDlgPrintEx2(hWnd, p, cascade_mode, POLICY_CURRENT_VERSION);
+}
+void CmPolicyDlgPrintEx2(HWND hWnd, CM_POLICY *p, bool cascade_mode, bool ver)
+{
+	POLICY *pol;
+	UINT i;
+	LVB *b;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	pol = p->Policy;
+
+	b = LvInsertStart();
+
+	for (i = 0;i < NUM_POLICY_ITEM;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+
+		if (cascade_mode)
+		{
+			if (PolicyIsSupportedForCascade(i) == false)
+			{
+				continue;
+			}
+		}
+
+		if (IS_POLICY_FOR_CURRENT_VER(i, ver))
+		{
+			if (policy_item[i].TypeInt == false)
+			{
+				// bool 型
+				UniStrCpy(tmp, sizeof(tmp), POLICY_BOOL(pol, i) ? _UU("POL_BOOL_ENABLE") : (p->Extension ? _UU("POL_BOOL_DISABLE_EX") : _UU("POL_BOOL_DISABLE")));
+			}
+			else
+			{
+				// int 型
+				if (policy_item[i].AllowZero && POLICY_INT(pol, i) == 0)
+				{
+					UniStrCpy(tmp, sizeof(tmp), _UU("POL_INT_ZERO"));
+				}
+				else
+				{
+					UniFormat(tmp, sizeof(tmp), _UU(policy_item[i].FormatStr), POLICY_INT(pol, i));
+				}
+			}
+
+			LvInsertAdd(b, ICO_MACHINE, (void *)i, 2, GetPolicyTitle(i), tmp);
+		}
+	}
+
+	LvInsertEnd(b, hWnd, L_POLICY);
+}
+
+// ポリシー一覧ダイアログ
+UINT CmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CM_POLICY *p = (CM_POLICY *)param;
+	NMHDR *n;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		FormatText(hWnd, 0, p->AccountName);
+		FormatText(hWnd, S_TITLE, p->AccountName);
+		p->hWnd = hWnd;
+		if (p->CmStatus != NULL)
+		{
+			p->CmStatus->hWndPolicy = hWnd;
+		}
+
+		// カラム初期化
+		LvInit(hWnd, L_POLICY);
+		LvInsertColumn(hWnd, L_POLICY, 0, _UU("POL_TITLE_STR"), 375);
+		LvInsertColumn(hWnd, L_POLICY, 1, _UU("POL_VALUE_STR"), 100);
+
+		// 表示
+		CmPolicyDlgPrint(hWnd, p);
+
+		// 1 つ目を選択
+		LvSelect(hWnd, L_POLICY, 0);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_POLICY:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				// 選択変更
+				if (LvIsSelected(hWnd, L_POLICY) == false)
+				{
+					SetText(hWnd, S_DESCRIPTION, L"");
+				}
+				else
+				{
+					UINT index = LvGetSelected(hWnd, L_POLICY);
+					UINT id = (UINT)LvGetParam(hWnd, L_POLICY, index);
+					if (id < NUM_POLICY_ITEM)
+					{
+						SetText(hWnd, S_DESCRIPTION, GetPolicyDescription(id));
+					}
+				}
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	LvSortHander(hWnd, msg, wParam, lParam, L_POLICY);
+
+	return 0;
+}
+
+// ポリシー一覧ダイアログの表示
+void CmPolicyDlg(HWND hWnd, CM_STATUS *st)
+{
+	RPC_CLIENT_GET_CONNECTION_STATUS s;
+	POLICY *policy;
+	CM_POLICY cp;
+	// 引数チェック
+	if (hWnd == NULL || st == NULL)
+	{
+		return;
+	}
+
+	// ポリシーの取得
+	Zero(&s, sizeof(s));
+	UniStrCpy(s.AccountName, sizeof(s.AccountName), st->AccountName);
+	if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+	{
+		return;
+	}
+	if (s.Active == false)
+	{
+		return;
+	}
+
+	policy = &s.Policy;
+
+	Zero(&cp, sizeof(cp));
+	UniStrCpy(cp.AccountName, sizeof(cp.AccountName), st->AccountName);
+	cp.Policy = policy;
+	cp.CmStatus = st;
+
+	Dialog(hWnd, D_CM_POLICY, CmPolicyDlgProc, &cp);
+
+	st->hWndPolicy = NULL;
+
+	CiFreeClientGetConnectionStatus(&s);
+}
+
+// 証明書の表示
+void CmStatusDlgPrintCert(HWND hWnd, CM_STATUS *st, bool server)
+{
+	RPC_CLIENT_GET_CONNECTION_STATUS s;
+	X *x, *issuer;
+	// 引数チェック
+	if (hWnd == NULL || st == NULL)
+	{
+		return;
+	}
+
+	// 最新情報を取得する
+	Zero(&s, sizeof(s));
+	UniStrCpy(s.AccountName, sizeof(s.AccountName), st->AccountName);
+	if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	if (s.Active == false)
+	{
+		// 接続切断
+		Close(hWnd);
+		return;
+	}
+
+	if (server == false)
+	{
+		// クライアント証明書の表示
+		x = s.ClientX;
+	}
+	else
+	{
+		// サーバー証明書の表示
+		x = s.ServerX;
+	}
+
+	cm->WindowCount++;
+	issuer = CmGetIssuer(x);
+	CertDlg(hWnd, x, issuer, true);
+	FreeX(issuer);
+	cm->WindowCount--;
+
+	CiFreeClientGetConnectionStatus(&s);
+}
+
+// ステータスダイアログの情報を表示
+void CmStatusDlgPrint(HWND hWnd, CM_STATUS *cmst)
+{
+	RPC_CLIENT_GET_CONNECTION_STATUS s;
+	LVB *b;
+	// 引数チェック
+	if (hWnd == NULL || cmst == NULL)
+	{
+		return;
+	}
+
+	// 最新情報を取得する
+	Zero(&s, sizeof(s));
+	UniStrCpy(s.AccountName, sizeof(s.AccountName), cmst->AccountName);
+	if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	if (s.Active == false)
+	{
+		// 接続切断
+		Close(hWnd);
+		return;
+	}
+
+	// ステータスダイアログのリストボックスにステータスを表示する
+	b = LvInsertStart();
+	CmPrintStatusToListView(b, &s);
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	LvAutoSize(hWnd, L_STATUS);
+
+	SetEnable(hWnd, B_POLICY, s.Connected);
+
+	SetEnable(hWnd, B_SERVER_CERT, s.ServerX != NULL);
+	SetEnable(hWnd, B_CLIENT_CERT, s.ClientX != NULL);
+
+	CiFreeClientGetConnectionStatus(&s);
+}
+
+// ステータスダイアログのリストボックスにステータスを表示する
+void CmPrintStatusToListView(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s)
+{
+	CmPrintStatusToListViewEx(b, s, false);
+}
+void CmPrintStatusToListViewEx(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode)
+{
+	wchar_t tmp[MAX_SIZE];
+	char str[MAX_SIZE];
+	char vv[128];
+	// 引数チェック
+	if (b == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (server_mode == false)
+	{
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_ACCOUNT_NAME"), s->AccountName);
+
+		if (s->Connected == false)
+		{
+			wchar_t *st = _UU("CM_ST_CONNECTED_FALSE");
+			switch (s->SessionStatus)
+			{
+			case CLIENT_STATUS_CONNECTING:
+				st = _UU("CM_ST_CONNECTING");
+				break;
+			case CLIENT_STATUS_NEGOTIATION:
+				st = _UU("CM_ST_NEGOTIATION");
+				break;
+			case CLIENT_STATUS_AUTH:
+				st = _UU("CM_ST_AUTH");
+				break;
+			case CLIENT_STATUS_ESTABLISHED:
+				st = _UU("CM_ST_ESTABLISHED");
+				break;
+			case CLIENT_STATUS_RETRY:
+				st = _UU("CM_ST_RETRY");
+				break;
+			case CLIENT_STATUS_IDLE:
+				st = _UU("CM_ST_IDLE");
+				break;
+			}
+			LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTED"), st);
+		}
+		else
+		{
+			LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTED"), _UU("CM_ST_CONNECTED_TRUE"));
+		}
+	}
+
+	if (s->Connected)
+	{
+		if (s->VLanId == 0)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_NO_VLAN"));
+		}
+		else
+		{
+			UniToStru(tmp, s->VLanId);
+		}
+
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_VLAN_ID"), tmp);
+
+		if (server_mode == false)
+		{
+			StrToUni(tmp, sizeof(tmp), s->ServerName);
+			LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_NAME"), tmp);
+
+			UniFormat(tmp, sizeof(tmp), _UU("CM_ST_PORT_TCP"), s->ServerPort);
+			LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_PORT"), tmp);
+		}
+
+		StrToUni(tmp, sizeof(tmp), s->ServerProductName);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_NAME"), tmp);
+
+		UniFormat(tmp, sizeof(tmp), L"%u.%02u", s->ServerProductVer / 100, s->ServerProductVer % 100);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_VER"), tmp);
+		UniFormat(tmp, sizeof(tmp), L"Build %u", s->ServerProductBuild);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_BUILD"), tmp);
+	}
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL);
+	LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_START_TIME"), tmp);
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablisiedTime), NULL);
+	LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablisiedTime == 0 ? _UU("CM_ST_NONE") : tmp);
+
+	if (s->Connected)
+	{
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->CurrentConnectionEstablishTime), NULL);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CURR_ESTAB_TIME"), tmp);
+	}
+
+	if (server_mode == false)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_STR"), s->NumConnectionsEatablished);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_ESTABLISHED"), tmp);
+	}
+
+	if (s->Connected)
+	{
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_HALF_CONNECTION"), s->HalfConnection ? _UU("CM_ST_HALF_TRUE") : _UU("CM_ST_HALF_FALSE"));
+
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_QOS"), s->QoS ? _UU("CM_ST_QOS_TRUE") : _UU("CM_ST_QOS_FALSE"));
+
+		UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnections);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP"), tmp);
+
+		if (s->HalfConnection)
+		{
+			UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsUpload);
+			LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP_UPLOAD"), tmp);
+			UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsDownload);
+			LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP_DOWNLOAD"), tmp);
+		}
+
+		UniFormat(tmp, sizeof(tmp), L"%u", s->MaxTcpConnections);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_MAX_TCP"), tmp);
+
+		if (s->UseEncrypt == false)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_FALSE"));
+		}
+		else
+		{
+			if (StrLen(s->CipherName) != 0)
+			{
+				UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE"), s->CipherName);
+			}
+			else
+			{
+				UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE2"));
+			}
+		}
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_USE_ENCRYPT"), tmp);
+
+		if (s->UseCompress)
+		{
+			UINT percent = 0;
+			if ((s->TotalRecvSize + s->TotalSendSize) > 0)
+			{
+				percent = (UINT)((UINT64)100 - (UINT64)(s->TotalRecvSizeReal + s->TotalSendSizeReal) * (UINT64)100 /
+					(s->TotalRecvSize + s->TotalSendSize));
+				percent = MAKESURE(percent, 0, 100);
+			}
+
+			UniFormat(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_TRUE"), percent);
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_FALSE"));
+		}
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_USE_COMPRESS"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), s->SessionName);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SESSION_NAME"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), s->ConnectionName);
+		if (UniStrCmpi(tmp, L"INITING") != 0)
+		{
+			LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTION_NAME"), tmp);
+		}
+
+		BinToStr(str, sizeof(str), s->SessionKey, sizeof(s->SessionKey));
+		StrToUni(tmp, sizeof(tmp), str);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SESSION_KEY"), tmp);
+
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_BRIDGE_MODE"), s->IsBridgeMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_MONITOR_MODE"), s->IsMonitorMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+		ToStr3(vv, sizeof(vv), s->TotalSendSize);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->TotalRecvSize);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastCount);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_UCAST_NUM"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastBytes);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_UCAST_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastCount);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_BCAST_NUM"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastBytes);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_BCAST_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastCount);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_UCAST_NUM"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastBytes);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_UCAST_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastCount);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_BCAST_NUM"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastBytes);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_BCAST_SIZE"), tmp);
+	}
+}
+
+// ステータスダイアログプロシージャ
+UINT CmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	wchar_t tmp[MAX_SIZE];
+	CM_STATUS *s = (CM_STATUS *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetIcon(hWnd, 0, ICO_TOWER);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_TITLE"), s->AccountName);
+		SetText(hWnd, 0, tmp);
+		FormatText(hWnd, S_TITLE, s->AccountName);
+		DlgFont(hWnd, S_TITLE, 0, 1);
+
+		Add(cm->StatusWindowList, hWnd);
+
+		SetTimer(hWnd, 1, 500, NULL);
+
+		LvInitEx(hWnd, L_STATUS, true);
+		ListView_SetImageList(DlgItem(hWnd, L_STATUS), NULL, LVSIL_NORMAL);
+		ListView_SetImageList(DlgItem(hWnd, L_STATUS), NULL, LVSIL_SMALL);
+		LvInsertColumn(hWnd, L_STATUS, 0, _UU("CM_ST_COLUMN_1"), 160);
+		LvInsertColumn(hWnd, L_STATUS, 1, _UU("CM_ST_COLUMN_2"), 270);
+
+		CmStatusDlgPrint(hWnd, s);
+
+		break;
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			CmStatusDlgPrint(hWnd, s);
+			SetTimer(hWnd, 1, 500, NULL);
+			break;
+		}
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			// 閉じる
+			Close(hWnd);
+			break;
+		case B_POLICY:
+			// ポリシー表示
+			CmPolicyDlg(hWnd, s);
+			break;
+		case B_SERVER_CERT:
+			CmStatusDlgPrintCert(hWnd, s, true);
+			break;
+		case B_CLIENT_CERT:
+			CmStatusDlgPrintCert(hWnd, s, false);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		Delete(cm->StatusWindowList, hWnd);
+		if (s->hWndPolicy != NULL)
+		{
+			EndDialog(s->hWndPolicy, false);
+			s->hWndPolicy = NULL;
+		}
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ステータスダイアログの表示
+void CmStatusDlg(HWND hWnd, wchar_t *account_name)
+{
+	CM_STATUS *s;
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+
+	s = ZeroMalloc(sizeof(CM_STATUS));
+	UniStrCpy(s->AccountName, sizeof(s->AccountName), account_name);
+
+	Dialog(hWnd, D_CONNECTION_STATUS, CmStatusDlgProc, s);
+
+	Free(s);
+}
+
+// ステータスの表示
+void CmStatus(HWND hWnd, wchar_t *account_name)
+{
+	UINT i;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+
+	UniFormat(tmp, sizeof(tmp), _UU("CM_ST_TITLE"), account_name);
+
+	for (i = 0;i < LIST_NUM(cm->StatusWindowList);i++)
+	{
+		HWND h = LIST_DATA(cm->StatusWindowList, i);
+		if (h != NULL)
+		{
+			wchar_t tmp2[MAX_SIZE];
+			if (GetTxt(h, 0, tmp2, sizeof(tmp2)))
+			{
+				if (UniStrCmpi(tmp2, tmp) == 0)
+				{
+					SetActiveWindow(h);
+					return;
+				}
+			}
+		}
+	}
+
+	CmStatusDlg(hWnd, account_name);
+}
+
+// 削除
+void CmDeleteAccount(HWND hWnd, wchar_t *account_name)
+{
+	RPC_CLIENT_DELETE_ACCOUNT c;
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+	Zero(&c, sizeof(c));
+	UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+	CmVoice("delete_config_1");
+	if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_ACCOUNT_MSG"), account_name)
+		== IDNO)
+	{
+		return;
+	}
+
+	CALL(hWnd, CcDeleteAccount(cm->Client, &c));
+	CmVoice("delete_config_2");
+}
+
+// 切断
+void CmDisconnect(HWND hWnd, wchar_t *account_name)
+{
+	RPC_CLIENT_CONNECT c;
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+
+	Zero(&c, sizeof(c));
+	UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+	cm->PositiveDisconnectFlag = true;
+
+	CALL(hWnd, CcDisconnect(cm->Client, &c));
+}
+
+// 宣伝ウインドウの表示
+void SmShowPublicVpnServerHtml(HWND hWnd)
+{
+	char *langstr = _SS("LANGSTR");
+
+	if(StrCmpi(langstr, "Japanese") == 0)
+	{
+		ShowHtml(hWnd, PUBLIC_SERVER_HTML, PUBLIC_SERVER_TAG);
+	}
+	else
+	{
+		ShowHtml(hWnd, PUBLIC_SERVER_HTML_EN, PUBLIC_SERVER_TAG);
+	}
+}
+
+// 接続
+void CmConnect(HWND hWnd, wchar_t *account_name)
+{
+	RPC_CLIENT_CONNECT c;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || account_name == NULL)
+	{
+		return;
+	}
+
+	if (IsEnable(hWnd, 0) == false)
+	{
+		return;
+	}
+
+	if (hWnd == cm->hMainWnd)
+	{
+		if (LvNum(hWnd, L_VLAN) == 0 && cm->Client->Win9x)
+		{
+			if (MsgBox(hWnd, MB_ICONINFORMATION | MB_YESNO, _UU("CM_NO_VLAN_2")) == IDNO)
+			{
+				return;
+			}
+			else
+			{
+				if (cm->server_name == NULL)
+				{
+					Command(hWnd, CMD_NEW_VLAN);
+					return;
+				}
+				else
+				{
+					MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_VLAN_REMOTE_ERROR"));
+				}
+				return;
+			}
+		}
+	}
+
+	// 警告を表示 (必要な場合)
+	if (CmWarningDesktop(hWnd, account_name) == false)
+	{
+		return;
+	}
+
+	if (cm->server_name == NULL)
+	{
+		if (cm->BadProcessChecked == false)
+		{
+			cm->BadProcessChecked = true;
+
+			CheckBadProcesses(hWnd);
+		}
+	}
+
+	if (cm->server_name == NULL)
+	{
+		// Windows バージョンチェック
+		RPC_WINVER winver;
+		wchar_t winver_msg_client[3800];
+
+		GetWinVer(&winver);
+		Zero(winver_msg_client, sizeof(winver_msg_client));
+
+		if (IsSupportedWinVer(&winver) == false)
+		{
+			SYSTEMTIME st;
+
+			LocalTime(&st);
+
+			UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+				_UU("WINVER_ERROR_PC_LOCAL"),
+				winver.Title,
+				_UU("WINVER_ERROR_VPNCLIENT"),
+				SUPPORTED_WINDOWS_LIST,
+				_UU("WINVER_ERROR_PC_LOCAL"),
+				_UU("WINVER_ERROR_VPNCLIENT"),
+				_UU("WINVER_ERROR_VPNCLIENT"),
+				_UU("WINVER_ERROR_VPNCLIENT"),
+				st.wYear, st.wMonth);
+		}
+
+		if (UniIsEmptyStr(winver_msg_client) == false)
+		{
+			OnceMsgEx(hWnd, _UU("WINVER_TITLE"), winver_msg_client,
+				true, ICO_WARNING, NULL);
+		}
+	}
+
+	i = LvSearchStr(hWnd, L_ACCOUNT, 0, account_name);
+	if (i != INFINITE)
+	{
+		wchar_t *tmp = LvGetStr(hWnd, L_ACCOUNT, i, 2);
+		if (tmp != NULL)
+		{
+			wchar_t tag[MAX_SIZE];
+			StrToUni(tag, sizeof(tag), PUBLIC_SERVER_NAME);
+
+			if (UniSearchStrEx(tmp, tag, 0, false) != INFINITE)
+			{
+				SmShowPublicVpnServerHtml(hWnd);
+			}
+
+			Free(tmp);
+		}
+	}
+
+	Zero(&c, sizeof(c));
+	UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+	CmSetForegroundProcessToCnService();
+
+	if (CALL(hWnd, CcConnect(cm->Client, &c)))
+	{
+		cm->ConnectStartedFlag = true;
+	}
+}
+
+// 指定されたメニュー項目を太字にするかどうか判断する
+bool CmIsBold(UINT id)
+{
+	return false;
+}
+
+// 指定されたメニュー項目を有効にするかどうか判断する
+bool CmIsEnabled(HWND hWnd, UINT id)
+{
+	UINT index;
+	wchar_t *name;
+	bool locked = false;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	locked = cm->CmSetting.LockMode;
+
+	if (locked)
+	{
+		switch (id)
+		{
+		case CMD_NEW:
+		case CMD_CLONE:
+		case CMD_IMPORT_ACCOUNT:
+		case CMD_DELETE:
+		case CMD_TCPIP:
+		case CMD_OPTION:
+		case CMD_VOIDE_NONE:
+		case CMD_VOICE_NORMAL:
+		case CMD_VOICE_ODD:
+		case CMD_STARTUP:
+		case CMD_NOSTARTUP:
+		case CMD_TRAFFIC:
+		case CMD_MMCSS:
+			return false;
+		case CMD_NEW_VLAN:
+		case CMD_ENABLE_VLAN:
+		case CMD_DISABLE_VLAN:
+		case CMD_DELETE_VLAN:
+		case CMD_REINSTALL:
+		case CMD_WINNET:
+			if (cm->CmEasyModeSupported)
+			{
+				return false;
+			}
+		}
+	}
+
+	switch (id)
+	{
+	case CMD_SHOWPORT:
+	case CMD_GRID:
+		if (cm->IconView)
+		{
+			return false;
+		}
+		return true;
+	case CMD_TCPIP:
+		if (MsIsTcpConfigSupported() == false)
+		{
+			return false;
+		}
+		return cm->server_name != NULL ? false : true;
+	case CMD_MMCSS:
+		if (MsIsVista() == false || IsEmptyStr(cm->server_name) == false)
+		{
+			return false;
+		}
+		if (OS_IS_SERVER(GetOsType()))
+		{
+			return false;
+		}
+		return true;
+	case CMD_TRAYICON:
+	case CMD_TRAFFIC:
+		return (cm->server_name == NULL);
+	case CMD_NETIF:
+		if (MsIsNt() == false)
+		{
+			return false;
+		}
+		return (cm->server_name == NULL);
+	case CMD_CM_SETTING:
+		return cm->CmSettingSupported;
+	case CMD_CONNECT:
+	case CMD_DISCONNECT:
+	case CMD_STATUS:
+	case CMD_RENAME:
+	case CMD_DELETE:
+		if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+		{
+			return false;
+		}
+		if (LvIsSelected(hWnd, L_ACCOUNT) == false)
+		{
+			return false;
+		}
+		else
+		{
+			// 選択されているアカウントが接続中かどうか判別する
+			UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+			wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+			wchar_t *name = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+			bool is_connected = false;
+			if (str != NULL)
+			{
+				if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+				{
+					is_connected = true;
+				}
+				Free(str);
+			}
+			if (name != NULL)
+			{
+				if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_ASP")) == 0)
+				{
+					Free(name);
+					return false;
+				}
+				Free(name);
+			}
+			if (id == CMD_CONNECT || id == CMD_RENAME || id == CMD_DELETE)
+			{
+				return !is_connected;
+			}
+			else
+			{
+				return is_connected;
+			}
+		}
+		break;
+	case CMD_DISCONNECT_ALL:
+		if (CmGetNumConnected(hWnd) == 0)
+		{
+			return false;
+		}
+		else
+		{
+			return true;
+		}
+	case CMD_SHORTCUT:
+		// ショートカットの作成
+		if (cm->Client->Rpc->Sock->RemoteIP.addr[0] != 127)
+		{
+			return false;
+		}
+	case CMD_EXPORT_ACCOUNT:
+		if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+		{
+			return false;
+		}
+		name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+		if (name != NULL)
+		{
+			if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_ASP")) == 0)
+			{
+				Free(name);
+				return false;
+			}
+			Free(name);
+		}
+		return LvIsSelected(hWnd, L_ACCOUNT);
+	case CMD_CLONE:
+		if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+		{
+			return false;
+		}
+		name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+		if (name != NULL)
+		{
+			if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_ASP")) == 0)
+			{
+				Free(name);
+				return false;
+			}
+			Free(name);
+		}
+		return LvIsSelected(hWnd, L_ACCOUNT);
+	case CMD_STARTUP:
+	case CMD_NOSTARTUP:
+		name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+		if (name != NULL)
+		{
+			if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_ASP")) == 0)
+			{
+				Free(name);
+				return false;
+			}
+			Free(name);
+		}
+		if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+		{
+			return false;
+		}
+		if (LvIsSelected(hWnd, L_ACCOUNT) == false)
+		{
+			return false;
+		}
+		else
+		{
+			// 選択されているアカウントがスタートアップアカウントかどうか判別する
+			UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+			bool is_startup = (bool)LvGetParam(hWnd, L_ACCOUNT, i);
+			if (id == CMD_STARTUP)
+			{
+				return !is_startup;
+			}
+			else
+			{
+				return is_startup;
+			}
+		}
+		break;
+	case CMD_NEW_VLAN:
+		if (cm->Client->Unix == false && cm->Client->Win9x == false)
+		{
+			if (cm->server_name != NULL)
+			{
+				return false;
+			}
+		}
+		if (cm->Client->Win9x)
+		{
+			if (LvNum(hWnd, L_VLAN) >= 1)
+			{
+				// Win9x では 2 枚以上の仮想 LAN カードをインストールできない
+				return false;
+			}
+		}
+		break;
+	case CMD_PROPERTY:
+		name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+		if (name != NULL)
+		{
+			if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_ASP")) == 0)
+			{
+				Free(name);
+				return false;
+			}
+			Free(name);
+		}
+		if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+		{
+			return false;
+		}
+		return LvIsSelected(hWnd, L_ACCOUNT);
+	case CMD_DELETE_VLAN:
+		if (LvIsMultiMasked(hWnd, L_VLAN))
+		{
+			return false;
+		}
+		return LvIsSelected(hWnd, L_VLAN);
+	case CMD_ENABLE_VLAN:
+		if (cm->Client->Win9x)
+		{
+			return false;
+		}
+		if (LvIsMultiMasked(hWnd, L_VLAN))
+		{
+			return false;
+		}
+		index = LvGetSelected(hWnd, L_VLAN);
+		if (index == INFINITE)
+		{
+			return false;
+		}
+		else
+		{
+			wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 1);
+			if (s != NULL)
+			{
+				if (UniStrCmpi(s, _UU("CM_VLAN_DISABLED")) == 0)
+				{
+					Free(s);
+					return true;
+				}
+				Free(s);
+			}
+			return false;
+		}
+		break;
+	case CMD_DISABLE_VLAN:
+		if (cm->Client->Win9x)
+		{
+			return false;
+		}
+		if (LvIsMultiMasked(hWnd, L_VLAN))
+		{
+			return false;
+		}
+		index = LvGetSelected(hWnd, L_VLAN);
+		if (index == INFINITE)
+		{
+			return false;
+		}
+		else
+		{
+			wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 1);
+			if (s != NULL)
+			{
+				if (UniStrCmpi(s, _UU("CM_VLAN_ENABLED")) == 0)
+				{
+					Free(s);
+					return true;
+				}
+				Free(s);
+			}
+			return false;
+		}
+		break;
+	case CMD_REINSTALL:
+		if (cm->server_name != NULL)
+		{
+			return false;
+		}
+		if (cm->Client->Win9x || cm->Client->Unix)
+		{
+			// Win9x と UNIX 系では仮想 LAN カードのアップグレード不可
+			return false;
+		}
+		if (LvIsMultiMasked(hWnd, L_VLAN))
+		{
+			return false;
+		}
+		return LvIsSelected(hWnd, L_VLAN);
+	case CMD_WINNET:
+		{
+			UINT os_type = GetOsInfo()->OsType;
+
+			if (OS_IS_WINDOWS_NT(os_type) && GET_KETA(os_type, 100) >= 2)
+			{
+				if (cm->server_name != NULL)
+				{
+					return false;
+				}
+
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		break;
+	case CMD_EXIT:
+		return cm->TrayInited;
+	}
+	return true;
+}
+
+// VLAN デバイス名を表示名に変換
+void CmVLanNameToPrintName(char *str, UINT size, char *name)
+{
+	// 引数チェック
+	if (str == NULL || name == NULL)
+	{
+		return;
+	}
+
+	Format(str, size, VLAN_ADAPTER_NAME_TAG, name);
+}
+
+// 表示名を VLAN デバイス名に変換
+bool CmPrintNameToVLanName(char *name, UINT size, char *str)
+{
+	// 引数チェック
+	if (name == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	if (StartWith(str, VLAN_ADAPTER_NAME))
+	{
+		if (StrLen(str) < (StrLen(VLAN_ADAPTER_NAME) + 3))
+		{
+			return false;
+		}
+
+		StrCpy(name, size, str + StrLen(VLAN_ADAPTER_NAME) + 3);
+
+		return true;
+	}
+
+	return false;
+}
+
+// アカウントリストの初期化
+void CmInitAccountList(HWND hWnd)
+{
+	CmInitAccountListEx(hWnd, false);
+}
+void CmInitAccountListEx(HWND hWnd, bool easy)
+{
+	UINT width[5];
+	BUF *b;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 設定読み込み
+	b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "AccountListColumnWidth");
+	if ((b != NULL) && (b->Size == sizeof(width)))
+	{
+		Copy(width, b->Buf, sizeof(width));
+	}
+	else if ((b != NULL) && (b->Size == (sizeof(width) - sizeof(UINT))))
+	{
+		// 旧バージョンからの移行
+		Zero(width, sizeof(width));
+		Copy(width, b->Buf, sizeof(width) - sizeof(UINT));
+		width[4] = width[3];
+		width[3] = 0;
+	}
+	else
+	{
+		Zero(width, sizeof(width));
+	}
+	FreeBuf(b);
+
+	LvInitEx2(hWnd, L_ACCOUNT, false, easy);
+
+//	LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_TRACKSELECT);
+
+	// カラムの初期化
+	if (easy == false)
+	{
+		LvInsertColumn(hWnd, L_ACCOUNT, 0, _UU("CM_ACCOUNT_COLUMN_1"), width[0] == 0 ? 215 : width[0]);
+		LvInsertColumn(hWnd, L_ACCOUNT, 1, _UU("CM_ACCOUNT_COLUMN_2"), width[1] == 0 ? 80 : width[1]);
+		LvInsertColumn(hWnd, L_ACCOUNT, 2, _UU("CM_ACCOUNT_COLUMN_3"), width[2] == 0 ? 220 : width[2]);
+		LvInsertColumn(hWnd, L_ACCOUNT, 3, _UU("CM_ACCOUNT_COLUMN_3_2"), width[3] == 0 ? 90 : width[3]);
+		LvInsertColumn(hWnd, L_ACCOUNT, 4, _UU("CM_ACCOUNT_COLUMN_4"), (width[4] == 0 || width[4] == 250) ? 120 : width[4]);
+
+		//LvSetBkImage(hWnd, L_ACCOUNT, "|ClientBack2.bmp");
+	}
+	else
+	{
+		LvInsertColumn(hWnd, L_ACCOUNT, 0, _UU("CM_ACCOUNT_COLUMN_1"), 345);
+		LvInsertColumn(hWnd, L_ACCOUNT, 1, _UU("CM_ACCOUNT_COLUMN_2"), 140);
+		LvInsertColumn(hWnd, L_ACCOUNT, 2, _UU("CM_ACCOUNT_COLUMN_3"), 0);
+		LvInsertColumn(hWnd, L_ACCOUNT, 3, _UU("CM_ACCOUNT_COLUMN_3_2"), 0);
+		LvInsertColumn(hWnd, L_ACCOUNT, 4, _UU("CM_ACCOUNT_COLUMN_4"), 0);
+	}
+
+}
+
+// アカウントリストの解放
+void CmSaveAccountListPos(HWND hWnd)
+{
+	UINT width[5];
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < 5;i++)
+	{
+		width[i] = LvGetColumnWidth(hWnd, L_ACCOUNT, i);
+	}
+
+	MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "AccountListColumnWidth", width, sizeof(width));
+}
+
+// VLAN リストの初期化
+void CmInitVLanList(HWND hWnd)
+{
+	UINT width[4];
+	BUF *b;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 設定読み込み
+	b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "VLanListColumnWidth");
+	if ((b != NULL) && (b->Size == sizeof(width)))
+	{
+		Copy(width, b->Buf, sizeof(width));
+	}
+	else
+	{
+		Zero(width, sizeof(width));
+	}
+	FreeBuf(b);
+
+	LvInit(hWnd, L_VLAN);
+
+//	LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_TRACKSELECT);
+
+	// カラムの初期化
+	LvInsertColumn(hWnd, L_VLAN, 0, _UU("CM_VLAN_COLUMN_1"), width[0] == 0 ? 310 : width[0]);
+	LvInsertColumn(hWnd, L_VLAN, 1, _UU("CM_VLAN_COLUMN_2"), width[1] == 0 ? 120 : width[1]);
+	LvInsertColumn(hWnd, L_VLAN, 2, _UU("CM_VLAN_COLUMN_3"), width[2] == 0 ? 175 : width[2]);
+	LvInsertColumn(hWnd, L_VLAN, 3, _UU("CM_VLAN_COLUMN_4"), width[3] == 0 ? 120 : width[3]);
+
+	// 背景イメージ
+	LvSetBkImage(hWnd, L_VLAN, "|ClientBack2.bmp");
+}
+
+// VLAN リストの解放
+void CmSaveVLanListPos(HWND hWnd)
+{
+	UINT width[4];
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < 4;i++)
+	{
+		width[i] = LvGetColumnWidth(hWnd, L_VLAN, i);
+	}
+
+	MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "VLanListColumnWidth", width, sizeof(width));
+}
+
+// アカウントリストの更新
+void CmRefreshAccountList(HWND hWnd)
+{
+	CmRefreshAccountListEx(hWnd, false);
+	CmRefreshEasy();
+}
+void CmRefreshAccountListEx(HWND hWnd, bool easy)
+{
+	CmRefreshAccountListEx2(hWnd, easy, false);
+}
+void CmRefreshAccountListEx2(HWND hWnd, bool easy, bool style_changed)
+{
+	UINT num = 0;
+	RPC_CLIENT_ENUM_ACCOUNT a;
+	UINT num_connecting = 0, num_connected = 0;
+	wchar_t tmp[MAX_SIZE];
+	wchar_t new_inserted_item[MAX_ACCOUNT_NAME_LEN + 1];
+	bool select_new_insteted_item = true;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// アイコン / 詳細表示の切り替え
+	LvSetView(hWnd, L_ACCOUNT, cm->IconView == false || easy);
+
+	// グリッド表示
+	if (cm->ShowGrid || easy)
+	{
+		LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_GRIDLINES);
+	}
+	else
+	{
+		LvRemoveStyle(hWnd, L_ACCOUNT, LVS_EX_GRIDLINES);
+	}
+
+	if (style_changed)
+	{
+		// フォントの変更
+		if (easy == false)
+		{
+			if (cm->VistaStyle)
+			{
+				SetFontMeiryo(hWnd, L_ACCOUNT);
+			}
+			else
+			{
+				SetFontDefault(hWnd, L_ACCOUNT);
+			}
+
+			if (cm->VistaStyle && (cm->IconView == false))
+			{
+				LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_FULLROWSELECT);
+			}
+			else
+			{
+				LvRemoveStyle(hWnd, L_ACCOUNT, LVS_EX_FULLROWSELECT);
+			}
+		}
+	}
+
+	Zero(new_inserted_item, sizeof(new_inserted_item));
+
+	if (LvNum(hWnd, L_ACCOUNT) == 0)
+	{
+		select_new_insteted_item = false;
+	}
+
+	// アカウントリストの列挙
+	if (CALL(hWnd, CcEnumAccount(cm->Client, &a)))
+	{
+		UINT i;
+		LVB *b = LvInsertStart();
+
+		if (cm->CmSetting.LockMode == false && (easy == false))
+		{
+			// 特別なアイコン
+			LvInsertAdd(b, ICO_NEW, NULL, 4, _UU("CM_NEW_ICON"), L"", L"", L"");
+			LvInsertAdd(b, ICO_INTERNET, NULL, 4, _UU("CM_ASP"), L"", L"", L"");
+		}
+
+		for (i = 0;i < a.NumItem;i++)
+		{
+			RPC_CLIENT_ENUM_ACCOUNT_ITEM *t = a.Items[i];
+			UINT icon;
+			wchar_t tmp[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			char tmp3[MAX_SIZE];
+			wchar_t tmp4[MAX_SIZE];
+			IP ip;
+			char ip_str[MAX_SIZE];
+
+			// IPv6 アドレスの場合の特別処理
+			if (StrToIP6(&ip, t->ServerName) && StartWith(t->ServerName, "[") == false)
+			{
+				Format(ip_str, sizeof(ip_str),
+					"[%s]", t->ServerName);
+			}
+			else
+			{
+				StrCpy(ip_str, sizeof(ip_str), t->ServerName);
+			}
+
+			// アイコンの決定
+			if (t->Active == false)
+			{
+				if (t->StartupAccount == false)
+				{
+					icon = ICO_SERVER_OFFLINE;
+				}
+				else
+				{
+					icon = ICO_SERVER_OFFLINE_EX;
+				}
+			}
+			else
+			{
+				num++;
+				if (t->StartupAccount == false)
+				{
+					icon = ICO_SERVER_ONLINE;
+				}
+				else
+				{
+					icon = ICO_SERVER_ONLINE_EX;
+				}
+			}
+
+			// 追加
+			if (easy == false)
+			{
+				//CmVLanNameToPrintName(tmp3, sizeof(tmp3), t->DeviceName);
+				StrCpy(tmp3, sizeof(tmp3), t->DeviceName);
+				StrToUni(tmp, sizeof(tmp), tmp3);
+			}
+			else
+			{
+				StrToUni(tmp, sizeof(tmp), t->DeviceName);
+			}
+
+			if (t->Port == 0 || cm->ShowPort == false)
+			{
+				// ポート番号不明
+				UniFormat(tmp2, sizeof(tmp2), L"%S (%s)", ip_str, CmGetProtocolName(t->ProxyType));
+			}
+			else
+			{
+				// ポート番号併記
+				UniFormat(tmp2, sizeof(tmp2), L"%S:%u (%s)", ip_str, t->Port, CmGetProtocolName(t->ProxyType));
+			}
+
+			if (LvSearchStr(hWnd, L_ACCOUNT, 0, t->AccountName) == INFINITE)
+			{
+				UniStrCpy(new_inserted_item, sizeof(new_inserted_item), t->AccountName);
+			}
+
+			// 仮想 HUB 名
+			StrToUni(tmp4, sizeof(tmp4), t->HubName);
+
+			if (easy == false)
+			{
+				LvInsertAdd(b, icon, (void *)t->StartupAccount, 5, t->AccountName,
+					t->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+					(t->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+					tmp2, tmp4,
+					tmp);
+			}
+			else
+			{
+				LvInsertAdd(b, icon, (void *)t->StartupAccount, 5, t->AccountName,
+					t->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+					(t->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+					tmp2, tmp4,
+					tmp);
+			}
+
+			if (t->Active)
+			{
+				if (t->Connected)
+				{
+					num_connected++;
+				}
+				else
+				{
+					num_connecting++;
+				}
+			}
+		}
+
+		LvInsertEnd(b, hWnd, L_ACCOUNT);
+
+		CiFreeClientEnumAccount(&a);
+
+		if (select_new_insteted_item)
+		{
+			if (UniStrLen(new_inserted_item) >= 1)
+			{
+				LvSelect(hWnd, L_ACCOUNT, INFINITE);
+				LvSelect(hWnd, L_ACCOUNT, LvSearchStr(hWnd, L_ACCOUNT, 0, new_inserted_item));
+			}
+		}
+	}
+
+	if (easy == false)
+	{
+		// 音声ガイドのため、新しく接続されたり、切断されたりした場合を検出する
+		if (cm->UpdateConnectedNumFlag == false)
+		{
+			cm->UpdateConnectedNumFlag = true;
+			cm->OldConnectedNum = num;
+		}
+		else
+		{
+			if (cm->OldConnectedNum != num)
+			{
+				if (cm->OldConnectedNum < num)
+				{
+					CmVoice("connect");
+				}
+				else
+				{
+					CmVoice("disconnect");
+
+					if (cm->CmSetting.EasyMode && cm->PositiveDisconnectFlag == false)
+					{
+						CmShowEasy();
+					}
+
+					cm->PositiveDisconnectFlag = false;
+				}
+				cm->OldConnectedNum = num;
+			}
+		}
+
+		if (num_connecting == 0 && num_connected == 0)
+		{
+			// 接続中も接続完了も無し
+			UniStrCpy(tmp, sizeof(tmp), _UU("CM_TRAY_NOT_CONNECTED"));
+		}
+		else if (num_connected == 0)
+		{
+			// 接続中だけ有り
+			UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_1"), num_connecting);
+		}
+		else if (num_connecting == 0)
+		{
+			// 接続完了だけ有り
+			UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_2"), num_connected);
+		}
+		else
+		{
+			// 両方有り
+			UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_0"), num_connected, num_connecting);
+		}
+
+		if (num_connecting == 0 && num_connected == 0)
+		{
+			cm->TrayAnimation = false;
+			cm->TraySpeedAnimation = false;
+		}
+		else
+		{
+			cm->TrayAnimation = true;
+
+			if (num_connecting == 0)
+			{
+				cm->TraySpeedAnimation = false;
+			}
+			else
+			{
+				cm->TraySpeedAnimation = true;
+			}
+		}
+
+		CmChangeTrayString(hWnd, tmp);
+	}
+
+	Refresh(hWnd);
+
+	//ジャンプリストを更新
+	CmUpdateJumpList(0);
+}
+
+// VLAN リストの更新
+void CmRefreshVLanList(HWND hWnd)
+{
+	CmRefreshVLanListEx(hWnd, false);
+}
+void CmRefreshVLanListEx(HWND hWnd, bool style_changed)
+{
+	RPC_CLIENT_ENUM_VLAN e;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	LvSetView(hWnd, L_VLAN, cm->IconView == false);
+
+	// グリッド表示
+	if (cm->ShowGrid)
+	{
+		LvSetStyle(hWnd, L_VLAN, LVS_EX_GRIDLINES);
+	}
+	else
+	{
+		LvRemoveStyle(hWnd, L_VLAN, LVS_EX_GRIDLINES);
+	}
+
+	if (style_changed)
+	{
+		// フォントの変更
+		if (cm->VistaStyle)
+		{
+			SetFontMeiryo(hWnd, L_VLAN);
+		}
+		else
+		{
+			SetFontDefault(hWnd, L_VLAN);
+		}
+
+		if (cm->VistaStyle && (cm->IconView == false))
+		{
+			LvSetStyle(hWnd, L_VLAN, LVS_EX_FULLROWSELECT);
+		}
+		else
+		{
+			LvRemoveStyle(hWnd, L_VLAN, LVS_EX_FULLROWSELECT);
+		}
+	}
+
+	// 列挙
+	Zero(&e, sizeof(e));
+	if (CALL(hWnd, CcEnumVLan(cm->Client, &e)))
+	{
+		LVB *b = LvInsertStart();
+		UINT i;
+		for (i = 0;i < e.NumItem;i++)
+		{
+			wchar_t name[MAX_SIZE];
+			wchar_t mac[MAX_SIZE];
+			wchar_t ver[MAX_SIZE];
+			char str[MAX_SIZE];
+			wchar_t *status;
+			RPC_CLIENT_ENUM_VLAN_ITEM *v = e.Items[i];
+
+			// デバイス名
+			CmVLanNameToPrintName(str, sizeof(str), v->DeviceName);
+			StrToUni(name, sizeof(name), str);
+
+			// 状態
+			status = v->Enabled ? _UU("CM_VLAN_ENABLED") : _UU("CM_VLAN_DISABLED");
+
+			// MAC アドレス
+			StrToUni(mac, sizeof(mac), v->MacAddress);
+
+			// バージョン
+			StrToUni(ver, sizeof(ver), v->Version);
+
+			LvInsertAdd(b, v->Enabled ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE, NULL, 4,
+				name, status, mac, ver);
+		}
+		LvInsertEnd(b, hWnd, L_VLAN);
+
+		CiFreeClientEnumVLan(&e);
+	}
+}
+
+// プロトコル名文字列を取得
+wchar_t *CmGetProtocolName(UINT n)
+{
+	return GetProtocolName(n);
+}
+
+// 表示更新
+void CmRefresh(HWND hWnd)
+{
+	CmRefreshEx(hWnd, false);
+}
+void CmRefreshEx(HWND hWnd, bool style_changed)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// サイズ更新
+	CmMainWindowOnSize(hWnd);
+
+	// VLAN リストの更新
+	CmRefreshVLanListEx(hWnd, style_changed);
+
+	// アカウントリストの更新
+	CmRefreshAccountListEx2(hWnd, false, style_changed);
+
+	// ステータスバーの更新
+	CmRefreshStatusBar(hWnd);
+}
+
+// 指定されたメニュー項目をチェックするかどうか判断する
+bool CmIsChecked(UINT id)
+{
+	switch (id)
+	{
+	case CMD_TRAYICON:
+		return cm->HideTrayIcon == false;
+	case CMD_STATUSBAR:
+		return cm->HideStatusBar == false;
+	case CMD_VISTASTYLE:
+		return cm->VistaStyle;
+	case CMD_ICON:
+		return cm->IconView;
+	case CMD_DETAIL:
+		return cm->IconView == false;
+	case CMD_GRID:
+		return cm->ShowGrid;
+	case CMD_VOIDE_NONE:
+		return cm->DisableVoice;
+	case CMD_SHOWPORT:
+		return cm->ShowPort;
+	case CMD_VOICE_NORMAL:
+		if (cm->DisableVoice)
+		{
+			return false;
+		}
+		else
+		{
+			return cm->VoiceId == VOICE_SSK;
+		}
+	case CMD_VOICE_ODD:
+		if (cm->DisableVoice)
+		{
+			return false;
+		}
+		else
+		{
+			return cm->VoiceId == VOICE_AHO;
+		}
+	}
+	return false;
+}
+
+// メニューがポップアップされた
+void CmMainWindowOnPopupMenu(HWND hWnd, HMENU hMenu, UINT pos)
+{
+	UINT num_menu, i, id;
+	// 引数チェック
+	if (hWnd == NULL || hMenu == NULL)
+	{
+		return;
+	}
+
+	num_menu = GetMenuItemCount(hMenu);
+	for (i = 0;i < num_menu;i++)
+	{
+		id = GetMenuItemID(hMenu, i);
+
+		if (id != INFINITE)
+		{
+			bool enable_flag = CmIsEnabled(hWnd, id);
+			bool checked_flag = CmIsChecked(id);
+			bool bold_flag = CmIsBold(id);
+			MENUITEMINFO info;
+
+			Zero(&info, sizeof(info));
+			info.cbSize = sizeof(info);
+			info.fMask = MIIM_STATE;
+			info.fState = (enable_flag ? MFS_ENABLED : MFS_DISABLED) |
+				(checked_flag ? MFS_CHECKED : MFS_UNCHECKED) |
+				(bold_flag ? MFS_DEFAULT : 0);
+
+			if (id == CMD_ICON || id == CMD_DETAIL || id == CMD_VOIDE_NONE ||
+				id == CMD_VOICE_NORMAL || id == CMD_VOICE_ODD)
+			{
+				info.fMask |= MIIM_FTYPE;
+				info.fType = MFT_RADIOCHECK;
+			}
+
+			SetMenuItemInfo(hMenu, id, false, &info);
+		}
+
+		if (id == CMD_RECENT)
+		{
+			HMENU sub = CmCreateRecentSubMenu(hWnd, CM_TRAY_MENU_RECENT_ID_START);
+
+			if (sub != NULL)
+			{
+				DeleteMenu(hMenu, i, MF_BYPOSITION);
+				MsInsertMenu(hMenu, i, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+					(UINT_PTR)sub, _UU("CM_TRAY_MENU_RECENT"));
+			}
+			else
+			{
+				MENUITEMINFO info;
+
+				Zero(&info, sizeof(info));
+				info.cbSize = sizeof(info);
+				info.fMask = MIIM_STATE;
+				info.fState = MFS_DISABLED;
+
+				SetMenuItemInfo(hMenu, id, false, &info);
+			}
+		}
+	}
+}
+
+// メインウインドウタイトルの設定
+wchar_t *CmGenerateMainWindowTitle()
+{
+	wchar_t tmp[MAX_SIZE];
+	if (cm->server_name == NULL)
+	{
+		UniFormat(tmp, sizeof(tmp), L"%s", _UU("CM_TITLE"));
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), L"%s - %S", _UU("CM_TITLE"), cm->server_name);
+	}
+
+	return CopyUniStr(tmp);
+}
+
+// タスクトレイの初期化
+void CmInitTray(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (cm->server_name != NULL)
+	{
+		return;
+	}
+
+	if (cm->TrayInited)
+	{
+		return;
+	}
+
+	MsShowIconOnTray(hWnd, LoadSmallIcon(CmGetTrayIconId(false, 0)), _UU("CM_TRAY_INITING"), WM_CM_TRAY_MESSAGE);
+
+	cm->TrayInited = true;
+	cm->TrayAnimation = false;
+
+	SetTimer(hWnd, 2, CM_TRAY_ANIMATION_INTERVAL / 4, NULL);
+}
+
+// タスクトレイの文字列の変更
+void CmChangeTrayString(HWND hWnd, wchar_t *str)
+{
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return;
+	}
+	if (cm->TrayInited == false)
+	{
+		return;
+	}
+
+	MsChangeIconOnTray(NULL, str);
+}
+
+// タスクトレイの解放
+void CmFreeTray(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (cm->TrayInited == false)
+	{
+		return;
+	}
+
+	MsHideIconOnTray();
+
+	cm->TrayInited = false;
+}
+void CmFreeTrayExternal(void *hWnd)
+{
+	CmFreeTray((HWND)hWnd);
+}
+
+// タスクトレイに対する定期的な処理
+void CmPollingTray(HWND hWnd)
+{
+	UINT interval;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (cm->TrayInited == false)
+	{
+		return;
+	}
+
+	MsChangeIconOnTray(LoadSmallIcon(CmGetTrayIconId(cm->TrayAnimation, cm->TrayAnimationCounter)),
+		NULL);
+
+	cm->TrayAnimationCounter++;
+
+	KillTimer(hWnd, 2);
+	interval = CM_TRAY_ANIMATION_INTERVAL / 4;
+	if (cm->TraySpeedAnimation)
+	{
+		interval /= 4;
+	}
+	SetTimer(hWnd, 2, interval, NULL);
+}
+
+// アニメーション用のタスクトレイのアイコン ID の取得
+UINT CmGetTrayIconId(bool animation, UINT animation_counter)
+{
+	if (animation == false)
+	{
+		return ICO_TRAY0;
+	}
+	else
+	{
+		switch (animation_counter % 4)
+		{
+		case 0:
+			return ICO_TRAY1;
+
+		case 1:
+			return ICO_TRAY2;
+
+		case 2:
+			return ICO_TRAY3;
+
+		default:
+			return ICO_TRAY4;
+		}
+	}
+}
+
+// メインウインドウの初期化
+void CmMainWindowOnInit(HWND hWnd)
+{
+	wchar_t *s;
+	BUF *b;
+	bool startup_mode = cm->StartupMode;
+	CM_SETTING a;
+	bool fake = false;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// リストのフォント設定
+	SetFontMeiryo(hWnd, L_ACCOUNT);
+	SetFontMeiryo(hWnd, L_VLAN);
+
+	// 現在の vpnclient の設定を取得する
+	Zero(&a, sizeof(a));
+	CcGetCmSetting(cm->Client, &a);
+
+	if (a.EasyMode)
+	{
+		fake = true;
+	}
+
+	InitMenuInternational(GetMenu(hWnd), "CM_MENU");
+
+	cm->HideStatusBar = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "HideStatusBar");
+	cm->HideTrayIcon = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "HideTrayIcon");
+	cm->IconView = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "IconView");
+	cm->ShowGrid = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "ShowGrid");
+
+	if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle"))
+	{
+		cm->VistaStyle = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle");
+	}
+	else
+	{
+		cm->VistaStyle = MsIsVista();
+	}
+
+	if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "ShowPort"))
+	{
+		cm->ShowPort = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "ShowPort");
+	}
+	else
+	{
+		cm->ShowPort = false;
+	}
+
+	if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice"))
+	{
+		cm->DisableVoice = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice");
+	}
+	else
+	{
+		cm->DisableVoice = true;
+	}
+	cm->VoiceId = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "VoiceId");
+
+	cm->StatusWindowList = NewList(NULL);
+
+	SetIcon(hWnd, 0, ICO_VPN);
+
+	s = CmGenerateMainWindowTitle();
+	SetText(hWnd, 0, s);
+	Free(s);
+
+	// ウインドウ位置の初期化
+	b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "WindowPlacement");
+	if (b != NULL && b->Size == sizeof(WINDOWPLACEMENT))
+	{
+		// ウインドウ位置を復元
+		WINDOWPLACEMENT *p;
+		p = ZeroMalloc(b->Size);
+		Copy(p, b->Buf, b->Size);
+
+		if (startup_mode)
+		{
+			p->showCmd = SW_SHOWMINIMIZED;
+		}
+
+		if (fake)
+		{
+			Copy(&cm->FakeWindowPlacement, p, sizeof(WINDOWPLACEMENT));
+		}
+		else
+		{
+			SetWindowPlacement(hWnd, p);
+		}
+		Free(p);
+	}
+	else
+	{
+		// ウインドウ位置を初期化
+		SetWindowPos(hWnd, NULL, 0, 0, CM_DEFAULT_WIDTH, CM_DEFAULT_HEIGHT, SWP_NOREDRAW);
+		Center(hWnd);
+		if (startup_mode)
+		{
+			ShowWindow(hWnd, SW_SHOWMINIMIZED);
+		}
+
+		if (fake)
+		{
+			WINDOWPLACEMENT p;
+
+			Zero(&p, sizeof(p));
+			p.length = sizeof(p);
+			GetWindowPlacement(hWnd, &p);
+			Copy(&cm->FakeWindowPlacement, &p, sizeof(WINDOWPLACEMENT));
+		}
+	}
+	FreeBuf(b);
+
+	if (fake)
+	{
+		SetWindowPos(hWnd, NULL, -200, -200, 100, 100,
+			SWP_NOREDRAW | SWP_SHOWWINDOW);
+	}
+
+	// ステータスバー関係の初期化
+	cm->hMainWnd = hWnd;
+	cm->hStatusBar = CreateStatusWindowW(WS_CHILD |
+		(cm->HideStatusBar == false ? WS_VISIBLE : 0),
+		_UU("CM_TITLE"),
+		hWnd, S_STATUSBAR);
+
+	UniStrCpy(cm->StatudBar1, sizeof(cm->StatudBar1), _UU("CM_TITLE"));
+	UniStrCpy(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_CONN_NO"));
+	UniFormat(cm->StatudBar3, sizeof(cm->StatudBar3), _UU("CM_PRODUCT_NAME"), CEDAR_BUILD);
+
+	cm->Icon2 = LoadSmallIcon(ICO_SERVER_OFFLINE);
+	cm->Icon3 = LoadSmallIcon(ICO_VPN);
+
+	// アカウントリストの初期化
+	CmInitAccountList(hWnd);
+
+	// VLAN リストの初期化
+	CmInitVLanList(hWnd);
+
+	// 表示更新
+	CmRefreshEx(hWnd, true);
+
+	// 通知クライアントのスレッドを開始
+	CmInitNotifyClientThread();
+
+	// タイマー設定
+	SetTimer(hWnd, 1, 128, NULL);
+
+	// タスクトレイの初期化
+	if (cm->server_name == NULL)
+	{
+		if (cm->HideTrayIcon == false)
+		{
+			CmInitTray(hWnd);
+		}
+	}
+
+	CmVoice("start");
+
+	if (startup_mode || a.EasyMode)
+	{
+		SetTimer(hWnd, 3, 1, NULL);
+	}
+
+	if (cm->import_file_name != NULL)
+	{
+		// 引数として指定されたファイルをインポートする
+		CmSendImportMessage(hWnd, cm->import_file_name, cm->CmSettingInitialFlag == CM_SETTING_INIT_NONE ? CM_IMPORT_FILENAME_MSG : CM_IMPORT_FILENAME_MSG_OVERWRITE);
+		/*if (a.LockMode == false)
+		{
+			CmImportAccountMainEx(hWnd, cm->import_file_name, cm->CmSettingInitialFlag != CM_SETTING_INIT_NONE);
+		}
+		else
+		{
+			MsgBox(cm->hEasyWnd ? cm->hEasyWnd : hWnd, MB_ICONEXCLAMATION, _UU("CM_VPN_FILE_IMPORT_NG"));
+		}*/
+	}
+
+	// CM_SETTING の適用
+	CmApplyCmSetting();
+
+	cm->StartupFinished = true;
+}
+
+// 通知クライアントのスレッドを開始
+void CmInitNotifyClientThread()
+{
+	cm->NotifyClient = CcConnectNotify(cm->Client);
+	if (cm->NotifyClient == false)
+	{
+		Close(cm->hMainWnd);
+		exit(0);
+	}
+	cm->NotifyClientThread = NewThread(CmNotifyClientThread, NULL);
+}
+
+// 通知クライアントスレッド
+void CmNotifyClientThread(THREAD *thread, void *param)
+{
+	NOTIFY_CLIENT *nc;
+	// 引数チェック
+	if (thread == NULL)
+	{
+		return;
+	}
+
+	nc = cm->NotifyClient;
+
+	// 次の通知を待機する
+	while (cm->Halt == false)
+	{
+		if (CcWaitNotify(nc))
+		{
+			// メッセージ送信
+			PostMessage(cm->hMainWnd, WM_CM_NOTIFY, 0, 0);
+		}
+		else
+		{
+			// 切断された
+			if (cm->Halt == false)
+			{
+				if (cm != NULL)
+				{
+					CmFreeTrayExternal((void *)cm->hMainWnd);
+				}
+				CncExit();
+				exit(0);
+			}
+			break;
+		}
+	}
+}
+
+// 通知クライアントのスレッドを終了
+void CmFreeNotifyClientThread()
+{
+	cm->Halt = true;
+
+	// 切断
+	CcStopNotify(cm->NotifyClient);
+
+	// スレッド終了を待機する
+	WaitThread(cm->NotifyClientThread, INFINITE);
+
+	// コネクション終了
+	CcDisconnectNotify(cm->NotifyClient);
+	ReleaseThread(cm->NotifyClientThread);
+}
+
+// メインウインドウのサイズ変更
+void CmMainWindowOnSize(HWND hWnd)
+{
+	RECT r;
+	UINT client_width, client_height;
+	UINT status_height;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// メインウインドウのクライアント領域のサイズを取得する
+	GetClientRect(hWnd, &r);
+	client_width = MAX(r.right - r.left, 0);
+	client_height = MAX(r.bottom - r.top, 0);
+
+	SendMsg(hWnd, S_STATUSBAR, WM_SIZE, 0, 0);
+
+	// ステータスバーのサイズを取得する
+	GetWindowRect(DlgItem(hWnd, S_STATUSBAR), &r);
+	status_height = MAX(r.bottom - r.top, 0);
+
+	if (cm->HideStatusBar == false)
+	{
+		client_height = MAX(client_height - status_height, 0);
+	}
+
+	MoveWindow(DlgItem(hWnd, L_ACCOUNT), 0, 0, client_width, client_height * 3 / 5 - 3, true);
+	MoveWindow(DlgItem(hWnd, L_VLAN), 0, client_height * 3 / 5, client_width, client_height * 2 / 5, true);
+
+	// ステータスバーの再描画
+	CmRedrawStatusBar(hWnd);
+}
+
+// 現在接続中のアカウントをすべて切断する
+void CmDisconnectAll(HWND hWnd)
+{
+	UINT i, num;
+	LIST *o;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 警告を表示する
+	num = CmGetNumConnected(hWnd);
+	if (num == 0)
+	{
+		return;
+	}
+
+	if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DISCONNECT_ALL"), num) == IDNO)
+	{
+		return;
+	}
+
+	cm->PositiveDisconnectFlag = true;
+
+	// 接続中のリストを作成する
+	o = NewListFast(NULL);
+
+	num = LvNum(hWnd, L_ACCOUNT);
+	for (i = 0;i < num;i++)
+	{
+		wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+		if (s != NULL)
+		{
+			if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+			{
+				Add(o, LvGetStr(hWnd, L_ACCOUNT, i, 0));
+			}
+			Free(s);
+		}
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t *s = LIST_DATA(o, i);
+		if (s != NULL)
+		{
+			CmDisconnect(hWnd, s);
+			Free(s);
+		}
+	}
+
+	ReleaseList(o);
+}
+
+// 現在接続中の接続設定数を取得する
+UINT CmGetNumConnected(HWND hWnd)
+{
+	UINT i, num, num_active;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	num_active = 0;
+	num = LvNum(hWnd, L_ACCOUNT);
+	for (i = 0;i < num;i++)
+	{
+		wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+		if (s != NULL)
+		{
+			if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+			{
+				num_active++;
+			}
+			Free(s);
+		}
+	}
+
+	return num_active;
+}
+
+// ステータスバー情報を更新
+void CmRefreshStatusBar(HWND hWnd)
+{
+	UINT num_active = CmGetNumConnected(hWnd);
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (num_active == 0)
+	{
+		UniStrCpy(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_CONN_NO"));
+		cm->Icon2 = LoadSmallIcon(ICO_SERVER_OFFLINE);
+	}
+	else
+	{
+		UniFormat(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_NUM_CONN_COUNT"), num_active);
+		cm->Icon2 = LoadSmallIcon(ICO_SERVER_ONLINE);
+	}
+
+	CmRedrawStatusBar(hWnd);
+}
+
+// ステータスバーの再描画
+void CmRedrawStatusBar(HWND hWnd)
+{
+	HWND h;
+	RECT r;
+	int width;
+	int x1, x2, x3;
+	int xx[3];
+	wchar_t tmp[MAX_SIZE];
+	HICON icon;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	h = cm->hStatusBar;
+
+	// ステータスバーの横幅を取得
+	GetWindowRect(h, &r);
+	width = MAX(r.right - r.left, 0);
+	x2 = 180;
+	x3 = 245;
+	x1 = MAX(width - x2 - x3, 0);
+
+	// 3 つの部分に分割する
+	xx[0] = x1;
+	xx[1] = x2 + x1;
+	xx[2] = x3 + x2 + x1;
+	SendMsg(h, 0, SB_SETPARTS, 3, (LPARAM)xx);
+
+	// アイコンを設定
+	icon = (HICON)SendMsg(h, 0, SB_GETICON, 1, 0);
+	if (icon != cm->Icon2)
+	{
+		SendMsg(h, 0, SB_SETICON, 1, (LPARAM)cm->Icon2);
+	}
+
+	icon = (HICON)SendMsg(h, 0, SB_GETICON, 2, 0);
+	if (icon != cm->Icon3)
+	{
+		SendMsg(h, 0, SB_SETICON, 2, (LPARAM)cm->Icon3);
+	}
+
+	// 文字列を設定
+	SendMsg(h, 0, SB_GETTEXTW, 0, (LPARAM)tmp);
+	if (UniStrCmp(tmp, cm->StatudBar1))
+	{
+		SendMsg(h, 0, SB_SETTEXTW, 0, (LPARAM)cm->StatudBar1);
+	}
+
+	SendMsg(h, 0, SB_GETTEXTW, 1, (LPARAM)tmp);
+	if (UniStrCmp(tmp, cm->StatudBar2))
+	{
+		SendMsg(h, 0, SB_SETTEXTW, 1, (LPARAM)cm->StatudBar2);
+	}
+
+	SendMsg(h, 0, SB_GETTEXTW, 2, (LPARAM)tmp);
+	if (UniStrCmp(tmp, cm->StatudBar3))
+	{
+		SendMsg(h, 0, SB_SETTEXTW, 2, (LPARAM)cm->StatudBar3);
+	}
+}
+
+// メインウインドウの位置情報を保存する
+void CmSaveMainWindowPos(HWND hWnd)
+{
+	WINDOWPLACEMENT p;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 設定の保存
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "HideStatusBar", cm->HideStatusBar);
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "HideTrayIcon", cm->HideTrayIcon);
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "IconView", cm->IconView);
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "ShowGrid", cm->ShowGrid);
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice", cm->DisableVoice);
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "VoiceId", cm->VoiceId);
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle", cm->VistaStyle);
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "ShowPort", cm->ShowPort);
+
+	// ウインドウ位置の保存
+	Zero(&p, sizeof(p));
+	p.length = sizeof(p);
+	GetWindowPlacement(hWnd, &p);
+
+	if (IsZero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement)) == false)
+	{
+		Copy(&p, &cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement));
+	}
+
+	MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "WindowPlacement", &p, sizeof(p));
+
+	CmSaveAccountListPos(hWnd);
+	CmSaveVLanListPos(hWnd);
+}
+
+// メインウインドウを閉じる
+void CmMainWindowOnQuit(HWND hWnd)
+{
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (cm->TrayInited)
+	{
+		if (MsgBox(hWnd, MB_YESNO | MB_ICONQUESTION,
+			_UU("CM_EXIT_MESSAGE")) == IDNO)
+		{
+			return;
+		}
+	}
+
+	if (cm->OnCloseDispatched)
+	{
+		return;
+	}
+	cm->OnCloseDispatched = true;
+
+	CmCloseEasy();
+
+	// トレイを解放
+	CmFreeTray(hWnd);
+
+	// メインウインドウの位置情報を保存する
+	CmSaveMainWindowPos(hWnd);
+
+	// ステータスウインドウを閉じる
+	for (i = 0;i < LIST_NUM(cm->StatusWindowList);i++)
+	{
+		HWND h = LIST_DATA(cm->StatusWindowList, i);
+		//EndDialog(h, 0);
+		PostMessage(h, WM_CLOSE, 0, 0);
+	}
+
+	ReleaseList(cm->StatusWindowList);
+	cm->StatusWindowList = NULL;
+
+	if (cm->WindowCount != 0)
+	{
+		// 強制終了
+		exit(0);
+	}
+
+	// 閉じる
+	CmFreeNotifyClientThread();
+
+	EndDialog(hWnd, false);
+}
+
+// 起動時に使用する mutex を開始
+bool CmStartStartupMutex()
+{
+	INSTANCE *o = NewSingleInstance(STARTUP_MUTEX_NAME);
+
+	if (o == NULL)
+	{
+		return false;
+	}
+
+	cm->StartupMutex = o;
+
+	return true;
+}
+
+// 起動時に使用する mutex を解放
+void CmEndStartupMutex()
+{
+	if (cm->StartupMutex != NULL)
+	{
+		FreeSingleInstance(cm->StartupMutex);
+
+		cm->StartupMutex = NULL;
+	}
+}
+
+// メインウインドウ
+void MainCMWindow()
+{
+	HWND h;
+	wchar_t *s;
+	CM_SETTING a;
+
+	if (CmStartStartupMutex() == false)
+	{
+		return;
+	}
+
+	s = CmGenerateMainWindowTitle();
+	h = SearchWindow(s);
+	Free(s);
+
+	Zero(&a, sizeof(a));
+	CcGetCmSetting(cm->Client, &a);
+	if (cm->server_name != NULL && a.EasyMode)
+	{
+		CmEndStartupMutex();
+		MsgBox(NULL, MB_ICONEXCLAMATION, _UU("CM_EASY_MODE_NOT_ON_REMOTE"));
+		return;
+	}
+
+	// 動作モードの変更
+	if (cm->CmSettingSupported)
+	{
+		if (cm->CmSettingInitialFlag == CM_SETTING_INIT_SELECT)
+		{
+			if (h != NULL)
+			{
+				CmEndStartupMutex();
+			}
+
+			// 選択画面を表示
+			CmSetting(NULL);
+
+			if (h != NULL)
+			{
+				goto SEND_MESSAGES;
+			}
+			else
+			{
+				return;
+			}
+		}
+		else if ((cm->CmSettingInitialFlag == CM_SETTING_INIT_EASY && cm->CmEasyModeSupported) || cm->CmSettingInitialFlag == CM_SETTING_INIT_NORMAL)
+		{
+			// 状態遷移
+			CM_SETTING a;
+
+			Zero(&a, sizeof(a));
+			CcGetCmSetting(cm->Client, &a);
+
+			if (cm->CmSettingInitialFlag == CM_SETTING_INIT_EASY)
+			{
+				a.EasyMode = true;
+			}
+			else
+			{
+				a.EasyMode = false;
+			}
+
+			CcSetCmSetting(cm->Client, &a);
+		}
+	}
+
+	if (h == NULL)
+	{
+		// 他に同じタイトルのウインドウが無いのでウインドウを作成する
+		if (cm->server_name == NULL)
+		{
+			CmInitTryToExecUiHelper();
+			CnWaitForCnServiceReady();
+		}
+		Dialog(NULL, D_CM_MAIN, CmMainWindowProc, NULL);
+		CmFreeTryToExecUiHelper();
+	}
+	else
+	{
+SEND_MESSAGES:
+		CmEndStartupMutex();
+
+		// すでに同じタイトルのウインドウが存在する場合はそれをアクティブにして
+		// 自分自身は終了する
+		SetForegroundWindow(h);
+		SendMessage(h, WM_CM_SHOW, 0, 0);
+		SetForegroundWindow(h);
+
+		if (cm->CmSettingInitialFlag != CM_SETTING_INIT_NONE)
+		{
+			// CM_SETTING が変更されたのでそれを通知する
+			SendMessage(h, WM_CM_SETTING_CHANGED_MESSAGE, 0, 0);
+		}
+
+		if (cm->import_file_name != NULL)
+		{
+			UINT msg;
+			if (cm->CmSettingInitialFlag == CM_SETTING_INIT_NONE)
+			{
+				msg = CM_IMPORT_FILENAME_MSG;
+			}
+			else
+			{
+				msg = CM_IMPORT_FILENAME_MSG_OVERWRITE;
+			}
+
+			CmSendImportMessage(h, cm->import_file_name, msg);
+		}
+	}
+
+	CmEndStartupMutex();
+}
+
+// インポートメッセージの送信
+void CmSendImportMessage(HWND hWnd, wchar_t *filename, UINT msg)
+{
+	COPYDATASTRUCT cpy;
+	// 引数チェック
+	if (hWnd == NULL || filename == NULL)
+	{
+		return;
+	}
+
+	// インポートすべきファイルを指定する
+	Zero(&cpy, sizeof(cpy));
+
+	cpy.cbData = UniStrSize(filename);
+	cpy.lpData = filename;
+	cpy.dwData = msg;
+
+	SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&cpy);
+}
+
+// ログインダイアログ
+UINT CmLoginDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	// 引数チェック
+	wchar_t server_name[MAX_SIZE];
+	char password[MAX_PASSWORD_LEN + 1];
+	bool bad_pass;
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		if (cm->server_name != NULL)
+		{
+			StrToUni(server_name, sizeof(server_name), cm->server_name);
+		}
+		else
+		{
+			UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+		}
+		FormatText(hWnd, S_TITLE, server_name);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (cm->server_name != NULL)
+			{
+				StrToUni(server_name, sizeof(server_name), cm->server_name);
+			}
+			else
+			{
+				UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+			}
+			GetTxtA(hWnd, E_PASSWORD, password, sizeof(password));
+			cm->Client = CcConnectRpc(cm->server_name == NULL ? "127.0.0.1" : cm->server_name,
+				password, &bad_pass, NULL, 0);
+			if (cm->Client == NULL)
+			{
+				MsgBox(hWnd, MB_ICONSTOP, _UU("CM_BAD_PASSWORD"));
+				FocusEx(hWnd, E_PASSWORD);
+			}
+			else
+			{
+				EndDialog(hWnd, true);
+			}
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ログイン
+bool LoginCM()
+{
+	// まず空のパスワードでログインを試みる
+	bool bad_pass, no_remote;
+	wchar_t server_name[MAX_SIZE];
+	RPC_CLIENT_VERSION a;
+
+RETRY:
+	if (cm->server_name != NULL)
+	{
+		StrToUni(server_name, sizeof(server_name), cm->server_name);
+	}
+	else
+	{
+		UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+	}
+
+	// 接続試行
+	if ((cm->Client = CcConnectRpc(
+		cm->server_name == NULL ? "localhost" : cm->server_name,
+		"", &bad_pass, &no_remote, cm->StartupMode == false ? 0 : 60000)) == NULL)
+	{
+		if (no_remote)
+		{
+			// リモート接続が拒否された
+			if (MsgBoxEx(NULL, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("CM_NO_REMOTE"), server_name) == IDRETRY)
+			{
+				// 再試行
+				goto RETRY;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		else if (bad_pass)
+		{
+			if (Dialog(NULL, D_CM_LOGIN, CmLoginDlgProc, NULL) == false)
+			{
+				return false;
+			}
+		}
+		else
+		{
+			// 接続失敗
+			if (cm->StartupMode == false && MsgBoxEx(NULL, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("CM_CONNECT_FAILED"), server_name) == IDRETRY)
+			{
+				// 再試行
+				goto RETRY;
+			}
+			else
+			{
+				return false;
+			}
+		}
+	}
+
+	Zero(&a, sizeof(a));
+	CcGetClientVersion(cm->Client, &a);
+	if (a.ClientBuildInt >= 5192)
+	{
+		cm->CmSettingSupported = true;
+		cm->CmEasyModeSupported = true;
+		if (OS_IS_WINDOWS_9X(a.OsType))
+		{
+			cm->CmEasyModeSupported = false;
+		}
+	}
+
+	return true;
+}
+
+// メイン処理
+void MainCM()
+{
+	// 引数に /remote があればリモート接続の画面を出す
+	char *cmdline = GetCommandLineStr();
+
+	if (StrCmpi(cmdline, "/remote") == 0)
+	{
+		char *hostname = RemoteDlg(NULL, CM_REG_KEY, ICO_VPN, _UU("CM_TITLE"), _UU("CM_REMOTE_TITLE"), NULL);
+		if (hostname == NULL)
+		{
+			return;
+		}
+		if (cm->server_name != NULL)
+		{
+			Free(cm->server_name);
+		}
+		cm->server_name = NULL;
+		if (StrCmpi(hostname, "localhost") != 0 && StrCmpi(hostname, "127.0.0.1") != 0 )
+		{
+			cm->server_name = hostname;
+		}
+	}
+
+	if (StrCmpi(cmdline, "/startup") == 0)
+	{
+		// スタートアップモード
+		cm->StartupMode = true;
+	}
+
+	Free(cmdline);
+
+	if (IsZero(cm->ShortcutKey, SHA1_SIZE) == false)
+	{
+		//if (MsGetCurrentTerminalSessionId() == 0)
+		{
+			// ショートカット接続の開始
+			CmConnectShortcut(cm->ShortcutKey);
+		}/*
+		else
+		{
+			MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("CM_SHORTCUT_DESKTOP_MSG"),
+				MsGetCurrentTerminalSessionId());
+		}*/
+		return;
+	}
+
+	// ログイン
+	if (LoginCM() == false)
+	{
+		return;
+	}
+
+	//ジャンプリストの更新
+	CmUpdateJumpList(0);
+
+	// メインウインドウ
+	MainCMWindow();
+
+	// ログアウト
+	LogoutCM();
+}
+
+// ログアウト
+void LogoutCM()
+{
+	if (cm->Client != NULL)
+	{
+		CcDisconnectRpc(cm->Client);
+	}
+}
+
+// クライアント接続マネージャ起動関数
+void CMExec()
+{
+	// 初期化
+	InitCM();
+
+	// メイン処理
+	MainCM();
+
+	// 解放
+	FreeCM();
+}
+
+// HUB 列挙スレッド
+void CmEnumHubThread(THREAD *t, void *param)
+{
+	CM_ENUM_HUB *e = (CM_ENUM_HUB *)param;
+	HWND hWnd;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	e->Thread = t;
+	hWnd = e->hWnd;
+	LockList(cm->EnumHubList);
+	{
+		Add(cm->EnumHubList, e);
+	}
+	UnlockList(cm->EnumHubList);
+
+	// スレッド初期化完了
+	NoticeThreadInit(t);
+
+	// セッション作成
+	e->Session = NewRpcSession(cm->Cedar, e->ClientOption);
+	if (e->Session)
+	{
+		// HUB の列挙
+		e->Hub = EnumHub(e->Session);
+
+		if (e->Hub != NULL)
+		{
+			// 列挙完了
+			// コンボボックスに追加する
+			if (CbNum(hWnd, C_HUBNAME) == 0)
+			{
+				UINT i;
+				wchar_t tmp[MAX_SIZE];
+				for (i = 0;i < e->Hub->NumTokens;i++)
+				{
+					StrToUni(tmp, sizeof(tmp), e->Hub->Token[i]);
+					CbAddStr(hWnd, C_HUBNAME, tmp, 0);
+				}
+			}
+
+			// メモリ解放
+			FreeToken(e->Hub);
+		}
+
+		// セッション解放
+		ReleaseSession(e->Session);
+	}
+
+	LockList(cm->EnumHubList);
+	{
+		Delete(cm->EnumHubList, e);
+	}
+	UnlockList(cm->EnumHubList);
+
+	Free(e->ClientOption);
+	Free(e);
+}
+
+// HUB 列挙の開始
+void CmEnumHubStart(HWND hWnd, CLIENT_OPTION *o)
+{
+	CM_ENUM_HUB *e;
+	THREAD *t;
+	// 引数チェック
+	if (hWnd == NULL || o == NULL)
+	{
+		return;
+	}
+
+	if (StrLen(o->Hostname) == 0 ||
+		o->Port == 0)
+	{
+		return;
+	}
+
+	if (o->ProxyType != PROXY_DIRECT)
+	{
+		if (StrLen(o->ProxyName) == 0 ||
+			o->ProxyPort == 0)
+		{
+			return;
+		}
+	}
+
+	if (LvNum(hWnd, C_HUBNAME) != 0)
+	{
+		return;
+	}
+
+	e = ZeroMalloc(sizeof(CM_ENUM_HUB));
+	e->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	e->hWnd = hWnd;
+	Copy(e->ClientOption, o, sizeof(CLIENT_OPTION));
+
+	t = NewThread(CmEnumHubThread, e);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+}
+
+// HUB 列挙処理の初期化
+void CmInitEnumHub()
+{
+	cm->EnumHubList = NewList(NULL);
+}
+
+// HUB 列挙処理の解放
+void CmFreeEnumHub()
+{
+	LIST *o;
+	UINT i;
+	if (cm->EnumHubList == NULL)
+	{
+		return;
+	}
+
+	o = NewList(NULL);
+	LockList(cm->EnumHubList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(cm->EnumHubList);i++)
+		{
+			CM_ENUM_HUB *e = LIST_DATA(cm->EnumHubList, i);
+			Add(o, e->Thread);
+			AddRef(e->Thread->ref);
+		}
+	}
+	UnlockList(cm->EnumHubList);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		THREAD *t = LIST_DATA(o, i);
+		WaitThread(t, INFINITE);
+		ReleaseThread(t);
+	}
+	ReleaseList(o);
+
+	ReleaseList(cm->EnumHubList);
+}
+
+// クライアント接続マネージャの初期化
+#define APPID L"SoftEther.SoftEther UT-VPN Client"
+
+void InitCM()
+{
+	UNI_TOKEN_LIST *ut;
+	if (cm != NULL)
+	{
+		return;
+	}
+
+	//Set Application ID
+	if(JL_SetCurrentProcessExplicitAppUserModelID(APPID) != S_OK)
+	{
+	}
+
+	CmDeleteOldStartupTrayFile();
+
+	MsSetShutdownParameters(0x4ff, SHUTDOWN_NORETRY);
+
+	// メモリ確保
+	cm = ZeroMalloc(sizeof(CM));
+
+	// コマンドライン引数が設定されている場合はサーバー名として取り扱う
+	ut = GetCommandLineUniToken();
+
+	if (ut->NumTokens >= 1)
+	{
+		if (UniStrLen(ut->Token[0]) != 0)
+		{
+			if (UniStrCmpi(ut->Token[0], L"cm") != 0 && ut->Token[0][0] != L'/')
+			{
+				BUF *b = UniStrToBin(ut->Token[0]);
+				if (b->Size == SHA1_SIZE)
+				{
+					// 接続設定のショートカットキーとして扱う
+					Copy(cm->ShortcutKey, b->Buf, SHA1_SIZE);
+				}
+				else
+				{
+					if (UniEndWith(ut->Token[0], L".uvpn") == false)
+					{
+						// サーバー名として扱う
+						cm->server_name = CopyUniToStr(ut->Token[0]);
+					}
+					else
+					{
+						// インポートファイル名として扱う
+						cm->import_file_name = CopyUniStr(ut->Token[0]);
+					}
+				}
+				FreeBuf(b);
+			}
+			else if (UniStrCmpi(ut->Token[0], L"/easy") == 0)
+			{
+				// 簡易モード
+				if (ut->NumTokens >= 2)
+				{
+					// インポートすべき接続設定が指定されている
+					cm->import_file_name = CopyUniStr(ut->Token[1]);
+				}
+
+				cm->CmSettingInitialFlag = CM_SETTING_INIT_EASY;
+			}
+			else if (UniStrCmpi(ut->Token[0], L"/normal") == 0)
+			{
+				// 通常モード
+				if (ut->NumTokens >= 2)
+				{
+					// インポートすべき接続設定が指定されている
+					cm->import_file_name = CopyUniStr(ut->Token[1]);
+				}
+
+				cm->CmSettingInitialFlag = CM_SETTING_INIT_NORMAL;
+			}
+			else if (UniStrCmpi(ut->Token[0], L"/select") == 0)
+			{
+				// 選択画面
+				cm->CmSettingInitialFlag = CM_SETTING_INIT_SELECT;
+			}
+		}
+	}
+
+	UniFreeToken(ut);
+
+	InitWinUi(_UU("CM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+	// アルファブレンディング関係
+	UseAlpha = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha");
+	AlphaValue = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue");
+
+	cm->Cedar = NewCedar(NULL, NULL);
+	CmInitEnumHub();
+}
+
+// クライアント接続マネージャの終了
+void FreeCM()
+{
+	if (cm == NULL)
+	{
+		return;
+	}
+
+	CmFreeEnumHub();
+	ReleaseCedar(cm->Cedar);
+
+	FreeWinUi();
+
+	// メモリ解放
+	if (cm->server_name != NULL)
+	{
+		Free(cm->server_name);
+	}
+	Free(cm);
+	cm = NULL;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//JumpList ToDo
+// By Takao Ito
+void *CmUpdateJumpList(UINT start_id)
+{
+	HMENU h = NULL;
+	UINT i;
+	RPC_CLIENT_ENUM_ACCOUNT a;
+	LIST *o;
+	bool easy;
+
+	JL_PCustomDestinationList pcdl;
+	JL_PObjectCollection poc;
+	JL_PShellLink shell;
+	JL_PObjectArray poaRemoved;
+
+	HRESULT hr;
+
+	if (cm->server_name != NULL)
+	{
+		// 外部 PC の場合は利用しない
+		return NULL;
+	}
+
+	//試しに追加
+	if(SUCCEEDED(JL_CreateCustomDestinationList(&pcdl,APPID)))
+	{
+
+		JL_DeleteJumpList(pcdl,APPID);
+
+		easy = cm->CmSetting.EasyMode;
+
+		Zero(&a, sizeof(a));
+
+		
+		if (CcEnumAccount(cm->Client, &a) == ERR_NO_ERROR)
+		{
+			o = NewListFast(CiCompareClientAccountEnumItemByLastConnectDateTime);
+
+			for (i = 0;i < a.NumItem;i++)
+			{
+				RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = a.Items[i];
+
+				item->tmp1 = i;
+
+				if (item->LastConnectDateTime != 0)
+				{
+					Add(o, item);
+				}
+			}
+
+			Sort(o);
+
+			if(LIST_NUM(o) > 0)
+			{
+
+				if(SUCCEEDED(JL_BeginList(pcdl, &poaRemoved)))
+				{
+
+
+					//コレクションの作成
+					if(SUCCEEDED(JL_CreateObjectCollection(&poc)))
+					{
+
+						for (i = 0;i < MIN(LIST_NUM(o), CM_NUM_RECENT);i++)
+						{
+
+							RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = (RPC_CLIENT_ENUM_ACCOUNT_ITEM *)LIST_DATA(o, i);
+//							wchar_t tmp[MAX_PATH];
+							wchar_t *account_name;
+							char *server_name;
+							char *hub_name;
+//							CM_ACCOUNT *a;
+							UCHAR key[SHA1_SIZE];
+							RPC_CLIENT_GET_ACCOUNT c;
+
+
+							account_name = item->AccountName;
+							server_name = item->ServerName;
+							hub_name = item->HubName;
+
+
+
+							//
+							//a = CmGetExistAccountObject(hWnd, account_name);
+
+
+							//if (a == NULL)
+							//{
+							//continue;
+							//}
+
+							//Copy(key, a->ShortcutKey, SHA1_SIZE);
+							//
+
+							Zero(&c, sizeof(c));
+							UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+							if (CALL(NULL, CcGetAccount(cm->Client, &c)) == false)
+							{
+								break;
+							}
+
+							Copy(key, c.ShortcutKey, SHA1_SIZE);
+
+							if (IsZero(key, SHA1_SIZE))
+							{
+								//MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_SHORTCUT_UNSUPPORTED"));
+							}
+							else
+							{
+
+								//wchar_t target[MAX_PATH];
+								////wchar_t workdir[MAX_PATH];
+								//wchar_t args[MAX_PATH];
+								////wchar_t comment[MAX_SIZE];
+								//wchar_t icon[MAX_PATH];
+
+								char key_str[64];
+								wchar_t target[MAX_PATH];
+								//wchar_t workdir[MAX_PATH];
+								wchar_t args[MAX_PATH];
+								wchar_t commentW[MAX_SIZE];
+								wchar_t icon[MAX_PATH];
+								int iconNum;
+
+								//char icon = "C:\\Server.ico";
+
+								BinToStr(key_str, sizeof(key_str), key, SHA1_SIZE);
+								UniStrCpy(target, sizeof(target), MsGetExeFileNameW());
+								StrToUni(args, sizeof(args), key_str);
+								UniStrCpy(icon, sizeof(icon), MsGetExeFileNameW());
+								UniFormat(commentW, sizeof(commentW), _UU("CM_SHORTCUT_COMMENT"), account_name);
+
+								if(item->Connected)
+								{
+									iconNum = 1;
+								}
+								else
+								{
+									iconNum = 2;
+								}
+
+								hr = JL_CreateShellLink(
+									target,
+									args,
+									account_name,
+									icon,iconNum,
+									commentW,
+									&shell);
+
+								if(SUCCEEDED(hr))
+								{
+
+									if(SUCCEEDED(JL_ObjectCollectionAddShellLink(poc, shell)))
+									{
+										//Print("Add JumpList %d c:%s\n",i, comment);
+										//wprintf(comment);
+									}
+									JL_ReleaseShellLink(shell);
+								}
+							}
+
+							CiFreeClientGetAccount(&c);
+						}
+
+						hr = JL_AddCategoryToList(pcdl,poc,_UU("CM_JUMPLIST_RCCONNECT"),poaRemoved);
+
+						if(SUCCEEDED(hr))
+						{
+							//wprintf(L"AddCategory\n");
+
+							hr = JL_CommitList(pcdl);
+							if(SUCCEEDED(hr))
+							{
+								//wprintf(L"JumpList Commit\n");
+							}
+						}
+						else
+						{
+							//wprintf(L"Erro JumpList AddCategory %x\n", hr);
+						}
+
+						//リリース
+						JL_ReleaseObjectCollection(poc);
+					}
+				}
+
+			}
+
+
+			ReleaseList(o);
+
+			CiFreeClientEnumAccount(&a);
+		}
+
+		
+
+
+		/*
+			JL_BeginList(pcdl, &poaRemoved);
+
+			JL_CreateObjectCollection(&poc);
+
+			//てしゅと
+			for (i = 0; i < 5; i++)
+			{
+
+				JL_CreateShellLink(
+					"",
+					"",
+					L"せつぞく",
+					NULL,0,
+					NULL,
+					&shell);
+				JL_ObjectCollectionAddShellLink(poc, shell);
+
+				JL_ReleaseShellLink(shell);
+
+			}
+
+			JL_AddCategoryToList(pcdl,poc,_UU("CM_JUMPLIST_RCCONNECT"),poaRemoved);
+			JL_CommitList(pcdl);
+			JL_ReleaseObjectCollection(poc);
+
+		JL_ReleaseCustomDestinationList(pcdl);
+		*/
+
+	}
+
+	return h;
+}
+
+
+
+#endif	// WIN32
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CM.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CM.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CM.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,124 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// CM.h
+// CM.c のヘッダ
+
+#ifndef	CM_H
+#define	CM_H
+
+// 定数
+#define	CM_REG_KEY			"Software\\SoftEther Corporation\\UT-VPN\\Client Manager"
+#define	SECURE_MANAGER_KEY	"Software\\SoftEther Corporation\\UT-VPN\\SmartCard Manager"
+#define	CM_TRAFFIC_REG_KEY	"Software\\SoftEther Corporation\\UT-VPN\\Traffic Test Tool"
+
+
+#define	CM_TRY_EXEC_UI_HELPER_INTERVAL		5000
+
+#define	CM_DEFAULT_WIDTH	800
+#define	CM_DEFAULT_HEIGHT	600
+
+#define	WM_CM_NOTIFY		(WM_APP + 999)
+
+#define	CM_IMPORT_FILENAME_MSG	1267
+#define	CM_IMPORT_FILENAME_MSG_OVERWRITE	1268
+
+#define	CM_NUM_RECENT		8
+
+#define	PUBLIC_SERVER_HTML	"http://www.softether.com/jp/special/se2hub.aspx"
+#define PUBLIC_SERVER_HTML_EN "http://www.softether.com/jp/special/se2hub_en.aspx"
+#define	PUBLIC_SERVER_TAG	L"help:no; status:no; DialogWidth:600px; dialogHeight=700px"
+#define	PUBLIC_SERVER_NAME	"public.softether.com"
+
+#define	VOICE_SSK			0	// 佐々木さん (真面目)
+#define	VOICE_AHO			1	// 佐々木さん (ユニーク)
+
+// 外部エクスポート用コード
+
+// 構造体
+
+// 関数プロトタイプ
+void CMExec();
+void CmTraffic(HWND hWnd);
+void *CmStartUacHelper();
+void CmStopUacHelper(void *p);
+void *CmExecUiHelperMain();
+UINT CmGetSecureBitmapId(char *dest_hostname);
+
+#endif	// CM_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CMInner.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CMInner.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CMInner.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,600 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// CMInner.h
+// CM.c の内部向けヘッダ
+
+#define STARTUP_MUTEX_NAME	"utvpncmgr_startup_mutex"
+
+void CmVoice(char *name);
+
+typedef struct CM_UAC_HELPER
+{
+	THREAD *Thread;
+	volatile bool Halt;
+	EVENT *HaltEvent;
+} CM_UAC_HELPER;
+
+typedef struct CM_VOICE
+{
+	UINT voice_id;
+	char *perfix;
+} CM_VOICE;
+
+static CM_VOICE cm_voice[] =
+{
+	{VOICE_SSK,		"ssk"		},
+	{VOICE_AHO,		"aho"		},
+};
+
+typedef struct CM_ENUM_HUB
+{
+	HWND hWnd;
+	THREAD *Thread;
+	SESSION *Session;
+	CLIENT_OPTION *ClientOption;
+	TOKEN_LIST *Hub;
+} CM_ENUM_HUB;
+
+#define CM_SETTING_INIT_NONE		0
+#define CM_SETTING_INIT_EASY		1	// 簡易モードへ遷移
+#define CM_SETTING_INIT_NORMAL		2	// 通常モードへ遷移
+#define CM_SETTING_INIT_SELECT		3	// 選択画面を表示
+
+typedef struct CM
+{
+	HWND hMainWnd;
+	HWND hStatusBar;
+	REMOTE_CLIENT *Client;
+	char *server_name;
+	wchar_t *import_file_name;
+	bool HideStatusBar;
+	bool HideTrayIcon;
+	bool ShowGrid;
+	bool VistaStyle;
+	bool ShowPort;
+	wchar_t StatudBar1[MAX_SIZE];
+	wchar_t StatudBar2[MAX_SIZE];
+	wchar_t StatudBar3[MAX_SIZE];
+	HICON Icon2, Icon3;
+	bool IconView;
+	THREAD *NotifyClientThread;
+	NOTIFY_CLIENT *NotifyClient;
+	volatile bool Halt;
+	bool OnCloseDispatched;
+	LIST *StatusWindowList;
+	CEDAR *Cedar;
+	LIST *EnumHubList;
+	UINT WindowCount;
+	bool DisableVoice;
+	UINT VoiceId;
+	UINT OldConnectedNum;
+	bool UpdateConnectedNumFlag;
+	UCHAR ShortcutKey[SHA1_SIZE];
+	bool TrayInited;
+	bool TrayAnimation;
+	bool TraySpeedAnimation;
+	UINT TrayAnimationCounter;
+	bool StartupMode;
+	THREAD *TryExecUiHelperThread;
+	volatile bool TryExecUiHelperHalt;
+	HANDLE TryExecUiHelperProcessHandle;
+	EVENT *TryExecUiHelperHaltEvent;
+	bool WindowsShutdowning;
+	bool CmSettingSupported;
+	bool CmEasyModeSupported;
+	bool CmSettingInitialFlag;
+	CM_SETTING CmSetting;
+	HWND hEasyWnd;
+	bool StartupFinished;
+	bool ConnectStartedFlag;
+	bool PositiveDisconnectFlag;
+	wchar_t EasyLastSelectedAccountName[MAX_ACCOUNT_NAME_LEN + 1];
+	WINDOWPLACEMENT FakeWindowPlacement;
+	INSTANCE *StartupMutex;
+	bool BadProcessChecked;
+	bool MenuPopuping;
+	bool SplashHasBeenShown;
+} CM;
+
+typedef struct CM_STATUS
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];		// アカウント名
+	HWND hWndPolicy;					// ポリシーダイアログ
+} CM_STATUS;
+
+typedef struct CM_POLICY
+{
+	HWND hWnd;
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];		// アカウント名
+	POLICY *Policy;						// ポリシーダイアログ
+	CM_STATUS *CmStatus;				// CM_STATUS
+	bool Extension;						// 拡張
+} CM_POLICY;
+
+typedef struct CM_ACCOUNT
+{
+	bool EditMode;						// 編集モード (false: 新規作成モード)
+	bool LinkMode;						// リンクモード
+	bool NatMode;						// NAT モード
+	CLIENT_OPTION *ClientOption;		// クライアントオプション
+	CLIENT_AUTH *ClientAuth;			// 認証データ
+	bool Startup;						// スタートアップアカウント
+	bool CheckServerCert;				// サーバー証明書のチェック
+	X *ServerCert;						// サーバー証明書
+	char old_server_name[MAX_HOST_NAME_LEN + 1];	// 古いサーバー名
+	bool Inited;						// 初期化フラグ
+	POLICY Policy;						// ポリシー (リンクモードのみ)
+	struct SM_HUB *Hub;					// HUB
+	RPC *Rpc;							// RPC
+	bool OnlineFlag;					// オンライン フラグ
+	bool Flag1;							// フラグ 1
+	bool HideClientCertAuth;			// クライアント認証を隠す
+	bool HideSecureAuth;				// スマートカード認証を隠す
+	bool HideTrustCert;					// 信頼する証明機関ボタンを隠す
+	UCHAR ShortcutKey[SHA1_SIZE];		// ショートカットキー
+	bool LockMode;						// 設定ロックモード
+	bool Link_ConnectNow;				// すぐに接続を開始する
+	UINT PolicyVer;						// ポリシーバージョン
+} CM_ACCOUNT;
+
+typedef struct CM_CHANGE_PASSWORD
+{
+	CLIENT_OPTION *ClientOption;		// クライアントオプション
+	char Username[MAX_USERNAME_LEN + 1];	// ユーザー名
+	char HubName[MAX_HUBNAME_LEN + 1];		// HUB 名
+} CM_CHANGE_PASSWORD;
+
+typedef struct CM_TRAFFIC
+{
+	bool ServerMode;		// サーバーモード
+	bool Double;			// 2 倍モード
+	bool Raw;				// 生データモード
+	UINT Port;				// ポート番号
+	char Host[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	UINT NumTcp;			// TCP コネクション数
+	UINT Type;				// 種類
+	UINT Span;				// 期間
+} CM_TRAFFIC;
+
+typedef struct CM_TRAFFIC_DLG
+{
+	HWND hWnd;				// ウインドウハンドル
+	CM_TRAFFIC *Setting;	// 設定
+	TTS *Tts;				// 測定サーバー
+	TTC *Ttc;				// 測定クライアント
+	THREAD *HaltThread;		// 停止用スレッド
+	THREAD *ClientEndWaitThread;	// クライアントが終了するのを待機するスレッド
+	bool Started;			// 開始フラグ
+	bool Stopping;			// 停止中
+	UINT RetCode;			// 戻り値
+	TT_RESULT Result;		// 結果
+	EVENT *ResultShowEvent;	// 結果表示イベント
+	bool CloseDialogAfter;	// ダイアログを閉じるかどうかのフラグ
+} CM_TRAFFIC_DLG;
+
+// インターネット接続設定
+typedef struct CM_INTERNET_SETTING
+{
+	UINT ProxyType;								// プロキシサーバーの種類
+	char ProxyHostName[MAX_HOST_NAME_LEN + 1];	// プロキシサーバーホスト名
+	UINT ProxyPort;								// プロキシサーバーポート番号
+	char ProxyUsername[MAX_USERNAME_LEN + 1];	// プロキシサーバーユーザー名
+	char ProxyPassword[MAX_USERNAME_LEN + 1];	// プロキシサーバーパスワード
+} CM_INTERNET_SETTING;
+
+static CM *cm = NULL;
+
+void CmFreeTrayExternal(void *hWnd);
+
+// 通常 RPC 呼び出しマクロ
+__forceinline static bool CALL(HWND hWnd, UINT code)
+{
+	UINT ret = code;
+	if (ret != ERR_NO_ERROR)
+	{
+		if (ret == ERR_DISCONNECTED)
+		{
+			if (cm != NULL)
+			{
+				Close(cm->hMainWnd);
+			}
+			else
+			{
+				MsgBox(hWnd, MB_ICONSTOP, _UU("SM_DISCONNECTED"));
+			}
+
+			if (cm != NULL)
+			{
+				CmFreeTrayExternal((void *)cm->hMainWnd);
+			}
+			exit(0);
+		}
+		else
+		{
+			UINT flag = MB_ICONEXCLAMATION;
+			if (ret == ERR_VLAN_IS_USED)
+			{
+				CmVoice("using_vlan");
+			}
+			if (hWnd != NULL && cm != NULL && cm->hEasyWnd != NULL)
+			{
+				hWnd = cm->hEasyWnd;
+			}
+			if (hWnd != NULL && cm != NULL && hWnd == cm->hEasyWnd)
+			{
+				flag |= MB_SETFOREGROUND | MB_TOPMOST;
+			}
+			MsgBox(hWnd, flag, _E(ret));
+		}
+	}
+
+	if (ret == ERR_NO_ERROR)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// 拡張 RPC 呼び出しマクロ (エラー値を取得する)
+__forceinline static UINT CALLEX(HWND hWnd, UINT code)
+{
+	UINT ret = code;
+	if (ret != ERR_NO_ERROR)
+	{
+		if (ret == ERR_DISCONNECTED)
+		{
+			if (cm != NULL)
+			{
+				Close(cm->hMainWnd);
+			}
+			else
+			{
+				MsgBox(hWnd, MB_ICONSTOP, _UU("SM_DISCONNECTED"));
+			}
+			if (cm != NULL)
+			{
+				CmFreeTrayExternal((void *)cm->hMainWnd);
+			}
+			exit(0);
+		}
+	}
+
+	return ret;
+}
+
+typedef struct CM_LOADX
+{
+	X *x;
+} CM_LOADX;
+
+typedef struct CM_SETTING_DLG
+{
+	bool CheckPassword;
+	UCHAR HashedPassword[SHA1_SIZE];
+} CM_SETTING_DLG;
+
+typedef struct CM_EASY_DLG
+{
+	bool EndDialogCalled;
+} CM_EASY_DLG;
+
+
+// タスクトレイ関係
+#define	WM_CM_TRAY_MESSAGE			(WM_APP + 44)
+#define WM_CM_SETTING_CHANGED_MESSAGE	(WM_APP + 45)
+#define WM_CM_EASY_REFRESH			(WM_APP + 46)
+#define WM_CM_SHOW					(WM_APP + 47)
+#define	CMD_EASY_DBLCLICK			40697
+#define	CM_TRAY_ANIMATION_INTERVAL	3000
+#define	CM_TRAY_MAX_ITEMS			4096
+#define	CM_TRAY_MENU_ID_START		12000
+#define	CM_TRAY_MENU_CONNECT_ID_START	(CM_TRAY_MENU_ID_START + CM_TRAY_MAX_ITEMS)
+#define	CM_TRAY_MENU_STATUS_ID_START	(CM_TRAY_MENU_CONNECT_ID_START + CM_TRAY_MAX_ITEMS)
+#define	CM_TRAY_MENU_DISCONNECT_ID_START	(CM_TRAY_MENU_STATUS_ID_START + CM_TRAY_MAX_ITEMS)
+#define	CM_TRAY_MENU_RECENT_ID_START	(CM_TRAY_MENU_DISCONNECT_ID_START + CM_TRAY_MAX_ITEMS)
+#define	CM_TRAY_IS_CONNECT_ID(id)	(((id) >= CM_TRAY_MENU_CONNECT_ID_START) && (id) < CM_TRAY_MENU_STATUS_ID_START)
+#define	CM_TRAY_IS_STATUS_ID(id)	(((id) >= CM_TRAY_MENU_STATUS_ID_START) && (id) < CM_TRAY_MENU_DISCONNECT_ID_START)
+#define	CM_TRAY_IS_DISCONNECT_ID(id)	(((id) >= CM_TRAY_MENU_DISCONNECT_ID_START) && (id) < (CM_TRAY_MENU_DISCONNECT_ID_START + CM_TRAY_MAX_ITEMS))
+#define	CM_TRAY_IS_RECENT_ID(id)	(((id) >= CM_TRAY_MENU_RECENT_ID_START) && (id) < (CM_TRAY_MENU_RECENT_ID_START + CM_TRAY_MAX_ITEMS))
+
+// スプラッシュスクリーンの枠線の色
+#define	CM_SPLASH_BORDER_COLOR	(RGB(102, 0, 204))
+
+
+// 関数プロトタイプ
+void InitCM();
+void FreeCM();
+void MainCM();
+bool LoginCM();
+void LogoutCM();
+UINT CmLoginDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void MainCMWindow();
+void CmSendImportMessage(HWND hWnd, wchar_t *filename, UINT msg);
+UINT CmMainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmMainWindowOnSize(HWND hWnd);
+void CmMainWindowOnInit(HWND hWnd);
+void CmMainWindowOnQuit(HWND hWnd);
+void CmSaveMainWindowPos(HWND hWnd);
+void CmMainWindowOnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy);
+bool CmIsEnabled(HWND hWnd, UINT id);
+bool CmIsChecked(UINT id);
+bool CmIsBold(UINT id);
+void CmMainWindowOnPopupMenu(HWND hWnd, HMENU hMenu, UINT pos);
+void CmSaveMainWindowPos(HWND hWnd);
+void CmRedrawStatusBar(HWND hWnd);
+void CmRefresh(HWND hWnd);
+void CmRefreshEx(HWND hWnd, bool style_changed);
+void CmSetForegroundProcessToCnService();
+void CmInitAccountList(HWND hWnd);
+void CmInitAccountListEx(HWND hWnd, bool easy);
+void CmInitVLanList(HWND hWnd);
+void CmRefreshAccountList(HWND hWnd);
+void CmRefreshAccountListEx(HWND hWnd, bool easy);
+void CmRefreshAccountListEx2(HWND hWnd, bool easy, bool style_changed);
+void CmRefreshVLanList(HWND hWnd);
+void CmRefreshVLanListEx(HWND hWnd, bool style_changed);
+void CmSaveAccountListPos(HWND hWnd);
+void CmSaveVLanListPos(HWND hWnd);
+wchar_t *CmGetProtocolName(UINT n);
+void CmVLanNameToPrintName(char *str, UINT size, char *name);
+bool CmPrintNameToVLanName(char *name, UINT size, char *str);
+void CmMainWindowOnNotify(HWND hWnd, NMHDR *n);
+void CmOnKey(HWND hWnd, bool ctrl, bool alt, UINT key);
+void CmAccountListRightClick(HWND hWnd);
+void CmVLanListRightClick(HWND hWnd);
+void CmConnect(HWND hWnd, wchar_t *account_name);
+void CmDisconnect(HWND hWnd, wchar_t *account_name);
+void CmInitNotifyClientThread();
+void CmFreeNotifyClientThread();
+void CmNotifyClientThread(THREAD *thread, void *param);
+void CmDeleteAccount(HWND hWnd, wchar_t *account_name);
+void CmStatus(HWND hWnd, wchar_t *account_name);
+void CmStatusDlg(HWND hWnd, wchar_t *account_name);
+UINT CmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmStatusDlgPrint(HWND hWnd, CM_STATUS *cmst);
+void CmPrintStatusToListView(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s);
+void CmPrintStatusToListViewEx(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode);
+void CmStatusDlgPrintCert(HWND hWnd, CM_STATUS *st, bool server);
+void CmPolicyDlg(HWND hWnd, CM_STATUS *st);
+UINT CmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmPolicyDlgPrint(HWND hWnd, CM_POLICY *p);
+void CmPolicyDlgPrintEx(HWND hWnd, CM_POLICY *p, bool cascade_mode);
+void CmPolicyDlgPrintEx2(HWND hWnd, CM_POLICY *p, bool cascade_mode, bool ver);
+void CmNewAccount(HWND hWnd);
+void CmEditAccount(HWND hWnd, wchar_t *account_name);
+void CmGenerateNewAccountName(HWND hWnd, wchar_t *name, UINT size);
+void CmGenerateCopyName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name);
+void CmGenerateImportName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name);
+CM_ACCOUNT *CmCreateNewAccountObject(HWND hWnd);
+CM_ACCOUNT *CmGetExistAccountObject(HWND hWnd, wchar_t *account_name);
+void CmEnumHubStart(HWND hWnd, CLIENT_OPTION *o);
+void CmInitEnumHub();
+void CmFreeEnumHub();
+void CmFreeAccountObject(HWND hWnd, CM_ACCOUNT *a);
+bool CmEditAccountDlg(HWND hWnd, CM_ACCOUNT *a);
+UINT CmEditAccountDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmEditAccountDlgUpdate(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgInit(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgOnOk(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgStartEnumHub(HWND hWnd, CM_ACCOUNT *a);
+bool CmLoadXAndK(HWND hWnd, X **x, K **k);
+bool CmLoadK(HWND hWnd, K **k);
+bool CmLoadKEx(HWND hWnd, K **k, char *filename, UINT size);
+bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size);
+bool CmLoadXFromFileOrSecureCard(HWND hWnd, X **x);
+void CmLoadXFromFileOrSecureCardDlgInit(HWND hWnd, CM_LOADX *p);
+void CmLoadXFromFileOrSecureCardDlgUpdate(HWND hWnd, CM_LOADX *p);
+UINT CmLoadXFromFileOrSecureCardDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool CmLoadX(HWND hWnd, X **x);
+bool CmLoadXEx(HWND hWnd, X **x, char *filename, UINT size);
+bool CmLoadXExW(HWND hWnd, X **x, wchar_t *filename, UINT size);
+X *CmGetIssuer(X *x);
+bool CmProxyDlg(HWND hWnd, CLIENT_OPTION *a);
+void CmProxyDlgUpdate(HWND hWnd, CLIENT_OPTION *a);
+UINT CmProxyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool CmDetailDlg(HWND hWnd, CM_ACCOUNT *a);
+UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+char *CmNewVLanDlg(HWND hWnd);
+UINT CmNewVLanDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmCopyAccount(HWND hWnd, wchar_t *account_name);
+void CmExportAccount(HWND hWnd, wchar_t *account_name);
+void CmSortcut(HWND hWnd, wchar_t *account_name);
+void CmImportAccount(HWND hWnd);
+void CmImportAccountMain(HWND hWnd, wchar_t *filename);
+void CmImportAccountMainEx(HWND hWnd, wchar_t *filename, bool overwrite);
+void CmTrustDlg(HWND hWnd);
+UINT CmTrustDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrustDlgUpdate(HWND hWnd);
+void CmTrustDlgRefresh(HWND hWnd);
+void CmTrustImport(HWND hWnd);
+void CmTrustExport(HWND hWnd);
+void CmTrustView(HWND hWnd);
+void CmPassword(HWND hWnd);
+UINT CmPasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmPasswordRefresh(HWND hWnd);
+void CmRefreshStatusBar(HWND hWnd);
+UINT CmGetNumConnected(HWND hWnd);
+void CmDisconnectAll(HWND hWnd);
+wchar_t *CmGenerateMainWindowTitle();
+void CmConfigDlg(HWND hWnd);
+UINT CmConfigDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmConfigDlgInit(HWND hWnd);
+void CmConfigDlgRefresh(HWND hWnd);
+void CmConfigDlgOnOk(HWND hWnd);
+bool CmWarningDesktop(HWND hWnd, wchar_t *account_name);
+UINT CmDesktopDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmDesktopDlgInit(HWND hWnd, wchar_t *account_name);
+void CmChangePassword(HWND hWnd, CLIENT_OPTION *o, char *hubname, char *username);
+UINT CmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmChangePasswordUpdate(HWND hWnd, CM_CHANGE_PASSWORD *p);
+void SmShowPublicVpnServerHtml(HWND hWnd);
+void CmConnectShortcut(UCHAR *key);
+UINT CmSelectSecure(HWND hWnd, UINT current_id);
+void CmClientSecureManager(HWND hWnd);
+UINT CmClientSelectSecure(HWND hWnd);
+UINT CmSelectSecureDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSelectSecureDlgInit(HWND hWnd, UINT default_id);
+void CmSelectSecureDlgUpdate(HWND hWnd);
+void CmSecureManager(HWND hWnd, UINT id);
+void CmSecureManagerEx(HWND hWnd, UINT id, bool no_new_cert);
+UINT CmSecureManagerDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecureManagerDlgInit(HWND hWnd, UINT id);
+void CmSecureManagerDlgUpdate(HWND hWnd, UINT id);
+void CmSecureManagerDlgRefresh(HWND hWnd, UINT id);
+void CmSecureManagerDlgPrintList(HWND hWnd, LIST *o);
+void CmSecureManagerDlgPrintListEx(HWND hWnd, UINT id, LIST *o, UINT type);
+wchar_t *CmSecureObjTypeToStr(UINT type);
+UINT CmSecureType(HWND hWnd);
+UINT CmSecureTypeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecureManagerDlgImport(HWND hWnd, UINT id);
+void CmSecureManagerDlgDelete(HWND hWnd, UINT id);
+void CmSecureManagerDlgExport(HWND hWnd, UINT id);
+void CmSecureManagerDlgNewCert(HWND hWnd, UINT id);
+void CmSecurePin(HWND hWnd, UINT id);
+UINT CmSecurePinDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecurePinDlgUpdate(HWND hWnd);
+void CmInitTray(HWND hWnd);
+void CmPollingTray(HWND hWnd);
+void CmFreeTray(HWND hWnd);
+void CmChangeTrayString(HWND hWnd, wchar_t *str);
+UINT CmGetTrayIconId(bool animation, UINT animation_counter);
+void CmShowOrHideWindow(HWND hWnd);
+void CmShowTrayMenu(HWND hWnd);
+HMENU CmCreateTraySubMenu(HWND hWnd, bool flag, UINT start_id);
+HMENU CmCreateRecentSubMenu(HWND hWnd, UINT start_id);
+bool CmCheckPkcsEula(HWND hWnd, UINT id);
+UINT CmPkcsEulaDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmDeleteOldStartupTrayFile();
+UINT CmTrafficDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficDlgInit(HWND hWnd);
+bool CmTrafficDlgUpdate(HWND hWnd);
+void CmTrafficDlgOnOk(HWND hWnd);
+bool CmTrafficLoadFromReg(CM_TRAFFIC *t);
+void CmTrafficGetDefaultSetting(CM_TRAFFIC *t);
+void CmTrafficSaveToReg(CM_TRAFFIC *t);
+void CmTrafficDlgToStruct(HWND hWnd, CM_TRAFFIC *t);
+void CmExecTraffic(HWND hWnd, CM_TRAFFIC *t);
+UINT CmTrafficRunDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficRunDlgInit(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgStart(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgPrintProc(void *param, wchar_t *str);
+void CmTrafficRunDlgAddStr(HWND hWnd, wchar_t *str);
+void CmTrafficRunDlgHalt(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgHaltThread(THREAD *t, void *param);
+void CmTrafficRunDlgClientWaitThread(THREAD *t, void *param);
+void CmTrafficResult(HWND hWnd, TT_RESULT *r);
+UINT CmTrafficResultDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficResultDlgInit(HWND hWnd, TT_RESULT *res);
+void CmTryToExecUiHelper();
+void CmInitTryToExecUiHelper();
+void CmFreeTryToExecUiHelper();
+void CmTryToExecUiHelperThread(THREAD *thread, void *param);
+bool CmSetting(HWND hWnd);
+UINT CmSettingDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSettingDlgInit(HWND hWnd, CM_SETTING_DLG *d);
+void CmSettingDlgUpdate(HWND hWnd, CM_SETTING_DLG *d);
+void CmSettingDlgOnOk(HWND hWnd, CM_SETTING_DLG *d);
+void CmApplyCmSetting();
+void CmMainWindowOnTrayClicked(HWND hWnd, WPARAM wParam, LPARAM lParam);
+void CmShowEasy();
+void CmCloseEasy();
+void CmMainWindowOnShowEasy(HWND hWnd);
+UINT CmEasyDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmEasyDlgInit(HWND hWnd, CM_EASY_DLG *d);
+void CmEasyDlgUpdate(HWND hWnd, CM_EASY_DLG *d);
+void CmEasyDlgRefresh(HWND hWnd, CM_EASY_DLG *d);
+void CmRefreshEasy();
+void CmEasyDlgOnNotify(HWND hWnd, CM_EASY_DLG *d, NMHDR *n);
+void CmEasyDlgOnKey(HWND hWnd, CM_EASY_DLG *d, bool ctrl, bool alt, UINT key);
+void CmEasyDlgOnCommand(HWND hWnd, CM_EASY_DLG *d, WPARAM wParam, LPARAM lParam);
+bool CmStartStartupMutex();
+void CmEndStartupMutex();
+void CmSetUacWindowActive();
+void CmUacHelperThread(THREAD *thread, void *param);
+void CmProxyDlgUseForIE(HWND hWnd, CLIENT_OPTION *o);
+void CmGetSystemInternetSetting(CM_INTERNET_SETTING *setting);
+void CmProxyDlgSet(HWND hWnd, CLIENT_OPTION *o, CM_INTERNET_SETTING *setting);
+bool CmGetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type);
+void *CmUpdateJumpList(UINT start_id);
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Cedar.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Cedar.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Cedar.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1566 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Cedar.c
+// Cedar 通信モジュールプログラムコード
+
+// Build 7101
+
+
+#include "CedarPch.h"
+
+static UINT init_cedar_counter = 0;
+static REF *cedar_log_ref = NULL;
+static LOG *cedar_log;
+
+// 現在サポートされている Windows のバージョンかどうか取得する
+// (以前、XP までしか想定していないコードを Vista (Longhorn) で動作させたときに
+//  OS ごと大変おかしくなってしまったことがあるので、バージョンチェックは
+//  必ず行うようにした。ただし、警告メッセージを画面に表示するだけであり、
+//  動作は一応できるようにしている。)
+bool IsSupportedWinVer(RPC_WINVER *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return false;
+	}
+
+	if (v->IsWindows == false)
+	{
+		return true;
+	}
+
+	if (v->IsNT == false)
+	{
+		return true;
+	}
+
+	if (v->IsBeta)
+	{
+		return true;
+	}
+
+	if (v->VerMajor <= 4)
+	{
+		// Windows NT
+		return true;
+	}
+
+	if (v->VerMajor == 5 && v->VerMinor == 0)
+	{
+		// Windows 2000
+		if (v->ServicePack <= 4)
+		{
+			// SP4 までサポート
+			return true;
+		}
+	}
+
+	if (v->VerMajor == 5 && v->VerMinor == 1)
+	{
+		// Windows XP x86
+		if (v->ServicePack <= 3)
+		{
+			// SP3 までサポート
+			return true;
+		}
+	}
+
+	if (v->VerMajor == 5 && v->VerMinor == 2)
+	{
+		// Windows XP x64, Windows Server 2003
+		if (v->ServicePack <= 2)
+		{
+			// SP2 までサポート
+			return true;
+		}
+	}
+
+	if (v->VerMajor == 6 && v->VerMinor == 0)
+	{
+		// Windows Vista, Server 2008
+		if (v->ServicePack <= 2)
+		{
+			// SP2 までサポート
+			return true;
+		}
+	}
+
+	if (v->VerMajor == 6 && v->VerMinor == 1)
+	{
+		// Windows 7, Server 2008 R2
+		if (v->ServicePack <= 0)
+		{
+			// SP0 までサポート
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// Windows のバージョンを取得する
+void GetWinVer(RPC_WINVER *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32GetWinVer(v);
+#else	// OS_WIN32
+	Zero(v, sizeof(RPC_WINVER));
+	StrCpy(v->Title, sizeof(v->Title), GetOsInfo()->OsProductName);
+#endif	// OS_WIN32
+}
+
+// 簡易ログを閉じる
+void FreeTinyLog(TINY_LOG *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FileClose(t->io);
+	DeleteLock(t->Lock);
+	Free(t);
+}
+
+// 簡易ログの書き込み
+void WriteTinyLog(TINY_LOG *t, char *str)
+{
+	BUF *b;
+	char dt[MAX_PATH];
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	GetDateTimeStrMilli64(dt, sizeof(dt), LocalTime64());
+	StrCat(dt, sizeof(dt), ": ");
+
+	b = NewBuf();
+
+	WriteBuf(b, dt, StrLen(dt));
+	WriteBuf(b, str, StrLen(str));
+	WriteBuf(b, "\r\n", 2);
+
+	Lock(t->Lock);
+	{
+		FileWrite(t->io, b->Buf, b->Size);
+		FileFlush(t->io);
+	}
+	Unlock(t->Lock);
+
+	FreeBuf(b);
+}
+
+// 簡易ログの初期化
+TINY_LOG *NewTinyLog()
+{
+	char name[MAX_PATH];
+	SYSTEMTIME st;
+	TINY_LOG *t;
+
+	LocalTime(&st);
+
+	MakeDir(TINY_LOG_DIRNAME);
+
+	Format(name, sizeof(name), TINY_LOG_FILENAME,
+		st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+
+	t = ZeroMalloc(sizeof(TINY_LOG));
+
+	StrCpy(t->FileName, sizeof(t->FileName), name);
+	t->io = FileCreate(name);
+	t->Lock = NewLock();
+
+	return t;
+}
+
+// 非 SSL リストのエントリの比較
+int CompareNoSslList(void *p1, void *p2)
+{
+	NON_SSL *n1, *n2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	n1 = *(NON_SSL **)p1;
+	n2 = *(NON_SSL **)p2;
+	if (n1 == NULL || n2 == NULL)
+	{
+		return 0;
+	}
+	return CmpIpAddr(&n1->IpAddress, &n2->IpAddress);
+}
+
+// 指定された IP アドレスが非 SSL リストに存在するかどうかチェック
+bool IsInNoSsl(CEDAR *c, IP *ip)
+{
+	bool ret = false;
+	// 引数チェック
+	if (c == NULL || ip == NULL)
+	{
+		return false;
+	}
+
+	LockList(c->NonSslList);
+	{
+		NON_SSL *n = SearchNoSslList(c, ip);
+
+		if (n != NULL)
+		{
+			if (n->EntryExpires > Tick64() && n->Count > NON_SSL_MIN_COUNT)
+			{
+				n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES;
+				ret = true;
+			}
+		}
+	}
+	UnlockList(c->NonSslList);
+
+	return ret;
+}
+
+// 非 SSL リストのエントリをデクリメント
+void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec)
+{
+	// 引数チェック
+	if (c == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	LockList(c->NonSslList);
+	{
+		NON_SSL *n = SearchNoSslList(c, ip);
+
+		if (n != NULL)
+		{
+			if (n->Count >= num_dec)
+			{
+				n->Count -= num_dec;
+			}
+		}
+	}
+	UnlockList(c->NonSslList);
+}
+
+// 非 SSL リストにエントリを追加
+bool AddNoSsl(CEDAR *c, IP *ip)
+{
+	NON_SSL *n;
+	bool ret = true;
+	// 引数チェック
+	if (c == NULL || ip == NULL)
+	{
+		return true;
+	}
+
+	LockList(c->NonSslList);
+	{
+		DeleteOldNoSsl(c);
+
+		n = SearchNoSslList(c, ip);
+
+		if (n == NULL)
+		{
+			n = ZeroMalloc(sizeof(NON_SSL));
+			Copy(&n->IpAddress, ip, sizeof(IP));
+			n->Count = 0;
+
+			Add(c->NonSslList, n);
+		}
+
+		n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES;
+
+		n->Count++;
+
+		if (n->Count > NON_SSL_MIN_COUNT)
+		{
+			ret = false;
+		}
+	}
+	UnlockList(c->NonSslList);
+
+	return ret;
+}
+
+// 古い非 SSL リストの削除
+void DeleteOldNoSsl(CEDAR *c)
+{
+	UINT i;
+	LIST *o;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	o = NewListFast(NULL);
+
+	for (i = 0;i < LIST_NUM(c->NonSslList);i++)
+	{
+		NON_SSL *n = LIST_DATA(c->NonSslList, i);
+
+		if (n->EntryExpires <= Tick64())
+		{
+			Add(o, n);
+		}
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		NON_SSL *n = LIST_DATA(o, i);
+
+		Delete(c->NonSslList, n);
+		Free(n);
+	}
+
+	ReleaseList(o);
+}
+
+// 非 SSL リストの検索
+NON_SSL *SearchNoSslList(CEDAR *c, IP *ip)
+{
+	NON_SSL *n, t;
+	// 引数チェック
+	if (c == NULL || ip == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	Copy(&t.IpAddress, ip, sizeof(IP));
+
+	n = Search(c->NonSslList, &t);
+
+	if (n == NULL)
+	{
+		return NULL;
+	}
+
+	return n;
+}
+
+// 非 SSL リストの初期化
+void InitNoSslList(CEDAR *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->NonSslList = NewList(CompareNoSslList);
+}
+
+// 非 SSL リストの解放
+void FreeNoSslList(CEDAR *c)
+{
+	UINT i;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(c->NonSslList);i++)
+	{
+		NON_SSL *n = LIST_DATA(c->NonSslList, i);
+
+		Free(n);
+	}
+
+	ReleaseList(c->NonSslList);
+	c->NonSslList = NULL;
+}
+
+// Cedar ログをとる
+void CedarLog(char *str)
+{
+	char *tmp;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	if (cedar_log_ref == NULL)
+	{
+		return;
+	}
+
+	tmp = CopyStr(str);
+
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	if (StrLen(tmp) > 1)
+	{
+		if (tmp[StrLen(tmp) - 1] == '\n')
+		{
+			tmp[StrLen(tmp) - 1] = 0;
+		}
+		if (StrLen(tmp) > 1)
+		{
+			if (tmp[StrLen(tmp) - 1] == '\r')
+			{
+				tmp[StrLen(tmp) - 1] = 0;
+			}
+		}
+	}
+
+	InsertStringRecord(cedar_log, tmp);
+
+	Free(tmp);
+}
+
+// ログを開始する
+void StartCedarLog()
+{
+	if (cedar_log_ref == NULL)
+	{
+		cedar_log_ref = NewRef();
+	}
+	else
+	{
+		AddRef(cedar_log_ref);
+	}
+
+	cedar_log = NewLog("debug_log", "debug", LOG_SWITCH_DAY);
+}
+
+// ログを停止する
+void StopCedarLog()
+{
+	if (cedar_log_ref == NULL)
+	{
+		return;
+	}
+
+	if (Release(cedar_log_ref) == 0)
+	{
+		FreeLog(cedar_log);
+		cedar_log = NULL;
+		cedar_log_ref = NULL;
+	}
+}
+
+// トラフィックのパケットサイズを取得する
+UINT64 GetTrafficPacketSize(TRAFFIC *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return 0;
+	}
+
+	return t->Recv.BroadcastBytes + t->Recv.UnicastBytes +
+		t->Send.BroadcastBytes + t->Send.UnicastBytes;
+}
+
+// トラフィックのパケット数を取得する
+UINT64 GetTrafficPacketNum(TRAFFIC *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return 0;
+	}
+
+	return t->Recv.BroadcastCount + t->Recv.UnicastCount +
+		t->Send.BroadcastCount + t->Send.UnicastCount;
+}
+
+// 非表示パスワードの内容が変更されたかどうかチェックする
+bool IsHiddenPasswordChanged(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return true;
+	}
+
+	if (StrCmpi(str, HIDDEN_PASSWORD) == 0)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// 非表示パスワードを初期化する
+void InitHiddenPassword(char *str, UINT size)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	StrCpy(str, size, HIDDEN_PASSWORD);
+}
+
+// 証明書が仮想 HUB に登録されている CA によって署名されているかどうか確認する
+bool CheckSignatureByCaLinkMode(SESSION *s, X *x)
+{
+	LINK *k;
+	HUB *h;
+	bool ret = false;
+	// 引数チェック
+	if (s == NULL || x == NULL)
+	{
+		return false;
+	}
+
+	if (s->LinkModeClient == false || (k = s->Link) == NULL)
+	{
+		return false;
+	}
+
+	h = k->Hub;
+
+	if (h->HubDb != NULL)
+	{
+		LockList(h->HubDb->RootCertList);
+		{
+			X *root_cert;
+			root_cert = GetIssuerFromList(h->HubDb->RootCertList, x);
+			if (root_cert != NULL)
+			{
+				ret = true;
+			}
+		}
+		UnlockList(h->HubDb->RootCertList);
+	}
+
+	return ret;
+}
+
+// 証明書が Cedar に登録されている CA によって署名されているかどうか確認する
+bool CheckSignatureByCa(CEDAR *cedar, X *x)
+{
+	X *ca;
+	// 引数チェック
+	if (cedar == NULL || x == NULL)
+	{
+		return false;
+	}
+
+	// 指定された証明書を署名した CA を取得
+	ca = FindCaSignedX(cedar->CaList, x);
+	if (ca == NULL)
+	{
+		// 発見できなかった
+		return false;
+	}
+
+	// 発見した
+	FreeX(ca);
+	return true;
+}
+
+// 指定された証明書を署名した CA を取得
+X *FindCaSignedX(LIST *o, X *x)
+{
+	X *ret;
+	// 引数チェック
+	if (o == NULL || x == NULL)
+	{
+		return NULL;
+	}
+
+	ret = NULL;
+
+	LockList(o);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			X *ca = LIST_DATA(o, i);
+			if (CheckXDateNow(ca))
+			{
+				if (CompareName(ca->subject_name, x->issuer_name))
+				{
+					K *k = GetKFromX(ca);
+					if (k != NULL)
+					{
+						if (CheckSignature(x, k))
+						{
+							ret = CloneX(ca);
+						}
+						FreeK(k);
+					}
+				}
+				else if (CompareX(ca, x))
+				{
+					ret = CloneX(ca);
+				}
+			}
+
+			if (ret != NULL)
+			{
+				break;
+			}
+		}
+	}
+	UnlockList(o);
+
+	return ret;
+}
+
+// Cedar から CA を削除する
+bool DeleteCa(CEDAR *cedar, UINT ptr)
+{
+	bool b = false;
+	// 引数チェック
+	if (cedar == NULL || ptr == 0)
+	{
+		return false;
+	}
+
+	LockList(cedar->CaList);
+	{
+		UINT i;
+
+		for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+		{
+			X *x = LIST_DATA(cedar->CaList, i);
+
+			if (POINTER_TO_KEY(x) == ptr)
+			{
+				Delete(cedar->CaList, x);
+				FreeX(x);
+
+				b = true;
+
+				break;
+			}
+		}
+	}
+	UnlockList(cedar->CaList);
+
+	return b;
+}
+
+// Cedar に CA を追加する
+void AddCa(CEDAR *cedar, X *x)
+{
+	// 引数チェック
+	if (cedar == NULL || x == NULL)
+	{
+		return;
+	}
+
+	LockList(cedar->CaList);
+	{
+		UINT i;
+		bool ok = true;
+
+		for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+		{
+			X *exist_x = LIST_DATA(cedar->CaList, i);
+			if (CompareX(exist_x, x))
+			{
+				ok = false;
+				break;
+			}
+		}
+
+		if (ok)
+		{
+			Insert(cedar->CaList, CloneX(x));
+		}
+	}
+	UnlockList(cedar->CaList);
+}
+
+// Cedar からコネクションを削除する
+void DelConnection(CEDAR *cedar, CONNECTION *c)
+{
+	// 引数チェック
+	if (cedar == NULL || c == NULL)
+	{
+		return;
+	}
+
+	LockList(cedar->ConnectionList);
+	{
+		Debug("Connection %s Deleted from Cedar.\n", c->Name);
+		if (Delete(cedar->ConnectionList, c))
+		{
+			ReleaseConnection(c);
+		}
+	}
+	UnlockList(cedar->ConnectionList);
+}
+
+// 現在の未確立コネクション数を取得する
+UINT GetUnestablishedConnections(CEDAR *cedar)
+{
+	UINT i, ret;
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return 0;
+	}
+
+	ret = 0;
+
+	LockList(cedar->ConnectionList);
+	{
+		for (i = 0;i < LIST_NUM(cedar->ConnectionList);i++)
+		{
+			CONNECTION *c = LIST_DATA(cedar->ConnectionList, i);
+
+			switch (c->Type)
+			{
+			case CONNECTION_TYPE_CLIENT:
+			case CONNECTION_TYPE_INIT:
+			case CONNECTION_TYPE_LOGIN:
+			case CONNECTION_TYPE_ADDITIONAL:
+				switch (c->Status)
+				{
+				case CONNECTION_STATUS_ACCEPTED:
+				case CONNECTION_STATUS_NEGOTIATION:
+				case CONNECTION_STATUS_USERAUTH:
+					ret++;
+					break;
+				}
+				break;
+			}
+		}
+	}
+	UnlockList(cedar->ConnectionList);
+
+	return ret + Count(cedar->AcceptingSockets);
+}
+
+// Cedar にコネクションを追加する
+void AddConnection(CEDAR *cedar, CONNECTION *c)
+{
+	char tmp[MAX_SIZE];
+	UINT i;
+	// 引数チェック
+	if (cedar == NULL || c == NULL)
+	{
+		return;
+	}
+
+	//新しいコネクションの名前を決定する
+	i = Inc(cedar->ConnectionIncrement);
+	Format(tmp, sizeof(tmp), "CID-%u", i);
+	Lock(c->lock);
+	{
+		Free(c->Name);
+		c->Name = CopyStr(tmp);
+	}
+	Unlock(c->lock);
+
+	LockList(cedar->ConnectionList);
+	{
+		Add(cedar->ConnectionList, c);
+		AddRef(c->ref);
+		Debug("Connection %s Inserted to Cedar.\n", c->Name);
+	}
+	UnlockList(cedar->ConnectionList);
+}
+
+// すべてのコネクションを停止
+void StopAllConnection(CEDAR *c)
+{
+	UINT num;
+	UINT i;
+	CONNECTION **connections;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	LockList(c->ConnectionList);
+	{
+		connections = ToArray(c->ConnectionList);
+		num = LIST_NUM(c->ConnectionList);
+		DeleteAll(c->ConnectionList);
+	}
+	UnlockList(c->ConnectionList);
+
+	for (i = 0;i < num;i++)
+	{
+		StopConnection(connections[i], false);
+		ReleaseConnection(connections[i]);
+	}
+	Free(connections);
+}
+
+// CEDAR から HUB を削除
+void DelHub(CEDAR *c, HUB *h)
+{
+	DelHubEx(c, h, false);
+}
+void DelHubEx(CEDAR *c, HUB *h, bool no_lock)
+{
+	// 引数チェック
+	if (c == NULL || h == NULL)
+	{
+		return;
+	}
+
+	if (no_lock == false)
+	{
+		LockHubList(c);
+	}
+
+	if (Delete(c->HubList, h))
+	{
+		ReleaseHub(h);
+	}
+
+	if (no_lock == false)
+	{
+		UnlockHubList(c);
+	}
+}
+
+// CEDAR に HUB を追加
+void AddHub(CEDAR *c, HUB *h)
+{
+	// 引数チェック
+	if (c == NULL || h == NULL)
+	{
+		return;
+	}
+
+	LockHubList(c);
+	{
+#if	0
+		// HUB 数はここではチェックしないことにする
+		if (LIST_NUM(c->HubList) >= MAX_HUBS)
+		{
+			// 上限数超過
+			UnlockHubList(c);
+			return;
+		}
+#endif
+
+		// 同一名の HUB が存在しないかどうかチェック
+		if (IsHub(c, h->Name))
+		{
+			// 存在する
+			UnlockHubList(c);
+			return;
+		}
+
+		// HUB を登録する
+		Insert(c->HubList, h);
+		AddRef(h->ref);
+	}
+	UnlockHubList(c);
+}
+
+// CEDAR のすべての HUB を停止
+void StopAllHub(CEDAR *c)
+{
+	HUB **hubs;
+	UINT i, num;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	LockHubList(c);
+	{
+		hubs = ToArray(c->HubList);
+		num = LIST_NUM(c->HubList);
+		DeleteAll(c->HubList);
+	}
+	UnlockHubList(c);
+
+	for (i = 0;i < num;i++)
+	{
+		StopHub(hubs[i]);
+		ReleaseHub(hubs[i]);
+	}
+
+	Free(hubs);
+}
+
+// CEDAR にリスナーを追加
+void AddListener(CEDAR *c, LISTENER *r)
+{
+	// 引数チェック
+	if (c == NULL || r == NULL)
+	{
+		return;
+	}
+
+	LockList(c->ListenerList);
+	{
+		Add(c->ListenerList, r);
+		AddRef(r->ref);
+	}
+	UnlockList(c->ListenerList);
+}
+
+// CEDAR のすべてのリスナーを停止
+void StopAllListener(CEDAR *c)
+{
+	LISTENER **array;
+	UINT i, num;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	LockList(c->ListenerList);
+	{
+		array = ToArray(c->ListenerList);
+		num = LIST_NUM(c->ListenerList);
+		DeleteAll(c->ListenerList);
+	}
+	UnlockList(c->ListenerList);
+
+	for (i = 0;i < num;i++)
+	{
+		StopListener(array[i]);
+		ReleaseListener(array[i]);
+	}
+	Free(array);
+}
+
+// CEDAR の停止
+void StopCedar(CEDAR *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	// 停止フラグ
+	c->Halt = true;
+
+	// すべてのリスナーを停止
+	StopAllListener(c);
+	// すべてのコネクションを停止
+	StopAllConnection(c);
+	// すべての HUB を停止
+	StopAllHub(c);
+	// すべての L3 スイッチを解放
+	L3FreeAllSw(c);
+}
+
+// CEDAR のクリーンアップ
+void CleanupCedar(CEDAR *c)
+{
+	UINT i;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	FreeCedarLayer3(c);
+
+/*
+	for (i = 0;i < LIST_NUM(c->HubList);i++)
+	{
+		HUB *h = LIST_DATA(c->HubList, i);
+	}
+*/
+	for (i = 0;i < LIST_NUM(c->CaList);i++)
+	{
+		X *x = LIST_DATA(c->CaList, i);
+		FreeX(x);
+	}
+	ReleaseList(c->CaList);
+
+	ReleaseList(c->ListenerList);
+	ReleaseList(c->HubList);
+	ReleaseList(c->ConnectionList);
+	//CleanupUDPEntry(c);
+	ReleaseList(c->UDPEntryList);
+	DeleteLock(c->lock);
+	DeleteCounter(c->ConnectionIncrement);
+	DeleteCounter(c->CurrentSessions);
+
+	if (c->DebugLog != NULL)
+	{
+		FreeLog(c->DebugLog);
+	}
+
+	if (c->ServerX)
+	{
+		FreeX(c->ServerX);
+	}
+	if (c->ServerK)
+	{
+		FreeK(c->ServerK);
+	}
+
+	if (c->CipherList)
+	{
+		Free(c->CipherList);
+	}
+
+	for (i = 0;i < LIST_NUM(c->TrafficDiffList);i++)
+	{
+		TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);
+		Free(d->Name);
+		Free(d->HubName);
+		Free(d);
+	}
+
+	ReleaseList(c->TrafficDiffList);
+
+	Free(c->ServerStr);
+	Free(c->MachineName);
+
+	Free(c->HttpUserAgent);
+	Free(c->HttpAccept);
+	Free(c->HttpAcceptLanguage);
+	Free(c->HttpAcceptEncoding);
+
+	FreeTraffic(c->Traffic);
+
+	DeleteLock(c->TrafficLock);
+
+	FreeNetSvcList(c);
+
+	Free(c->VerString);
+	Free(c->BuildInfo);
+
+	FreeLocalBridgeList(c);
+
+	DeleteCounter(c->AssignedBridgeLicense);
+	DeleteCounter(c->AssignedClientLicense);
+
+	FreeNoSslList(c);
+
+	DeleteLock(c->CedarSuperLock);
+
+	DeleteCounter(c->AcceptingSockets);
+
+	Free(c);
+}
+
+// CEDAR の解放
+void ReleaseCedar(CEDAR *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	if (Release(c->ref) == 0)
+	{
+		CleanupCedar(c);
+	}
+}
+
+// CipherList のセット
+void SetCedarCipherList(CEDAR *cedar, char *name)
+{
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return;
+	}
+
+	if (cedar->CipherList != NULL)
+	{
+		Free(cedar->CipherList);
+	}
+	if (name != NULL)
+	{
+		cedar->CipherList = CopyStr(name);
+	}
+	else
+	{
+		cedar->CipherList = NULL;
+	}
+}
+
+// ネットサービスリストのソート
+int CompareNetSvc(void *p1, void *p2)
+{
+	NETSVC *n1, *n2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	n1 = *(NETSVC **)p1;
+	n2 = *(NETSVC **)p2;
+	if (n1 == NULL || n2 == NULL)
+	{
+		return 0;
+	}
+	if (n1->Port > n2->Port)
+	{
+		return 1;
+	}
+	else if (n1->Port < n2->Port)
+	{
+		return -1;
+	}
+	else if (n1->Udp > n2->Udp)
+	{
+		return 1;
+	}
+	else if (n1->Udp < n2->Udp)
+	{
+		return -1;
+	}
+	return 0;
+}
+
+// ネットサービスリストの初期化
+void InitNetSvcList(CEDAR *cedar)
+{
+	char filename[MAX_PATH] = "/etc/services";
+	BUF *b;
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	// 自力でがんばって読む
+	Format(filename, sizeof(filename), "%s\\drivers\\etc\\services", MsGetSystem32Dir());
+#endif
+
+	cedar->NetSvcList = NewList(CompareNetSvc);
+
+	b = ReadDump(filename);
+	if (b == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		char *s = CfgReadNextLine(b);
+		if (s == NULL)
+		{
+			break;
+		}
+
+		Trim(s);
+		if (s[0] != '#')
+		{
+			TOKEN_LIST *t = ParseToken(s, " \t/");
+			if (t->NumTokens >= 3)
+			{
+				NETSVC *n = ZeroMalloc(sizeof(NETSVC));
+				n->Name = CopyStr(t->Token[0]);
+				n->Udp = (StrCmpi(t->Token[2], "udp") == 0 ? true : false);
+				n->Port = ToInt(t->Token[1]);
+				Add(cedar->NetSvcList, n);
+			}
+			FreeToken(t);
+		}
+		Free(s);
+	}
+
+	FreeBuf(b);
+}
+
+// ネットサービス名の取得
+char *GetSvcName(CEDAR *cedar, bool udp, UINT port)
+{
+	char *ret = NULL;
+	NETSVC t;
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return NULL;
+	}
+
+	t.Udp = (udp == 0 ? false : true);
+	t.Port = port;
+
+	LockList(cedar->NetSvcList);
+	{
+		NETSVC *n = Search(cedar->NetSvcList, &t);
+		if (n != NULL)
+		{
+			ret = n->Name;
+		}
+	}
+	UnlockList(cedar->NetSvcList);
+
+	return ret;
+}
+
+// ネットサービスリストの解放
+void FreeNetSvcList(CEDAR *cedar)
+{
+	UINT i;
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(cedar->NetSvcList);i++)
+	{
+		NETSVC *n = LIST_DATA(cedar->NetSvcList, i);
+		Free(n->Name);
+		Free(n);
+	}
+	ReleaseList(cedar->NetSvcList);
+}
+
+// CEDAR の証明書の変更
+void SetCedarCert(CEDAR *c, X *server_x, K *server_k)
+{
+	// 引数チェック
+	if (server_x == NULL || server_k == NULL)
+	{
+		return;
+	}
+
+	Lock(c->lock);
+	{
+		if (c->ServerX != NULL)
+		{
+			FreeX(c->ServerX);
+		}
+
+		if (c->ServerK != NULL)
+		{
+			FreeK(c->ServerK);
+		}
+
+		c->ServerX = CloneX(server_x);
+		c->ServerK = CloneK(server_k);
+	}
+	Unlock(c->lock);
+}
+
+// デバッグログを有効にする
+void EnableDebugLog(CEDAR *c)
+{
+	// 引数チェック
+	if (c == NULL || c->DebugLog != NULL)
+	{
+		return;
+	}
+
+	c->DebugLog = NewLog("cedar_debug_log", "cedar", LOG_SWITCH_NO);
+}
+
+// CEDAR を VPN Bridge にする
+void SetCedarVpnBridge(CEDAR *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->Bridge = true;
+
+	Free(c->ServerStr);
+	c->ServerStr = CopyStr(CEDAR_BRIDGE_STR);
+}
+
+// CEDAR の作成
+CEDAR *NewCedar(X *server_x, K *server_k)
+{
+	CEDAR *c;
+	char tmp[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	char *beta_str;
+
+	c = ZeroMalloc(sizeof(CEDAR));
+
+	c->AcceptingSockets = NewCounter();
+
+	c->CedarSuperLock = NewLock();
+
+#ifdef	BETA_NUMBER
+	c->Beta = BETA_NUMBER;
+#endif	// BETA_NUMBER
+
+	InitNoSslList(c);
+
+	c->AssignedBridgeLicense = NewCounter();
+	c->AssignedClientLicense = NewCounter();
+
+	Rand(c->UniqueId, sizeof(c->UniqueId));
+
+	c->CreatedTick = Tick64();
+
+	c->lock = NewLock();
+	c->ref = NewRef();
+
+	c->CurrentTcpConnections = GetNumTcpConnectionsCounter();
+
+	c->ListenerList = NewList(CompareListener);
+	c->UDPEntryList = NewList(CompareUDPEntry);
+	c->HubList = NewList(CompareHub);
+	c->ConnectionList = NewList(CompareConnection);
+
+	c->ConnectionIncrement = NewCounter();
+	c->CurrentSessions = NewCounter();
+
+	if (server_k && server_x)
+	{
+		c->ServerK = CloneK(server_k);
+		c->ServerX = CloneX(server_x);
+	}
+
+	c->Version = CEDAR_VER;
+	c->Build = CEDAR_BUILD;
+	c->ServerStr = CopyStr(CEDAR_SERVER_STR);
+
+	GetMachineName(tmp, sizeof(tmp));
+	c->MachineName = CopyStr(tmp);
+
+	c->HttpUserAgent = CopyStr(DEFAULT_USER_AGENT);
+	c->HttpAccept = CopyStr(DEFAULT_ACCEPT);
+	c->HttpAcceptLanguage = CopyStr("ja");
+	c->HttpAcceptEncoding = CopyStr(DEFAULT_ENCODING);
+
+	c->Traffic = NewTraffic();
+	c->TrafficLock = NewLock();
+	c->CaList = NewList(CompareCert);
+
+	c->TrafficDiffList = NewList(NULL);
+
+	SetCedarCipherList(c, "RC4-MD5");
+
+	c->ClientId = _II("CLIENT_ID");
+
+	InitNetSvcList(c);
+
+	InitLocalBridgeList(c);
+
+	InitCedarLayer3(c);
+
+#ifdef	ALPHA_VERSION
+	beta_str = "Alpha";
+#else	// ALPHA_VERSION
+	beta_str = "Release Candidate";
+#endif	// ALPHA_VERSION
+
+	ToStr(tmp2, c->Beta);
+
+	Format(tmp, sizeof(tmp), "Version %u.%02u Build %u %s %s (%s)",
+		CEDAR_VER / 100, CEDAR_VER - (CEDAR_VER / 100) * 100,
+		CEDAR_BUILD,
+		c->Beta == 0 ? "" : beta_str,
+		c->Beta == 0 ? "" : tmp2,
+		_SS("LANGSTR"));
+	Trim(tmp);
+
+	if (true)
+	{
+		SYSTEMTIME st;
+		Zero(&st, sizeof(st));
+
+		st.wYear = BUILD_DATE_Y;
+		st.wMonth = BUILD_DATE_M;
+		st.wDay = BUILD_DATE_D;
+
+		c->BuiltDate = SystemToUINT64(&st);
+	}
+
+	c->VerString = CopyStr(tmp);
+
+	Format(tmp, sizeof(tmp), "Compiled %04u/%02u/%02u %02u:%02u:%02u by %s at %s",
+		BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D, BUILD_DATE_HO, BUILD_DATE_MI, BUILD_DATE_SE, BUILDER_NAME, BUILD_PLACE);
+
+	c->BuildInfo = CopyStr(tmp);
+
+	return c;
+}
+
+// 指定した日付よりも遅い日付にビルドされたものであるかどうか取得
+bool IsLaterBuild(CEDAR *c, UINT64 t)
+{
+	SYSTEMTIME sb, st;
+	UINT64 b;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	Zero(&sb, sizeof(sb));
+	Zero(&st, sizeof(st));
+
+	UINT64ToSystem(&sb, c->BuiltDate);
+	UINT64ToSystem(&st, t);
+
+	// 時刻データを無視
+	sb.wHour = sb.wMinute = sb.wSecond = sb.wMilliseconds = 0;
+	st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
+
+	b = SystemToUINT64(&sb);
+	t = SystemToUINT64(&st);
+
+	if (b > t)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// トラフィック情報の加算
+void AddTraffic(TRAFFIC *dst, TRAFFIC *diff)
+{
+	// 引数チェック
+	if (dst == NULL || diff == NULL)
+	{
+		return;
+	}
+
+	dst->Recv.BroadcastBytes += diff->Recv.BroadcastBytes;
+	dst->Recv.BroadcastCount += diff->Recv.BroadcastCount;
+	dst->Recv.UnicastBytes += diff->Recv.UnicastBytes;
+	dst->Recv.UnicastCount += diff->Recv.UnicastCount;
+
+	dst->Send.BroadcastBytes += diff->Send.BroadcastBytes;
+	dst->Send.BroadcastCount += diff->Send.BroadcastCount;
+	dst->Send.UnicastBytes += diff->Send.UnicastBytes;
+	dst->Send.UnicastCount += diff->Send.UnicastCount;
+}
+
+// トラフィック情報の作成
+TRAFFIC *NewTraffic()
+{
+	TRAFFIC *t;
+
+	// メモリ確保
+	t = ZeroMalloc(sizeof(TRAFFIC));
+	return t;
+}
+
+// トラフィック情報の解放
+void FreeTraffic(TRAFFIC *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// メモリ解放
+	Free(t);
+}
+
+// Cedar 通信モジュールの初期化
+void InitCedar()
+{
+	if ((init_cedar_counter++) > 0)
+	{
+		return;
+	}
+
+	// プロトコル初期化
+	InitProtocol();
+}
+
+// Cedar 通信モジュールの解放
+void FreeCedar()
+{
+	if ((--init_cedar_counter) > 0)
+	{
+		return;
+	}
+
+	// プロトコル解放
+	FreeProtocol();
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Cedar.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Cedar.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Cedar.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1139 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Cedar.h
+// Cedar.c のヘッダ
+
+#ifndef	CEDAR_H
+#define	CEDAR_H
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// 製品情報関連定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	bool	UINT
+#define	BOOL	UINT
+
+// バージョン番号
+#define	CEDAR_VER					101
+
+// ビルド番号
+#define	CEDAR_BUILD					7101
+
+// ベータ番号
+//#define	BETA_NUMBER					2
+
+// ビルド担当者の名前を指定
+#ifndef	BUILDER_NAME
+#define	BUILDER_NAME		"yagi"
+#endif	// BUILDER_NAME
+
+// ビルドした場所を指定
+#ifndef	BUILD_PLACE
+#define	BUILD_PLACE			"pc25"
+#endif	// BUILD_PLACE
+
+// ビルド日時を指定
+#define	BUILD_DATE_Y		2010
+#define	BUILD_DATE_M		6
+#define	BUILD_DATE_D		27
+#define	BUILD_DATE_HO		18
+#define	BUILD_DATE_MI		40
+#define	BUILD_DATE_SE		28
+
+// 許容する時差
+#define	ALLOW_TIMESTAMP_DIFF		(UINT64)(3 * 24 * 60 * 60 * 1000)
+
+// SoftEther UT-VPN シリーズ製品名
+#define	CEDAR_PRODUCT_STR			"UT-VPN"
+
+// Server 製品名
+#define	CEDAR_SERVER_STR			"UT-VPN Server"
+
+// Bridge 製品名
+#define	CEDAR_BRIDGE_STR			"UT-VPN Bridge"
+
+// Server 製品名 (ベータ)
+#define	CEDAR_BETA_SERVER			"UT-VPN Server Pre Release"
+
+// VPN Server Manager 製品名
+#define	CEDAR_MANAGER_STR			"UT-VPN Server Manager"
+
+// VPN Command-Line Admin Tool 製品名
+#define	CEDAR_CUI_STR				"UT-VPN Command-Line Admin Tool"
+
+// VPN User-mode Router 製品名
+#define	CEDAR_ROUTER_STR			"UT-VPN User-mode Router"
+
+// VPN Client 製品名
+#define	CEDAR_CLIENT_STR			"UT-VPN Client"
+
+// VPN Client Manager 製品名
+#define CEDAR_CLIENT_MANAGER_STR	"UT-VPN Client Connection Manager"
+
+// VPN Server のカスケード接続時の製品名
+#define	CEDAR_SERVER_LINK_STR		"UT-VPN Server (Cascade Mode)"
+
+// VPN Server のサーバーファーム RPC 接続時の製品名
+#define	CEDAR_SERVER_FARM_STR		"UT-VPN Server (Cluster RPC Mode)"
+
+
+// IDS 検出用シグネチャの指定
+#define	CEDAR_SIGNATURE_STR			"SE-UTVPN-PROTOCOL"
+
+// スマートカードのデフォルトの RSA 証明書名
+#define	SECURE_DEFAULT_CERT_NAME	"VPN_RSA_CERT"
+
+// スマートカードのデフォルトの RSA 秘密鍵名
+#define	SECURE_DEFAULT_KEY_NAME		"VPN_RSA_KEY"
+
+// 8 文字の非表示パスワード文字列
+#define	HIDDEN_PASSWORD				"********"
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// 各種文字列の最大長の定義
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	MAX_ACCOUNT_NAME_LEN		255		// 最大アカウント名長
+#define	MAX_USERNAME_LEN			255		// ユーザー名最大長
+#define	MAX_PASSWORD_LEN			255		// パスワード名最大長
+#define	MAX_HOST_NAME_LEN			255		// ホスト名最大長
+#define	MAX_PROXY_USERNAME_LEN		255		// プロキシユーザー名最大長
+#define	MAX_PROXY_PASSWORD_LEN		255		// プロキシパスワード最大長
+#define	MAX_SERVER_STR_LEN			255		// サーバー文字列最大長
+#define	MAX_CLIENT_STR_LEN			255		// クライアント文字列最大長
+#define	MAX_HUBNAME_LEN				255		// HUB 名最大長
+#define	MAX_SESSION_NAME_LEN		255		// セッション名最大長
+#define	MAX_CONNECTION_NAME_LEN		255		// コネクション名最大長
+#define	MAX_DEVICE_NAME_LEN			31		// デバイス名最大長
+#define	MAX_DEVICE_NAME_LEN_9X		4		// Win9x での仮想 LAN カード名最大長
+#define	MAX_ACCESSLIST_NOTE_LEN		255		// アクセスリストのメモ最大長
+#define	MAX_SECURE_DEVICE_FILE_LEN	255		// セキュアデバイス内ファイル名最大長
+#define	MAX_ADMIN_OPTION_NAME_LEN	63		// 管理オプション名
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// サーバーおよびセッション管理関連定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	SERVER_MAX_SESSIONS			4096	// サーバーがサポートする最大セッション数
+#define SERVER_MAX_SESSIONS_FOR_64BIT	100000	// サーバーがサポートする最大セッション数 (64 bit)
+#define	NAT_MAX_SESSIONS			4096	// NAT がサポートする最大セッション数
+#define	MAX_HUBS					4096	// 仮想 HUB の最大数 (32 bit)
+#define MAX_HUBS_FOR_64BIT			100000	// 仮想 HUB の最大数 (64 bit)
+#define	MAX_ACCESSLISTS				4096	// アクセスリストの最大数
+#define	MAX_USERS					10000	// 最大ユーザー数
+#define	MAX_GROUPS					10000	// 最大グループ数
+#define	MAX_MAC_TABLES				65536	// 最大 MAC アドレステーブル数
+#define	MAX_IP_TABLES				65536	// 最大 IP アドレステーブル数
+#define	MAX_HUB_CERTS				4096	// 登録できるルート CA 最大数
+#define	MAX_HUB_CRLS				4096	// 登録できる CRL 最大数
+#define	MAX_HUB_ACS					4096	// 登録できる AC 最大数
+#define	MAX_HUB_LINKS				128		// 登録できるカスケード接続最大数
+#define	MAX_HUB_ADMIN_OPTIONS		4096	// 登録できる仮想 HUB 管理オプション最大数
+
+#define	MAX_PACKET_SIZE				1560	// 最大パケットサイズ
+#define	UDP_BUF_SIZE				(32 * 1024) // UDP パケットサイズの目安
+
+#define	MAX_SEND_SOCKET_QUEUE_SIZE	(1600 * 1600 * 1)	// 最大送信キューサイズ
+#define	MIN_SEND_SOCKET_QUEUE_SIZE	(1600 * 200 * 1)
+#define	MAX_SEND_SOCKET_QUEUE_NUM	128		// 最大送信キュー数
+#define	MAX_TCP_CONNECTION			32		// 最大 TCP コネクション数
+#define	SELECT_TIME					256
+#define	SELECT_TIME_FOR_NAT			30
+#define	SELECT_TIME_FOR_DELAYED_PKT	1		// 遅延パケットがある場合
+#define	MAX_STORED_QUEUE_NUM		1024		// セッションごとにストアできるキューの数
+#define	MAX_BUFFERING_PACKET_SIZE	(1600 * 1600)	// バッファリング可能なパケットサイズの最大値
+
+#define	TIMEOUT_MIN					(5 * 1000)	// 最小タイムアウト秒数
+#define	TIMEOUT_MAX					(60 * 1000)	// 最大タイムアウト秒数
+#define	TIMEOUT_DEFAULT				(30 * 1000) // デフォルトのタイムアウト秒数
+#define	CONNECTING_TIMEOUT			(15 * 1000)	// 接続中のタイムアウト秒数
+#define	CONNECTING_TIMEOUT_PROXY	(4 * 1000)	// 接続中のタイムアウト秒数 (Proxy)
+#define	CONNECTING_POOLING_SPAN		(3 * 1000) // 接続中のポーリング間隔
+#define	MIN_RETRY_INTERVAL			(5 * 1000)		// 最小リトライ間隔
+#define	MAX_RETRY_INTERVAL			(300 * 1000)	// 最大リトライ間隔
+#define	RETRY_INTERVAL_SPECIAL		(60 * 1000)		// 特別な場合の再接続間隔
+
+#define	MAC_MIN_LIMIT_COUNT			3		// 最小 MAC アドレス数制限値
+#define	IP_MIN_LIMIT_COUNT			4		// 最小 IPv4 アドレス数制限値
+#define	IP_MIN_LIMIT_COUNT_V6		5		// 最小 IPv6 アドレス数制限値
+#define	IP_LIMIT_WHEN_NO_ROUTING_V6	15		// NoRouting ポリシーが有効な場合の IPv6 アドレス数制限値
+
+#define	MAC_TABLE_EXCLUSIVE_TIME	(13 * 1000)			// MAC アドレスを占有することができる期間
+#define	IP_TABLE_EXCLUSIVE_TIME		(13 * 1000)			// IP アドレスを占有することができる期間
+#define	MAC_TABLE_EXPIRE_TIME		(600 * 1000)			// MAC アドレステーブル有効期限
+#define	IP_TABLE_EXPIRE_TIME		(60 * 1000)			// IP アドレステーブル有効期限
+#define	IP_TABLE_EXPIRE_TIME_DHCP	(5 * 60 * 1000)		// IP アドレステーブル有効期限 (DHCP の場合)
+#define	HUB_ARP_SEND_INTERVAL		(5 * 1000)			// ARP パケット送信間隔 (生存チェック)
+
+#define	LIMITER_SAMPLING_SPAN		1000	// トラフィック制限装置のサンプリング間隔
+
+#define	STORM_CHECK_SPAN			500		// ブロードキャストストームチェック間隔
+#define	STORM_DISCARD_VALUE_START	3		// ブロードキャストパケット破棄値開始値
+#define	STORM_DISCARD_VALUE_END		1024	// ブロードキャストパケット破棄値終了値
+
+#define	KEEP_INTERVAL_MIN			5		// パケット送出間隔最小値
+#define	KEEP_INTERVAL_DEFAULT		50		// パケット送出間隔デフォルト値
+#define	KEEP_INTERVAL_MAX			600		// パケット送出間隔最大値
+#define KEEP_TCP_TIMEOUT			1000	// TCP タイムアウト値
+
+#define	TICKET_EXPIRES				(60 * 1000)	// チケットの有効期限
+
+
+#define	FARM_BASE_POINT				100000		// クラスタ得点の基準値
+#define	FARM_DEFAULT_WEIGHT			100			// 標準の性能基準比
+
+
+// HTTPS サーバー / クライアント関連文字列定数
+#define	DEFAULT_USER_AGENT	"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)"
+#define	DEFAULT_ACCEPT		"image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/msword, application/vnd.ms-powerpoint, application/vnd.ms-excel, */*"
+#define	DEFAULT_ENCODING	"gzip, deflate"
+#define	HTTP_CONTENT_TYPE	"text/html; charset=iso-8859-1"
+#define	HTTP_CONTENT_TYPE2	"application/octet-stream"
+#define	HTTP_CONTENT_TYPE3	"image/jpeg"
+#define	HTTP_CONTENT_TYPE4	"text/html"
+#define	HTTP_CONTENT_TYPE5	"message/rfc822"
+#define	HTTP_KEEP_ALIVE		"timeout=15; max=19"
+#define	HTTP_VPN_TARGET		"/vpnsvc/vpn.cgi"
+#define	HTTP_VPN_TARGET2	"/vpnsvc/connect.cgi"
+#define HTTP_VPN_TARGET_POSTDATA	"VPNCONNECT"
+#define	HTTP_SAITAMA		"/saitama.jpg"
+#define	HTTP_PICTURES		"/picture"
+
+#define	SE_UDP_SIGN			"SE2P"		// 未使用 (旧 UDP モードのみ)
+
+// トラフィック情報更新間隔
+#define	INCREMENT_TRAFFIC_INTERVAL		(10 * 1000)
+
+// クライアント セッションの状態
+#define	CLIENT_STATUS_CONNECTING	0		// 接続中
+#define	CLIENT_STATUS_NEGOTIATION	1		// ネゴシエーション中
+#define	CLIENT_STATUS_AUTH			2		// ユーザー認証中
+#define	CLIENT_STATUS_ESTABLISHED	3		// 接続完了
+#define	CLIENT_STATUS_RETRY			4		// リトライまで待機中
+#define	CLIENT_STATUS_IDLE			5		// アイドル状態
+
+// ファイル転送時に一度に転送するブロック
+#define	FTP_BLOCK_SIZE				(640 * 1024)
+
+// syslog 設定
+#define SYSLOG_NONE							0		// syslog を使わない
+#define SYSLOG_SERVER_LOG					1		// サーバーログのみ
+#define SYSLOG_SERVER_AND_HUB_SECURITY_LOG	2		// サーバーと仮想 HUB セキュリティログ
+#define SYSLOG_SERVER_AND_HUB_ALL_LOG		3		// サーバー、仮想 HUB セキュリティおよびパケットログ
+
+#define SYSLOG_PORT					514			// syslog ポート番号
+#define SYSLOG_POLL_IP_INTERVAL		(UINT64)(3600 * 1000)	// IP アドレスを調べる間隔
+#define	SYSLOG_POLL_IP_INTERVAL_NG	(UINT64)(60 * 1000)	// IP アドレスを調べる間隔 (前回失敗時)
+
+//////////////////////////////////////////////////////////////////////
+// 
+// コネクション関連の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+// インターネット接続維持機能 (KeepAlive)
+
+#define	KEEP_RETRY_INTERVAL		(60 * 1000)			// 接続失敗時の再接続間隔
+#define	KEEP_MIN_PACKET_SIZE	1					// 最小パケットサイズ
+#define	KEEP_MAX_PACKET_SIZE	128					// 最大パケットサイズ
+#define	KEEP_POLLING_INTERVAL	250					// KEEP ポーリング間隔
+
+// 定数
+#define	RECV_BUF_SIZE				65536			// 一度に受信するバッファサイズ
+
+// プロキシの種類
+#define	PROXY_DIRECT			0	// 直接 TCP 接続
+#define	PROXY_HTTP				1	// HTTP プロキシサーバー経由接続
+#define	PROXY_SOCKS				2	// SOCKS プロキシサーバー経由接続
+
+// データの流れる方向
+#define	TCP_BOTH				0	// 双方向
+#define	TCP_SERVER_TO_CLIENT	1	// サーバー -> クライアント方向のみ
+#define	TCP_CLIENT_TO_SERVER	2	// クライアント -> サーバー方向のみ
+
+// コネクションの種類
+#define	CONNECTION_TYPE_CLIENT			0	// クライアント
+#define	CONNECTION_TYPE_INIT			1	// 初期化中
+#define	CONNECTION_TYPE_LOGIN			2	// ログインコネクション
+#define	CONNECTION_TYPE_ADDITIONAL		3	// 追加接続コネクション
+#define	CONNECTION_TYPE_FARM_RPC		4	// サーバーファーム用 RPC
+#define	CONNECTION_TYPE_ADMIN_RPC		5	// 管理用 RPC
+#define	CONNECTION_TYPE_ENUM_HUB		6	// HUB 列挙
+#define	CONNECTION_TYPE_PASSWORD		7	// パスワード変更
+
+// プロトコル
+#define	CONNECTION_TCP					0	// TCP プロトコル
+#define	CONNECTION_UDP					1	// UDP プロトコル
+#define	CONNECTION_HUB_LAYER3			6	// Layer-3 スイッチ セッション
+#define	CONNECTION_HUB_BRIDGE			7	// Bridge セッション
+#define	CONNECTION_HUB_SECURE_NAT		8	// Secure NAT セッション
+#define	CONNECTION_HUB_LINK_SERVER		9	// HUB リンクセッション
+
+
+// 状態
+#define	CONNECTION_STATUS_ACCEPTED		0	// 接続を受け付けた (クライアント側)
+#define	CONNECTION_STATUS_NEGOTIATION	1	// ネゴシエーション中
+#define	CONNECTION_STATUS_USERAUTH		2	// ユーザー認証中
+#define	CONNECTION_STATUS_ESTABLISHED	3	// コネクション確立済み
+#define	CONNECTION_STATUS_CONNECTING	0	// 接続中 (クライアント側)
+
+// KeepAlive パケットのマジックナンバー
+#define	KEEP_ALIVE_MAGIC				0xffffffff
+#define	MAX_KEEPALIVE_SIZE				512
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// 仮想 HUB 関連の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	SE_HUB_MAC_ADDR_SIGN				0xAE					// 仮想 HUB MAC アドレスのサイン
+
+// トラフィック差分値
+#define	TRAFFIC_DIFF_USER		0		// ユーザー
+#define	TRAFFIC_DIFF_HUB		1		// 仮想 HUB
+#define	MAX_TRAFFIC_DIFF		30000	// 最大件数
+
+// HUB の種類
+#define	HUB_TYPE_STANDALONE			0	// スタンドアロン HUB
+#define	HUB_TYPE_FARM_STATIC		1	// スタティック HUB
+#define	HUB_TYPE_FARM_DYNAMIC		2	// ダイナミック HUB
+
+// アクセスリストにおける遅延、ジッタ、パケットロス関係
+#define	HUB_ACCESSLIST_DELAY_MAX	10000		// 最大遅延
+#define	HUB_ACCESSLIST_JITTER_MAX	100			// 最大ジッタ
+#define	HUB_ACCESSLIST_LOSS_MAX		100			// 最大パケットロス
+
+// メッセージ関係
+#define	HUB_MAXMSG_LEN				20000		// 最大メッセージ文字数
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// ユーザー認証の種類
+// 
+//////////////////////////////////////////////////////////////////////
+
+// サーバー側における定数
+#define	AUTHTYPE_ANONYMOUS				0			// 匿名認証
+#define	AUTHTYPE_PASSWORD				1			// パスワード認証
+#define	AUTHTYPE_USERCERT				2			// ユーザー証明書認証
+#define	AUTHTYPE_ROOTCERT				3			// 信頼するルート証明期間が発行する証明書
+#define	AUTHTYPE_RADIUS					4			// Radius 認証
+#define	AUTHTYPE_NT						5			// Windows NT 認証
+#define	AUTHTYPE_TICKET					99			// チケット認証
+
+// クライアント側における定数
+#define	CLIENT_AUTHTYPE_ANONYMOUS		0			// 匿名認証
+#define	CLIENT_AUTHTYPE_PASSWORD		1			// パスワード認証
+#define	CLIENT_AUTHTYPE_PLAIN_PASSWORD	2			// プレーンパスワード認証
+#define	CLIENT_AUTHTYPE_CERT			3			// 証明書認証
+#define	CLIENT_AUTHTYPE_SECURE			4			// セキュアデバイス認証
+
+// Radius 関係
+#define	RADIUS_DEFAULT_PORT		1812			// デフォルトのポート番号
+#define	RADIUS_RETRY_INTERVAL	500				// 再送間隔
+#define	RADIUS_RETRY_TIMEOUT	(10 * 1000)		// タイムアウト時間
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// TCP リスナー関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+// Listen に失敗した場合の再試行回数
+#define	LISTEN_RETRY_TIME			(2 * 1000)		// 普通に Listen に失敗した場合
+#define LISTEN_RETRY_TIME_NOIPV6	(60 * 1000)		// IPv6 サポートが無効な場合
+
+
+// リスナーの使用するプロトコル
+#define	LISTENER_TCP				0		// TCP/IP
+#define	LISTENER_UDP				1		// UDP/IP
+
+// リスナーの状態
+#define	LISTENER_STATUS_TRYING		0		// 試行中
+#define	LISTENER_STATUS_LISTENING	1		// Listen 中
+
+// 最大の UDP パケットサイズ
+#define	UDP_PACKET_SIZE				65536
+
+// 標準の IP アドレスごとのコネクション数
+#define DEFAULT_MAX_CONNECTIONS_PER_IP	256
+#define MIN_MAX_CONNECTIONS_PER_IP	10		// 最小値
+
+// 許容される未処理のコネクション数
+#define	DEFAULT_MAX_UNESTABLISHED_CONNECTIONS	1000
+#define	MIN_MAX_UNESTABLISHED_CONNECTIONS	30	// 最小値
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// ログ関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	LOG_ENGINE_SAVE_START_CACHE_COUNT	100000		// 強制的に保存を開始する数
+#define	LOG_ENGINE_BUFFER_CACHE_SIZE_MAX	(10 * 1024 * 1024)	// 書き込みキャッシュサイズ
+
+// ファイル名などの定数
+#define	SERVER_LOG_DIR_NAME			"@server_log"
+#define	BRIDGE_LOG_DIR_NAME			SERVER_LOG_DIR_NAME
+#define	SERVER_LOG_PERFIX			"vpn"
+
+#define	HUB_SECURITY_LOG_DIR_NAME	"@security_log"
+#define	HUB_SECURITY_LOG_FILE_NAME	"@security_log/%s"
+#define	HUB_SECURITY_LOG_PREFIX		"sec"
+#define	HUB_PACKET_LOG_DIR_NAME		"@packet_log"
+#define	HUB_PACKET_LOG_FILE_NAME	"@packet_log/%s"
+#define	HUB_PACKET_LOG_PREFIX		"pkt"
+
+#define	NAT_LOG_DIR_NAME			"@secure_nat_log"
+#define	NAT_LOG_FILE_NAME			"@secure_nat_log/%s"
+#define	NAT_LOG_PREFIX				"snat"
+
+#define	CLIENT_LOG_DIR_NAME			"@client_log"
+#define	CLIENT_LOG_PREFIX			"client"
+
+// パケットログ設定
+#define	NUM_PACKET_LOG				16
+#define	PACKET_LOG_TCP_CONN			0		// TCP コネクションログ
+#define	PACKET_LOG_TCP				1		// TCP パケットログ
+#define	PACKET_LOG_DHCP				2		// DHCP ログ
+#define	PACKET_LOG_UDP				3		// UDP ログ
+#define	PACKET_LOG_ICMP				4		// ICMP ログ
+#define	PACKET_LOG_IP				5		// IP ログ
+#define	PACKET_LOG_ARP				6		// ARP ログ
+#define	PACKET_LOG_ETHERNET			7		// Ethernet ログ
+
+#define	PACKET_LOG_NONE				0		// 保存しない
+#define	PACKET_LOG_HEADER			1		// ヘッダのみ
+#define	PACKET_LOG_ALL				2		// データも保存する
+
+// ログ切り替えのタイミング
+#define	LOG_SWITCH_NO				0		// 切り替え無し
+#define	LOG_SWITCH_SECOND			1		// 1 秒単位
+#define	LOG_SWITCH_MINUTE			2		// 1 分単位
+#define	LOG_SWITCH_HOUR				3		// 1 時間単位
+#define	LOG_SWITCH_DAY				4		// 1 日単位
+#define	LOG_SWITCH_MONTH			5		// 1 ヶ月単位
+
+// ディスクの空き容量の最小サイズ
+#define	DISK_FREE_SPACE_MIN			1048576	// 1 MBytes
+#define	DISK_FREE_SPACE_DEFAULT		(DISK_FREE_SPACE_MIN * 100)	// 100 Mbytes
+
+// 空き容量をチェックする間隔
+#define	DISK_FREE_CHECK_INTERVAL	(5 * 60 * 1000)
+
+// 簡易ログ
+#define TINY_LOG_DIRNAME			"@tiny_log"
+#define TINY_LOG_FILENAME			"@tiny_log/%04u%02u%02u_%02u%02u%02u.log"
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// Carrier Edition 関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define CE_SNAPSHOT_INTERVAL		((UINT64)(3600 * 1000))
+//#define CE_SNAPSHOT_INTERVAL		((UINT64)(3000))
+#define CE_SNAPSHOT_POLLING_INTERVAL	(1 * 1000)
+#define CE_SNAPSHOT_POLLING_INTERVAL_LICENSE	(30 * 1000)
+#define CE_SNAPSHOT_DIR_NAME		"@carrier_log"
+#define CE_SNAPSHOT_PREFIX			"carrier"
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// 通信プロトコル関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+// 管理者ユーザー名
+#define	ADMINISTRATOR_USERNAME		"administrator"
+// HTTP ヘッダの 1 行のサイズの最大値
+#define	HTTP_HEADER_LINE_MAX_SIZE	4096
+// PACK に含める乱数サイズの最大値
+#define	HTTP_PACK_RAND_SIZE_MAX		1000
+// ランダムサイズの最大値
+#define	RAND_SIZE_MAX				4096
+// ランダムサイズキャッシュの有効期限
+#define	RAND_SIZE_CACHE_EXPIRE		(24 * 60 * 60 * 1000)
+// 管理許可 IP アドレスリストファイル名
+#define	ADMINIP_TXT					"@adminip.txt"
+
+#define NON_SSL_MIN_COUNT			60
+#define NON_SSL_ENTRY_EXPIRES		(60 * 60 * 1000)
+
+//////////////////////////////////////////////////////////////////////
+// 
+// カスケード接続関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	LINK_DEVICE_NAME		"_SEHUBLINKCLI_"
+#define	LINK_USER_NAME			"link"
+#define	LINK_USER_NAME_PRINT	"Cascade"
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// SecureNAT 接続関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	SNAT_DEVICE_NAME		"_SEHUBSECURENAT_"
+#define	SNAT_USER_NAME			"securenat"
+#define	SNAT_USER_NAME_PRINT	"SecureNAT"
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// Bridge 接続関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	BRIDGE_DEVICE_NAME				"_SEHUBBRIDGE_"
+#define	BRIDGE_USER_NAME				"localbridge"
+#define	BRIDGE_USER_NAME_PRINT			"Local Bridge"
+#define	BRIDGE_TRY_SPAN					1000
+#define	BRIDGE_NUM_DEVICE_CHECK_SPAN	(5 * 60 * 1000)
+#define BRIDGE_NETWORK_CONNECTION_STR	L"%s [%S]"
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// EtherLogger 関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	EL_ADMIN_PORT			22888
+#define	EL_CONFIG_FILENAME		"@etherlogger.config"
+#define	EL_PACKET_LOG_DIR_NAME	"@etherlogger_log"
+#define	EL_PACKET_LOG_FILE_NAME	"@etherlogger_log/%s"
+#define	EL_PACKET_LOG_PREFIX	"pkt"
+#define	EL_LICENSE_CHECK_SPAN	(10 * 1000)
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// Layer-3 Switch 関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	MAX_NUM_L3_SWITCH		4096
+#define	MAX_NUM_L3_IF			4096
+#define	MAX_NUM_L3_TABLE		4096
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// User-mode Router 関係の定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	ARP_ENTRY_EXPIRES			(30 * 1000)		// ARP テーブル有効期限
+#define	ARP_ENTRY_POLLING_TIME		(1 * 1000)		// ARP テーブル清掃タイマ
+#define	ARP_REQUEST_TIMEOUT			(200)			// ARP リクエストタイムアウト時間
+#define	ARP_REQUEST_GIVEUP			(5 * 1000)		// ARP リクエストの送信を諦める時刻
+#define	IP_WAIT_FOR_ARP_TIMEOUT		(5 * 1000)		// IP パケットが ARP テーブルを待つ合計時間
+#define	IP_COMBINE_TIMEOUT			(10 * 1000)		// IP パケットの結合タイムアウト
+#define	NAT_TCP_MAX_TIMEOUT			(2000000 * 1000)	// 最大 TCP セッションタイムアウト秒数
+#define	NAT_UDP_MAX_TIMEOUT			(2000000 * 1000)	// 最大 UDP セッションタイムアウト秒数
+#define	NAT_TCP_MIN_TIMEOUT			(5 * 60 * 1000)		// 最小 TCP セッションタイムアウト秒数
+#define	NAT_UDP_MIN_TIMEOUT			(10 * 1000)			// 最小 UDP セッションタイムアウト秒数
+#define	NAT_TCP_RECV_WINDOW_SIZE	64512				// TCP 受信ウインドウサイズ
+#define	NAT_TCP_SYNACK_SEND_TIMEOUT	250					// TCP SYN+ACK 送信間隔
+#define	NAT_SEND_BUF_SIZE			(64 * 1024)			// TCP 送信バッファサイズ
+#define	NAT_RECV_BUF_SIZE			(64 * 1024)			// TCP 受信バッファサイズ
+#define	NAT_TMPBUF_SIZE				(128 * 1024)		// TCP 一時メモリ領域サイズ
+#define	NAT_ACK_KEEPALIVE_SPAN		(5 * 1000)			// TCP キープアライブ用 ACK 送信間隔
+#define	NAT_INITIAL_RTT_VALUE		500					// 初期 RTT 値
+#define	NAT_FIN_SEND_INTERVAL		1000				// FIN 送信間隔
+#define	NAT_FIN_SEND_MAX_COUNT		5					// 合計 FIN 送信数
+#define	NAT_DNS_PROXY_PORT			53					// DNS プロキシポート番号
+#define	NAT_DNS_RESPONSE_TTL		(20 * 60)			// DNS 応答の TTL
+#define	NAT_DHCP_SERVER_PORT		67					// DHCP サーバーポート番号
+#define	DHCP_MIN_EXPIRE_TIMESPAN	(15 * 1000)			// DHCP 最小有効期限
+#define	DHCP_POLLING_INTERVAL		1000				// DHCP ポーリング間隔
+#define	X32							((UINT64)4294967296ULL)	// 32bit + 1
+#define	NAT_DNS_QUERY_TIMEOUT		(512)				// DNS クエリのタイムアウト値
+
+// ビーコン送信間隔
+#define	BEACON_SEND_INTERVAL		(5 * 1000)
+
+// IP パケットの結合用のキューで許容される合計サイズ クォータ
+#define	IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA	(50 * 1024 * 1024)
+
+// ヘッダサイズ定数
+#define	MAC_HEADER_SIZE				(sizeof(MAC_HEADER))
+#define	ARP_HEADER_SIZE				(sizeof(ARPV4_HEADER))
+#define	IP_HEADER_SIZE				(sizeof(IPV4_HEADER))
+#define	TCP_HEADER_SIZE				(sizeof(TCP_HEADER))
+#define	UDP_HEADER_SIZE				(sizeof(UDP_HEADER))
+
+// データ最大サイズ定数
+#define	MAX_L3_DATA_SIZE			(1500)
+#define	MAX_IP_DATA_SIZE			(MAX_L3_DATA_SIZE - IP_HEADER_SIZE)
+#define	MAX_TCP_DATA_SIZE			(MAX_IP_DATA_SIZE - TCP_HEADER_SIZE)
+#define	MAX_UDP_DATA_SIZE			(MAX_IP_DATA_SIZE - UDP_HEADER_SIZE)
+#define	MAX_IP_DATA_SIZE_TOTAL		(65535)
+
+// IP パケットオプション定数
+#define	DEFAULT_IP_TOS				0				// IP ヘッダの TOS
+#define	DEFAULT_IP_TTL				128				// IP ヘッダの TTL
+
+// NAT セッションの種類
+#define	NAT_TCP						0		// TCP NAT
+#define	NAT_UDP						1		// UDP NAT
+#define	NAT_DNS						2		// DNS NAT
+
+// NAT セッションの状態
+#define	NAT_TCP_CONNECTING			0		// 接続中
+#define	NAT_TCP_SEND_RESET			1		// RST を送信する (接続失敗または切断)
+#define	NAT_TCP_CONNECTED			2		// 接続完了
+#define	NAT_TCP_ESTABLISHED			3		// 接続確立済み
+#define	NAT_TCP_WAIT_DISCONNECT		4		// ソケット切断を待機
+
+// DHCP クライアント動作
+#define	DHCP_DISCOVER		1
+#define	DHCP_REQUEST		3
+
+// DHCP サーバー動作
+#define	DHCP_OFFER			2
+#define	DHCP_ACK			5
+#define	DHCP_NACK			6
+
+// DHCP 関係の定数
+#define	DHCP_ID_MESSAGE_TYPE		0x35
+#define	DHCP_ID_REQUEST_IP_ADDRESS	0x32
+#define	DHCP_ID_HOST_NAME			0x0c
+#define	DHCP_ID_SERVER_ADDRESS		0x36
+#define	DHCP_ID_LEASE_TIME			0x33
+#define	DHCP_ID_DOMAIN_NAME			0x0f
+#define	DHCP_ID_SUBNET_MASK			0x01
+#define	DHCP_ID_GATEWAY_ADDR		0x03
+#define	DHCP_ID_DNS_ADDR			0x06
+
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// UNIX 用仮想 LAN カード関係定数
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	TAP_FILENAME_1				"/dev/net/tun"
+#define	TAP_FILENAME_2				"/dev/tun"
+#define	TAP_MACOS_FILENAME			"/dev/tap0"
+
+
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// ライセンスデータベース関係
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	LICENSE_MAX_PRODUCT_NAME_LEN	255				// ライセンス製品名の最大長
+#define	LICENSE_KEYSTR_LEN				41				// ライセンスキーの長さ
+#define	LICENSE_LICENSEID_STR_LEN		33				// ライセンス ID の長さ
+
+
+// ライセンスされている製品エディション
+#define	LICENSE_EDITION_VPN3_NO_LICENSE					0		// ライセンス無し
+#define	LICENSE_EDITION_UTVPN_GPL						201		// UT-VPN (GPL)
+
+// ライセンスステータス
+#define	LICENSE_STATUS_OK				0		// 有効
+#define	LICENSE_STATUS_EXPIRED			1		// 無効 (有効期限切れ)
+#define	LICENSE_STATUS_ID_DIFF			2		// 無効 (システム ID 不一致)
+#define	LICENSE_STATUS_DUP				3		// 無効 (重複)
+#define	LICENSE_STATUS_INSUFFICIENT		4		// 無効 (必要な他のライセンスが不足)
+#define	LICENSE_STATUS_COMPETITION		5		// 無効 (他のライセンスと競合)
+#define	LICENSE_STATUS_NONSENSE			6		// 無効 (現在のエディションでは無意味)
+#define	LICENSE_STATUS_CPU				7		// 無効 (CPU の種類が不一致)
+
+
+#define	BIT_TO_BYTE(x)					(((x) + 7) / 8)
+#define	BYTE_TO_BIT(x)					((x) * 8)
+
+
+//////////////////////////////////////////////////////////////////////
+// 
+// エラーコード
+// 
+//////////////////////////////////////////////////////////////////////
+
+#define	ERR_NO_ERROR					0	// エラー無し
+#define	ERR_CONNECT_FAILED				1	// サーバーへの接続が失敗した
+#define	ERR_SERVER_IS_NOT_VPN			2	// 接続先サーバーは VPN サーバーではない
+#define	ERR_DISCONNECTED				3	// 接続が切断された
+#define	ERR_PROTOCOL_ERROR				4	// プロトコルエラー
+#define	ERR_CLIENT_IS_NOT_VPN			5	// 接続元クライアントは VPN クライアントではない
+#define	ERR_USER_CANCEL					6	// ユーザーキャンセル
+#define	ERR_AUTHTYPE_NOT_SUPPORTED		7	// 指定された認証方法はサポートされていない
+#define	ERR_HUB_NOT_FOUND				8	// HUB が存在しない
+#define	ERR_AUTH_FAILED					9	// 認証失敗
+#define	ERR_HUB_STOPPING				10	// HUB が停止中
+#define	ERR_SESSION_REMOVED				11	// セッションが削除された
+#define	ERR_ACCESS_DENIED				12	// アクセス拒否
+#define	ERR_SESSION_TIMEOUT				13	// セッションがタイムアウトした
+#define	ERR_INVALID_PROTOCOL			14	// プロトコルが不正
+#define	ERR_TOO_MANY_CONNECTION			15	// コネクション数が多すぎる
+#define	ERR_HUB_IS_BUSY					16	// HUB のセッション数が多すぎる
+#define	ERR_PROXY_CONNECT_FAILED		17	// プロキシサーバーへの接続が失敗した
+#define	ERR_PROXY_ERROR					18	// プロキシエラーが発生
+#define	ERR_PROXY_AUTH_FAILED			19	// プロキシサーバーでの認証に失敗
+#define	ERR_TOO_MANY_USER_SESSION		20	// 同一ユーザーのセッション数が多すぎる
+#define	ERR_LICENSE_ERROR				21	// ライセンスエラー
+#define	ERR_DEVICE_DRIVER_ERROR			22	// デバイスドライバエラー
+#define	ERR_INTERNAL_ERROR				23	// 内部エラー
+#define	ERR_SECURE_DEVICE_OPEN_FAILED	24	// セキュアデバイスを開けなかった
+#define	ERR_SECURE_PIN_LOGIN_FAILED		25	// PIN コードが違う
+#define	ERR_SECURE_NO_CERT				26	// 指定された証明書が格納されていない
+#define	ERR_SECURE_NO_PRIVATE_KEY		27	// 指定された秘密鍵が格納されていない
+#define	ERR_SECURE_CANT_WRITE			28	// 書き込み失敗
+#define	ERR_OBJECT_NOT_FOUND			29	// 指定されたオブジェクトが見つからない
+#define	ERR_VLAN_ALREADY_EXISTS			30	// 指定された名前の仮想 LAN カードは存在する
+#define	ERR_VLAN_INSTALL_ERROR			31	// 指定された仮想 LAN カードを生成できない
+#define	ERR_VLAN_INVALID_NAME			32	// 指定された仮想 LAN カードの名前は不正
+#define	ERR_NOT_SUPPORTED				33	// サポートされていない
+#define	ERR_ACCOUNT_ALREADY_EXISTS		34	// アカウントはすでに存在する
+#define	ERR_ACCOUNT_ACTIVE				35	// アカウントは動作中
+#define	ERR_ACCOUNT_NOT_FOUND			36	// 指定されたアカウントは無い
+#define	ERR_ACCOUNT_INACTIVE			37	// アカウントは停止中
+#define	ERR_INVALID_PARAMETER			38	// パラメータが不正
+#define	ERR_SECURE_DEVICE_ERROR			39	// セキュアデバイスの操作でエラーが発生した
+#define	ERR_NO_SECURE_DEVICE_SPECIFIED	40	// セキュアデバイスが指定されていない
+#define	ERR_VLAN_IS_USED				41	// 仮想 LAN カードはアカウントによって使用中
+#define	ERR_VLAN_FOR_ACCOUNT_NOT_FOUND	42	// アカウントの仮想 LAN カードが見つからない
+#define	ERR_VLAN_FOR_ACCOUNT_USED		43	// アカウントの仮想 LAN カードはすでに使用中
+#define	ERR_VLAN_FOR_ACCOUNT_DISABLED	44	// アカウントの仮想 LAN カードは無効化されている
+#define	ERR_INVALID_VALUE				45	// 値が不正
+#define	ERR_NOT_FARM_CONTROLLER			46	// ファームコントローラではない
+#define	ERR_TRYING_TO_CONNECT			47	// 接続を試行中
+#define	ERR_CONNECT_TO_FARM_CONTROLLER	48	// ファームコントローラへの接続に失敗
+#define	ERR_COULD_NOT_HOST_HUB_ON_FARM	49	// ファーム上に仮想 HUB を作成できなかった
+#define	ERR_FARM_MEMBER_HUB_ADMIN		50	// ファームメンバで HUB を管理することはできない
+#define	ERR_NULL_PASSWORD_LOCAL_ONLY	51	// 空文字のパスワードのためローカル接続のみ受付中
+#define	ERR_NOT_ENOUGH_RIGHT			52	// 権利が不足している
+#define	ERR_LISTENER_NOT_FOUND			53	// リスナーが見つからない
+#define	ERR_LISTENER_ALREADY_EXISTS		54	// すでにリスナーが存在している
+#define	ERR_NOT_FARM_MEMBER				55	// ファームメンバではない
+#define	ERR_CIPHER_NOT_SUPPORTED		56	// 暗号化アルゴリズムがサポートされていない
+#define	ERR_HUB_ALREADY_EXISTS			57	// HUB はすでに存在する
+#define	ERR_TOO_MANY_HUBS				58	// HUB が多すぎる
+#define	ERR_LINK_ALREADY_EXISTS			59	// リンクはすでに存在する
+#define	ERR_LINK_CANT_CREATE_ON_FARM	60	// リンクはサーバーファーム上に作成できない
+#define	ERR_LINK_IS_OFFLINE				61	// リンクはオフラインである
+#define	ERR_TOO_MANY_ACCESS_LIST		62	// アクセスリストが多すぎる
+#define	ERR_TOO_MANY_USER				63	// ユーザーが多すぎる
+#define	ERR_TOO_MANY_GROUP				64	// グループが多すぎる
+#define	ERR_GROUP_NOT_FOUND				65	// グループが見つからない
+#define	ERR_USER_ALREADY_EXISTS			66	// ユーザーがすでに存在する
+#define	ERR_GROUP_ALREADY_EXISTS		67	// グループがすでに存在する
+#define	ERR_USER_AUTHTYPE_NOT_PASSWORD	68	// ユーザーの認証方法はパスワード認証ではない
+#define	ERR_OLD_PASSWORD_WRONG			69	// 古いパスワードが間違っているかユーザーが存在しない
+#define	ERR_LINK_CANT_DISCONNECT		73	// カスケード セッションは切断できない
+#define	ERR_ACCOUNT_NOT_PRESENT			74	// VPN サーバーへの接続設定が未完了である
+#define	ERR_ALREADY_ONLINE				75	// すでにオンラインである
+#define	ERR_OFFLINE						76	// オフラインである
+#define	ERR_NOT_RSA_1024				77	// RSA 1024bit 以外の証明書である
+#define	ERR_SNAT_CANT_DISCONNECT		78	// SecureNAT セッションは切断できない
+#define	ERR_SNAT_NEED_STANDALONE		79	// SecureNAT はスタンドアロン HUB でしか動作しない
+#define	ERR_SNAT_NOT_RUNNING			80	// SecureNAT 機能が動作していない
+#define	ERR_SE_VPN_BLOCK				81	// システム管理者向けブロックツールで停止された (廃止)
+#define	ERR_BRIDGE_CANT_DISCONNECT		82	// Bridge セッションは切断できない
+#define	ERR_LOCAL_BRIDGE_STOPPING		83	// Bridge 機能は停止している
+#define	ERR_LOCAL_BRIDGE_UNSUPPORTED	84	// Bridge 機能がサポートされていない
+#define	ERR_CERT_NOT_TRUSTED			85	// 接続先サーバーの証明書が信頼できない
+#define	ERR_PRODUCT_CODE_INVALID		86	// 製品コードが違う
+#define	ERR_VERSION_INVALID				87	// バージョンが違う
+#define	ERR_CAPTURE_DEVICE_ADD_ERROR	88	// キャプチャデバイス追加失敗
+#define	ERR_VPN_CODE_INVALID			89	// VPN コードが違う
+#define	ERR_CAPTURE_NOT_FOUND			90	// キャプチャデバイスが見つからない
+#define	ERR_LAYER3_CANT_DISCONNECT		91	// Layer-3 セッションは切断できない
+#define	ERR_LAYER3_SW_EXISTS			92	// すでに同一の L3 スイッチが存在する
+#define	ERR_LAYER3_SW_NOT_FOUND			93	// Layer-3 スイッチが見つからない
+#define	ERR_INVALID_NAME				94	// 名前が不正
+#define	ERR_LAYER3_IF_ADD_FAILED		95	// インターフェイスの追加に失敗した
+#define	ERR_LAYER3_IF_DEL_FAILED		96	// インターフェイスの削除に失敗した
+#define	ERR_LAYER3_IF_EXISTS			97	// 指定したインターフェイスはすでに存在する
+#define	ERR_LAYER3_TABLE_ADD_FAILED		98	// ルーティングテーブルの追加に失敗した
+#define	ERR_LAYER3_TABLE_DEL_FAILED		99	// ルーティングテーブルの削除に失敗した
+#define	ERR_LAYER3_TABLE_EXISTS			100	// 指定したルーティングテーブルはすでに存在する
+#define	ERR_BAD_CLOCK					101	// 時刻がおかしい
+#define	ERR_LAYER3_CANT_START_SWITCH	102	// 仮想レイヤ 3 スイッチを開始できない
+#define	ERR_CLIENT_LICENSE_NOT_ENOUGH	103	// クライアント接続ライセンス数不足
+#define	ERR_BRIDGE_LICENSE_NOT_ENOUGH	104 // ブリッジ接続ライセンス数不足
+#define	ERR_SERVER_CANT_ACCEPT			105	// 技術的な問題で Accept していない
+#define	ERR_SERVER_CERT_EXPIRES			106	// 接続先 VPN サーバーの有効期限が切れている
+#define	ERR_MONITOR_MODE_DENIED			107	// モニタポートモードは拒否された
+#define	ERR_BRIDGE_MODE_DENIED			108	// ブリッジまたはルーティングモードは拒否された
+#define	ERR_IP_ADDRESS_DENIED			109	// クライアント IP アドレスが拒否された
+#define	ERR_TOO_MANT_ITEMS				110	// 項目数が多すぎる
+#define	ERR_MEMORY_NOT_ENOUGH			111	// メモリ不足
+#define	ERR_OBJECT_EXISTS				112	// オブジェクトはすでに存在している
+#define	ERR_FATAL						113	// 致命的なエラーが発生した
+#define	ERR_SERVER_LICENSE_FAILED		114	// サーバー側でライセンス違反が発生した
+#define	ERR_SERVER_INTERNET_FAILED		115	// サーバー側がインターネットに接続されていない
+#define	ERR_CLIENT_LICENSE_FAILED		116	// クライアント側でライセンス違反が発生した
+#define	ERR_BAD_COMMAND_OR_PARAM		117	// コマンドまたはパラメータが不正
+#define	ERR_INVALID_LICENSE_KEY			118	// ライセンスキー不正
+#define	ERR_NO_VPN_SERVER_LICENSE		119	// VPN Server の有効なライセンスが無い
+#define	ERR_NO_VPN_CLUSTER_LICENSE		120	// クラスタライセンスが無い
+#define ERR_NOT_ADMINPACK_SERVER		121	// Administrator Pack ライセンスを持ったサーバーに接続しようとしていない
+#define ERR_NOT_ADMINPACK_SERVER_NET	122	// Administrator Pack ライセンスを持ったサーバーに接続しようとしていない (.NET 用)
+#define ERR_BETA_EXPIRES				123	// 接続先 VPN Server のベータ版の有効期限が切れている
+#define ERR_BRANDED_C_TO_S				124 // 接続制限用のブランド化文字列が異なる(サーバ側での認証用)
+#define ERR_BRANDED_C_FROM_S			125	// 接続制限用のブランド化文字列が異なる(クライアント側での認証用)
+#define	ERR_AUTO_DISCONNECTED			126	// 一定時間が経過したため VPN セッションが切断された
+#define	ERR_CLIENT_ID_REQUIRED			127	// クライアント ID が一致していない
+#define	ERR_TOO_MANY_USERS_CREATED		128	// 作成されているユーザー数が多すぎる
+#define	ERR_SUBSCRIPTION_IS_OLDER		129	// サブスクリプションの期限が VPN Server のビルド日時よりも前である
+#define	ERR_UTVPN_NOT_SUPPORT_THIS_AUTH	130	// UT-VPN はこの認証方法を実装していない
+#define	ERR_UTVPN_NOT_SUPPORT_THIS_FUNC	131	// UT-VPN はこの機能を実装していない
+
+
+////////////////////////////
+// 全般的に使用される構造体
+
+// ネットワーク サービス
+typedef struct NETSVC
+{
+	bool Udp;						// false=TCP, true=UDP
+	UINT Port;						// ポート番号
+	char *Name;						// 名称
+} NETSVC;
+
+// トラフィックデータエントリ
+typedef struct TRAFFIC_ENTRY
+{
+	UINT64 BroadcastCount;			// ブロードキャストパケット数
+	UINT64 BroadcastBytes;			// ブロードキャストバイト数
+	UINT64 UnicastCount;			// ユニキャストカウント数
+	UINT64 UnicastBytes;			// ユニキャストバイト数
+} TRAFFIC_ENTRY;
+
+// トラフィックデータ
+typedef struct TRAFFIC
+{
+	TRAFFIC_ENTRY Send;				// 送信データ
+	TRAFFIC_ENTRY Recv;				// 受信データ
+} TRAFFIC;
+
+// 非 SSL 接続元
+typedef struct NON_SSL
+{
+	IP IpAddress;					// IP アドレス
+	UINT64 EntryExpires;			// エントリの有効期限
+	UINT Count;						// 接続回数
+} NON_SSL;
+
+// 簡易ログ保存
+typedef struct TINY_LOG
+{
+	char FileName[MAX_PATH];		// ファイル名
+	IO *io;							// ファイル
+	LOCK *Lock;						// ロック
+} TINY_LOG;
+
+// CEDAR 構造体
+typedef struct CEDAR
+{
+	LOCK *lock;						// ロック
+	REF *ref;						// 参照カウンタ
+	COUNTER *AcceptingSockets;		// Accept 中のソケット数
+	UINT Type;						// 種類
+	LIST *ListenerList;				// リスナーリスト
+	LIST *HubList;					// HUB リスト
+	LIST *ConnectionList;			// ネゴシエーション中のコネクションリスト
+	LIST *CaList;					// CA のリスト
+	volatile bool Halt;				// 停止フラグ
+	COUNTER *ConnectionIncrement;	// コネクションインクリメントカウンタ
+	X *ServerX;						// サーバー証明書
+	K *ServerK;						// サーバー証明書の秘密鍵
+	char *CipherList;				// 暗号化アルゴリズムのリスト
+	UINT Version;					// バージョン情報
+	UINT Build;						// ビルド番号
+	char *ServerStr;				// サーバー文字列
+	char *MachineName;				// コンピュータ名
+	char *HttpUserAgent;			// HTTP ユーザーエージェント
+	char *HttpAccept;				// HTTP Accept
+	char *HttpAcceptLanguage;		// HTTP Accept Language
+	char *HttpAcceptEncoding;		// HTTP Accept Encoding
+	TRAFFIC *Traffic;				// トラフィック情報
+	LOCK *TrafficLock;				// トラフィック情報ロック
+	LIST *UDPEntryList;				// UDP エントリリスト
+	COUNTER *CurrentSessions;		// 現在のセッション数
+	COUNTER *CurrentTcpConnections;	// 現在の TCP コネクション数
+	LIST *NetSvcList;				// ネットワークサービスリスト
+	char *VerString;				// バージョン文字列
+	char *BuildInfo;				// ビルド情報
+	struct CLIENT *Client;			// クライアント
+	struct SERVER *Server;			// サーバー
+	UINT64 CreatedTick;				// 生成日時
+	bool CheckExpires;				// 有効期限をチェックする
+	LIST *TrafficDiffList;			// トラフィック差分リスト
+	struct LOG *DebugLog;			// デバッグログ
+	UCHAR UniqueId[16];				// ユニーク ID
+	LIST *LocalBridgeList;			// ローカルブリッジリスト
+	bool Bridge;					// ブリッジ版
+	LIST *L3SwList;					// Layer-3 スイッチリスト
+	COUNTER *AssignedClientLicense;	// 割り当て済みクライアントライセンス数
+	COUNTER *AssignedBridgeLicense;	// 割り当て済みブリッジライセンス数
+	UINT64 LicenseViolationTick;	// ライセンス違反発生
+	LIST *NonSslList;				// 非 SSL 接続リスト
+	struct WEBUI *WebUI;			// WebUI サービス用データ
+	UINT Beta;						// ベータ番号
+	LOCK *CedarSuperLock;			// シーダー スーパー ロック！
+	bool DisableIPv6Listener;		// IPv6 リスナーを無効にする
+	UINT ClientId;					// クライアント ID
+	UINT64 BuiltDate;				// ビルドされた日付
+} CEDAR;
+
+// CEDAR の種類
+#define	CEDAR_CLIENT				0	// クライアント
+#define	CEDAR_STANDALONE_SERVER		1	// スタンドアロンサーバー
+#define	CEDAR_FARM_CONTROLLER		2	// サーバーファーム コントローラ
+#define	CEDAR_FARM_MEMBER			3	// サーバーファーム メンバー
+
+
+////////////////////////////
+// ヘッダファイルの読み込み
+
+// 型
+#include <Cedar/CedarType.h>
+// アカウントマネージャ
+#include <Cedar/Account.h>
+// リスナー モジュール
+#include <Cedar/Listener.h>
+// TCP/IP
+#include <Cedar/TcpIp.h>
+// ログ保存モジュール
+#include <Cedar/Logging.h>
+// コネクション管理
+#include <Cedar/Connection.h>
+// セッション管理
+#include <Cedar/Session.h>
+// RPC
+#include <Cedar/Remote.h>
+// HUB 管理
+#include <Cedar/Hub.h>
+// セキュリティアカウントマネージャ
+#include <Cedar/Sam.h>
+// プロトコル
+#include <Cedar/Protocol.h>
+// HUB 間リンク
+#include <Cedar/Link.h>
+// ユーザーモード仮想ホスト
+#include <Cedar/Virtual.h>
+// SecureNAT
+#include <Cedar/SecureNAT.h>
+// コンソール サービス
+#include <Cedar/Console.h>
+// vpncmd ユーティリティ
+#include <Cedar/Command.h>
+
+#ifdef	OS_WIN32
+// Sen デバイスドライバ
+#include <Sen/Sen.h>
+#endif	// OS_WIN32
+
+// Sen デバイスドライバ操作用ライブラリ
+#include <Cedar/VLan.h>
+// ブリッジ
+#include <Cedar/Bridge.h>
+// Layer-3 スイッチ
+#include <Cedar/Layer3.h>
+// テスト用仮想 LAN カード
+#include <Cedar/NullLan.h>
+// クライアント
+#include <Cedar/Client.h>
+/// サーバー
+#include <Cedar/Server.h>
+// ライセンスデータベース
+#include <Cedar/Database.h>
+// 管理 RPC
+#include <Cedar/Admin.h>
+// User-mode Router
+#include <Cedar/Nat.h>
+
+#ifdef	OS_WIN32
+
+// Win32 ユーザーインターフェイス
+#include <Cedar/WinUi.h>
+// Win32 クライアント接続マネージャ
+#include <Cedar/CM.h>
+// Win32 Server Manager
+#include <Cedar/SM.h>
+// Win32 User-mode Router Manager
+#include <Cedar/NM.h>
+// Win32 Network Utility
+#include <Cedar/UT.h>
+// Win32 HTML 表示モジュール
+#include <Cedar/Win32Html.h>
+
+#endif
+
+
+
+
+////////////////////////////
+// 関数プロトタイプ
+
+TRAFFIC *NewTraffic();
+void FreeTraffic(TRAFFIC *t);
+CEDAR *NewCedar(X *server_x, K *server_k);
+void SetCedarVpnBridge(CEDAR *c);
+void SetCedarCert(CEDAR *c, X *server_x, K *server_k);
+void ReleaseCedar(CEDAR *c);
+void CleanupCedar(CEDAR *c);
+void StopCedar(CEDAR *c);
+void AddListener(CEDAR *c, LISTENER *r);
+void StopAllListener(CEDAR *c);
+void AddTraffic(TRAFFIC *dst, TRAFFIC *diff);
+void AddHub(CEDAR *c, HUB *h);
+void DelHub(CEDAR *c, HUB *h);
+void DelHubEx(CEDAR *c, HUB *h, bool no_lock);
+void StopAllHub(CEDAR *c);
+void StopAllConnection(CEDAR *c);
+void AddConnection(CEDAR *cedar, CONNECTION *c);
+UINT GetUnestablishedConnections(CEDAR *cedar);
+void DelConnection(CEDAR *cedar, CONNECTION *c);
+void SetCedarCipherList(CEDAR *cedar, char *name);
+void InitCedar();
+void FreeCedar();
+void AddCa(CEDAR *cedar, X *x);
+bool DeleteCa(CEDAR *cedar, UINT ptr);
+bool CheckSignatureByCa(CEDAR *cedar, X *x);
+bool CheckSignatureByCaLinkMode(SESSION *s, X *x);
+X *FindCaSignedX(LIST *o, X *x);
+void InitNetSvcList(CEDAR *cedar);
+void FreeNetSvcList(CEDAR *cedar);
+int CompareNetSvc(void *p1, void *p2);
+char *GetSvcName(CEDAR *cedar, bool udp, UINT port);
+void InitHiddenPassword(char *str, UINT size);
+bool IsHiddenPasswordChanged(char *str);
+UINT64 GetTrafficPacketSize(TRAFFIC *t);
+UINT64 GetTrafficPacketNum(TRAFFIC *t);
+void EnableDebugLog(CEDAR *c);
+void StartCedarLog();
+void StopCedarLog();
+void CedarLog(char *str);
+int CompareNoSslList(void *p1, void *p2);
+void InitNoSslList(CEDAR *c);
+void FreeNoSslList(CEDAR *c);
+bool AddNoSsl(CEDAR *c, IP *ip);
+void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec);
+void DeleteOldNoSsl(CEDAR *c);
+NON_SSL *SearchNoSslList(CEDAR *c, IP *ip);
+bool IsInNoSsl(CEDAR *c, IP *ip);
+void FreeTinyLog(TINY_LOG *t);
+void WriteTinyLog(TINY_LOG *t, char *str);
+TINY_LOG *NewTinyLog();
+void GetWinVer(RPC_WINVER *v);
+bool IsSupportedWinVer(RPC_WINVER *v);
+bool IsLaterBuild(CEDAR *c, UINT64 t);
+
+
+#endif	// CEDAR_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarPch.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarPch.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarPch.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,82 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// CedarPch.c
+// Cedar 用プリコンパイルヘッダ生成コード
+
+#include "CedarPch.h"
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarPch.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarPch.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarPch.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,91 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// CedarPch.h
+// Cedar 用プリコンパイルヘッダ生成用ヘッダファイル
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarType.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarType.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/CedarType.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,528 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// CedarType.h
+// Cedar が使用している型の一覧
+
+#ifndef	CEDARTYPE_H
+#define	CEDARTYPE_H
+
+
+// ==============================================================
+//   Remote Procedure Call
+// ==============================================================
+
+typedef struct RPC RPC;
+
+
+// ==============================================================
+//   Account
+// ==============================================================
+
+typedef struct POLICY_ITEM POLICY_ITEM;
+typedef struct POLICY POLICY;
+typedef struct USERGROUP USERGROUP;
+typedef struct USER USER;
+typedef struct AUTHPASSWORD AUTHPASSWORD;
+typedef struct AUTHUSERCERT AUTHUSERCERT;
+typedef struct AUTHROOTCERT AUTHROOTCERT;
+typedef struct AUTHRADIUS AUTHRADIUS;
+typedef struct AUTHNT AUTHNT;
+
+
+// ==============================================================
+//   Listener
+// ==============================================================
+
+typedef struct LISTENER LISTENER;
+typedef struct TCP_ACCEPTED_PARAM TCP_ACCEPTED_PARAM;
+typedef struct UDP_ENTRY UDP_ENTRY;
+
+
+// ==============================================================
+//   Logging
+// ==============================================================
+
+typedef struct PACKET_LOG PACKET_LOG;
+typedef struct HUB_LOG HUB_LOG;
+typedef struct RECORD RECORD;
+typedef struct LOG LOG;
+typedef struct ERASER ERASER;
+typedef struct SLOG SLOG;
+
+
+// ==============================================================
+//   Connection
+// ==============================================================
+
+typedef struct KEEP KEEP;
+typedef struct SECURE_SIGN SECURE_SIGN;
+typedef struct RC4_KEY_PAIR RC4_KEY_PAIR;
+typedef struct CLIENT_OPTION CLIENT_OPTION;
+typedef struct CLIENT_AUTH CLIENT_AUTH;
+typedef struct TCPSOCK TCPSOCK;
+typedef struct TCP TCP;
+typedef struct UDP UDP;
+typedef struct BLOCK BLOCK;
+typedef struct CONNECTION CONNECTION;
+
+
+// ==============================================================
+//   Session
+// ==============================================================
+
+typedef struct NODE_INFO NODE_INFO;
+typedef struct PACKET_ADAPTER PACKET_ADAPTER;
+typedef struct SESSION SESSION;
+typedef struct UI_PASSWORD_DLG UI_PASSWORD_DLG;
+typedef struct UI_MSG_DLG UI_MSG_DLG;
+typedef struct UI_NICINFO UI_NICINFO;
+typedef struct UI_CONNECTERROR_DLG UI_CONNECTERROR_DLG;
+typedef struct UI_CHECKCERT UI_CHECKCERT;
+
+
+// ==============================================================
+//   Hub
+// ==============================================================
+
+typedef struct SE_LINK SE_LINK;
+typedef struct TEST_HISTORY TEST_HISTORY;
+typedef struct SE_TEST SE_TEST;
+typedef struct HUBDB HUBDB;
+typedef struct TRAFFIC_LIMITER TRAFFIC_LIMITER;
+typedef struct STORM STORM;
+typedef struct HUB_PA HUB_PA;
+typedef struct HUB_OPTION HUB_OPTION;
+typedef struct MAC_TABLE_ENTRY MAC_TABLE_ENTRY;
+typedef struct IP_TABLE_ENTRY IP_TABLE_ENTRY;
+typedef struct LOOP_LIST LOOP_LIST;
+typedef struct ACCESS ACCESS;
+typedef struct TICKET TICKET;
+typedef struct TRAFFIC_DIFF TRAFFIC_DIFF;
+typedef struct HUB HUB;
+typedef struct ADMIN_OPTION ADMIN_OPTION;
+typedef struct CRL CRL;
+typedef struct AC AC;
+
+
+// ==============================================================
+//   Protocol
+// ==============================================================
+
+typedef struct CHECK_CERT_THREAD_PROC CHECK_CERT_THREAD_PROC;
+typedef struct SECURE_SIGN_THREAD_PROC SECURE_SIGN_THREAD_PROC;
+typedef struct RAND_CACHE RAND_CACHE;
+typedef struct HTTP_VALUE HTTP_VALUE;
+typedef struct HTTP_HEADER HTTP_HEADER;
+typedef struct SEND_SIGNATURE_PARAM SEND_SIGNATURE_PARAM;
+
+
+// ==============================================================
+//   Link
+// ==============================================================
+
+typedef struct LINK LINK;
+
+
+// ==============================================================
+//   Virtual
+// ==============================================================
+
+typedef struct ARP_ENTRY ARP_ENTRY;
+typedef struct ARP_WAIT ARP_WAIT;
+typedef struct IP_WAIT IP_WAIT;
+typedef struct IP_PART IP_PART;
+typedef struct IP_COMBINE IP_COMBINE;
+typedef struct NAT_ENTRY NAT_ENTRY;
+typedef struct TCP_OPTION TCP_OPTION;
+typedef struct VH VH;
+typedef struct VH_OPTION VH_OPTION;
+typedef struct DHCP_OPTION DHCP_OPTION;
+typedef struct DHCP_OPTION_LIST DHCP_OPTION_LIST;
+typedef struct DHCP_LEASE DHCP_LEASE;
+
+
+// ==============================================================
+//   VLAN
+// ==============================================================
+
+typedef struct ROUTE_TRACKING ROUTE_TRACKING;
+typedef struct VLAN VLAN;
+typedef struct INSTANCE_LIST INSTANCE_LIST;
+typedef struct VLAN_PARAM VLAN_PARAM;
+
+#ifdef	OS_UNIX
+typedef struct UNIX_VLAN_LIST UNIX_VLAN_LIST;
+#endif	// OS_UNIX
+
+// ==============================================================
+//   Null LAN
+// ==============================================================
+
+typedef struct NULL_LAN NULL_LAN;
+
+
+// ==============================================================
+//   Bridge
+// ==============================================================
+
+typedef struct ETH ETH;
+typedef struct BRIDGE BRIDGE;
+typedef struct LOCALBRIDGE LOCALBRIDGE;
+
+
+// ==============================================================
+//   Layer-3 Switch
+// ==============================================================
+
+typedef struct L3IF L3IF;
+typedef struct L3SW L3SW;
+typedef struct L3TABLE L3TABLE;
+typedef struct L3ARPENTRY L3ARPENTRY;
+typedef struct L3ARPWAIT L3ARPWAIT;
+typedef struct L3PACKET L3PACKET;
+
+
+// ==============================================================
+//   Client
+// ==============================================================
+
+typedef struct ACCOUNT ACCOUNT;
+typedef struct CLIENT_CONFIG CLIENT_CONFIG;
+typedef struct RPC_CLIENT_VERSION RPC_CLIENT_VERSION;
+typedef struct RPC_CLIENT_PASSWORD RPC_CLIENT_PASSWORD;
+typedef struct RPC_CLIENT_PASSWORD_SETTING RPC_CLIENT_PASSWORD_SETTING;
+typedef struct RPC_CLIENT_ENUM_CA_ITEM RPC_CLIENT_ENUM_CA_ITEM;
+typedef struct RPC_CLIENT_ENUM_CA RPC_CLIENT_ENUM_CA;
+typedef struct RPC_CERT RPC_CERT;
+typedef struct RPC_CLIENT_DELETE_CA RPC_CLIENT_DELETE_CA;
+typedef struct RPC_GET_CA RPC_GET_CA;
+typedef struct RPC_GET_ISSUER RPC_GET_ISSUER;
+typedef struct RPC_CLIENT_ENUM_SECURE_ITEM RPC_CLIENT_ENUM_SECURE_ITEM;
+typedef struct RPC_CLIENT_ENUM_SECURE RPC_CLIENT_ENUM_SECURE;
+typedef struct RPC_USE_SECURE RPC_USE_SECURE;
+typedef struct RPC_ENUM_OBJECT_IN_SECURE RPC_ENUM_OBJECT_IN_SECURE;
+typedef struct RPC_CLIENT_CREATE_VLAN RPC_CLIENT_CREATE_VLAN;
+typedef struct RPC_CLIENT_GET_VLAN RPC_CLIENT_GET_VLAN;
+typedef struct RPC_CLIENT_SET_VLAN RPC_CLIENT_SET_VLAN;
+typedef struct RPC_CLIENT_ENUM_VLAN_ITEM RPC_CLIENT_ENUM_VLAN_ITEM;
+typedef struct RPC_CLIENT_ENUM_VLAN RPC_CLIENT_ENUM_VLAN;
+typedef struct RPC_CLIENT_CREATE_ACCOUNT RPC_CLIENT_CREATE_ACCOUNT;
+typedef struct RPC_CLIENT_ENUM_ACCOUNT_ITEM RPC_CLIENT_ENUM_ACCOUNT_ITEM;
+typedef struct RPC_CLIENT_ENUM_ACCOUNT RPC_CLIENT_ENUM_ACCOUNT;
+typedef struct RPC_CLIENT_DELETE_ACCOUNT RPC_CLIENT_DELETE_ACCOUNT;
+typedef struct RPC_RENAME_ACCOUNT RPC_RENAME_ACCOUNT;
+typedef struct RPC_CLIENT_GET_ACCOUNT RPC_CLIENT_GET_ACCOUNT;
+typedef struct RPC_CLIENT_CONNECT RPC_CLIENT_CONNECT;
+typedef struct RPC_CLIENT_GET_CONNECTION_STATUS RPC_CLIENT_GET_CONNECTION_STATUS;
+typedef struct CLIENT_RPC_CONNECTION CLIENT_RPC_CONNECTION;
+typedef struct CLIENT CLIENT;
+typedef struct RPC_CLIENT_NOTIFY RPC_CLIENT_NOTIFY;
+typedef struct REMOTE_CLIENT REMOTE_CLIENT;
+typedef struct NOTIFY_CLIENT NOTIFY_CLIENT;
+typedef struct UNIX_VLAN UNIX_VLAN;
+typedef struct CM_SETTING CM_SETTING;
+
+
+// ==============================================================
+//   Server
+// ==============================================================
+
+typedef struct HUB_LIST HUB_LIST;
+typedef struct FARM_TASK FARM_TASK;
+typedef struct FARM_MEMBER FARM_MEMBER;
+typedef struct FARM_CONTROLLER FARM_CONTROLLER;
+typedef struct SERVER_LISTENER SERVER_LISTENER;
+typedef struct SERVER SERVER;
+typedef struct RPC_ENUM_SESSION RPC_ENUM_SESSION;
+typedef struct RPC_SESSION_STATUS RPC_SESSION_STATUS;
+typedef struct CAPS CAPS;
+typedef struct CAPSLIST CAPSLIST;
+typedef struct LOG_FILE LOG_FILE;
+typedef struct SYSLOG_SETTING SYSLOG_SETTING;
+typedef struct HUB_SNAPSHOT HUB_SNAPSHOT;
+typedef struct SERVER_SNAPSHOT SERVER_SNAPSHOT;
+typedef struct SERVER_HUB_CREATE_HISTORY SERVER_HUB_CREATE_HISTORY;
+
+// ==============================================================
+//   Server Admin Tool
+// ==============================================================
+
+typedef struct ADMIN ADMIN;
+typedef struct RPC_TEST RPC_TEST;
+typedef struct RPC_SERVER_INFO RPC_SERVER_INFO;
+typedef struct RPC_SERVER_STATUS RPC_SERVER_STATUS;
+typedef struct RPC_LISTENER RPC_LISTENER;
+typedef struct RPC_LISTENER_LIST RPC_LISTENER_LIST;
+typedef struct RPC_STR RPC_STR;
+typedef struct RPC_SET_PASSWORD RPC_SET_PASSWORD;
+typedef struct RPC_FARM RPC_FARM;
+typedef struct RPC_FARM_HUB RPC_FARM_HUB;
+typedef struct RPC_FARM_INFO RPC_FARM_INFO;
+typedef struct RPC_ENUM_FARM_ITEM RPC_ENUM_FARM_ITEM;
+typedef struct RPC_ENUM_FARM RPC_ENUM_FARM;
+typedef struct RPC_FARM_CONNECTION_STATUS RPC_FARM_CONNECTION_STATUS;
+typedef struct RPC_KEY_PAIR RPC_KEY_PAIR;
+typedef struct RPC_HUB_OPTION RPC_HUB_OPTION;
+typedef struct RPC_RADIUS RPC_RADIUS;
+typedef struct RPC_HUB RPC_HUB;
+typedef struct RPC_CREATE_HUB RPC_CREATE_HUB;
+typedef struct RPC_ENUM_HUB_ITEM RPC_ENUM_HUB_ITEM;
+typedef struct RPC_ENUM_HUB RPC_ENUM_HUB;
+typedef struct RPC_DELETE_HUB RPC_DELETE_HUB;
+typedef struct RPC_ENUM_CONNECTION_ITEM RPC_ENUM_CONNECTION_ITEM;
+typedef struct RPC_ENUM_CONNECTION RPC_ENUM_CONNECTION;
+typedef struct RPC_DISCONNECT_CONNECTION RPC_DISCONNECT_CONNECTION;
+typedef struct RPC_CONNECTION_INFO RPC_CONNECTION_INFO;
+typedef struct RPC_SET_HUB_ONLINE RPC_SET_HUB_ONLINE;
+typedef struct RPC_HUB_STATUS RPC_HUB_STATUS;
+typedef struct RPC_HUB_LOG RPC_HUB_LOG;
+typedef struct RPC_HUB_ADD_CA RPC_HUB_ADD_CA;
+typedef struct RPC_HUB_ENUM_CA_ITEM RPC_HUB_ENUM_CA_ITEM;
+typedef struct RPC_HUB_ENUM_CA RPC_HUB_ENUM_CA;
+typedef struct RPC_HUB_GET_CA RPC_HUB_GET_CA;
+typedef struct RPC_HUB_DELETE_CA RPC_HUB_DELETE_CA;
+typedef struct RPC_CREATE_LINK RPC_CREATE_LINK;
+typedef struct RPC_ENUM_LINK_ITEM RPC_ENUM_LINK_ITEM;
+typedef struct RPC_ENUM_LINK RPC_ENUM_LINK;
+typedef struct RPC_LINK_STATUS RPC_LINK_STATUS;
+typedef struct RPC_LINK RPC_LINK;
+typedef struct RPC_ENUM_ACCESS_LIST RPC_ENUM_ACCESS_LIST;
+typedef struct RPC_ADD_ACCESS RPC_ADD_ACCESS;
+typedef struct RPC_DELETE_ACCESS RPC_DELETE_ACCESS;
+typedef struct RPC_SET_USER RPC_SET_USER;
+typedef struct RPC_ENUM_USER_ITEM RPC_ENUM_USER_ITEM;
+typedef struct RPC_ENUM_USER RPC_ENUM_USER;
+typedef struct RPC_SET_GROUP RPC_SET_GROUP;
+typedef struct RPC_ENUM_GROUP_ITEM RPC_ENUM_GROUP_ITEM;
+typedef struct RPC_ENUM_GROUP RPC_ENUM_GROUP;
+typedef struct RPC_DELETE_USER RPC_DELETE_USER;
+typedef struct RPC_ENUM_SESSION_ITEM RPC_ENUM_SESSION_ITEM;
+typedef struct RPC_DELETE_SESSION RPC_DELETE_SESSION;
+typedef struct RPC_ENUM_MAC_TABLE_ITEM RPC_ENUM_MAC_TABLE_ITEM;
+typedef struct RPC_ENUM_MAC_TABLE RPC_ENUM_MAC_TABLE;
+typedef struct RPC_ENUM_IP_TABLE_ITEM RPC_ENUM_IP_TABLE_ITEM;
+typedef struct RPC_ENUM_IP_TABLE RPC_ENUM_IP_TABLE;
+typedef struct RPC_DELETE_TABLE RPC_DELETE_TABLE;
+typedef struct RPC_KEEP RPC_KEEP;
+typedef struct RPC_ENUM_ETH_ITEM RPC_ENUM_ETH_ITEM;
+typedef struct RPC_ENUM_ETH RPC_ENUM_ETH;
+typedef struct RPC_LOCALBRIDGE RPC_LOCALBRIDGE;
+typedef struct RPC_ENUM_LOCALBRIDGE RPC_ENUM_LOCALBRIDGE;
+typedef struct RPC_BRIDGE_SUPPORT RPC_BRIDGE_SUPPORT;
+typedef struct RPC_CONFIG RPC_CONFIG;
+typedef struct RPC_ADMIN_OPTION RPC_ADMIN_OPTION;
+typedef struct RPC_L3SW RPC_L3SW;
+typedef struct RPC_L3IF RPC_L3IF;
+typedef struct RPC_L3TABLE RPC_L3TABLE;
+typedef struct RPC_ENUM_L3SW_ITEM RPC_ENUM_L3SW_ITEM;
+typedef struct RPC_ENUM_L3SW RPC_ENUM_L3SW;
+typedef struct RPC_ENUM_L3IF RPC_ENUM_L3IF;
+typedef struct RPC_ENUM_L3TABLE RPC_ENUM_L3TABLE;
+typedef struct RPC_CRL RPC_CRL;
+typedef struct RPC_ENUM_CRL_ITEM RPC_ENUM_CRL_ITEM;
+typedef struct RPC_ENUM_CRL RPC_ENUM_CRL;
+typedef struct RPC_INT RPC_INT;
+typedef struct RPC_AC_LIST RPC_AC_LIST;
+typedef struct RPC_ENUM_LOG_FILE_ITEM RPC_ENUM_LOG_FILE_ITEM;
+typedef struct RPC_ENUM_LOG_FILE RPC_ENUM_LOG_FILE;
+typedef struct RPC_READ_LOG_FILE RPC_READ_LOG_FILE;
+typedef struct DOWNLOAD_PROGRESS DOWNLOAD_PROGRESS;
+typedef struct RPC_RENAME_LINK RPC_RENAME_LINK;
+typedef struct RPC_ENUM_LICENSE_KEY RPC_ENUM_LICENSE_KEY;
+typedef struct RPC_ENUM_LICENSE_KEY_ITEM RPC_ENUM_LICENSE_KEY_ITEM;
+typedef struct RPC_LICENSE_STATUS RPC_LICENSE_STATUS;
+typedef struct RPC_ENUM_ETH_VLAN_ITEM RPC_ENUM_ETH_VLAN_ITEM;
+typedef struct RPC_ENUM_ETH_VLAN RPC_ENUM_ETH_VLAN;
+typedef struct RPC_MSG RPC_MSG;
+typedef struct RPC_WINVER RPC_WINVER;
+
+
+// ==============================================================
+//  NAT
+// ==============================================================
+
+typedef struct NAT NAT;
+typedef struct NAT_ADMIN NAT_ADMIN;
+typedef struct RPC_DUMMY RPC_DUMMY;
+typedef struct RPC_NAT_STATUS RPC_NAT_STATUS;
+typedef struct RPC_NAT_INFO RPC_NAT_INFO;
+typedef struct RPC_ENUM_NAT_ITEM RPC_ENUM_NAT_ITEM;
+typedef struct RPC_ENUM_NAT RPC_ENUM_NAT;
+typedef struct RPC_ENUM_DHCP_ITEM RPC_ENUM_DHCP_ITEM;
+typedef struct RPC_ENUM_DHCP RPC_ENUM_DHCP;
+
+
+// ==============================================================
+//  SecureNAT
+// ==============================================================
+
+typedef struct SNAT SNAT;
+
+
+// ==============================================================
+//  TcpIp
+// ==============================================================
+
+typedef struct MAC_HEADER MAC_HEADER;
+typedef struct ARPV4_HEADER ARPV4_HEADER;
+typedef struct IPV4_HEADER IPV4_HEADER;
+typedef struct TAGVLAN_HEADER TAGVLAN_HEADER;
+typedef struct UDP_HEADER UDP_HEADER;
+typedef struct UDPV4_PSEUDO_HEADER UDPV4_PSEUDO_HEADER;
+typedef struct TCPV4_PSEUDO_HEADER TCPV4_PSEUDO_HEADER;
+typedef struct TCP_HEADER TCP_HEADER;
+typedef struct ICMP_HEADER ICMP_HEADER;
+typedef struct ICMP_ECHO ICMP_ECHO;
+typedef struct DHCPV4_HEADER DHCPV4_HEADER;
+typedef struct DNSV4_HEADER DNSV4_HEADER;
+typedef struct BPDU_HEADER BPDU_HEADER;
+typedef struct LLC_HEADER LLC_HEADER;
+typedef struct PKT PKT;
+typedef struct IPV6_HEADER_PACKET_INFO IPV6_HEADER_PACKET_INFO;
+typedef struct IPV6_HEADER IPV6_HEADER;
+typedef struct IPV6_OPTION_HEADER IPV6_OPTION_HEADER;
+typedef struct IPV6_FRAGMENT_HEADER IPV6_FRAGMENT_HEADER;
+typedef struct IPV6_PSEUDO_HEADER IPV6_PSEUDO_HEADER;
+typedef struct ICMPV6_ROUTER_SOLICIATION_HEADER ICMPV6_ROUTER_SOLICIATION_HEADER;
+typedef struct ICMPV6_ROUTER_ADVERTISEMENT_HEADER ICMPV6_ROUTER_ADVERTISEMENT_HEADER;
+typedef struct ICMPV6_NEIGHBOR_SOLICIATION_HEADER ICMPV6_NEIGHBOR_SOLICIATION_HEADER;
+typedef struct ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER;
+typedef struct ICMPV6_OPTION_LIST ICMPV6_OPTION_LIST;
+typedef struct ICMPV6_OPTION ICMPV6_OPTION;
+typedef struct ICMPV6_OPTION_LINK_LAYER ICMPV6_OPTION_LINK_LAYER;
+typedef struct ICMPV6_OPTION_PREFIX ICMPV6_OPTION_PREFIX;
+typedef struct ICMPV6_OPTION_MTU ICMPV6_OPTION_MTU;
+typedef struct IPV6_HEADER_INFO IPV6_HEADER_INFO;
+typedef struct ICMPV6_HEADER_INFO ICMPV6_HEADER_INFO;
+
+
+// ==============================================================
+//  Console
+// ==============================================================
+
+typedef struct PARAM PARAM;
+typedef struct PARAM_VALUE PARAM_VALUE;
+typedef struct CONSOLE CONSOLE;
+typedef struct LOCAL_CONSOLE_PARAM LOCAL_CONSOLE_PARAM;
+typedef struct CMD CMD;
+typedef struct CMD_EVAL_MIN_MAX CMD_EVAL_MIN_MAX;
+
+
+// ==============================================================
+//  Command
+// ==============================================================
+
+typedef struct PS PS;
+typedef struct PC PC;
+typedef struct CT CT;
+typedef struct CTC CTC;
+typedef struct CTR CTR;
+typedef struct TTC TTC;
+typedef struct TTS TTS;
+typedef struct TT_RESULT TT_RESULT;
+typedef struct TTS_SOCK TTS_SOCK;
+typedef struct TTC_SOCK TTC_SOCK;
+typedef struct PT PT;
+
+// ==============================================================
+//  EtherLogger
+// ==============================================================
+
+typedef struct EL EL;
+typedef struct EL_DEVICE EL_DEVICE;
+typedef struct EL_LICENSE_STATUS EL_LICENSE_STATUS;
+typedef struct RPC_ADD_DEVICE RPC_ADD_DEVICE;
+typedef struct RPC_DELETE_DEVICE RPC_DELETE_DEVICE;
+typedef struct RPC_ENUM_DEVICE_ITEM RPC_ENUM_DEVICE_ITEM;
+typedef struct RPC_ENUM_DEVICE RPC_ENUM_DEVICE;
+typedef struct RPC_EL_LICENSE_STATUS RPC_EL_LICENSE_STATUS;
+
+
+// ==============================================================
+//  Database
+// ==============================================================
+
+typedef struct LICENSE_SYSTEM LICENSE_SYSTEM;
+typedef struct LICENSE_DATA LICENSE_DATA;
+typedef struct LICENSE LICENSE;
+typedef struct LICENSE_STATUS LICENSE_STATUS;
+
+
+
+
+#endif	// CEDARTYPE_H
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Client.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Client.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Client.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,9916 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Client.c
+// クライアントマネージャ
+
+#include "CedarPch.h"
+
+static CLIENT *client = NULL;
+static LISTENER *cn_listener = NULL;
+static LOCK *cn_listener_lock = NULL;
+static UINT64 cn_next_allow = 0;
+
+#ifdef	OS_WIN32
+
+#endif	// OS_WIN32
+
+// 注意: VPN Client サービスを実装するこのソースコードの一部には、
+// リエントラント (Reentrant: 再入可能) でないコードが含まれている。
+// もともと VPN Client のサービスと GUI (クライアント接続マネージャ) は一体
+// のものとして開発され、途中で分離された。その際に本来であれば TLS 等を用いて
+// スレッドセーフにしなければならない部分が、もとのままになってしまっている。
+// したがって、ごくまれに、GUI (クライアント接続マネージャ) や utvpncmd が
+// 複数個、1 個の VPN Client サービスに対して接続して、ほぼ同時に何らかの
+// 内部状態を変化させる処理を行ったとき、戻り値に不整合が生じる場合がある。
+
+// RPC_CLIENT_ENUM_ACCOUNT_ITEM を最終接続日時で逆ソート
+int CiCompareClientAccountEnumItemByLastConnectDateTime(void *p1, void *p2)
+{
+	RPC_CLIENT_ENUM_ACCOUNT_ITEM *a1, *a2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	a1 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p1;
+	a2 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p2;
+	if (a1 == NULL || a2 == NULL)
+	{
+		return 0;
+	}
+	if (a1->LastConnectDateTime > a2->LastConnectDateTime)
+	{
+		return -1;
+	}
+	else if (a1->LastConnectDateTime < a2->LastConnectDateTime)
+	{
+		return 1;
+	}
+
+	return 0;
+}
+
+// マシンが変更されていた場合はすべての仮想 LAN カードの MAC アドレスを乱数に設定する
+// このあたりは急いで実装したのでコードがあまり美しくない。
+// Q. なぜこのような処理が必要なのか?
+// A. Windows をインストールし、次に VPN Client をインストールして仮想 LAN カード
+//    を作成した状態を初期状態として HDD イメージをクローンし社内の複数の PC に
+//    インストールするような企業が存在する。
+//    そのような企業においてクローン後も仮想 LAN カードの MAC アドレスがすべて同一
+//    であれば障害の理由になる可能性があるためである。
+void CiChangeAllVLanMacAddressIfMachineChanged(CLIENT *c)
+{
+	UCHAR current_hash[SHA1_SIZE];
+	UCHAR current_hash_old[SHA1_SIZE];
+	UCHAR saved_hash[SHA1_SIZE];
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+#ifdef OS_WIN32
+	if (MsIsAdmin() == false)
+	{
+		return;
+	}
+#endif
+
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	CiGetCurrentMachineHash(current_hash);
+	CiGetCurrentMachineHashOld(current_hash_old);
+
+	if (CiReadLastMachineHash(saved_hash) == false)
+	{
+		CiWriteLastMachineHash(current_hash);
+		return;
+	}
+
+	if (Cmp(saved_hash, current_hash_old, SHA1_SIZE) == 0)
+	{
+		CiWriteLastMachineHash(current_hash);
+		return;
+	}
+
+	if (Cmp(saved_hash, current_hash, SHA1_SIZE) == 0)
+	{
+		return;
+	}
+
+	if (CiWriteLastMachineHash(current_hash) == false)
+	{
+		return;
+	}
+
+	CiChangeAllVLanMacAddress(c);
+}
+
+// 現在のマシンハッシュを取得する (古い方式)
+// このあたりは急いで実装したのでコードがあまり美しくない。
+void CiGetCurrentMachineHashOld(void *data)
+{
+	char name[MAX_PATH];
+	char *product_id = NULL;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	// プロダクト ID
+	product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductId");
+	if (product_id == NULL)
+	{
+		product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", "ProductId");
+	}
+
+	StrCpy(name, sizeof(name), product_id);
+
+	Free(product_id);
+
+#else	// OS_WIN32
+	GetMachineName(name, sizeof(name));
+#endif	// OS_WIN32
+
+	Trim(name);
+	StrUpper(name);
+
+	Hash(data, name, StrLen(name), true);
+}
+
+// 現在のマシンハッシュを取得する
+void CiGetCurrentMachineHash(void *data)
+{
+	char name[MAX_PATH];
+	char *product_id = NULL;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return;
+	}
+
+	GetMachineName(name, sizeof(name));
+
+	Trim(name);
+	StrUpper(name);
+
+	Hash(data, name, StrLen(name), true);
+}
+
+// マシンハッシュを書き込む
+bool CiWriteLastMachineHash(void *data)
+{
+	// 引数チェック
+	if (data == NULL)
+	{
+		return false;
+	}
+
+#ifdef OS_WIN32
+	if (MsRegWriteBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash_UTVPNClient", data, SHA1_SIZE, true) == false)
+	{
+		return false;
+	}
+
+	return true;
+#else	// OS_WIN32
+	return false;
+#endif	// OS_WIN32
+}
+
+// 前回のマシンハッシュを取得する
+bool CiReadLastMachineHash(void *data)
+{
+	BUF *b = NULL;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return false;
+	}
+
+#ifdef OS_WIN32
+	b = MsRegReadBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash_UTVPNClient", true);
+	if (b == NULL)
+	{
+		return false;
+	}
+	if (b->Size == SHA1_SIZE)
+	{
+		Copy(data, b->Buf, b->Size);
+		FreeBuf(b);
+
+		return true;
+	}
+
+	FreeBuf(b);
+	return false;
+#else	// OS_WIN32
+	return false;
+#endif	// OS_WIN32
+}
+
+// すべての仮想 LAN カードの MAC アドレスを乱数に設定する
+void CiChangeAllVLanMacAddress(CLIENT *c)
+{
+	RPC_CLIENT_ENUM_VLAN t;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CtEnumVLan(c, &t))
+	{
+		UINT i;
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_CLIENT_ENUM_VLAN_ITEM *e = t.Items[i];
+			UCHAR mac[6];
+
+			if (StrToMac(mac, e->MacAddress) && mac[1] == 0xAC)
+			{
+				char *name = e->DeviceName;
+				RPC_CLIENT_SET_VLAN s;
+				UCHAR mac[6];
+
+				GenMacAddress(mac);
+
+				Zero(&s, sizeof(s));
+				StrCpy(s.DeviceName, sizeof(s.DeviceName), name);
+
+				MacToStr(s.MacAddress, sizeof(s.MacAddress), mac);
+
+				CtSetVLan(c, &s);
+			}
+		}
+
+		CiFreeClientEnumVLan(&t);
+	}
+}
+
+// 通知サービスの準備が完了するまで待機する
+void CnWaitForCnServiceReady()
+{
+	UINT64 start_time = Tick64();
+
+	while ((start_time + (UINT64)CLIENT_WAIT_CN_READY_TIMEOUT) >= Tick64())
+	{
+		if (CnIsCnServiceReady())
+		{
+			break;
+		}
+
+		SleepThread(100);
+	}
+}
+
+// 通知サービスの準備が完了しているかどうかチェックする
+// このあたりは急いで実装したのでコードがあまり美しくない。
+bool CnIsCnServiceReady()
+{
+	SOCK *s;
+	// 通知サービスの起動を確認する
+	if (CnCheckAlreadyExists(false) == false)
+	{
+		// 起動していない
+		return false;
+	}
+
+	// TCP ポートへの接続を試行する
+	s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, 500);
+	if (s == NULL)
+	{
+		// TCP ポートを開いていない
+		return false;
+	}
+
+	Disconnect(s);
+	ReleaseSock(s);
+
+	// 起動していた
+	return true;
+}
+
+// すでに通知サービスが動作しているかどうかチェックする
+bool CnCheckAlreadyExists(bool lock)
+{
+	bool ret = false;
+
+#ifdef	OS_WIN32
+	ret = Win32CnCheckAlreadyExists(lock);
+#endif
+
+	return ret;
+}
+
+typedef struct CNC_STATUS_PRINTER_WINDOW_PARAM
+{
+	THREAD *Thread;
+	SESSION *Session;
+	SOCK *Sock;
+} CNC_STATUS_PRINTER_WINDOW_PARAM;
+
+typedef struct CNC_CONNECT_ERROR_DLG_THREAD_PARAM
+{
+	SESSION *Session;
+	SOCK *Sock;
+	bool HaltThread;
+	EVENT *Event;
+} CNC_CONNECT_ERROR_DLG_THREAD_PARAM;
+
+
+// Win32 における utvpnclient.exe のファイル名を取得する
+char *CiGetVpnClientExeFileName()
+{
+	if (Is64() == false)
+	{
+		return CLIENT_WIN32_EXE_FILENAME;
+	}
+	else
+	{
+		if (IsX64())
+		{
+			return CLIENT_WIN32_EXE_FILENAME_X64;
+		}
+		else
+		{
+			return CLIENT_WIN32_EXE_FILENAME_IA64;
+		}
+	}
+}
+
+// 証明書チェックダイアログクライアント強制停止用スレッド
+void CncCheckCertHaltThread(THREAD *thread, void *param)
+{
+	CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		if (dp->Session->Halt || dp->HaltThread)
+		{
+			break;
+		}
+
+		Wait(dp->Event, 100);
+	}
+
+	Disconnect(dp->Sock);
+}
+
+// 証明書チェックダイアログの表示
+void CncCheckCert(SESSION *session, UI_CHECKCERT *dlg)
+{
+	SOCK *s;
+	PACK *p;
+	CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+	THREAD *t;
+	// 引数チェック
+	if (dlg == NULL || session == NULL)
+	{
+		return;
+	}
+
+	s = CncConnect();
+	if (s == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "check_cert");
+	PackAddUniStr(p, "AccountName", dlg->AccountName);
+	PackAddStr(p, "ServerName", dlg->ServerName);
+	PackAddX(p, "x", dlg->x);
+	PackAddX(p, "parent_x", dlg->parent_x);
+	PackAddX(p, "old_x", dlg->old_x);
+	PackAddBool(p, "DiffWarning", dlg->DiffWarning);
+	PackAddBool(p, "Ok", dlg->Ok);
+	PackAddBool(p, "SaveServerCert", dlg->SaveServerCert);
+
+	SendPack(s, p);
+	FreePack(p);
+
+	dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+	dp->Sock = s;
+	dp->Event = NewEvent();
+	dp->Session = session;
+
+	t = NewThread(CncCheckCertHaltThread, dp);
+
+	p = RecvPack(s);
+	if (p != NULL)
+	{
+		dlg->Ok = PackGetBool(p, "Ok");
+		dlg->DiffWarning = PackGetBool(p, "DiffWarning");
+		dlg->SaveServerCert = PackGetBool(p, "SaveServerCert");
+
+		FreePack(p);
+	}
+
+	dp->HaltThread = true;
+	Set(dp->Event);
+
+	WaitThread(t, INFINITE);
+
+	ReleaseEvent(dp->Event);
+	Free(dp);
+	ReleaseThread(t);
+
+	Disconnect(s);
+	ReleaseSock(s);
+}
+
+// スマートカード署名ダイアログ
+bool CncSecureSignDlg(SECURE_SIGN *sign)
+{
+	SOCK *s;
+	PACK *p;
+	bool ret = false;
+	// 引数チェック
+	if (sign == NULL)
+	{
+		return false;
+	}
+
+	s = CncConnect();
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "secure_sign");
+	OutRpcSecureSign(p, sign);
+
+	SendPack(s, p);
+	FreePack(p);
+
+	p = RecvPack(s);
+	if (p != NULL)
+	{
+		ret = PackGetBool(p, "ret");
+
+		if (ret)
+		{
+			FreeRpcSecureSign(sign);
+
+			Zero(sign, sizeof(SECURE_SIGN));
+			InRpcSecureSign(sign, p);
+		}
+
+		FreePack(p);
+	}
+
+	Disconnect(s);
+	ReleaseSock(s);
+
+	return ret;
+}
+
+// NIC 情報ダイアログの表示
+SOCK *CncNicInfo(UI_NICINFO *info)
+{
+	SOCK *s;
+	PACK *p;
+	bool ret = false;
+	// 引数チェック
+	if (info == NULL)
+	{
+		return NULL;
+	}
+
+	s = CncConnectEx(200);
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "nicinfo");
+	PackAddStr(p, "NicName", info->NicName);
+	PackAddUniStr(p, "AccountName", info->AccountName);
+
+	SendPack(s, p);
+	FreePack(p);
+
+	return s;
+}
+
+// NIC 情報ダイアログを閉じる
+void CncNicInfoFree(SOCK *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Disconnect(s);
+	ReleaseSock(s);
+}
+
+// メッセージダイアログの表示
+SOCK *CncMsgDlg(UI_MSG_DLG *dlg)
+{
+	SOCK *s;
+	PACK *p;
+	bool ret = false;
+	char *utf;
+	// 引数チェック
+	if (dlg == NULL)
+	{
+		return NULL;
+	}
+
+	s = CncConnectEx(200);
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "msg_dialog");
+	PackAddStr(p, "ServerName", dlg->ServerName);
+	PackAddStr(p, "HubName", dlg->HubName);
+	utf = CopyUniToUtf(dlg->Msg);
+	PackAddData(p, "Msg", utf, StrLen(utf));
+	Free(utf);
+
+	SendPack(s, p);
+	FreePack(p);
+
+	return s;
+}
+
+// メッセージダイアログを閉じる
+void CndMsgDlgFree(SOCK *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Disconnect(s);
+	ReleaseSock(s);
+}
+
+// パスワード入力ダイアログクライアント強制停止用スレッド
+void CncPasswordDlgHaltThread(THREAD *thread, void *param)
+{
+	CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		if (dp->Session->Halt || dp->HaltThread)
+		{
+			break;
+		}
+
+		Wait(dp->Event, 100);
+	}
+
+	Disconnect(dp->Sock);
+}
+
+// パスワード入力ダイアログの表示
+bool CncPasswordDlg(SESSION *session, UI_PASSWORD_DLG *dlg)
+{
+	SOCK *s;
+	PACK *p;
+	CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+	THREAD *t;
+	bool ret = false;
+	// 引数チェック
+	if (dlg == NULL || session == NULL)
+	{
+		return false;
+	}
+
+	s = CncConnect();
+	if (s == NULL)
+	{
+		Wait(session->HaltEvent, session->RetryInterval);
+		return true;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "password_dialog");
+	PackAddInt(p, "Type", dlg->Type);
+	PackAddStr(p, "Username", dlg->Username);
+	PackAddStr(p, "Password", dlg->Password);
+	PackAddStr(p, "ServerName", dlg->ServerName);
+	PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec);
+	PackAddBool(p, "ProxyServer", dlg->ProxyServer);
+	PackAddBool(p, "AdminMode", dlg->AdminMode);
+	PackAddBool(p, "ShowNoSavePassword", dlg->ShowNoSavePassword);
+	PackAddBool(p, "NoSavePassword", dlg->NoSavePassword);
+
+	SendPack(s, p);
+	FreePack(p);
+
+	dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+	dp->Session = session;
+	dp->Sock = s;
+	dp->Event = NewEvent();
+
+	t = NewThread(CncConnectErrorDlgHaltThread, dp);
+
+	p = RecvPack(s);
+	if (p != NULL)
+	{
+		ret = PackGetBool(p, "ok");
+		dlg->NoSavePassword = PackGetBool(p, "NoSavePassword");
+		dlg->ProxyServer = PackGetBool(p, "ProxyServer");
+		dlg->Type = PackGetInt(p, "Type");
+		PackGetStr(p, "Username", dlg->Username, sizeof(dlg->Username));
+		PackGetStr(p, "Password", dlg->Password, sizeof(dlg->Password));
+
+		FreePack(p);
+	}
+
+	dp->HaltThread = true;
+	Set(dp->Event);
+
+	WaitThread(t, INFINITE);
+
+	ReleaseEvent(dp->Event);
+	Free(dp);
+	ReleaseThread(t);
+
+	Disconnect(s);
+	ReleaseSock(s);
+
+	return ret;
+}
+
+// 接続エラーダイアログクライアント強制停止用スレッド
+void CncConnectErrorDlgHaltThread(THREAD *thread, void *param)
+{
+	CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		if (dp->Session->Halt || dp->HaltThread)
+		{
+			break;
+		}
+
+		Wait(dp->Event, 100);
+	}
+
+	Disconnect(dp->Sock);
+}
+
+// 接続エラーダイアログの表示
+bool CncConnectErrorDlg(SESSION *session, UI_CONNECTERROR_DLG *dlg)
+{
+	SOCK *s;
+	PACK *p;
+	CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+	THREAD *t;
+	bool ret = false;
+	// 引数チェック
+	if (dlg == NULL || session == NULL)
+	{
+		return false;
+	}
+
+	s = CncConnect();
+	if (s == NULL)
+	{
+		Wait(session->HaltEvent, session->RetryInterval);
+		return true;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "connecterror_dialog");
+	PackAddUniStr(p, "AccountName", dlg->AccountName);
+	PackAddStr(p, "ServerName", dlg->ServerName);
+	PackAddInt(p, "Err", dlg->Err);
+	PackAddInt(p, "CurrentRetryCount", dlg->CurrentRetryCount);
+	PackAddInt(p, "RetryLimit", dlg->RetryLimit);
+	PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec);
+	PackAddBool(p, "HideWindow", dlg->HideWindow);
+
+	SendPack(s, p);
+	FreePack(p);
+
+	dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+	dp->Session = session;
+	dp->Sock = s;
+	dp->Event = NewEvent();
+
+	t = NewThread(CncConnectErrorDlgHaltThread, dp);
+
+	p = RecvPack(s);
+	if (p != NULL)
+	{
+		ret = PackGetBool(p, "ok");
+		dlg->HideWindow = PackGetBool(p, "HideWindow");
+
+		FreePack(p);
+	}
+
+	dp->HaltThread = true;
+	Set(dp->Event);
+
+	WaitThread(t, INFINITE);
+
+	ReleaseEvent(dp->Event);
+	Free(dp);
+	ReleaseThread(t);
+
+	Disconnect(s);
+	ReleaseSock(s);
+
+	return ret;
+}
+
+// ステータス表示器クライアント用スレッド
+void CncStatusPrinterWindowThreadProc(THREAD *thread, void *param)
+{
+	CNC_STATUS_PRINTER_WINDOW_PARAM *pp;
+	SOCK *sock;
+	PACK *p;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	pp = (CNC_STATUS_PRINTER_WINDOW_PARAM *)param;
+	sock = pp->Sock;
+	pp->Thread = thread;
+	AddRef(pp->Thread->ref);
+
+	NoticeThreadInit(thread);
+
+	p = RecvPack(sock);
+	if (p != NULL)
+	{
+		// セッションを停止する
+		StopSessionEx(pp->Session, true);
+
+		FreePack(p);
+	}
+}
+
+// ステータス表示器クライアントの作成
+SOCK *CncStatusPrinterWindowStart(SESSION *s)
+{
+	SOCK *sock;
+	PACK *p;
+	THREAD *t;
+	CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	sock = CncConnect();
+
+	if (sock == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "status_printer");
+	PackAddUniStr(p, "account_name", s->Account->ClientOption->AccountName);
+
+	if (SendPack(sock, p) == false)
+	{
+		FreePack(p);
+		ReleaseSock(sock);
+
+		return NULL;
+	}
+
+	FreePack(p);
+
+	param = ZeroMalloc(sizeof(CNC_STATUS_PRINTER_WINDOW_PARAM));
+	param->Sock = sock;
+	param->Session = s;
+
+	sock->Param = param;
+
+	t = NewThread(CncStatusPrinterWindowThreadProc, param);
+	WaitThreadInit(t);
+
+	ReleaseThread(t);
+
+	return sock;
+}
+
+// ステータス表示器に対して文字列を送信
+void CncStatusPrinterWindowPrint(SOCK *s, wchar_t *str)
+{
+	CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || str == NULL)
+	{
+		return;
+	}
+
+	param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param;
+
+	p = NewPack();
+	PackAddUniStr(p, "string", str);
+	SendPack(s, p);
+	FreePack(p);
+}
+
+// ステータス表示器クライアントの停止
+void CncStatusPrinterWindowStop(SOCK *s)
+{
+	CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param;
+
+	// クライアントソケット切断
+	Disconnect(s);
+
+	// スレッド終了
+	WaitThread(param->Thread, INFINITE);
+	ReleaseThread(param->Thread);
+
+	Free(param);
+	ReleaseSock(s);
+}
+
+// Windows Vista 用のドライバインストーラの起動
+bool CncExecDriverInstaller(char *arg)
+{
+	SOCK *s = CncConnect();
+	PACK *p;
+	bool ret;
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "exec_driver_installer");
+	PackAddStr(p, "arg", arg);
+
+	SendPack(s, p);
+	FreePack(p);
+
+	p = RecvPack(s);
+	if (p == NULL)
+	{
+		Disconnect(s);
+		ReleaseSock(s);
+		return false;
+	}
+
+	ret = PackGetBool(p, "ret");
+
+	FreePack(p);
+
+	Disconnect(s);
+	ReleaseSock(s);
+
+	return ret;
+}
+
+// 現在動作しているクライアント通知サービスにソケットを解放させる
+void CncReleaseSocket()
+{
+	SOCK *s = CncConnect();
+	PACK *p;
+	if (s == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "release_socket");
+
+#ifdef OS_WIN32
+	PackAddInt(p, "pid", MsGetProcessId());
+#endif	// OS_WIN32
+
+	SendPack(s, p);
+	FreePack(p);
+
+	Disconnect(s);
+	ReleaseSock(s);
+}
+
+// クライアント通知サービスのセッション ID の取得
+UINT CncGetSessionId()
+{
+	SOCK *s = CncConnect();
+	PACK *p;
+	UINT ret;
+	if (s == NULL)
+	{
+		return INFINITE;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "function", "get_session_id");
+
+	SendPack(s, p);
+	FreePack(p);
+
+	p = RecvPack(s);
+	if (p == NULL)
+	{
+		Disconnect(s);
+		ReleaseSock(s);
+		return INFINITE;
+	}
+
+	ret = PackGetInt(p, "session_id");
+
+	FreePack(p);
+
+	Disconnect(s);
+	ReleaseSock(s);
+
+	return ret;
+}
+
+// クライアント通知サービスのプロセスの終了
+void CncExit()
+{
+	SOCK *s = CncConnectEx(256);
+	PACK *p;
+	if (s != NULL)
+	{
+		p = NewPack();
+		PackAddStr(p, "function", "exit");
+
+		SendPack(s, p);
+
+		FreePack(p);
+
+		FreePack(RecvPack(s));
+
+		Disconnect(s);
+		ReleaseSock(s);
+	}
+
+#ifdef	OS_WIN32
+	MsKillOtherInstanceEx("utvpnclient");
+#endif	// OS_WIN32
+}
+
+// クライアント通知サービスへの接続
+SOCK *CncConnect()
+{
+	return CncConnectEx(0);
+}
+SOCK *CncConnectEx(UINT timeout)
+{
+	SOCK *s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, timeout);
+
+	return s;
+}
+
+#ifdef	OS_WIN32
+
+// 証明書チェックダイアログ用スレッド
+void Win32CnCheckCertThreadProc(THREAD *thread, void *param)
+{
+	UI_CHECKCERT *dlg;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	dlg = (UI_CHECKCERT *)param;
+
+	CheckCertDlg(dlg);
+	{
+		PACK *p = NewPack();
+
+		PackAddBool(p, "Ok", dlg->Ok);
+		PackAddBool(p, "SaveServerCert", dlg->SaveServerCert);
+
+		SendPack(dlg->Sock, p);
+		FreePack(p);
+
+		FreePack(RecvPack(dlg->Sock));
+	}
+
+	Disconnect(dlg->Sock);
+}
+
+// 証明書チェックダイアログ
+void Win32CnCheckCert(SOCK *s, PACK *p)
+{
+	UI_CHECKCERT dlg;
+	THREAD *t;
+	Zero(&dlg, sizeof(dlg));
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName));
+	PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+	dlg.x = PackGetX(p, "x");
+	dlg.parent_x = PackGetX(p, "parent_x");
+	dlg.old_x = PackGetX(p, "old_x");
+	dlg.DiffWarning = PackGetBool(p, "DiffWarning");
+	dlg.Ok = PackGetBool(p, "Ok");
+	dlg.SaveServerCert = PackGetBool(p, "SaveServerCert");
+	dlg.Sock = s;
+
+	t = NewThread(Win32CnCheckCertThreadProc, &dlg);
+
+	FreePack(RecvPack(s));
+
+	dlg.Halt = true;
+
+	WaitThread(t, INFINITE);
+	ReleaseThread(t);
+
+	FreeX(dlg.parent_x);
+	FreeX(dlg.old_x);
+	FreeX(dlg.x);
+}
+
+// メッセージ表示ダイアログスレッドプロシージャ
+void Win32CnMsgDlgThreadProc(THREAD *thread, void *param)
+{
+	UI_MSG_DLG *dlg = (UI_MSG_DLG *)param;
+	wchar_t tmp[MAX_SIZE];
+	char url[MAX_SIZE];
+	// 引数チェック
+	if (thread == NULL || dlg == NULL)
+	{
+		return;
+	}
+
+	UniFormat(tmp, sizeof(tmp), _UU("CM_MSG_TITLE"),
+		dlg->ServerName, dlg->HubName);
+
+	if (IsURLMsg(dlg->Msg, url, sizeof(url)) == false)
+	{
+		OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt);
+	}
+	else
+	{
+		if (MsExecute(url, NULL) == false)
+		{
+			OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt);
+		}
+	}
+
+	Disconnect(dlg->Sock);
+}
+
+// NIC 情報ダイアログスレッドプロシージャ
+void Win32CnNicInfoThreadProc(THREAD *thread, void *param)
+{
+	UI_NICINFO *info = (UI_NICINFO *)param;
+	// 引数チェック
+	if (thread == NULL || info == NULL)
+	{
+		return;
+	}
+
+	if (MsIsNt())
+	{
+		// Windows 9x 系ではダイアログを表示しない
+		NicInfo(info);
+	}
+
+	Disconnect(info->Sock);
+}
+
+// NIC 情報ダイアログ
+void Win32CnNicInfo(SOCK *s, PACK *p)
+{
+	UI_NICINFO info;
+	THREAD *t;
+	Zero(&info, sizeof(info));
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackGetStr(p, "NicName", info.NicName, sizeof(info.NicName));
+	PackGetUniStr(p, "AccountName", info.AccountName, sizeof(info.AccountName));
+
+	info.Sock = s;
+
+	t = NewThread(Win32CnNicInfoThreadProc, &info);
+
+	FreePack(RecvPack(s));
+
+	info.Halt = true;
+
+	WaitThread(t, INFINITE);
+	ReleaseThread(t);
+}
+
+// メッセージ表示ダイアログ
+void Win32CnMsgDlg(SOCK *s, PACK *p)
+{
+	UI_MSG_DLG dlg;
+	THREAD *t;
+	UINT utf_size;
+	char *utf;
+	wchar_t *msg;
+	Zero(&dlg, sizeof(dlg));
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+	PackGetStr(p, "HubName", dlg.HubName, sizeof(dlg.HubName));
+
+	utf_size = PackGetDataSize(p, "Msg");
+	utf = ZeroMalloc(utf_size + 8);
+
+	PackGetData(p, "Msg", utf);
+
+	msg = CopyUtfToUni(utf);
+	Free(utf);
+
+	dlg.Sock = s;
+	dlg.Msg = msg;
+
+	t = NewThread(Win32CnMsgDlgThreadProc, &dlg);
+
+	FreePack(RecvPack(s));
+
+	dlg.Halt = true;
+
+	WaitThread(t, INFINITE);
+	ReleaseThread(t);
+
+	Free(msg);
+}
+
+// パスワード入力ダイアログ用スレッド
+void Win32CnPasswordDlgThreadProc(THREAD *thread, void *param)
+{
+	UI_PASSWORD_DLG *dlg;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	dlg = (UI_PASSWORD_DLG *)param;
+
+	if (PasswordDlg(NULL, dlg))
+	{
+		PACK *p = NewPack();
+
+		PackAddBool(p, "ok", true);
+		PackAddStr(p, "Username", dlg->Username);
+		PackAddStr(p, "Password", dlg->Password);
+		PackAddInt(p, "Type", dlg->Type);
+		PackAddBool(p, "ProxyServer", dlg->ProxyServer);
+		PackAddBool(p, "NoSavePassword", dlg->NoSavePassword);
+
+		SendPack(dlg->Sock, p);
+		FreePack(p);
+
+		FreePack(RecvPack(dlg->Sock));
+	}
+
+	Disconnect(dlg->Sock);
+}
+
+// パスワード入力ダイアログ
+void Win32CnPasswordDlg(SOCK *s, PACK *p)
+{
+	UI_PASSWORD_DLG dlg;
+	THREAD *t = NULL;
+	Zero(&dlg, sizeof(dlg));
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	dlg.Type = PackGetInt(p, "Type");
+	PackGetStr(p, "Username", dlg.Username, sizeof(dlg.Username));
+	PackGetStr(p, "Password", dlg.Password, sizeof(dlg.Password));
+	PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+	dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec");
+	dlg.ProxyServer = PackGetBool(p, "ProxyServer");
+	dlg.AdminMode = PackGetBool(p, "AdminMode");
+	dlg.ShowNoSavePassword = PackGetBool(p, "ShowNoSavePassword");
+	dlg.NoSavePassword = PackGetBool(p, "NoSavePassword");
+	dlg.CancelEvent = NewEvent();
+	dlg.Sock = s;
+
+	t = NewThread(Win32CnPasswordDlgThreadProc, &dlg);
+
+	FreePack(RecvPack(s));
+
+	Set(dlg.CancelEvent);
+
+	WaitThread(t, INFINITE);
+	ReleaseEvent(dlg.CancelEvent);
+	ReleaseThread(t);
+}
+
+// 接続エラーダイアログ用スレッド
+void Win32CnConnectErrorDlgThreadProc(THREAD *thread, void *param)
+{
+	UI_CONNECTERROR_DLG *dlg;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	dlg = (UI_CONNECTERROR_DLG *)param;
+
+	if (ConnectErrorDlg(dlg))
+	{
+		PACK *p = NewPack();
+
+		PackAddBool(p, "ok", true);
+		PackAddBool(p, "HideWindow", dlg->HideWindow);
+
+		SendPack(dlg->Sock, p);
+		FreePack(p);
+
+		FreePack(RecvPack(dlg->Sock));
+	}
+
+	Disconnect(dlg->Sock);
+}
+
+// 接続エラーダイアログ (Win32)
+void Win32CnConnectErrorDlg(SOCK *s, PACK *p)
+{
+	UI_CONNECTERROR_DLG dlg;
+	THREAD *t;
+	Zero(&dlg, sizeof(dlg));
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName));
+	PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+	dlg.Err = PackGetInt(p, "Err");
+	dlg.CurrentRetryCount = PackGetInt(p, "CurrentRetryCount");
+	dlg.RetryLimit = PackGetInt(p, "RetryLimit");
+	dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec");
+	dlg.HideWindow = PackGetBool(p, "HideWindow");
+	dlg.CancelEvent = NewEvent();
+	dlg.Sock = s;
+
+	t = NewThread(Win32CnConnectErrorDlgThreadProc, &dlg);
+
+	FreePack(RecvPack(s));
+
+	Set(dlg.CancelEvent);
+
+	WaitThread(t, INFINITE);
+	ReleaseEvent(dlg.CancelEvent);
+	ReleaseThread(t);
+}
+
+// ステータス表示器 (Win32)
+void Win32CnStatusPrinter(SOCK *s, PACK *p)
+{
+	STATUS_WINDOW *w;
+	wchar_t account_name[MAX_ACCOUNT_NAME_LEN + 1];
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackGetUniStr(p, "account_name", account_name, sizeof(account_name));
+
+	w = StatusPrinterWindowStart(s, account_name);
+
+	while (true)
+	{
+		PACK *p = RecvPack(s);
+
+		if (p == NULL)
+		{
+			// 切断されたのでダイアログを終了する
+			break;
+		}
+		else
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			// 文字列を書き換える
+			PackGetUniStr(p, "string", tmp, sizeof(tmp));
+
+			StatusPrinterWindowPrint(w, tmp);
+
+			FreePack(p);
+		}
+	}
+
+	StatusPrinterWindowStop(w);
+}
+
+// ドライバインストーラの起動 (Windows Vista 用)
+void Win32CnExecDriverInstaller(SOCK *s, PACK *p)
+{
+	char arg[MAX_SIZE];
+	bool ret;
+	void *helper = NULL;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (PackGetStr(p, "arg", arg, sizeof(arg)) == false)
+	{
+		return;
+	}
+
+	if (MsIsVista())
+	{
+		helper = CmStartUacHelper();
+	}
+
+	ret = MsExecDriverInstaller(arg);
+
+	CmStopUacHelper(helper);
+
+	p = NewPack();
+	PackAddBool(p, "ret", ret);
+	SendPack(s, p);
+
+	FreePack(p);
+}
+
+#endif	// OS_WIN32
+
+// ドライバインストーラの起動
+void CnExecDriverInstaller(SOCK *s, PACK *p)
+{
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32CnExecDriverInstaller(s, p);
+#endif	// OS_WIN32
+}
+
+// 証明書確認ダイアログ
+void CnCheckCert(SOCK *s, PACK *p)
+{
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32CnCheckCert(s, p);
+#endif	// OS_WIN32
+}
+
+// NIC 情報ダイアログ
+void CnNicInfo(SOCK *s, PACK *p)
+{
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32CnNicInfo(s, p);
+#endif	// OS_WIN32
+}
+
+// メッセージ表示ダイアログ
+void CnMsgDlg(SOCK *s, PACK *p)
+{
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32CnMsgDlg(s, p);
+#endif	// OS_WIN32
+}
+
+// パスワード入力ダイアログ
+void CnPasswordDlg(SOCK *s, PACK *p)
+{
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32CnPasswordDlg(s, p);
+#endif	// OS_WIN32
+}
+
+// 接続エラーダイアログ
+void CnConnectErrorDlg(SOCK *s, PACK *p)
+{
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32CnConnectErrorDlg(s, p);
+#endif	// OS_WIN32
+}
+
+// ステータス表示器
+void CnStatusPrinter(SOCK *s, PACK *p)
+{
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32CnStatusPrinter(s, p);
+#endif	// OS_WIN32
+}
+
+// クライアント通知サービスリスナースレッド
+// このあたりは急いで実装したのでコードがあまり美しくない。
+void CnListenerProc(THREAD *thread, void *param)
+{
+	TCP_ACCEPTED_PARAM *data = (TCP_ACCEPTED_PARAM *)param;
+	SOCK *s;
+	PACK *p;
+	// 引数チェック
+	if (data == NULL || thread == NULL)
+	{
+		return;
+	}
+
+	s = data->s;
+	AddRef(s->ref);
+	NoticeThreadInit(thread);
+
+	if (s->LocalIP.addr[0] == 127)
+	{
+		p = RecvPack(s);
+
+		if (p != NULL)
+		{
+			char function[MAX_SIZE];
+
+			if (PackGetStr(p, "function", function, sizeof(function)))
+			{
+				if (StrCmpi(function, "status_printer") == 0)
+				{
+					CnStatusPrinter(s, p);
+				}
+				else if (StrCmpi(function, "connecterror_dialog") == 0)
+				{
+					CnConnectErrorDlg(s, p);
+				}
+				else if (StrCmpi(function, "msg_dialog") == 0)
+				{
+					CnMsgDlg(s, p);
+				}
+				else if (StrCmpi(function, "nicinfo") == 0)
+				{
+					CnNicInfo(s, p);
+				}
+				else if (StrCmpi(function, "password_dialog") == 0)
+				{
+					CnPasswordDlg(s, p);
+				}
+				else if (StrCmpi(function, "secure_sign") == 0)
+				{
+					CnSecureSign(s, p);
+				}
+				else if (StrCmpi(function, "check_cert") == 0)
+				{
+					CnCheckCert(s, p);
+				}
+				else if (StrCmpi(function, "exit") == 0)
+				{
+#ifdef	OS_WIN32
+					MsTerminateProcess();
+#else	// OS_WIN32
+					_exit(0);
+#endif	// OS_WIN32
+				}
+				else if (StrCmpi(function, "get_session_id") == 0)
+				{
+					PACK *p = NewPack();
+#ifdef	OS_WIN32
+					PackAddInt(p, "session_id", MsGetCurrentTerminalSessionId());
+#endif	// OS_WIN32
+					SendPack(s, p);
+					FreePack(p);
+				}
+				else if (StrCmpi(function, "exec_driver_installer") == 0)
+				{
+					CnExecDriverInstaller(s, p);
+				}
+				else if (StrCmpi(function, "release_socket") == 0)
+				{
+					// リスナーを停止する
+					CnReleaseSocket(s, p);
+				}
+			}
+
+			FreePack(p);
+		}
+	}
+
+	Disconnect(s);
+	ReleaseSock(s);
+}
+
+// Secure Sign を行う
+void CnSecureSign(SOCK *s, PACK *p)
+{
+	SECURE_SIGN sign;
+	bool ret = false;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(&sign, sizeof(sign));
+	InRpcSecureSign(&sign, p);
+
+#ifdef	OS_WIN32
+	// Win32: ダイアログを表示
+	ret = Win32CiSecureSign(&sign);
+#else	// OS_WIN32
+	// UNIX: 未実装
+	ret = false;
+#endif	// OS_WIN32
+
+	p = NewPack();
+
+	OutRpcSecureSign(p, &sign);
+	FreeRpcSecureSign(&sign);
+
+	PackAddBool(p, "ret", ret);
+
+	SendPack(s, p);
+	FreePack(p);
+}
+
+// リスナーを停止する
+void CnReleaseSocket(SOCK *s, PACK *p)
+{
+	UINT pid = 0;
+	UINT current_pid = 0;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	pid = PackGetInt(p, "pid");
+
+#ifdef	OS_WIN32
+	current_pid = MsGetProcessId();
+#endif	// OS_WIN32
+
+	if (current_pid == pid)
+	{
+		return;
+	}
+
+	Lock(cn_listener_lock);
+	{
+		if (cn_listener != NULL)
+		{
+			if (cn_listener->Halt == false)
+			{
+				StopListener(cn_listener);
+
+				cn_next_allow = Tick64() + (6 * 1000);
+			}
+		}
+	}
+	Unlock(cn_listener_lock);
+}
+
+// クライアント通知サービスの開始
+void CnStart()
+{
+	CEDAR *cedar;
+	LISTENER *o;
+	UINT last_cursor_hash = 0;
+	bool last_session_active = false;
+
+	cn_next_allow = 0;
+	cn_listener_lock = NewLock();
+
+#ifdef	OS_WIN32
+	MsSetShutdownParameters(0xff, 0x00000001);
+	InitWinUi(_UU("CN_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+#endif	// OS_WIN32
+
+	cedar = NewCedar(NULL, NULL);
+
+	if (CnCheckAlreadyExists(true))
+	{
+		// すでに起動している
+		ReleaseCedar(cedar);
+#ifdef	OS_WIN32
+		FreeWinUi();
+#endif	// OS_WIN32
+		return;
+	}
+
+#ifdef	OS_WIN32
+	MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY,
+		"NotifyServerProcessId", MsGetProcessId());
+#endif	// OS_WIN32
+
+BEGIN_LISTENER:
+	Lock(cn_listener_lock);
+	cn_listener = o = NewListenerEx(cedar, LISTENER_TCP, CLIENT_NOTIFY_PORT, CnListenerProc, NULL);
+	Unlock(cn_listener_lock);
+
+	while (true)
+	{
+		UINT current_cursor_hash = 0;
+		bool cursor_changed = false;
+
+#ifdef	OS_WIN32
+		// 現在のカーソル位置を取得
+		current_cursor_hash = MsGetCursorPosHash();
+#endif	// OS_WIN32
+
+		if (last_cursor_hash != current_cursor_hash)
+		{
+			// カーソル位置をチェック
+			cursor_changed = true;
+			last_cursor_hash = current_cursor_hash;
+		}
+
+		Lock(cn_listener_lock);
+
+		// リスナーが開始した後一定間隔で状態をチェックする
+		if (cn_listener->Status == LISTENER_STATUS_TRYING || cn_listener->Halt)
+		{
+			bool session_active = false;
+#ifdef	OS_WIN32
+			session_active = MsIsCurrentTerminalSessionActive();
+			if (cursor_changed)
+			{
+				// カーソル位置が変化してもターミナルセッションがアクティブでない
+				// 場合は変化していないものと見なす
+				if (session_active == false)
+				{
+					cursor_changed = false;
+				}
+			}
+			if (last_session_active != session_active)
+			{
+				// カーソルが変化していなくてもターミナルセッション
+				// 前回と比較してアクティブになった場合はカーソルが変化した
+				// ものとみなす
+				last_session_active = session_active;
+
+				if (session_active)
+				{
+					cursor_changed = true;
+				}
+			}
+#endif	// OS_WIN32
+
+			// ポートが開けない場合
+			if (cn_next_allow <= Tick64())
+			{
+				if (cursor_changed || cn_listener->Halt)
+				{
+					if (cursor_changed)
+					{
+						// マウスカーソルが移動しているので自分がポートを開く権利を持っている
+						// と判断できる。
+						// そこで、他のプロセスが持っているポートを強制的に奪う。
+						CncReleaseSocket();
+					}
+
+					if (cn_listener->Halt)
+					{
+						ReleaseListener(cn_listener);
+						cn_listener = NULL;
+
+						Unlock(cn_listener_lock);
+						goto BEGIN_LISTENER;
+					}
+				}
+			}
+		}
+
+		Unlock(cn_listener_lock);
+
+		SleepThread(1000);
+	}
+}
+
+// バッファからアカウント情報を読み込む
+RPC_CLIENT_CREATE_ACCOUNT *CiCfgToAccount(BUF *b)
+{
+	RPC_CLIENT_CREATE_ACCOUNT *t;
+	FOLDER *f;
+	ACCOUNT *a;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	f = CfgBufTextToFolder(b);
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	a = CiLoadClientAccount(f);
+
+	CfgDeleteFolder(f);
+
+	if (a == NULL)
+	{
+		return NULL;
+	}
+
+	DeleteLock(a->lock);
+
+	t = ZeroMalloc(sizeof(RPC_CLIENT_CREATE_ACCOUNT));
+	t->ClientOption = a->ClientOption;
+	t->ClientAuth = a->ClientAuth;
+	t->StartupAccount = a->StartupAccount;
+	t->CheckServerCert = a->CheckServerCert;
+	t->ServerCert = a->ServerCert;
+	Free(a);
+
+	return t;
+}
+
+// アカウント情報をバッファに書き出す
+BUF *CiAccountToCfg(RPC_CLIENT_CREATE_ACCOUNT *t)
+{
+	BUF *b;
+	FOLDER *root;
+	ACCOUNT a;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	root = CfgCreateFolder(NULL, TAG_ROOT);
+	Zero(&a, sizeof(a));
+	a.ClientOption = t->ClientOption;
+	a.ClientAuth = t->ClientAuth;
+	a.CheckServerCert = t->CheckServerCert;
+	a.ServerCert = t->ServerCert;
+	a.StartupAccount = t->StartupAccount;
+
+	CiWriteAccountData(root, &a);
+
+	b = CfgFolderToBufEx(root, true, true);
+	CfgDeleteFolder(root);
+
+	return b;
+}
+
+// RPC ディスパッチルーチン
+PACK *CiRpcDispatch(RPC *rpc, char *name, PACK *p)
+{
+	CLIENT *c = rpc->Param;
+	PACK *ret;
+	// 引数チェック
+	if (rpc == NULL || name == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	ret = NewPack();
+
+	if (StrCmpi(name, "GetClientVersion") == 0)
+	{
+		RPC_CLIENT_VERSION a;
+		if (CtGetClientVersion(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientVersion(ret, &a);
+		}
+	}
+	else if (StrCmpi(name, "GetCmSetting") == 0)
+	{
+		CM_SETTING a;
+		if (CtGetCmSetting(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcCmSetting(ret, &a);
+		}
+	}
+	else if (StrCmpi(name, "SetCmSetting") == 0)
+	{
+		CM_SETTING a;
+		Zero(&a, sizeof(a));
+		InRpcCmSetting(&a, p);
+		if (CtSetCmSetting(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "SetPassword") == 0)
+	{
+		RPC_CLIENT_PASSWORD a;
+		InRpcClientPassword(&a, p);
+		if (CtSetPassword(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "GetPasswordSetting") == 0)
+	{
+		RPC_CLIENT_PASSWORD_SETTING a;
+		if (CtGetPasswordSetting(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientPasswordSetting(ret, &a);
+		}
+	}
+	else if (StrCmpi(name, "EnumCa") == 0)
+	{
+		RPC_CLIENT_ENUM_CA a;
+		if (CtEnumCa(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientEnumCa(ret, &a);
+			CiFreeClientEnumCa(&a);
+		}
+	}
+	else if (StrCmpi(name, "AddCa") == 0)
+	{
+		RPC_CERT a;
+		InRpcCert(&a, p);
+		if (CtAddCa(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		FreeX(a.x);
+	}
+	else if (StrCmpi(name, "DeleteCa") == 0)
+	{
+		RPC_CLIENT_DELETE_CA a;
+		InRpcClientDeleteCa(&a, p);
+		if (CtDeleteCa(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "GetCa") == 0)
+	{
+		RPC_GET_CA a;
+		InRpcGetCa(&a, p);
+		if (CtGetCa(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcGetCa(ret, &a);
+		}
+		CiFreeGetCa(&a);
+	}
+	else if (StrCmpi(name, "EnumSecure") == 0)
+	{
+		RPC_CLIENT_ENUM_SECURE a;
+		if (CtEnumSecure(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientEnumSecure(ret, &a);
+			CiFreeClientEnumSecure(&a);
+		}
+	}
+	else if (StrCmpi(name, "UseSecure") == 0)
+	{
+		RPC_USE_SECURE a;
+		InRpcUseSecure(&a, p);
+		if (CtUseSecure(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "GetUseSecure") == 0)
+	{
+		RPC_USE_SECURE a;
+		Zero(&a, sizeof(a));
+		if (CtGetUseSecure(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcUseSecure(ret, &a);
+		}
+	}
+	else if (StrCmpi(name, "EnumObjectInSecure") == 0)
+	{
+		RPC_ENUM_OBJECT_IN_SECURE a;
+		if (CtEnumObjectInSecure(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcEnumObjectInSecure(ret, &a);
+			CiFreeEnumObjectInSecure(&a);
+		}
+	}
+	else if (StrCmpi(name, "CreateVLan") == 0)
+	{
+		RPC_CLIENT_CREATE_VLAN a;
+		InRpcCreateVLan(&a, p);
+		if (CtCreateVLan(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "UpgradeVLan") == 0)
+	{
+		RPC_CLIENT_CREATE_VLAN a;
+		InRpcCreateVLan(&a, p);
+		if (CtUpgradeVLan(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "GetVLan") == 0)
+	{
+		RPC_CLIENT_GET_VLAN a;
+		InRpcClientGetVLan(&a, p);
+		if (CtGetVLan(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientGetVLan(ret, &a);
+		}
+	}
+	else if (StrCmpi(name, "SetVLan") == 0)
+	{
+		RPC_CLIENT_SET_VLAN a;
+		InRpcClientSetVLan(&a, p);
+		if (CtSetVLan(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "EnumVLan") == 0)
+	{
+		RPC_CLIENT_ENUM_VLAN a;
+		if (CtEnumVLan(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientEnumVLan(ret, &a);
+			CiFreeClientEnumVLan(&a);
+		}
+	}
+	else if (StrCmpi(name, "DeleteVLan") == 0)
+	{
+		RPC_CLIENT_CREATE_VLAN a;
+		InRpcCreateVLan(&a, p);
+		if (CtDeleteVLan(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "EnableVLan") == 0)
+	{
+		RPC_CLIENT_CREATE_VLAN a;
+		InRpcCreateVLan(&a, p);
+		if (CtEnableVLan(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "DisableVLan") == 0)
+	{
+		RPC_CLIENT_CREATE_VLAN a;
+		InRpcCreateVLan(&a, p);
+		if (CtDisableVLan(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "CreateAccount") == 0)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT a;
+		InRpcClientCreateAccount(&a, p);
+		if (CtCreateAccount(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		CiFreeClientCreateAccount(&a);
+	}
+	else if (StrCmpi(name, "EnumAccount") == 0)
+	{
+		RPC_CLIENT_ENUM_ACCOUNT a;
+		if (CtEnumAccount(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientEnumAccount(ret, &a);
+			CiFreeClientEnumAccount(&a);
+		}
+	}
+	else if (StrCmpi(name, "DeleteAccount") == 0)
+	{
+		RPC_CLIENT_DELETE_ACCOUNT a;
+		InRpcClientDeleteAccount(&a, p);
+		if (CtDeleteAccount(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "SetStartupAccount") == 0)
+	{
+		RPC_CLIENT_DELETE_ACCOUNT a;
+		InRpcClientDeleteAccount(&a, p);
+		if (CtSetStartupAccount(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "RemoveStartupAccount") == 0)
+	{
+		RPC_CLIENT_DELETE_ACCOUNT a;
+		InRpcClientDeleteAccount(&a, p);
+		if (CtRemoveStartupAccount(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "GetIssuer") == 0)
+	{
+		RPC_GET_ISSUER a;
+		InRpcGetIssuer(&a, p);
+		if (CtGetIssuer(c, &a))
+		{
+			OutRpcGetIssuer(ret, &a);
+		}
+		else
+		{
+			RpcError(ret, c->Err);
+		}
+		CiFreeGetIssuer(&a);
+	}
+	else if (StrCmpi(name, "SetAccount") == 0)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT a;
+		InRpcClientCreateAccount(&a, p);
+		if (CtSetAccount(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		CiFreeClientCreateAccount(&a);
+	}
+	else if (StrCmpi(name, "GetAccount") == 0)
+	{
+		RPC_CLIENT_GET_ACCOUNT a;
+		InRpcClientGetAccount(&a, p);
+		if (CtGetAccount(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientGetAccount(ret, &a);
+		}
+		CiFreeClientGetAccount(&a);
+	}
+	else if (StrCmpi(name, "RenameAccount") == 0)
+	{
+		RPC_RENAME_ACCOUNT a;
+		InRpcRenameAccount(&a, p);
+		if (CtRenameAccount(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "SetClientConfig") == 0)
+	{
+		CLIENT_CONFIG a;
+		InRpcClientConfig(&a, p);
+		if (CtSetClientConfig(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "GetClientConfig") == 0)
+	{
+		CLIENT_CONFIG a;
+		if (CtGetClientConfig(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientConfig(ret, &a);
+		}
+	}
+	else if (StrCmpi(name, "Connect") == 0)
+	{
+		RPC_CLIENT_CONNECT a;
+		InRpcClientConnect(&a, p);
+		if (CtConnect(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "Disconnect") == 0)
+	{
+		RPC_CLIENT_CONNECT a;
+		InRpcClientConnect(&a, p);
+		if (CtDisconnect(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+	}
+	else if (StrCmpi(name, "GetAccountStatus") == 0)
+	{
+		RPC_CLIENT_GET_CONNECTION_STATUS a;
+		InRpcClientGetConnectionStatus(&a, p);
+		if (CtGetAccountStatus(c, &a) == false)
+		{
+			RpcError(ret, c->Err);
+		}
+		else
+		{
+			OutRpcClientGetConnectionStatus(ret, &a);
+		}
+		CiFreeClientGetConnectionStatus(&a);
+	}
+	else
+	{
+		FreePack(ret);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+// CM_SETTING の設定
+UINT CcSetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a)
+{
+	PACK *ret, *p;
+	UINT err;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcCmSetting(p, a);
+
+	ret = RpcCall(r->Rpc, "SetCmSetting", p);
+
+	if (RpcIsOk(ret))
+	{
+		FreePack(ret);
+		return 0;
+	}
+	else
+	{
+		err = RpcGetError(ret);
+		FreePack(ret);
+		return err;
+	}
+}
+
+// CM_SETTING の取得
+UINT CcGetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a)
+{
+	PACK *ret;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "GetCmSetting", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcCmSetting(a, ret);
+		FreePack(ret);
+		return 0;
+	}
+	else
+	{
+		UINT err = RpcGetError(ret);
+		FreePack(ret);
+		return err;
+	}
+}
+
+// クライアントバージョンの取得
+UINT CcGetClientVersion(REMOTE_CLIENT *r, RPC_CLIENT_VERSION *a)
+{
+	PACK *ret;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "GetClientVersion", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientVersion(a, ret);
+		FreePack(ret);
+		return 0;
+	}
+	else
+	{
+		UINT err = RpcGetError(ret);
+		FreePack(ret);
+		return err;
+	}
+}
+
+// パスワードの設定
+UINT CcSetPassword(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD *pass)
+{
+	PACK *ret, *p;
+	// 引数チェック
+	if (r == NULL || pass == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+
+	OutRpcClientPassword(p, pass);
+
+	ret = RpcCall(r->Rpc, "SetPassword", p);
+
+	if (RpcIsOk(ret))
+	{
+		FreePack(ret);
+		return 0;
+	}
+	else
+	{
+		UINT err = RpcGetError(ret);
+		FreePack(ret);
+		return err;
+	}
+}
+
+// パスワード設定の取得
+UINT CcGetPasswordSetting(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+	PACK *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "GetPasswordSetting", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientPasswordSetting(a, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+	return err;
+}
+
+// CA の列挙
+UINT CcEnumCa(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_CA *e)
+{
+	PACK *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || e == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "EnumCa", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientEnumCa(e, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// CA の追加
+UINT CcAddCa(REMOTE_CLIENT *r, RPC_CERT *cert)
+{
+	PACK *p, *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || cert == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcCert(p, cert);
+
+	ret = RpcCall(r->Rpc, "AddCa", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// CA の削除
+UINT CcDeleteCa(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_CA *c)
+{
+	PACK *p, *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || c == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientDeleteCa(p, c);
+
+	ret = RpcCall(r->Rpc, "DeleteCa", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// 署名者の取得
+UINT CcGetIssuer(REMOTE_CLIENT *r, RPC_GET_ISSUER *a)
+{
+	PACK *p, *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcGetIssuer(p, a);
+
+	ret = RpcCall(r->Rpc, "GetIssuer", p);
+
+	if (RpcIsOk(ret))
+	{
+		if (a->x != NULL)
+		{
+			FreeX(a->x);
+			a->x = NULL;
+		}
+		InRpcGetIssuer(a, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// CA の取得
+UINT CcGetCa(REMOTE_CLIENT *r, RPC_GET_CA *get)
+{
+	PACK *p, *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || get == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcGetCa(p, get);
+
+	ret = RpcCall(r->Rpc, "GetCa", p);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcGetCa(get, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// セキュアデバイスの列挙
+UINT CcEnumSecure(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_SECURE *e)
+{
+	PACK *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || e == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "EnumSecure", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientEnumSecure(e, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// 使用しているセキュアデバイスの取得
+UINT CcGetUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec)
+{
+	PACK *p, *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || sec == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+
+	ret = RpcCall(r->Rpc, "GetUseSecure", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+	else
+	{
+		InRpcUseSecure(sec, ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// セキュアデバイスの使用
+UINT CcUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec)
+{
+	PACK *p, *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || sec == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcUseSecure(p, sec);
+
+	ret = RpcCall(r->Rpc, "UseSecure", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// セキュアデバイス内のオブジェクトの列挙
+UINT CcEnumObjectInSecure(REMOTE_CLIENT *r, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+	PACK *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || e == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "EnumObjectInSecure", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcEnumObjectInSecure(e, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// VLAN の作成
+UINT CcCreateVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	char *s = NULL;
+	// 引数チェック
+	if (r == NULL || create == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcCreateVLan(p, create);
+
+#ifdef	OS_WIN32
+	s = MsNoWarningSoundInit();
+#endif	// OS_WIN32
+
+	ret = RpcCall(r->Rpc, "CreateVLan", p);
+
+#ifdef	OS_WIN32
+	MsNoWarningSoundFree(s);
+#endif	// OS_WIN32
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// VLAN のアップグレード
+UINT CcUpgradeVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	char *s = NULL;
+	// 引数チェック
+	if (r == NULL || create == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcCreateVLan(p, create);
+
+#ifdef	OS_WIN32
+	s = MsNoWarningSoundInit();
+#endif	// OS_WIN32
+
+	ret = RpcCall(r->Rpc, "UpgradeVLan", p);
+
+#ifdef	OS_WIN32
+	MsNoWarningSoundFree(s);
+#endif	// OS_WIN32
+
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// VLAN の取得
+UINT CcGetVLan(REMOTE_CLIENT *r, RPC_CLIENT_GET_VLAN *get)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || get == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientGetVLan(p, get);
+
+	ret = RpcCall(r->Rpc, "GetVLan", p);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientGetVLan(get, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// VLAN の設定
+UINT CcSetVLan(REMOTE_CLIENT *r, RPC_CLIENT_SET_VLAN *set)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || set == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientSetVLan(p, set);
+
+	ret = RpcCall(r->Rpc, "SetVLan", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// VLAN の列挙
+UINT CcEnumVLan(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_VLAN *e)
+{
+	PACK *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || e == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "EnumVLan", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientEnumVLan(e, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// VLAN の削除
+UINT CcDeleteVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *d)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || d == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcCreateVLan(p, d);
+
+	ret = RpcCall(r->Rpc, "DeleteVLan", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// VLAN の有効化
+UINT CcEnableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || vlan == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcCreateVLan(p, vlan);
+
+	ret = RpcCall(r->Rpc, "EnableVLan", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// VLAN の無効化
+UINT CcDisableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || vlan == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcCreateVLan(p, vlan);
+
+	ret = RpcCall(r->Rpc, "DisableVLan", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// アカウントの作成
+UINT CcCreateAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientCreateAccount(p, a);
+
+	ret = RpcCall(r->Rpc, "CreateAccount", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// アカウントの列挙
+UINT CcEnumAccount(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+	PACK *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || e == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "EnumAccount", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		UINT i;
+		InRpcClientEnumAccount(e, ret);
+
+		for (i = 0;i < e->NumItem;i++)
+		{
+			RPC_CLIENT_ENUM_ACCOUNT_ITEM *t = e->Items[i];
+
+			if (IsEmptyStr(t->HubName) && t->Port == 0)
+			{
+				UINT err2;
+				RPC_CLIENT_GET_ACCOUNT a;
+
+				// 古いバージョンの VPN Client では列挙時に HUB 名とポート番号
+				// を取得できないので、別途取得する。
+				Zero(&a, sizeof(a));
+				UniStrCpy(a.AccountName, sizeof(a.AccountName), t->AccountName);
+				err2 = CcGetAccount(r, &a);
+				if (err2 == ERR_NO_ERROR)
+				{
+					StrCpy(t->HubName, sizeof(t->HubName), a.ClientOption->HubName);
+					t->Port = a.ClientOption->Port;
+
+					CiFreeClientGetAccount(&a);
+				}
+			}
+		}
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// スタートアップを解除する
+UINT CcRemoveStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientDeleteAccount(p, a);
+
+	ret = RpcCall(r->Rpc, "RemoveStartupAccount", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// スタートアップにする
+UINT CcSetStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientDeleteAccount(p, a);
+
+	ret = RpcCall(r->Rpc, "SetStartupAccount", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// アカウントの削除
+UINT CcDeleteAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientDeleteAccount(p, a);
+
+	ret = RpcCall(r->Rpc, "DeleteAccount", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// アカウントの設定
+UINT CcSetAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientCreateAccount(p, a);
+
+	ret = RpcCall(r->Rpc, "SetAccount", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// アカウントの取得
+UINT CcGetAccount(REMOTE_CLIENT *r, RPC_CLIENT_GET_ACCOUNT *a)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || a == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientGetAccount(p, a);
+
+	ret = RpcCall(r->Rpc, "GetAccount", p);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientGetAccount(a, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// アカウント名の変更
+UINT CcRenameAccount(REMOTE_CLIENT *r, RPC_RENAME_ACCOUNT *rename)
+{
+	PACK *p, *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || rename == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcRenameAccount(p, rename);
+
+	ret = RpcCall(r->Rpc, "RenameAccount", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// クライアント設定の設定
+UINT CcSetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o)
+{
+	PACK *p, *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || o == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientConfig(p, o);
+
+	ret = RpcCall(r->Rpc, "SetClientConfig", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// クライアント設定の取得
+UINT CcGetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o)
+{
+	PACK *ret;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || o == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	ret = RpcCall(r->Rpc, "GetClientConfig", NULL);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientConfig(o, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// サービスをフォアグラウンドプロセスに設定する
+void CcSetServiceToForegroundProcess(REMOTE_CLIENT *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+	// 廃止
+/*
+	if (r->Rpc != NULL && r->Rpc->Sock != NULL && r->Rpc->Sock->RemoteIP.addr[0] == 127)
+	{
+		if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) &&
+			GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+		{
+			// Windows 2000 以降でのみこの操作は行う
+			RPC_CLIENT_VERSION v;
+			Zero(&v, sizeof(v));
+
+			if (r->ClientBuildInt == 0)
+			{
+				CcGetClientVersion(r, &v);
+				r->ClientBuildInt = v.ClientBuildInt;
+				r->ProcessId = v.ProcessId;
+			}
+			if (r->ProcessId != 0 && r->ClientBuildInt <= 5080)
+			{
+#ifdef	OS_WIN32
+				// サービスプロセスをフォアグラウンドウインドウに設定する
+				AllowFGWindow(v.ProcessId);
+#endif	// OS_WIN32
+			}
+		}
+	}*/
+}
+
+// 接続
+UINT CcConnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || connect == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	CcSetServiceToForegroundProcess(r);
+
+	p = NewPack();
+	OutRpcClientConnect(p, connect);
+
+	ret = RpcCall(r->Rpc, "Connect", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// 切断
+UINT CcDisconnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || connect == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	CcSetServiceToForegroundProcess(r);
+
+	p = NewPack();
+	OutRpcClientConnect(p, connect);
+
+	ret = RpcCall(r->Rpc, "Disconnect", p);
+
+	if (RpcIsOk(ret) == false)
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+// アカウント状況の取得
+UINT CcGetAccountStatus(REMOTE_CLIENT *r, RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+	PACK *ret, *p;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || st == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	p = NewPack();
+	OutRpcClientGetConnectionStatus(p, st);
+
+	ret = RpcCall(r->Rpc, "GetAccountStatus", p);
+
+	if (RpcIsOk(ret))
+	{
+		InRpcClientGetConnectionStatus(st, ret);
+	}
+	else
+	{
+		err = RpcGetError(ret);
+	}
+
+	FreePack(ret);
+
+	return err;
+}
+
+
+// クライアントサービスが接続マネージャに対して通知を送信する
+void CiNotify(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	// すべての通知イベントを起動する
+	LockList(c->NotifyCancelList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++)
+		{
+			CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i);
+			Cancel(cancel);
+		}
+	}
+	UnlockList(c->NotifyCancelList);
+}
+
+// RPC_CLIENT_ENUM_ACCOUNT の解放
+void CiFreeClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *a)
+{
+	UINT i;
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < a->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_ACCOUNT_ITEM *e = a->Items[i];
+		Free(e);
+	}
+	Free(a->Items);
+}
+
+
+// 一定時間ごとに設定ファイルを保存するスレッド
+void CiSaverThread(THREAD *t, void *param)
+{
+	CLIENT *c = (CLIENT *)param;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	NoticeThreadInit(t);
+
+	// 一定時間待つ
+	while (c->Halt == false)
+	{
+		Wait(c->SaverHalter, CLIENT_SAVER_INTERVAL);
+
+		// 保存
+		CiSaveConfigurationFile(c);
+	}
+}
+
+// 設定データ自動保存の初期化
+void CiInitSaver(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->SaverHalter = NewEvent();
+
+	c->SaverThread = NewThread(CiSaverThread, c);
+	WaitThreadInit(c->SaverThread);
+}
+
+// 設定データ自動保存の解放
+void CiFreeSaver(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->Halt = true;
+	Set(c->SaverHalter);
+	WaitThread(c->SaverThread, INFINITE);
+	ReleaseThread(c->SaverThread);
+
+	ReleaseEvent(c->SaverHalter);
+}
+
+// CM_SETTING
+void InRpcCmSetting(CM_SETTING *c, PACK *p)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(CM_SETTING));
+	c->EasyMode = PackGetBool(p, "EasyMode");
+	c->LockMode = PackGetBool(p, "LockMode");
+	PackGetData2(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword));
+}
+void OutRpcCmSetting(PACK *p, CM_SETTING *c)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddBool(p, "EasyMode", c->EasyMode);
+	PackAddBool(p, "LockMode", c->LockMode);
+	PackAddData(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword));
+}
+
+// CLIENT_CONFIG
+void InRpcClientConfig(CLIENT_CONFIG *c, PACK *p)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(CLIENT_CONFIG));
+	c->UseKeepConnect = PackGetInt(p, "UseKeepConnect") == 0 ? false : true;
+	c->KeepConnectPort = PackGetInt(p, "KeepConnectPort");
+	c->KeepConnectProtocol = PackGetInt(p, "KeepConnectProtocol");
+	c->KeepConnectInterval = PackGetInt(p, "KeepConnectInterval");
+	c->AllowRemoteConfig = PackGetInt(p, "AllowRemoteConfig") == 0 ? false : true;
+	PackGetStr(p, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost));
+}
+void OutRpcClientConfig(PACK *p, CLIENT_CONFIG *c)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "UseKeepConnect", c->UseKeepConnect);
+	PackAddInt(p, "KeepConnectPort", c->KeepConnectPort);
+	PackAddInt(p, "KeepConnectProtocol", c->KeepConnectProtocol);
+	PackAddInt(p, "KeepConnectInterval", c->KeepConnectInterval);
+	PackAddInt(p, "AllowRemoteConfig", c->AllowRemoteConfig);
+	PackAddStr(p, "KeepConnectHost", c->KeepConnectHost);
+}
+
+// RPC_CLIENT_VERSION
+void InRpcClientVersion(RPC_CLIENT_VERSION *ver, PACK *p)
+{
+	// 引数チェック
+	if (ver == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(ver, sizeof(RPC_CLIENT_VERSION));
+	PackGetStr(p, "ClientProductName", ver->ClientProductName, sizeof(ver->ClientProductName));
+	PackGetStr(p, "ClientVersionString", ver->ClientVersionString, sizeof(ver->ClientVersionString));
+	PackGetStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString));
+	ver->ClientVerInt = PackGetInt(p, "ClientVerInt");
+	ver->ClientBuildInt = PackGetInt(p, "ClientBuildInt");
+	ver->ProcessId = PackGetInt(p, "ProcessId");
+	ver->OsType = PackGetInt(p, "OsType");
+}
+void OutRpcClientVersion(PACK *p, RPC_CLIENT_VERSION *ver)
+{
+	// 引数チェック
+	if (ver == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "ClientProductName", ver->ClientProductName);
+	PackAddStr(p, "ClientVersionString", ver->ClientVersionString);
+	PackAddStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString);
+	PackAddInt(p, "ClientVerInt", ver->ClientVerInt);
+	PackAddInt(p, "ClientBuildInt", ver->ClientBuildInt);
+	PackAddInt(p, "ProcessId", ver->ProcessId);
+	PackAddInt(p, "OsType", ver->OsType);
+}
+
+// RPC_CLIENT_PASSWORD
+void InRpcClientPassword(RPC_CLIENT_PASSWORD *pw, PACK *p)
+{
+	// 引数チェック
+	if (pw == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(pw, sizeof(RPC_CLIENT_PASSWORD));
+	PackGetStr(p, "Password", pw->Password, sizeof(pw->Password));
+	pw->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly");
+}
+void OutRpcClientPassword(PACK *p, RPC_CLIENT_PASSWORD *pw)
+{
+	// 引数チェック
+	if (pw == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "Password", pw->Password);
+	PackAddInt(p, "PasswordRemoteOnly", pw->PasswordRemoteOnly);
+}
+
+// RPC_CLIENT_PASSWORD_SETTING
+void InRpcClientPasswordSetting(RPC_CLIENT_PASSWORD_SETTING *a, PACK *p)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(a, sizeof(RPC_CLIENT_PASSWORD_SETTING));
+
+	a->IsPasswordPresented = PackGetInt(p, "IsPasswordPresented") == 0 ? false : true;
+	a->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly") == 0 ? false : true;
+}
+void OutRpcClientPasswordSetting(PACK *p, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "IsPasswordPresented", a->IsPasswordPresented);
+	PackAddInt(p, "PasswordRemoteOnly", a->PasswordRemoteOnly);
+}
+
+// RPC_CLIENT_ENUM_CA
+void InRpcClientEnumCa(RPC_CLIENT_ENUM_CA *e, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(e, sizeof(RPC_CLIENT_ENUM_CA));
+	e->NumItem = PackGetNum(p, "NumItem");
+
+	e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem);
+	for (i = 0;i < e->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_CA_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM));
+		e->Items[i] = item;
+
+		item->Key = PackGetIntEx(p, "Key", i);
+		PackGetUniStrEx(p, "SubjectName", item->SubjectName, sizeof(item->SubjectName), i);
+		PackGetUniStrEx(p, "IssuerName", item->IssuerName, sizeof(item->IssuerName), i);
+		item->Expires = PackGetInt64Ex(p, "Expires", i);
+	}
+}
+void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddNum(p, "NumItem", e->NumItem);
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_CA_ITEM *item = e->Items[i];
+		PackAddIntEx(p, "Key", item->Key, i, e->NumItem);
+		PackAddUniStrEx(p, "SubjectName", item->SubjectName, i, e->NumItem);
+		PackAddUniStrEx(p, "IssuerName", item->IssuerName, i, e->NumItem);
+		PackAddInt64Ex(p, "Expires", item->Expires, i, e->NumItem);
+	}
+}
+
+// RPC_GET_ISSUER
+void InRpcGetIssuer(RPC_GET_ISSUER *c, PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(RPC_GET_ISSUER));
+	b = PackGetBuf(p, "x");
+	if (b != NULL)
+	{
+		if (c->x != NULL)
+		{
+			FreeX(c->x);
+		}
+		c->x = BufToX(b, false);
+		FreeBuf(b);
+	}
+
+	b = PackGetBuf(p, "issuer_x");
+	if (b != NULL)
+	{
+		c->issuer_x = BufToX(b, false);
+		FreeBuf(b);
+	}
+}
+void OutRpcGetIssuer(PACK *p, RPC_GET_ISSUER *c)
+{
+	BUF *b;
+	// 引数チェック
+	if (p == NULL || c == NULL)
+	{
+		return;
+	}
+
+	if (c->x != NULL)
+	{
+		b = XToBuf(c->x, false);
+
+		PackAddBuf(p, "x", b);
+		FreeBuf(b);
+	}
+
+	if (c->issuer_x != NULL)
+	{
+		b = XToBuf(c->issuer_x, false);
+
+		PackAddBuf(p, "issuer_x", b);
+		FreeBuf(b);
+	}
+}
+
+// TRAFFIC_EX
+void InRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(TRAFFIC));
+	t->Recv.BroadcastBytes = PackGetInt64Ex(p, "Ex.Recv.BroadcastBytes", i);
+	t->Recv.BroadcastCount = PackGetInt64Ex(p, "Ex.Recv.BroadcastCount", i);
+	t->Recv.UnicastBytes = PackGetInt64Ex(p, "Ex.Recv.UnicastBytes", i);
+	t->Recv.UnicastCount = PackGetInt64Ex(p, "Ex.Recv.UnicastCount", i);
+	t->Send.BroadcastBytes = PackGetInt64Ex(p, "Ex.Send.BroadcastBytes", i);
+	t->Send.BroadcastCount = PackGetInt64Ex(p, "Ex.Send.BroadcastCount", i);
+	t->Send.UnicastBytes = PackGetInt64Ex(p, "Ex.Send.UnicastBytes", i);
+	t->Send.UnicastCount = PackGetInt64Ex(p, "Ex.Send.UnicastCount", i);
+}
+void OutRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i, UINT num)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt64Ex(p, "Ex.Recv.BroadcastBytes", t->Recv.BroadcastBytes, i, num);
+	PackAddInt64Ex(p, "Ex.Recv.BroadcastCount", t->Recv.BroadcastCount, i, num);
+	PackAddInt64Ex(p, "Ex.Recv.UnicastBytes", t->Recv.UnicastBytes, i, num);
+	PackAddInt64Ex(p, "Ex.Recv.UnicastCount", t->Recv.UnicastCount, i, num);
+	PackAddInt64Ex(p, "Ex.Send.BroadcastBytes", t->Send.BroadcastBytes, i, num);
+	PackAddInt64Ex(p, "Ex.Send.BroadcastCount", t->Send.BroadcastCount, i, num);
+	PackAddInt64Ex(p, "Ex.Send.UnicastBytes", t->Send.UnicastBytes, i, num);
+	PackAddInt64Ex(p, "Ex.Send.UnicastCount", t->Send.UnicastCount, i, num);
+}
+
+// TRAFFIC
+void InRpcTraffic(TRAFFIC *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(TRAFFIC));
+	t->Recv.BroadcastBytes = PackGetInt64(p, "Recv.BroadcastBytes");
+	t->Recv.BroadcastCount = PackGetInt64(p, "Recv.BroadcastCount");
+	t->Recv.UnicastBytes = PackGetInt64(p, "Recv.UnicastBytes");
+	t->Recv.UnicastCount = PackGetInt64(p, "Recv.UnicastCount");
+	t->Send.BroadcastBytes = PackGetInt64(p, "Send.BroadcastBytes");
+	t->Send.BroadcastCount = PackGetInt64(p, "Send.BroadcastCount");
+	t->Send.UnicastBytes = PackGetInt64(p, "Send.UnicastBytes");
+	t->Send.UnicastCount = PackGetInt64(p, "Send.UnicastCount");
+}
+void OutRpcTraffic(PACK *p, TRAFFIC *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt64(p, "Recv.BroadcastBytes", t->Recv.BroadcastBytes);
+	PackAddInt64(p, "Recv.BroadcastCount", t->Recv.BroadcastCount);
+	PackAddInt64(p, "Recv.UnicastBytes", t->Recv.UnicastBytes);
+	PackAddInt64(p, "Recv.UnicastCount", t->Recv.UnicastCount);
+	PackAddInt64(p, "Send.BroadcastBytes", t->Send.BroadcastBytes);
+	PackAddInt64(p, "Send.BroadcastCount", t->Send.BroadcastCount);
+	PackAddInt64(p, "Send.UnicastBytes", t->Send.UnicastBytes);
+	PackAddInt64(p, "Send.UnicastCount", t->Send.UnicastCount);
+}
+
+// RPC_CERT
+void InRpcCert(RPC_CERT *c, PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(RPC_CERT));
+	b = PackGetBuf(p, "x");
+	if (b == NULL)
+	{
+		return;
+	}
+
+	c->x = BufToX(b, false);
+	FreeBuf(b);
+}
+void OutRpcCert(PACK *p, RPC_CERT *c)
+{
+	BUF *b;
+	// 引数チェック
+	if (p == NULL || c == NULL)
+	{
+		return;
+	}
+
+	if (c->x != NULL)
+	{
+		b = XToBuf(c->x, false);
+
+		PackAddBuf(p, "x", b);
+
+		FreeBuf(b);
+	}
+}
+
+// RPC_CLIENT_DELETE_CA
+void InRpcClientDeleteCa(RPC_CLIENT_DELETE_CA *c, PACK *p)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(RPC_CLIENT_DELETE_CA));
+	c->Key = PackGetInt(p, "Key");
+}
+void OutRpcClientDeleteCa(PACK *p, RPC_CLIENT_DELETE_CA *c)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "Key", c->Key);
+}
+
+// RPC_GET_CA
+void InRpcGetCa(RPC_GET_CA *c, PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(RPC_GET_CA));
+
+	c->Key = PackGetInt(p, "Key");
+
+	b = PackGetBuf(p, "x");
+	if (b != NULL)
+	{
+		c->x = BufToX(b, false);
+
+		FreeBuf(b);
+	}
+}
+void OutRpcGetCa(PACK *p, RPC_GET_CA *c)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "Key", c->Key);
+
+	if (c->x != NULL)
+	{
+		BUF *b = XToBuf(c->x, false);
+
+		PackAddBuf(p, "x", b);
+
+		FreeBuf(b);
+	}
+}
+
+// RPC_CLIENT_ENUM_SECURE
+void InRpcClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(e, sizeof(RPC_CLIENT_ENUM_SECURE));
+
+	e->NumItem = PackGetNum(p, "NumItem");
+	e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem);
+	for (i = 0;i < e->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM));
+
+		item->DeviceId = PackGetIntEx(p, "DeviceId", i);
+		item->Type = PackGetIntEx(p, "Type", i);
+		PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+		PackGetStrEx(p, "Manufacturer", item->Manufacturer, sizeof(item->Manufacturer), i);
+	}
+}
+void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddNum(p, "NumItem", e->NumItem);
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i];
+
+		PackAddIntEx(p, "DeviceId", item->DeviceId, i, e->NumItem);
+		PackAddIntEx(p, "Type", item->Type, i, e->NumItem);
+		PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);
+		PackAddStrEx(p, "Manufacturer", item->Manufacturer, i, e->NumItem);
+	}
+}
+
+// RPC_USE_SECURE
+void InRpcUseSecure(RPC_USE_SECURE *u, PACK *p)
+{
+	// 引数チェック
+	if (u == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(u, sizeof(RPC_USE_SECURE));
+	u->DeviceId = PackGetInt(p, "DeviceId");
+}
+void OutRpcUseSecure(PACK *p, RPC_USE_SECURE *u)
+{
+	// 引数チェック
+	if (u == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "DeviceId", u->DeviceId);
+}
+
+// RPC_ENUM_OBJECT_IN_SECURE の解放
+void CiFreeEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *a)
+{
+	UINT i;
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < a->NumItem;i++)
+	{
+		Free(a->ItemName[i]);
+	}
+	Free(a->ItemName);
+	Free(a->ItemType);
+}
+
+// RPC_ENUM_OBJECT_IN_SECURE
+void InRpcEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *e, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(e, sizeof(RPC_ENUM_OBJECT_IN_SECURE));
+
+	e->NumItem = PackGetNum(p, "NumItem");
+	e->hWnd = PackGetInt(p, "hWnd");
+	e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem);
+	e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem);
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		char name[MAX_SIZE];
+
+		Zero(name, sizeof(name));
+		PackGetStrEx(p, "ItemName", name, sizeof(name), i);
+		e->ItemName[i] = CopyStr(name);
+
+		e->ItemType[i] = PackGetIntEx(p, "ItemType", i) ? true : false;
+	}
+}
+void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddNum(p, "NumItem", e->NumItem);
+	PackAddInt(p, "hWnd", e->hWnd);
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		PackAddStrEx(p, "ItemName", e->ItemName[i], i, e->NumItem);
+		PackAddIntEx(p, "ItemType", e->ItemType[i], i, e->NumItem);
+	}
+}
+
+// RPC_CLIENT_CREATE_VLAN
+void InRpcCreateVLan(RPC_CLIENT_CREATE_VLAN *v, PACK *p)
+{
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(v, sizeof(RPC_CLIENT_CREATE_VLAN));
+	PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+}
+void OutRpcCreateVLan(PACK *p, RPC_CLIENT_CREATE_VLAN *v)
+{
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "DeviceName", v->DeviceName);
+}
+
+// RPC_CLIENT_GET_VLAN
+void InRpcClientGetVLan(RPC_CLIENT_GET_VLAN *v, PACK *p)
+{
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(v, sizeof(RPC_CLIENT_GET_VLAN));
+	PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+	v->Enabled = PackGetInt(p, "Enabled") ? true : false;
+	PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress));
+	PackGetStr(p, "Version", v->Version, sizeof(v->Version));
+	PackGetStr(p, "FileName", v->FileName, sizeof(v->FileName));
+	PackGetStr(p, "Guid", v->Guid, sizeof(v->Guid));
+}
+void OutRpcClientGetVLan(PACK *p, RPC_CLIENT_GET_VLAN *v)
+{
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "DeviceName", v->DeviceName);
+	PackAddInt(p, "Enabled", v->Enabled);
+	PackAddStr(p, "MacAddress", v->MacAddress);
+	PackAddStr(p, "Version", v->Version);
+	PackAddStr(p, "FileName", v->FileName);
+	PackAddStr(p, "Guid", v->Guid);
+}
+
+// RPC_CLIENT_SET_VLAN
+void InRpcClientSetVLan(RPC_CLIENT_SET_VLAN *v, PACK *p)
+{
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(v, sizeof(RPC_CLIENT_SET_VLAN));
+	PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+	PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress));
+}
+void OutRpcClientSetVLan(PACK *p, RPC_CLIENT_SET_VLAN *v)
+{
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "DeviceName", v->DeviceName);
+	PackAddStr(p, "MacAddress", v->MacAddress);
+}
+
+// RPC_CLIENT_ENUM_VLAN
+void InRpcClientEnumVLan(RPC_CLIENT_ENUM_VLAN *v, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(v, sizeof(RPC_CLIENT_ENUM_VLAN));
+	v->NumItem = PackGetNum(p, "NumItem");
+	v->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * v->NumItem);
+
+	for (i = 0;i < v->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i] =
+			ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+
+		PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+		item->Enabled = PackGetIntEx(p, "Enabled", i) ? true : false;
+		PackGetStrEx(p, "MacAddress", item->MacAddress, sizeof(item->MacAddress), i);
+		PackGetStrEx(p, "Version", item->Version, sizeof(item->Version), i);
+	}
+}
+void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddNum(p, "NumItem", v->NumItem);
+
+	for (i = 0;i < v->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i];
+
+		PackAddStrEx(p, "DeviceName", item->DeviceName, i, v->NumItem);
+		PackAddIntEx(p, "Enabled", item->Enabled, i, v->NumItem);
+		PackAddStrEx(p, "MacAddress", item->MacAddress, i, v->NumItem);
+		PackAddStrEx(p, "Version", item->Version, i, v->NumItem);
+	}
+}
+
+// CLIENT_OPTION
+void InRpcClientOption(CLIENT_OPTION *c, PACK *p)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(CLIENT_OPTION));
+
+	PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+	PackGetStr(p, "Hostname", c->Hostname, sizeof(c->Hostname));
+	c->Port = PackGetInt(p, "Port");
+	c->PortUDP = PackGetInt(p, "PortUDP");
+	c->ProxyType = PackGetInt(p, "ProxyType");
+	c->ProxyPort = PackGetInt(p, "ProxyPort");
+	c->NumRetry = PackGetInt(p, "NumRetry");
+	c->RetryInterval = PackGetInt(p, "RetryInterval");
+	c->MaxConnection = PackGetInt(p, "MaxConnection");
+	c->AdditionalConnectionInterval = PackGetInt(p, "AdditionalConnectionInterval");
+	c->ConnectionDisconnectSpan = PackGetInt(p, "ConnectionDisconnectSpan");
+	c->HideStatusWindow = PackGetBool(p, "HideStatusWindow");
+	c->HideNicInfoWindow = PackGetBool(p, "HideNicInfoWindow");
+	c->DisableQoS = PackGetBool(p, "DisableQoS");
+	PackGetStr(p, "ProxyName", c->ProxyName, sizeof(c->ProxyName));
+	PackGetStr(p, "ProxyUsername", c->ProxyUsername, sizeof(c->ProxyUsername));
+	PackGetStr(p, "ProxyPassword", c->ProxyPassword, sizeof(c->ProxyPassword));
+	PackGetStr(p, "HubName", c->HubName, sizeof(c->HubName));
+	PackGetStr(p, "DeviceName", c->DeviceName, sizeof(c->DeviceName));
+	c->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false;
+	c->UseCompress = PackGetInt(p, "UseCompress") ? true : false;
+	c->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false;
+	c->NoRoutingTracking = PackGetInt(p, "NoRoutingTracking") ? true : false;
+	c->RequireMonitorMode = PackGetBool(p, "RequireMonitorMode");
+	c->RequireBridgeRoutingMode = PackGetBool(p, "RequireBridgeRoutingMode");
+	c->FromAdminPack = PackGetBool(p, "FromAdminPack");
+	c->NoTls1 = PackGetBool(p, "NoTls1");
+}
+void OutRpcClientOption(PACK *p, CLIENT_OPTION *c)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddUniStr(p, "AccountName", c->AccountName);
+	PackAddStr(p, "Hostname", c->Hostname);
+	PackAddStr(p, "ProxyName", c->ProxyName);
+	PackAddStr(p, "ProxyUsername", c->ProxyUsername);
+	PackAddStr(p, "ProxyPassword", c->ProxyPassword);
+	PackAddStr(p, "HubName", c->HubName);
+	PackAddStr(p, "DeviceName", c->DeviceName);
+	PackAddInt(p, "Port", c->Port);
+	PackAddInt(p, "PortUDP", c->PortUDP);
+	PackAddInt(p, "ProxyType", c->ProxyType);
+	PackAddInt(p, "ProxyPort", c->ProxyPort);
+	PackAddInt(p, "NumRetry", c->NumRetry);
+	PackAddInt(p, "RetryInterval", c->RetryInterval);
+	PackAddInt(p, "MaxConnection", c->MaxConnection);
+	PackAddInt(p, "UseEncrypt", c->UseEncrypt);
+	PackAddInt(p, "UseCompress", c->UseCompress);
+	PackAddInt(p, "HalfConnection", c->HalfConnection);
+	PackAddInt(p, "NoRoutingTracking", c->NoRoutingTracking);
+	PackAddInt(p, "AdditionalConnectionInterval", c->AdditionalConnectionInterval);
+	PackAddInt(p, "ConnectionDisconnectSpan", c->ConnectionDisconnectSpan);
+	PackAddBool(p, "HideStatusWindow", c->HideStatusWindow);
+	PackAddBool(p, "HideNicInfoWindow", c->HideNicInfoWindow);
+	PackAddBool(p, "RequireMonitorMode", c->RequireMonitorMode);
+	PackAddBool(p, "RequireBridgeRoutingMode", c->RequireBridgeRoutingMode);
+	PackAddBool(p, "DisableQoS", c->DisableQoS);
+	PackAddBool(p, "FromAdminPack", c->FromAdminPack);
+	PackAddBool(p, "NoTls1", c->NoTls1);
+}
+
+// CLIENT_AUTH
+void InRpcClientAuth(CLIENT_AUTH *c, PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(CLIENT_AUTH));
+	c->AuthType = PackGetInt(p, "AuthType");
+	PackGetStr(p, "Username", c->Username, sizeof(c->Username));
+
+	switch (c->AuthType)
+	{
+	case CLIENT_AUTHTYPE_ANONYMOUS:
+		break;
+
+	case CLIENT_AUTHTYPE_PASSWORD:
+		if (PackGetDataSize(p, "HashedPassword") == SHA1_SIZE)
+		{
+			PackGetData(p, "HashedPassword", c->HashedPassword);
+		}
+		break;
+
+	case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+		PackGetStr(p, "PlainPassword", c->PlainPassword, sizeof(c->PlainPassword));
+		break;
+
+	case CLIENT_AUTHTYPE_CERT:
+		b = PackGetBuf(p, "ClientX");
+		if (b != NULL)
+		{
+			c->ClientX = BufToX(b, false);
+			FreeBuf(b);
+		}
+		b = PackGetBuf(p, "ClientK");
+		if (b != NULL)
+		{
+			c->ClientK = BufToK(b, true, false, NULL);
+			FreeBuf(b);
+		}
+		break;
+
+	case CLIENT_AUTHTYPE_SECURE:
+		PackGetStr(p, "SecurePublicCertName", c->SecurePublicCertName, sizeof(c->SecurePublicCertName));
+		PackGetStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName, sizeof(c->SecurePrivateKeyName));
+		break;
+	}
+}
+void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "AuthType", c->AuthType);
+	PackAddStr(p, "Username", c->Username);
+
+	switch (c->AuthType)
+	{
+	case CLIENT_AUTHTYPE_ANONYMOUS:
+		break;
+
+	case CLIENT_AUTHTYPE_PASSWORD:
+		PackAddData(p, "HashedPassword", c->HashedPassword, SHA1_SIZE);
+		break;
+
+	case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+		PackAddStr(p, "PlainPassword", c->PlainPassword);
+		break;
+
+	case CLIENT_AUTHTYPE_CERT:
+		b = XToBuf(c->ClientX, false);
+		if (b != NULL)
+		{
+			PackAddBuf(p, "ClientX", b);
+			FreeBuf(b);
+		}
+		b = KToBuf(c->ClientK, false, NULL);
+		if (b != NULL)
+		{
+			PackAddBuf(p, "ClientK", b);
+			FreeBuf(b);
+		}
+		break;
+
+	case CLIENT_AUTHTYPE_SECURE:
+		PackAddStr(p, "SecurePublicCertName", c->SecurePublicCertName);
+		PackAddStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName);
+		break;
+	}
+}
+
+// RPC_CLIENT_CREATE_ACCOUNT
+void InRpcClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *c, PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(RPC_CLIENT_CREATE_ACCOUNT));
+	c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+	InRpcClientOption(c->ClientOption, p);
+	InRpcClientAuth(c->ClientAuth, p);
+
+	c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false;
+	c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false;
+	b = PackGetBuf(p, "ServerCert");
+	if (b != NULL)
+	{
+		c->ServerCert = BufToX(b, false);
+		FreeBuf(b);
+	}
+	PackGetData2(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey));
+}
+void OutRpcClientCreateAccount(PACK *p, RPC_CLIENT_CREATE_ACCOUNT *c)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	OutRpcClientOption(p, c->ClientOption);
+	OutRpcClientAuth(p, c->ClientAuth);
+
+	PackAddInt(p, "StartupAccount", c->StartupAccount);
+	PackAddInt(p, "CheckServerCert", c->CheckServerCert);
+	if (c->ServerCert != NULL)
+	{
+		b = XToBuf(c->ServerCert, false);
+		if (b != NULL)
+		{
+			PackAddBuf(p, "ServerCert", b);
+			FreeBuf(b);
+		}
+	}
+	PackAddData(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey));
+}
+
+// RPC_CLIENT_ENUM_ACCOUNT
+void InRpcClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *e, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(e, sizeof(RPC_CLIENT_ENUM_ACCOUNT));
+
+	e->NumItem = PackGetNum(p, "NumItem");
+	e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem);
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i] =
+			ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM));
+
+		PackGetUniStrEx(p, "AccountName", item->AccountName, sizeof(item->AccountName), i);
+		PackGetStrEx(p, "UserName", item->UserName, sizeof(item->UserName), i);
+		PackGetStrEx(p, "ServerName", item->ServerName, sizeof(item->ServerName), i);
+		PackGetStrEx(p, "ProxyName", item->ProxyName, sizeof(item->ProxyName), i);
+		PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+		item->ProxyType = PackGetIntEx(p, "ProxyType", i);
+		item->Active = PackGetIntEx(p, "Active", i) ? true : false;
+		item->StartupAccount = PackGetIntEx(p, "StartupAccount", i) ? true : false;
+		item->Connected = PackGetBoolEx(p, "Connected", i);
+		item->Port = PackGetIntEx(p, "Port", i);
+		PackGetStrEx(p, "HubName", item->HubName, sizeof(item->HubName), i);
+		item->CreateDateTime = PackGetInt64Ex(p, "CreateDateTime", i);
+		item->UpdateDateTime = PackGetInt64Ex(p, "UpdateDateTime", i);
+		item->LastConnectDateTime = PackGetInt64Ex(p, "LastConnectDateTime", i);
+	}
+}
+void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddNum(p, "NumItem", e->NumItem);
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i];
+
+		PackAddUniStrEx(p, "AccountName", item->AccountName, i, e->NumItem);
+		PackAddStrEx(p, "UserName", item->UserName, i, e->NumItem);
+		PackAddStrEx(p, "ServerName", item->ServerName, i, e->NumItem);
+		PackAddStrEx(p, "ProxyName", item->ProxyName, i, e->NumItem);
+		PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);
+		PackAddIntEx(p, "ProxyType", item->ProxyType, i, e->NumItem);
+		PackAddIntEx(p, "Active", item->Active, i, e->NumItem);
+		PackAddIntEx(p, "StartupAccount", item->StartupAccount, i, e->NumItem);
+		PackAddBoolEx(p, "Connected", item->Connected, i, e->NumItem);
+		PackAddIntEx(p, "Port", item->Port, i, e->NumItem);
+		PackAddStrEx(p, "HubName", item->HubName, i, e->NumItem);
+		PackAddInt64Ex(p, "CreateDateTime", item->CreateDateTime, i, e->NumItem);
+		PackAddInt64Ex(p, "UpdateDateTime", item->UpdateDateTime, i, e->NumItem);
+		PackAddInt64Ex(p, "LastConnectDateTime", item->LastConnectDateTime, i, e->NumItem);
+	}
+}
+
+// RPC_CLIENT_DELETE_ACCOUNT
+void InRpcClientDeleteAccount(RPC_CLIENT_DELETE_ACCOUNT *a, PACK *p)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(a, sizeof(RPC_CLIENT_DELETE_ACCOUNT));
+	PackGetUniStr(p, "AccountName", a->AccountName, sizeof(a->AccountName));
+}
+void OutRpcClientDeleteAccount(PACK *p, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddUniStr(p, "AccountName", a->AccountName);
+}
+
+// RPC_RENAME_ACCOUNT
+void InRpcRenameAccount(RPC_RENAME_ACCOUNT *a, PACK *p)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(a, sizeof(RPC_RENAME_ACCOUNT));
+
+	PackGetUniStr(p, "OldName", a->OldName, sizeof(a->OldName));
+	PackGetUniStr(p, "NewName", a->NewName, sizeof(a->NewName));
+}
+void OutRpcRenameAccount(PACK *p, RPC_RENAME_ACCOUNT *a)
+{
+	// 引数チェック
+	if (a == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddUniStr(p, "OldName", a->OldName);
+	PackAddUniStr(p, "NewName", a->NewName);
+}
+
+// RPC_CLIENT_GET_ACCOUNT
+void InRpcClientGetAccount(RPC_CLIENT_GET_ACCOUNT *c, PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(RPC_CLIENT_GET_ACCOUNT));
+
+	c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+	PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+	c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false;
+	c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false;
+	b = PackGetBuf(p, "ServerCert");
+	if (b != NULL)
+	{
+		c->ServerCert = BufToX(b, false);
+		FreeBuf(b);
+	}
+
+	InRpcClientOption(c->ClientOption, p);
+	InRpcClientAuth(c->ClientAuth, p);
+
+	c->CreateDateTime = PackGetInt64(p, "CreateDateTime");
+	c->UpdateDateTime = PackGetInt64(p, "UpdateDateTime");
+	c->LastConnectDateTime = PackGetInt64(p, "LastConnectDateTime");
+
+	PackGetData2(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);
+}
+void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddUniStr(p, "AccountName", c->AccountName);
+	PackAddInt(p, "StartupAccount", c->StartupAccount);
+	PackAddInt(p, "CheckServerCert", c->CheckServerCert);
+
+	if (c->ServerCert != NULL)
+	{
+		b = XToBuf(c->ServerCert, false);
+		if (b != NULL)
+		{
+			PackAddBuf(p, "ServerCert", b);
+			FreeBuf(b);
+		}
+	}
+
+	OutRpcClientOption(p, c->ClientOption);
+	OutRpcClientAuth(p, c->ClientAuth);
+
+	PackAddData(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);
+
+	PackAddInt64(p, "CreateDateTime", c->CreateDateTime);
+	PackAddInt64(p, "UpdateDateTime", c->UpdateDateTime);
+	PackAddInt64(p, "LastConnectDateTime", c->LastConnectDateTime);
+}
+
+// RPC_CLIENT_CONNECT
+void InRpcClientConnect(RPC_CLIENT_CONNECT *c, PACK *p)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(c, sizeof(RPC_CLIENT_CONNECT));
+
+	PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+}
+void OutRpcClientConnect(PACK *p, RPC_CLIENT_CONNECT *c)
+{
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddUniStr(p, "AccountName", c->AccountName);
+}
+
+// POLICY
+void InRpcPolicy(POLICY *o, PACK *p)
+{
+	POLICY *pol;
+	// 引数チェック
+	if (o == NULL || p == NULL)
+	{
+		return;
+	}
+
+	pol = PackGetPolicy(p);
+	Copy(o, pol, sizeof(POLICY));
+	Free(pol);
+}
+void OutRpcPolicy(PACK *p, POLICY *o)
+{
+	// 引数チェック
+	if (o == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddPolicy(p, o);
+}
+
+// RPC_CLIENT_GET_CONNECTION_STATUS
+void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(s, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS));
+
+	PackGetUniStr(p, "AccountName", s->AccountName, sizeof(s->AccountName));
+
+	PackGetStr(p, "ServerName", s->ServerName, sizeof(s->ServerName));
+	PackGetStr(p, "ServerProductName", s->ServerProductName, sizeof(s->ServerProductName));
+	PackGetStr(p, "CipherName", s->CipherName, sizeof(s->CipherName));
+	PackGetStr(p, "SessionName", s->SessionName, sizeof(s->SessionName));
+	PackGetStr(p, "ConnectionName", s->ConnectionName, sizeof(s->ConnectionName));
+
+	if (PackGetDataSize(p, "SessionKey") == SHA1_SIZE)
+	{
+		PackGetData(p, "SessionKey", s->SessionKey);
+	}
+
+	s->SessionStatus = PackGetInt(p, "SessionStatus");
+	s->ServerPort = PackGetInt(p, "ServerPort");
+	s->ServerProductVer = PackGetInt(p, "ServerProductVer");
+	s->ServerProductBuild = PackGetInt(p, "ServerProductBuild");
+	s->NumConnectionsEatablished = PackGetInt(p, "NumConnectionsEatablished");
+	s->MaxTcpConnections = PackGetInt(p, "MaxTcpConnections");
+	s->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+	s->NumTcpConnectionsUpload = PackGetInt(p, "NumTcpConnectionsUpload");
+	s->NumTcpConnectionsDownload = PackGetInt(p, "NumTcpConnectionsDownload");
+
+	s->StartTime = PackGetInt64(p, "StartTime");
+	s->FirstConnectionEstablisiedTime = PackGetInt64(p, "FirstConnectionEstablisiedTime");
+	s->CurrentConnectionEstablishTime = PackGetInt64(p, "CurrentConnectionEstablishTime");
+	s->TotalSendSize = PackGetInt64(p, "TotalSendSize");
+	s->TotalRecvSize = PackGetInt64(p, "TotalRecvSize");
+	s->TotalSendSizeReal = PackGetInt64(p, "TotalSendSizeReal");
+	s->TotalRecvSizeReal = PackGetInt64(p, "TotalRecvSizeReal");
+
+	s->Active = PackGetInt(p, "Active") ? true : false;
+	s->Connected = PackGetInt(p, "Connected") ? true : false;
+	s->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false;
+	s->QoS = PackGetInt(p, "QoS") ? true : false;
+	s->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false;
+	s->UseCompress = PackGetInt(p, "UseCompress") ? true : false;
+
+	s->IsBridgeMode = PackGetBool(p, "IsBridgeMode");
+	s->IsMonitorMode = PackGetBool(p, "IsMonitorMode");
+
+	s->VLanId = PackGetInt(p, "VLanId");
+
+	b = PackGetBuf(p, "ServerX");
+	if (b != NULL)
+	{
+		s->ServerX = BufToX(b, false);
+		FreeBuf(b);
+	}
+
+	b = PackGetBuf(p, "ClientX");
+	if (b != NULL)
+	{
+		s->ClientX = BufToX(b, false);
+		FreeBuf(b);
+	}
+
+	InRpcPolicy(&s->Policy, p);
+
+	InRpcTraffic(&s->Traffic, p);
+}
+void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *c)
+{
+	BUF *b;
+	// 引数チェック
+	if (p == NULL || c == NULL)
+	{
+		return;
+	}
+
+	PackAddUniStr(p, "AccountName", c->AccountName);
+
+	PackAddStr(p, "ServerName", c->ServerName);
+	PackAddStr(p, "ServerProductName", c->ServerProductName);
+	PackAddStr(p, "CipherName", c->CipherName);
+	PackAddStr(p, "SessionName", c->SessionName);
+	PackAddStr(p, "ConnectionName", c->ConnectionName);
+
+	PackAddData(p, "SessionKey", c->SessionKey, SHA1_SIZE);
+
+	PackAddInt(p, "Active", c->Active);
+	PackAddInt(p, "Connected", c->Connected);
+	PackAddInt(p, "SessionStatus", c->SessionStatus);
+	PackAddInt(p, "ServerPort", c->ServerPort);
+	PackAddInt(p, "ServerProductVer", c->ServerProductVer);
+	PackAddInt(p, "ServerProductBuild", c->ServerProductBuild);
+	PackAddInt(p, "NumConnectionsEatablished", c->NumConnectionsEatablished);
+	PackAddInt(p, "HalfConnection", c->HalfConnection);
+	PackAddInt(p, "QoS", c->QoS);
+	PackAddInt(p, "MaxTcpConnections", c->MaxTcpConnections);
+	PackAddInt(p, "NumTcpConnections", c->NumTcpConnections);
+	PackAddInt(p, "NumTcpConnectionsUpload", c->NumTcpConnectionsUpload);
+	PackAddInt(p, "NumTcpConnectionsDownload", c->NumTcpConnectionsDownload);
+	PackAddInt(p, "UseEncrypt", c->UseEncrypt);
+	PackAddInt(p, "UseCompress", c->UseCompress);
+
+	PackAddBool(p, "IsBridgeMode", c->IsBridgeMode);
+	PackAddBool(p, "IsMonitorMode", c->IsMonitorMode);
+
+	PackAddInt64(p, "StartTime", c->StartTime);
+	PackAddInt64(p, "FirstConnectionEstablisiedTime", c->FirstConnectionEstablisiedTime);
+	PackAddInt64(p, "CurrentConnectionEstablishTime", c->CurrentConnectionEstablishTime);
+	PackAddInt64(p, "TotalSendSize", c->TotalSendSize);
+	PackAddInt64(p, "TotalRecvSize", c->TotalRecvSize);
+	PackAddInt64(p, "TotalSendSizeReal", c->TotalSendSizeReal);
+	PackAddInt64(p, "TotalRecvSizeReal", c->TotalRecvSizeReal);
+
+	PackAddInt(p, "VLanId", c->VLanId);
+
+	OutRpcPolicy(p, &c->Policy);
+
+	OutRpcTraffic(p, &c->Traffic);
+
+	if (c->ServerX != NULL)
+	{
+		b = XToBuf(c->ServerX, false);
+		PackAddBuf(p, "ServerX", b);
+		FreeBuf(b);
+	}
+
+	if (c->ClientX != NULL)
+	{
+		b = XToBuf(c->ClientX, false);
+		PackAddBuf(p, "ClientX", b);
+		FreeBuf(b);
+	}
+}
+
+void InRpcClientNotify(RPC_CLIENT_NOTIFY *n, PACK *p)
+{
+	// 引数チェック
+	if (n == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(n, sizeof(RPC_CLIENT_NOTIFY));
+
+	n->NotifyCode = PackGetInt(p, "NotifyCode");
+}
+void OutRpcClientNotify(PACK *p, RPC_CLIENT_NOTIFY *n)
+{
+	// 引数チェック
+	if (n == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NotifyCode", n->NotifyCode);
+}
+
+// 通知メイン
+void CiNotifyMain(CLIENT *c, SOCK *s)
+{
+	CANCEL *cancel;
+	// 引数チェック
+	if (c == NULL || s == NULL)
+	{
+		return;
+	}
+
+	// キャンセルを登録
+	cancel = NewCancel();
+	LockList(c->NotifyCancelList);
+	{
+		Add(c->NotifyCancelList, cancel);
+	}
+	UnlockList(c->NotifyCancelList);
+
+	// 待機
+	while (true)
+	{
+		char ch = '@';
+		SOCKSET set;
+		InitSockSet(&set);
+		AddSockSet(&set, s);
+		Select(&set, INFINITE, cancel, NULL);
+
+		if (c->Halt)
+		{
+			// 強制終了
+			break;
+		}
+
+		// 1 バイト送信
+		if (Send(s, &ch, 1, false) == 0)
+		{
+			// 切断された
+			break;
+		}
+	}
+
+	// 切断
+	Disconnect(s);
+
+	// キャンセルを登録解除
+	LockList(c->NotifyCancelList);
+	{
+		Delete(c->NotifyCancelList, cancel);
+	}
+	UnlockList(c->NotifyCancelList);
+
+	ReleaseCancel(cancel);
+}
+
+// RPC 受付コード
+void CiRpcAccepted(CLIENT *c, SOCK *s)
+{
+	UCHAR hashed_password[SHA1_SIZE];
+	UINT rpc_mode;
+	UINT retcode;
+	RPC *rpc;
+	// 引数チェック
+	if (c == NULL || s == NULL)
+	{
+		return;
+	}
+
+	// RPC モード受信
+	if (RecvAll(s, &rpc_mode, sizeof(UINT), false) == false)
+	{
+		return;
+	}
+
+	rpc_mode = Endian32(rpc_mode);
+
+	if (rpc_mode == CLIENT_RPC_MODE_NOTIFY)
+	{
+		// 通知モード
+		CiNotifyMain(c, s);
+		return;
+	}
+	else if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT || rpc_mode == CLIENT_RPC_MODE_SHORTCUT_DISCONNECT)
+	{
+		// ショートカットキー受信
+		UCHAR key[SHA1_SIZE];
+		UINT err = ERR_NO_ERROR;
+		if (RecvAll(s, key, SHA1_SIZE, false))
+		{
+			UINT i;
+			wchar_t title[MAX_ACCOUNT_NAME_LEN + 1];
+			bool ok = false;
+			// 指定された接続設定に接続する
+			LockList(c->AccountList);
+			{
+				for (i = 0;i < LIST_NUM(c->AccountList);i++)
+				{
+					ACCOUNT *a = LIST_DATA(c->AccountList, i);
+					Lock(a->lock);
+					{
+						if (Cmp(a->ShortcutKey, key, SHA1_SIZE) == 0)
+						{
+							ok = true;
+							UniStrCpy(title, sizeof(title), a->ClientOption->AccountName);
+						}
+					}
+					Unlock(a->lock);
+				}
+			}
+			UnlockList(c->AccountList);
+
+			if (ok == false)
+			{
+				err = ERR_ACCOUNT_NOT_FOUND;
+			}
+			else
+			{
+				RPC_CLIENT_CONNECT t;
+				Zero(&t, sizeof(t));
+				UniStrCpy(t.AccountName, sizeof(t.AccountName), title);
+
+				if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT)
+				{
+					// 接続
+					if (CtConnect(c, &t))
+					{
+						err = ERR_NO_ERROR;
+					}
+					else
+					{
+						err = c->Err;
+					}
+				}
+				else
+				{
+					// 接続
+					if (CtDisconnect(c, &t))
+					{
+						err = ERR_NO_ERROR;
+					}
+					else
+					{
+						err = c->Err;
+					}
+				}
+			}
+
+			err = Endian32(err);
+			SendAll(s, &err, sizeof(UINT), false);
+			RecvAll(s, &err, sizeof(UINT), false);
+		}
+		return;
+	}
+
+	// パスワード受信
+	if (RecvAll(s, hashed_password, SHA1_SIZE, false) == false)
+	{
+		return;
+	}
+
+	retcode = 0;
+
+	// パスワード比較
+	if (Cmp(hashed_password, c->EncryptedPassword, SHA1_SIZE) != 0)
+	{
+		retcode = 1;
+	}
+
+	if (c->PasswordRemoteOnly && s->RemoteIP.addr[0] == 127)
+	{
+		// リモートのみパスワードを要求するモードで、ローカルから接続された場合は
+		// パスワードを常に正しいと見なす
+		retcode = 0;
+	}
+
+	Lock(c->lock);
+	{
+		if (c->Config.AllowRemoteConfig == false)
+		{
+			// リモート管理が禁止されている場合は
+			// このコネクションが外部からのものであるかどうか識別する
+			if (s->RemoteIP.addr[0] != 127)
+			{
+				retcode = 2;
+			}
+		}
+	}
+	Unlock(c->lock);
+
+	retcode = Endian32(retcode);
+	// エラーコード送信
+	if (SendAll(s, &retcode, sizeof(UINT), false) == false)
+	{
+		return;
+	}
+
+
+
+	if (retcode != 0)
+	{
+		// エラーによる切断
+		return;
+	}
+
+	// RPC サーバー作成
+	rpc = StartRpcServer(s, CiRpcDispatch, c);
+
+	// RPC サーバー動作
+	RpcServer(rpc);
+
+	// RPC サーバーの解放
+	EndRpc(rpc);
+}
+
+// RPC 受付スレッド
+void CiRpcAcceptThread(THREAD *thread, void *param)
+{
+	CLIENT_RPC_CONNECTION *conn;
+	CLIENT *c;
+	SOCK *s;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	conn = (CLIENT_RPC_CONNECTION *)param;
+	s = conn->Sock;
+	c = conn->Client;
+	AddRef(s->ref);
+
+	// RPC コネクションリストに追加
+	LockList(c->RpcConnectionList);
+	{
+		Add(c->RpcConnectionList, conn);
+	}
+	UnlockList(c->RpcConnectionList);
+
+	NoticeThreadInit(thread);
+
+	// メイン処理
+	CiRpcAccepted(c, s);
+
+	// コネクションリストから解放
+	LockList(c->RpcConnectionList);
+	{
+		Delete(c->RpcConnectionList, conn);
+	}
+	UnlockList(c->RpcConnectionList);
+
+	ReleaseSock(conn->Sock);
+	ReleaseThread(conn->Thread);
+	Free(conn);
+
+	Disconnect(s);
+	ReleaseSock(s);
+}
+
+// RPC サーバースレッド
+void CiRpcServerThread(THREAD *thread, void *param)
+{
+	CLIENT *c;
+	SOCK *listener;
+	UINT i;
+	LIST *thread_list;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	c = (CLIENT *)param;
+
+	// RPC コネクションリスト
+	c->RpcConnectionList = NewList(NULL);
+
+	// ポートを開く
+	listener = NULL;
+	for (i = CLIENT_CONFIG_PORT;i < (CLIENT_CONFIG_PORT + 5);i++)
+	{
+		listener = Listen(i);
+		if (listener != NULL)
+		{
+			break;
+		}
+	}
+
+	if (listener == NULL)
+	{
+		// エラー
+		Alert("SoftEther UT-VPN Client RPC Port Open Failed.", CEDAR_CLIENT_STR);
+		return;
+	}
+
+	c->RpcListener = listener;
+	AddRef(listener->ref);
+
+	NoticeThreadInit(thread);
+
+	while (true)
+	{
+		// クライアント接続を待機
+		CLIENT_RPC_CONNECTION *conn;
+		SOCK *s = Accept(listener);
+		if (s == NULL)
+		{
+			// 停止
+			break;
+		}
+
+		// クライアント処理用スレッドを作成する
+		conn = ZeroMalloc(sizeof(CLIENT_RPC_CONNECTION));
+		conn->Client = c;
+		conn->Sock = s;
+		AddRef(s->ref);
+
+		conn->Thread = NewThread(CiRpcAcceptThread, (void *)conn);
+		WaitThreadInit(conn->Thread);
+
+		ReleaseSock(s);
+	}
+
+	// リスナーを解放
+	ReleaseSock(listener);
+
+	thread_list = NewListFast(NULL);
+
+	// すべての通知イベントを起動する
+	LockList(c->NotifyCancelList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++)
+		{
+			CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i);
+			Cancel(cancel);
+		}
+	}
+	UnlockList(c->NotifyCancelList);
+
+	// まだ接続しているすべてのコネクションを切断する
+	LockList(c->RpcConnectionList);
+	{
+		for (i = 0;i < LIST_NUM(c->RpcConnectionList);i++)
+		{
+			CLIENT_RPC_CONNECTION *cc = LIST_DATA(c->RpcConnectionList, i);
+			AddRef(cc->Thread->ref);
+			Add(thread_list, cc->Thread);
+			Disconnect(cc->Sock);
+		}
+	}
+	UnlockList(c->RpcConnectionList);
+
+	for (i = 0;i < LIST_NUM(thread_list);i++)
+	{
+		THREAD *t = LIST_DATA(thread_list, i);
+		WaitThread(t, INFINITE);
+		ReleaseThread(t);
+	}
+
+	ReleaseList(c->RpcConnectionList);
+	ReleaseList(thread_list);
+}
+
+// Keep を開始
+void CiInitKeep(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->Keep = StartKeep();
+
+	// 設定の適用
+	if (c->Config.UseKeepConnect)
+	{
+		KEEP *k = c->Keep;
+		Lock(k->lock);
+		{
+			StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost);
+			k->ServerPort = c->Config.KeepConnectPort;
+			k->Interval = c->Config.KeepConnectInterval * 1000;
+			k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false;
+			k->Enable = true;
+		}
+		Unlock(k->lock);
+	}
+}
+
+// Keep を停止
+void CiFreeKeep(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	StopKeep(c->Keep);
+	c->Keep = NULL;
+}
+
+// RPC を開始
+void CiStartRpcServer(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->RpcThread = NewThread(CiRpcServerThread, (void *)c);
+	WaitThreadInit(c->RpcThread);
+}
+
+// RPC を終了
+void CiStopRpcServer(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	Disconnect(c->RpcListener);
+	ReleaseSock(c->RpcListener);
+
+	WaitThread(c->RpcThread, INFINITE);
+	ReleaseThread(c->RpcThread);
+}
+
+// 次の通知を待機する
+bool CcWaitNotify(NOTIFY_CLIENT *n)
+{
+	UCHAR c;
+	// 引数チェック
+	if (n == NULL)
+	{
+		return false;
+	}
+
+	// 1 文字受信する
+	if (RecvAll(n->Sock, &c, 1, false) == false)
+	{
+		// 切断された
+		return false;
+	}
+
+	return true;
+}
+
+// 通知クライアントとして接続する
+NOTIFY_CLIENT *CcConnectNotify(REMOTE_CLIENT *rc)
+{
+	NOTIFY_CLIENT *n;
+	SOCK *s;
+	char tmp[MAX_SIZE];
+	bool rpc_mode = false;
+	UINT port;
+	// 引数チェック
+	if (rc == NULL || rc->Rpc == NULL || rc->Rpc->Sock == NULL)
+	{
+		return NULL;
+	}
+
+	// 接続
+	IPToStr(tmp, sizeof(tmp), &rc->Rpc->Sock->RemoteIP);
+	port = rc->Rpc->Sock->RemotePort;
+
+	s = Connect(tmp, port);
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	rpc_mode = Endian32(rpc_mode);
+	if (SendAll(s, &rpc_mode, sizeof(rpc_mode), false) == false)
+	{
+		ReleaseSock(s);
+		return NULL;
+	}
+
+	n = ZeroMalloc(sizeof(NOTIFY_CLIENT));
+	n->Sock = s;
+
+	return n;
+}
+
+// 通知クライアントを停止する
+void CcStopNotify(NOTIFY_CLIENT *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	Disconnect(n->Sock);
+}
+
+// 通知クライアントを削除する
+void CcDisconnectNotify(NOTIFY_CLIENT *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	// 切断
+	Disconnect(n->Sock);
+	ReleaseSock(n->Sock);
+
+	// メモリ解放
+	Free(n);
+}
+
+// リモート接続を切断する
+void CcDisconnectRpc(REMOTE_CLIENT *rc)
+{
+	// 引数チェック
+	if (rc == NULL)
+	{
+		return;
+	}
+
+	RpcFree(rc->Rpc);
+	Free(rc);
+}
+
+// クライアントに接続しショートカット接続設定を起動する
+UINT CcShortcut(UCHAR *key)
+{
+	UINT ret;
+	// 引数チェック
+	if (key == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, false, 0);
+
+	return ret;
+}
+
+// 接続中のショートカット接続を切断する
+UINT CcShortcutDisconnect(UCHAR *key)
+{
+	UINT ret;
+	// 引数チェック
+	if (key == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, true, 0);
+
+	return ret;
+}
+
+// クライアントにリモート接続する
+REMOTE_CLIENT *CcConnectRpc(char *server_name, char *password, bool *bad_pass, bool *no_remote, UINT wait_retry)
+{
+	return CcConnectRpcEx(server_name, password, bad_pass, no_remote, NULL, NULL, false, wait_retry);
+}
+REMOTE_CLIENT *CcConnectRpcEx(char *server_name, char *password, bool *bad_pass, bool *no_remote, UCHAR *key, UINT *key_error_code, bool shortcut_disconnect, UINT wait_retry)
+{
+	SOCK *s;
+	UINT i;
+	UINT retcode;
+	UINT rpc_mode = CLIENT_RPC_MODE_MANAGEMENT;
+	RPC *rpc;
+	REMOTE_CLIENT *ret;
+	UCHAR hash_password[SHA1_SIZE];
+	UINT port_start;
+	UINT64 try_started = 0;
+	bool ok;
+	// 引数チェック
+	if (server_name == NULL)
+	{
+		return NULL;
+	}
+	if (password == NULL)
+	{
+		password = "";
+	}
+
+	if (key_error_code != NULL)
+	{
+		*key_error_code = ERR_NO_ERROR;
+	}
+
+	if (bad_pass != NULL)
+	{
+		*bad_pass = false;
+	}
+
+	if (no_remote != NULL)
+	{
+		*no_remote = false;
+	}
+
+	port_start = CLIENT_CONFIG_PORT - 1;
+
+RETRY:
+	port_start++;
+
+	if (port_start >= (CLIENT_CONFIG_PORT + 5))
+	{
+		return NULL;
+	}
+
+	ok = false;
+
+	while (true)
+	{
+		for (i = port_start;i < (CLIENT_CONFIG_PORT + 5);i++)
+		{
+			if (CheckTCPPort(server_name, i))
+			{
+				ok = true;
+				break;
+			}
+		}
+
+		if (ok)
+		{
+			break;
+		}
+
+		if (wait_retry == 0)
+		{
+			break;
+		}
+
+		if (try_started == 0)
+		{
+			try_started = Tick64();
+		}
+
+		if ((try_started + (UINT64)wait_retry) <= Tick64())
+		{
+			break;
+		}
+	}
+
+	if (ok == false)
+	{
+		if (key_error_code)
+		{
+			*key_error_code = ERR_CONNECT_FAILED;
+		}
+		return NULL;
+	}
+
+	port_start = i;
+
+	s = Connect(server_name, i);
+	if (s == NULL)
+	{
+		if (key_error_code)
+		{
+			*key_error_code = ERR_CONNECT_FAILED;
+		}
+		goto RETRY;
+	}
+
+	Hash(hash_password, password, StrLen(password), true);
+
+	if (key != NULL)
+	{
+		if (shortcut_disconnect == false)
+		{
+			rpc_mode = CLIENT_RPC_MODE_SHORTCUT;
+		}
+		else
+		{
+			rpc_mode = CLIENT_RPC_MODE_SHORTCUT_DISCONNECT;
+		}
+	}
+
+	rpc_mode = Endian32(rpc_mode);
+	SendAdd(s, &rpc_mode, sizeof(UINT));
+
+	if (key != NULL)
+	{
+		SendAdd(s, key, SHA1_SIZE);
+	}
+	else
+	{
+		SendAdd(s, hash_password, SHA1_SIZE);
+	}
+
+	if (SendNow(s, false) == false)
+	{
+		ReleaseSock(s);
+		goto RETRY;
+	}
+
+	if (RecvAll(s, &retcode, sizeof(UINT), false) == false)
+	{
+		ReleaseSock(s);
+		goto RETRY;
+	}
+
+	retcode = Endian32(retcode);
+
+	if (retcode >= 1024)
+	{
+		goto RETRY;
+	}
+
+	if (key != NULL)
+	{
+		if (key_error_code)
+		{
+			*key_error_code = retcode;
+		}
+		SendAll(s, &retcode, sizeof(UINT), false);
+		ReleaseSock(s);
+		return NULL;
+	}
+
+	switch (retcode)
+	{
+	case 1:
+		if (bad_pass != NULL)
+		{
+			*bad_pass = true;
+		}
+		break;
+	case 2:
+		if (no_remote != NULL)
+		{
+			*no_remote = true;
+		}
+		break;
+	}
+
+	if (retcode != 0)
+	{
+		ReleaseSock(s);
+		return NULL;
+	}
+
+	rpc = StartRpcClient(s, NULL);
+
+	ReleaseSock(s);
+
+	ret = ZeroMalloc(sizeof(REMOTE_CLIENT));
+	ret->Rpc = rpc;
+	rpc->Param = ret;
+
+	if (ret != NULL)
+	{
+		RPC_CLIENT_VERSION t;
+		Zero(&t, sizeof(t));
+		CcGetClientVersion(ret, &t);
+		ret->OsType = t.OsType;
+		ret->Unix = OS_IS_UNIX(ret->OsType);
+		ret->Win9x = OS_IS_WINDOWS_9X(ret->OsType);
+	}
+
+	return ret;
+}
+
+// セッションから RPC_CLIENT_GET_CONNECTION_STATUS を取得
+void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s)
+{
+	// 引数チェック
+	if (st == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Lock(s->lock);
+	{
+		// 動作フラグ
+		st->Active = true;
+
+		// セッションステータス
+		st->SessionStatus = s->ClientStatus;
+
+		// アカウント名
+		UniStrCpy(st->AccountName, sizeof(st->AccountName), s->ClientOption->AccountName);
+
+		if (s->ClientStatus == CLIENT_STATUS_ESTABLISHED && s->Connection != NULL)
+		{
+			Lock(s->Connection->lock);
+			{
+				// 接続済みフラグ
+				st->Connected = true;
+				// 製品名
+				StrCpy(st->ServerProductName, sizeof(st->ServerProductName), s->Connection->ServerStr);
+				// バージョン
+				st->ServerProductVer = s->Connection->ServerVer;
+				// ビルド番号
+				st->ServerProductBuild = s->Connection->ServerBuild;
+				// サーバー証明書
+				st->ServerX = CloneX(s->Connection->ServerX);
+				// クライアント証明書
+				st->ClientX = CloneX(s->Connection->ClientX);
+				// このコネクションの接続完了時刻
+				st->CurrentConnectionEstablishTime = TickToTime(s->CurrentConnectionEstablishTime);
+				// 最大の TCP コネクション数
+				st->MaxTcpConnections = s->MaxConnection;
+				// ハーフコネクション
+				st->HalfConnection = s->HalfConnection;
+				// VLAN
+				st->VLanId = s->VLanId;
+				// VoIP / QoS
+				st->QoS = s->QoS;
+				if (s->Connection->Protocol == CONNECTION_TCP)
+				{
+					UINT i;
+					// 現在の TCP コネクション数
+					LockList(s->Connection->Tcp->TcpSockList);
+					{
+						st->NumTcpConnections = LIST_NUM(s->Connection->Tcp->TcpSockList);
+						if (st->HalfConnection)
+						{
+							for (i = 0;i < st->NumTcpConnections;i++)
+							{
+								TCPSOCK *ts = LIST_DATA(s->Connection->Tcp->TcpSockList, i);
+								if (ts->Direction & TCP_SERVER_TO_CLIENT)
+								{
+									st->NumTcpConnectionsDownload++;
+								}
+								else
+								{
+									st->NumTcpConnectionsUpload++;
+								}
+							}
+						}
+					}
+					UnlockList(s->Connection->Tcp->TcpSockList);
+				}
+				// 暗号化の使用
+				st->UseEncrypt = s->UseEncrypt;
+				if (st->UseEncrypt)
+				{
+					StrCpy(st->CipherName, sizeof(st->CipherName), s->Connection->CipherName);
+				}
+				// 圧縮の使用
+				st->UseCompress = s->UseCompress;
+				// セッションキー
+				Copy(st->SessionKey, s->SessionKey, SHA1_SIZE);
+				// ポリシー
+				Copy(&st->Policy, s->Policy, sizeof(POLICY));
+				// データサイズ
+				if (s->ServerMode == false)
+				{
+					st->TotalSendSize = s->TotalSendSize;
+					st->TotalRecvSize = s->TotalRecvSize;
+					st->TotalRecvSizeReal = s->TotalRecvSizeReal;
+					st->TotalSendSizeReal = s->TotalSendSizeReal;
+				}
+				else
+				{
+					st->TotalSendSize = s->TotalRecvSize;
+					st->TotalRecvSize = s->TotalSendSize;
+					st->TotalRecvSizeReal = s->TotalSendSizeReal;
+					st->TotalSendSizeReal = s->TotalRecvSizeReal;
+				}
+				// セッション名
+				StrCpy(st->SessionName, sizeof(st->SessionName), s->Name);
+				// コネクション名
+				StrCpy(st->ConnectionName, sizeof(st->ConnectionName), s->Connection->Name);
+				// サーバー名
+				StrCpy(st->ServerName, sizeof(st->ServerName), s->Connection->ServerName);
+				// ポート番号
+				st->ServerPort = s->Connection->ServerPort;
+				// トラフィックデータ
+				Lock(s->TrafficLock);
+				{
+					Copy(&st->Traffic, s->Traffic, sizeof(TRAFFIC));
+				}
+				Unlock(s->TrafficLock);
+
+				st->IsBridgeMode = s->IsBridgeMode;
+				st->IsMonitorMode = s->IsMonitorMode;
+			}
+			Unlock(s->Connection->lock);
+		}
+		// 接続開始時刻
+		st->StartTime = TickToTime(s->CreatedTime);
+		// 最初のコネクションの接続完了時刻
+		st->FirstConnectionEstablisiedTime = TickToTime(s->FirstConnectionEstablisiedTime);
+		// これまでに確立したコネクション数
+		st->NumConnectionsEatablished = s->NumConnectionsEatablished;
+	}
+	Unlock(s->lock);
+}
+
+// 接続ステータスの取得
+bool CtGetAccountStatus(CLIENT *c, RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+	// 引数チェック
+	if (c == NULL || st == NULL)
+	{
+		return false;
+	}
+
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *r;
+
+		// アカウントを検索
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), st->AccountName);
+
+		r = Search(c->AccountList, &t);
+		if (r == NULL)
+		{
+			// 指定したアカウントは見つからない
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		Lock(r->lock);
+		{
+			Zero(st, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS));
+			if (r->ClientSession != NULL)
+			{
+				SESSION *s = r->ClientSession;
+				CiGetSessionStatus(st, s);
+			}
+		}
+		Unlock(r->lock);
+	}
+	UnlockList(c->AccountList);
+
+	return true;
+}
+
+// 接続ステータスの解放
+void CiFreeClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+	// 引数チェック
+	if (st == NULL)
+	{
+		return;
+	}
+
+	if (st->ServerX != NULL)
+	{
+		FreeX(st->ServerX);
+	}
+
+	if (st->ClientX != NULL)
+	{
+		FreeX(st->ClientX);
+	}
+}
+
+// サーバー証明書の確認プロシージャ
+bool CiCheckCertProc(SESSION *s, CONNECTION *c, X *server_x, bool *expired)
+{
+#ifdef	OS_WIN32
+	ACCOUNT *a;
+	X *old_x = NULL;
+	UI_CHECKCERT dlg;
+	// 引数チェック
+	if (s == NULL || c == NULL || server_x == NULL)
+	{
+		return false;
+	}
+
+	if (expired != NULL)
+	{
+		*expired = false;
+	}
+
+	Zero(&dlg, sizeof(dlg));
+
+	a = s->Account;
+	if (a == NULL)
+	{
+		return false;
+	}
+
+	Lock(a->lock);
+	{
+		if (a->CheckServerCert == false)
+		{
+			// サーバー証明書を検証しない
+			Unlock(a->lock);
+			return true;
+		}
+
+		if (a->ServerCert != NULL)
+		{
+			old_x = CloneX(a->ServerCert);
+		}
+	}
+	Unlock(a->lock);
+
+	if (CheckXDateNow(server_x) == false)
+	{
+		// 有効期限が切れている
+		if (old_x != NULL)
+		{
+			FreeX(old_x);
+		}
+
+		if (expired != NULL)
+		{
+			*expired = true;
+		}
+
+		return false;
+	}
+
+	if (old_x != NULL)
+	{
+		if (CompareX(old_x, server_x))
+		{
+			// すでに登録されている証明書と完全一致した
+			if (old_x != NULL)
+			{
+				FreeX(old_x);
+			}
+			return true;
+		}
+		else
+		{
+			dlg.DiffWarning = true;
+		}
+	}
+
+	// この証明書は信頼できないのでダイアログボックスを出して確認する
+	UniStrCpy(dlg.AccountName, sizeof(dlg.AccountName), a->ClientOption->AccountName);
+	StrCpy(dlg.ServerName, sizeof(dlg.ServerName), a->ClientOption->Hostname);
+	dlg.x = server_x;
+	dlg.old_x = old_x;
+	
+	dlg.Session = s;
+	AddRef(s->ref);
+
+	CncCheckCert(s, &dlg);
+
+	ReleaseSession(s);
+
+	if (old_x != NULL)
+	{
+		FreeX(old_x);
+	}
+
+	if (dlg.Ok && dlg.SaveServerCert)
+	{
+		// このサーバー証明書を保存し次回から信頼する
+		Lock(a->lock);
+		{
+			if (a->ServerCert != NULL)
+			{
+				FreeX(a->ServerCert);
+			}
+
+			a->ServerCert = CloneX(server_x);
+		}
+		Unlock(a->lock);
+		CiSaveConfigurationFile(s->Cedar->Client);
+	}
+
+	return dlg.Ok;
+#else	// OS_WIN32
+	ACCOUNT *a;
+	X *old_x = NULL;
+	// 引数チェック
+	if (s == NULL || c == NULL || server_x == NULL)
+	{
+		return false;
+	}
+
+	if (expired != NULL)
+	{
+		*expired = false;
+	}
+
+	a = s->Account;
+	if (a == NULL)
+	{
+		return false;
+	}
+
+	Lock(a->lock);
+	{
+		if (a->CheckServerCert == false)
+		{
+			// サーバー証明書を検証しない
+			Unlock(a->lock);
+			return true;
+		}
+
+		if (a->ServerCert != NULL)
+		{
+			old_x = CloneX(a->ServerCert);
+		}
+	}
+	Unlock(a->lock);
+
+	if (CheckXDateNow(server_x) == false)
+	{
+		// 有効期限が切れている
+		if (old_x != NULL)
+		{
+			FreeX(old_x);
+		}
+
+		if (expired != NULL)
+		{
+			*expired = true;
+		}
+
+		return false;
+	}
+
+	if (old_x != NULL)
+	{
+		if (CompareX(old_x, server_x))
+		{
+			// すでに登録されている証明書と完全一致した
+			if (old_x != NULL)
+			{
+				FreeX(old_x);
+			}
+			return true;
+		}
+		else
+		{
+			// 不一致
+			if (old_x != NULL)
+			{
+				FreeX(old_x);
+			}
+			return false;
+		}
+	}
+
+	if (old_x != NULL)
+	{
+		FreeX(old_x);
+	}
+
+	return false;
+#endif	// OS_WIN32
+}
+
+// セキュアデバイスを使用した署名プロシージャ
+bool CiSecureSignProc(SESSION *s, CONNECTION *c, SECURE_SIGN *sign)
+{
+	// Win32 の場合は UI を使用することができる
+	return CncSecureSignDlg(sign);
+}
+
+#ifdef	OS_WIN32
+// 署名プロシージャ (Win32 用)
+bool Win32CiSecureSign(SECURE_SIGN *sign)
+{
+	bool ret = false;
+	BUF *random;
+	// 引数チェック
+	if (sign == NULL)
+	{
+		return false;
+	}
+
+	random = NewBuf();
+	WriteBuf(random, sign->Random, SHA1_SIZE);
+
+	// バッチ処理
+	{
+		WINUI_SECURE_BATCH batch[] =
+		{
+			{WINUI_SECURE_READ_CERT, sign->SecurePublicCertName, true, NULL, NULL, NULL, NULL, NULL, NULL},
+			{WINUI_SECURE_SIGN_WITH_KEY, sign->SecurePrivateKeyName, true, random, NULL, NULL, NULL, NULL, NULL}
+		};
+
+		if (SecureDeviceWindow(NULL, batch, sizeof(batch) / sizeof(batch[0]),
+			sign->UseSecureDeviceId, sign->BitmapId) == false)
+		{
+			// 失敗
+			if (batch[0].OutputX != 0)
+			{
+				FreeX(batch[0].OutputX);
+			}
+			ret = false;
+		}
+		else
+		{
+			// 成功
+			ret = true;
+			sign->ClientCert = batch[0].OutputX;
+			Copy(sign->Signature, batch[1].OutputSign, 128);
+		}
+	}
+
+	FreeBuf(random);
+
+	return ret;
+}
+#endif	// OS_WIN32
+
+// 切断
+bool CtDisconnect(CLIENT *c, RPC_CLIENT_CONNECT *connect)
+{
+	bool ret = false;
+	ACCOUNT t, *r;
+	SESSION *s = NULL;
+	// 引数チェック
+	if (c == NULL || connect == NULL)
+	{
+		return false;
+	}
+
+	LockList(c->AccountList);
+	{
+
+		// アカウントを検索
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName);
+
+		r = Search(c->AccountList, &t);
+		if (r == NULL)
+		{
+			// 指定したアカウントは見つからない
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		Lock(r->lock);
+		{
+			if (r->ClientSession == NULL)
+			{
+				// 接続していない
+				CiSetError(c, ERR_ACCOUNT_INACTIVE);
+			}
+			else
+			{
+				s = r->ClientSession;
+				AddRef(s->ref);
+				// 切断完了
+				r->ClientSession = NULL;
+				ret = true;
+			}
+		}
+		Unlock(r->lock);
+	}
+	UnlockList(c->AccountList);
+
+	if (s != NULL)
+	{
+		// 接続を切断 (切断完了まで待機)
+		CLog(c, "LC_DISCONNECT", connect->AccountName);
+		StopSession(s);
+		ReleaseSession(s);
+	}
+
+	if (ret != false)
+	{
+		CiNotify(c);
+	}
+
+	return ret;
+}
+
+// 接続
+bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect)
+{
+	bool ret = false;
+	RPC_CLIENT_ENUM_VLAN t;
+	// 引数チェック
+	if (c == NULL || connect == NULL)
+	{
+		return false;
+	}
+
+	Lock(c->lockForConnect);
+	{
+		Zero(&t, sizeof(t));
+		if (CtEnumVLan(c, &t))
+		{
+			if (t.NumItem == 0)
+			{
+				// システムに仮想 LAN カードが 1 枚も無い
+				if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) || OS_IS_UNIX(GetOsInfo()->OsType))
+				{
+					// Windows NT 系または Linux 系の場合のみ、自動的に "VPN" という名前の
+					// 新しい仮想 LAN カードを作成する
+					RPC_CLIENT_CREATE_VLAN t;
+
+					Zero(&t, sizeof(t));
+					StrCpy(t.DeviceName, sizeof(t.DeviceName), "VPN");
+					CtCreateVLan(c,  &t);
+				}
+			}
+
+			CiFreeClientEnumVLan(&t);
+		}
+	}
+	Unlock(c->lockForConnect);
+
+	CiNormalizeAccountVLan(c);
+
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *r;
+		bool unix_disabled = false;
+
+		// アカウントを検索
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName);
+
+		r = Search(c->AccountList, &t);
+		if (r == NULL)
+		{
+			// 指定したアカウントは見つからない
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+#ifndef	OS_WIN32
+		// 仮想 LAN カードを検索する
+		LockList(c->UnixVLanList);
+		{
+			UNIX_VLAN *v, t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.Name, sizeof(t.Name), r->ClientOption->DeviceName);
+
+			v = Search(c->UnixVLanList, &t);
+			if (v == NULL)
+			{
+				UnlockList(c->UnixVLanList);
+				CiSetError(c, ERR_OBJECT_NOT_FOUND);
+				return false;
+			}
+
+			unix_disabled = v->Enabled ? false : true;
+		}
+		UnlockList(c->UnixVLanList);
+#endif	// OS_WIN32
+
+		Lock(r->lock);
+		{
+			bool already_used = false;
+			UINT i;
+
+			if (r->ClientSession != NULL)
+			{
+				// すでに接続中
+				CiSetError(c, ERR_ACCOUNT_ACTIVE);
+			}
+			else if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE &&
+				client->UseSecureDeviceId == 0)
+			{
+				// セキュアデバイスが指定されていない
+				CiSetError(c, ERR_NO_SECURE_DEVICE_SPECIFIED);
+			}
+#ifdef	OS_WIN32
+			else if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, r->ClientOption->DeviceName) == false)
+			{
+				// 仮想 LAN カードが見つからない
+				CiSetError(c, ERR_VLAN_FOR_ACCOUNT_NOT_FOUND);
+				CiNotify(c);
+			}
+			else if (MsIsVLanEnabled(r->ClientOption->DeviceName) == false)
+			{
+				// 仮想 LAN カードは無効化されている
+				CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED);
+				CiNotify(c);
+			}
+#else	// OS_WIN32
+			else if (unix_disabled)
+			{
+				// 仮想 LAN カードは無効化されている
+				CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED);
+				CiNotify(c);
+			}
+#endif	// OS_WIN32
+			else
+			{
+				// 仮想 LAN カードがすでに別のアカウントで使用されているかどうか調べる
+				for (i = 0;i < LIST_NUM(c->AccountList);i++)
+				{
+					ACCOUNT *a = LIST_DATA(c->AccountList, i);
+					if (a != r)
+					{
+						if (StrCmpi(a->ClientOption->DeviceName,
+							r->ClientOption->DeviceName) == 0)
+						{
+							if (a->ClientSession != NULL)
+							{
+								already_used = true;
+								break;
+							}
+						}
+					}
+				}
+
+				if (already_used)
+				{
+					CiSetError(c, ERR_VLAN_FOR_ACCOUNT_USED);
+				}
+				else
+				{
+					// 接続を開始
+					PACKET_ADAPTER *pa = VLanGetPacketAdapter();
+
+					if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+					{
+						// セキュアデバイス認証のためのプロシージャを登録する
+						r->ClientAuth->SecureSignProc = CiSecureSignProc;
+					}
+					else
+					{
+						r->ClientAuth->SecureSignProc = NULL;
+					}
+
+					if (r->CheckServerCert)
+					{
+						// サーバー証明書確認のためのプロシージャを登録する
+						r->ClientAuth->CheckCertProc = CiCheckCertProc;
+					}
+					else
+					{
+						r->ClientAuth->CheckCertProc = NULL;
+					}
+
+					r->StatusPrinter = CiClientStatusPrinter;
+					r->LastConnectDateTime = SystemTime64();
+
+					CLog(c, "LC_CONNECT", connect->AccountName);
+
+					r->ClientSession = NewClientSessionEx(c->Cedar, r->ClientOption, r->ClientAuth, pa, r);
+					Notify(r->ClientSession, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+					ret = true;
+				}
+			}
+		}
+		Unlock(r->lock);
+
+	}
+	UnlockList(c->AccountList);
+
+	CiSaveConfigurationFile(c);
+
+	return ret;
+}
+
+// アカウント情報の取得
+bool CtGetAccount(CLIENT *c, RPC_CLIENT_GET_ACCOUNT *a)
+{
+	// 引数チェック
+	if (c == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *r;
+
+		// アカウントを検索
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+		r = Search(c->AccountList, &t);
+		if (r == NULL)
+		{
+			// 指定したアカウントは見つからない
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		Lock(r->lock);
+		{
+			// クライアントオプションをコピー
+			if (a->ClientOption != NULL)
+			{
+				Free(a->ClientOption);
+			}
+			a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+			Copy(a->ClientOption, r->ClientOption, sizeof(CLIENT_OPTION));
+
+			// 認証データをコピー
+			if (a->ClientAuth != NULL)
+			{
+				CiFreeClientAuth(a->ClientAuth);
+			}
+			a->ClientAuth = CopyClientAuth(r->ClientAuth);
+
+			a->StartupAccount = r->StartupAccount;
+
+			a->CheckServerCert = r->CheckServerCert;
+			a->ServerCert = NULL;
+			if (r->ServerCert != NULL)
+			{
+				a->ServerCert = CloneX(r->ServerCert);
+			}
+
+			// ショートカットキー
+			Copy(a->ShortcutKey, r->ShortcutKey, SHA1_SIZE);
+
+			a->CreateDateTime = r->CreateDateTime;
+			a->LastConnectDateTime = r->LastConnectDateTime;
+			a->UpdateDateTime = r->UpdateDateTime;
+		}
+		Unlock(r->lock);
+
+	}
+	UnlockList(c->AccountList);
+
+	return true;
+}
+
+// アカウント名の変更
+bool CtRenameAccount(CLIENT *c, RPC_RENAME_ACCOUNT *rename)
+{
+	bool ret;
+	// 引数チェック
+	if (c == NULL || rename == NULL)
+	{
+		return false;
+	}
+
+	ret = false;
+
+	if (UniStrCmp(rename->NewName, rename->OldName) == 0)
+	{
+		// 名前が変更されていない
+		return true;
+	}
+
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *r, *r2;
+
+		if (UniStrLen(rename->NewName) == 0)
+		{
+			// 名前が不正
+			CiSetError(c, ERR_INVALID_VALUE);
+			UnlockList(c->AccountList);
+			return false;
+		}
+
+		// 古いアカウント名を検索
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->OldName);
+
+		r = Search(c->AccountList, &t);
+		if (r == NULL)
+		{
+			// 指定したアカウントは見つからない
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		// 新しいアカウント名を検索
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->NewName);
+
+		r2 = Search(c->AccountList, &t);
+		if (r2 != NULL)
+		{
+			// 指定した名前のアカウントはすでに存在する
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		Lock(r->lock);
+		{
+			// アカウントの動作状態チェック
+			if (r->ClientSession != NULL)
+			{
+				// アカウントは動作中
+				Unlock(r->lock);
+				UnlockList(c->AccountList);
+				CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+				return false;
+			}
+
+			// アカウント名を更新
+			UniStrCpy(r->ClientOption->AccountName, sizeof(r->ClientOption->AccountName),
+				rename->NewName);
+
+			CLog(c, "LC_RENAME_ACCOUNT", rename->OldName, rename->NewName);
+
+			ret = true;
+		}
+		Unlock(r->lock);
+
+		Sort(c->AccountList);
+
+	}
+	UnlockList(c->AccountList);
+
+	CiSaveConfigurationFile(c);
+
+	CiNotify(c);
+
+	return ret;
+}
+
+// クライアント設定の設定
+bool CtSetClientConfig(CLIENT *c, CLIENT_CONFIG *o)
+{
+	KEEP *k;
+	// 引数チェック
+	if (c == NULL || o == NULL)
+	{
+		return false;
+	}
+
+	if (o->UseKeepConnect)
+	{
+		if (IsEmptyStr(o->KeepConnectHost) ||
+			o->KeepConnectPort == 0 ||
+			o->KeepConnectPort >= 65536)
+		{
+			CiSetError(c, ERR_INVALID_PARAMETER);
+			return false;
+		}
+	}
+
+	Lock(c->lock);
+	{
+		Copy(&c->Config, o, sizeof(CLIENT_CONFIG));
+	}
+	Unlock(c->lock);
+
+	// 設定の保存
+	CiSaveConfigurationFile(c);
+
+	// Keep Connect の適用
+	k = c->Keep;
+	Lock(k->lock);
+	{
+		if (o->UseKeepConnect)
+		{
+			StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost);
+			k->ServerPort = c->Config.KeepConnectPort;
+			k->Interval = c->Config.KeepConnectInterval * 1000;
+			k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false;
+			k->Enable = true;
+		}
+		else
+		{
+			k->Enable = false;
+		}
+	}
+	Unlock(k->lock);
+
+	return true;
+}
+
+// ククライアント設定の取得
+bool CtGetClientConfig(CLIENT *c, CLIENT_CONFIG *o)
+{
+	// 引数チェック
+	if (c == NULL || o == NULL)
+	{
+		return false;
+	}
+
+	Lock(c->lock);
+	{
+		Copy(o, &c->Config, sizeof(CLIENT_CONFIG));
+	}
+	Unlock(c->lock);
+
+	return true;
+}
+
+// アカウントのスタートアップ属性を解除する
+bool CtRemoveStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+	bool ret;
+	// 引数チェック
+	if (c == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	ret = false;
+
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *r;
+		// アカウントの検索
+
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+		r = Search(c->AccountList, &t);
+		if (r == NULL)
+		{
+			// 指定したアカウントは見つからない
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		Lock(r->lock);
+		{
+			// スタートアップアカウントを解除する
+			ret = true;
+			r->StartupAccount = false;
+		}
+		Unlock(r->lock);
+	}
+	UnlockList(c->AccountList);
+
+	if (ret)
+	{
+		CiSaveConfigurationFile(c);
+		CiNotify(c);
+	}
+
+	return ret;
+}
+
+// アカウントをスタートアップアカウントにする
+bool CtSetStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+	bool ret;
+	// 引数チェック
+	if (c == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	ret = false;
+
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *r;
+		// アカウントの検索
+
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+		r = Search(c->AccountList, &t);
+		if (r == NULL)
+		{
+			// 指定したアカウントは見つからない
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		Lock(r->lock);
+		{
+			// スタートアップアカウントにする
+			ret = true;
+			r->StartupAccount = true;
+		}
+		Unlock(r->lock);
+	}
+	UnlockList(c->AccountList);
+
+	if (ret)
+	{
+		CiSaveConfigurationFile(c);
+		CiNotify(c);
+	}
+
+	return ret;
+}
+
+// アカウントの削除
+bool CtDeleteAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+	bool ret;
+	// 引数チェック
+	if (c == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	ret = false;
+
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *r;
+		// アカウントの検索
+
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+		r = Search(c->AccountList, &t);
+		if (r == NULL)
+		{
+			// 指定したアカウントは見つからない
+			UnlockList(c->AccountList);
+
+			Free(t.ClientOption);
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		Lock(r->lock);
+		{
+			// アカウントの動作状態チェック
+			if (r->ClientSession != NULL)
+			{
+				// アカウントは動作中
+				Unlock(r->lock);
+				UnlockList(c->AccountList);
+				CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+				return false;
+			}
+
+			// このアカウントをリストから削除する
+			Delete(c->AccountList, r);
+		}
+		Unlock(r->lock);
+
+		// このアカウントのメモリを解放する
+		CiFreeAccount(r);
+
+		CLog(c, "LC_DELETE_ACCOUNT", a->AccountName);
+		ret = true;
+
+	}
+	UnlockList(c->AccountList);
+
+	if (ret)
+	{
+		CiSaveConfigurationFile(c);
+		CiNotify(c);
+	}
+
+	return ret;
+}
+
+// アカウントの列挙
+bool CtEnumAccount(CLIENT *c, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+	// 引数チェック
+	if (c == NULL || e == NULL)
+	{
+		return false;
+	}
+
+	LockList(c->AccountList);
+	{
+		UINT i;
+		// アカウント件数
+		e->NumItem = LIST_NUM(c->AccountList);
+		e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem);
+
+		for (i = 0;i < e->NumItem;i++)
+		{
+			ACCOUNT *a = LIST_DATA(c->AccountList, i);
+			RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM));
+			e->Items[i] = item;
+
+			// アカウント名
+			UniStrCpy(item->AccountName, sizeof(item->AccountName), a->ClientOption->AccountName);
+
+			// ユーザー名
+			StrCpy(item->UserName, sizeof(item->UserName), a->ClientAuth->Username);
+
+			// サーバー名
+			StrCpy(item->ServerName, sizeof(item->ServerName), a->ClientOption->Hostname);
+
+			// プロキシ種類
+			item->ProxyType = a->ClientOption->ProxyType;
+
+			// デバイス名
+			StrCpy(item->DeviceName, sizeof(item->DeviceName), a->ClientOption->DeviceName);
+
+			// プロキシ情報
+			if (item->ProxyType != PROXY_DIRECT)
+			{
+				StrCpy(item->ProxyName, sizeof(item->ProxyName), a->ClientOption->ProxyName);
+			}
+
+			// スタートアップ
+			item->StartupAccount = a->StartupAccount;
+
+			// 動作フラグ
+			item->Active = (a->ClientSession == NULL ? false : true);
+
+			// 接続フラグ
+			item->Connected = (item->Active == false) ? false : a->ClientSession->ConnectSucceed;
+
+			// ポート番号
+			item->Port = a->ClientOption->Port;
+
+			// 仮想 HUB 名
+			StrCpy(item->HubName, sizeof(item->HubName), a->ClientOption->HubName);
+
+			item->CreateDateTime = a->CreateDateTime;
+			item->LastConnectDateTime = a->LastConnectDateTime;
+			item->UpdateDateTime = a->UpdateDateTime;
+		}
+	}
+	UnlockList(c->AccountList);
+
+	return true;
+}
+
+// アカウントの設定
+bool CtSetAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+	// 引数チェック
+	if (c == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	// 既存のアカウントが存在するかどうかチェック
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *ret;
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+			a->ClientOption->AccountName);
+
+		ret = Search(c->AccountList, &t);
+		if (ret == NULL)
+		{
+			// 存在しない
+			UnlockList(c->AccountList);
+			Free(t.ClientOption);
+
+			CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+
+			return false;
+		}
+		Free(t.ClientOption);
+
+		if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+		{
+			if (a->ClientAuth->ClientX == NULL ||
+				a->ClientAuth->ClientX->is_compatible_bit == false ||
+				a->ClientAuth->ClientK == NULL)
+			{
+				// クライアント証明書が不正
+				UnlockList(c->AccountList);
+				CiSetError(c, ERR_NOT_RSA_1024);
+				return false;
+			}
+		}
+
+		if (a->ServerCert != NULL && a->ServerCert->is_compatible_bit == false)
+		{
+			// サーバー証明書が不正
+			UnlockList(c->AccountList);
+			CiSetError(c, ERR_NOT_RSA_1024);
+			return false;
+		}
+
+		Lock(ret->lock);
+		{
+
+#if	0
+			// 現在のバージョンではアカウント動作中でも設定の書き換えは行われる
+			// (ただし次回接続時まで設定は適用されない)
+			if (ret->ClientSession != NULL)
+			{
+				// アカウントが動作中である
+				Unlock(ret->lock);
+				UnlockList(c->AccountList);
+
+				CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+				return false;
+			}
+#endif
+
+			// クライアント認証データの削除
+			CiFreeClientAuth(ret->ClientAuth);
+
+			// クライアント認証データのコピー
+			ret->ClientAuth = CopyClientAuth(a->ClientAuth);
+
+			// クライアントオプションの削除
+			Free(ret->ClientOption);
+
+			// クライアントオプションのコピー
+			ret->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+			Copy(ret->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+
+			ret->StartupAccount = a->StartupAccount;
+
+			ret->CheckServerCert = a->CheckServerCert;
+
+			if (a->ServerCert != NULL)
+			{
+				if (ret->ServerCert != NULL)
+				{
+					FreeX(ret->ServerCert);
+				}
+				ret->ServerCert = CloneX(a->ServerCert);
+			}
+			else
+			{
+				if (ret->ServerCert != NULL)
+				{
+					FreeX(ret->ServerCert);
+				}
+				ret->ServerCert = false;
+			}
+
+			ret->UpdateDateTime = SystemTime64();
+		}
+		Unlock(ret->lock);
+	}
+	UnlockList(c->AccountList);
+
+	CiSaveConfigurationFile(c);
+
+	CiNotify(c);
+
+	return true;
+}
+
+// アカウントの作成
+bool CtCreateAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+	// 引数チェック
+	if (c == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	// 既存のアカウントが存在するかどうかチェック
+	LockList(c->AccountList);
+	{
+		ACCOUNT t, *ret, *new_account;
+		t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+			a->ClientOption->AccountName);
+
+		ret = Search(c->AccountList, &t);
+		if (ret != NULL)
+		{
+			// すでに存在する
+			UnlockList(c->AccountList);
+			Free(t.ClientOption);
+
+			CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS);
+
+			return false;
+		}
+
+		Free(t.ClientOption);
+
+		if (UniStrLen(a->ClientOption->AccountName) == 0)
+		{
+			// 名前が不正
+			UnlockList(c->AccountList);
+			CiSetError(c, ERR_INVALID_VALUE);
+			return false;
+		}
+
+		if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+		{
+			if (a->ClientAuth->ClientX == NULL ||
+				a->ClientAuth->ClientX->is_compatible_bit == false ||
+				a->ClientAuth->ClientK == NULL)
+			{
+				// クライアント証明書が不正
+				UnlockList(c->AccountList);
+				CiSetError(c, ERR_NOT_RSA_1024);
+				return false;
+			}
+		}
+
+		if (a->ServerCert != NULL && a->ServerCert->is_compatible_bit == false)
+		{
+			// サーバー証明書が不正
+			UnlockList(c->AccountList);
+			CiSetError(c, ERR_NOT_RSA_1024);
+			return false;
+		}
+
+		// 新しいアカウントを追加する
+		new_account = ZeroMalloc(sizeof(ACCOUNT));
+		new_account->lock = NewLock();
+
+		// クライアント認証データのコピー
+		new_account->ClientAuth = CopyClientAuth(a->ClientAuth);
+
+		// クライアントオプションのコピー
+		new_account->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		Copy(new_account->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+
+		new_account->StartupAccount = a->StartupAccount;
+
+		new_account->CheckServerCert = a->CheckServerCert;
+		if (a->ServerCert != NULL)
+		{
+			new_account->ServerCert = CloneX(a->ServerCert);
+		}
+
+		// ショートカットキー
+		if (IsZero(a->ShortcutKey, SHA1_SIZE))
+		{
+			Rand(new_account->ShortcutKey, SHA1_SIZE);
+		}
+		else
+		{
+			Copy(new_account->ShortcutKey, a->ShortcutKey, SHA1_SIZE);
+		}
+
+		new_account->CreateDateTime = new_account->UpdateDateTime = SystemTime64();
+
+		// リストに挿入する
+		Insert(c->AccountList, new_account);
+
+		CLog(c, "LC_NEW_ACCOUNT", a->ClientOption->AccountName);
+	}
+	UnlockList(c->AccountList);
+
+	CiNormalizeAccountVLan(c);
+
+	CiSaveConfigurationFile(c);
+
+	CiNotify(c);
+
+	return true;
+}
+
+// アカウント取得構造体の解放
+void CiFreeClientGetAccount(RPC_CLIENT_GET_ACCOUNT *a)
+{
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	// アカウント情報の解放
+	if (a->ServerCert != NULL)
+	{
+		FreeX(a->ServerCert);
+	}
+	CiFreeClientAuth(a->ClientAuth);
+	Free(a->ClientOption);
+}
+
+// アカウント作成構造体の解放
+void CiFreeClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	// アカウント情報の解放
+	if (a->ServerCert != NULL)
+	{
+		FreeX(a->ServerCert);
+	}
+	CiFreeClientAuth(a->ClientAuth);
+	Free(a->ClientOption);
+}
+
+// 仮想 LAN カードの停止
+bool CtDisableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+	UINT i;
+	bool used;
+	// 引数チェック
+	if (c == NULL || vlan == NULL)
+	{
+		return false;
+	}
+
+#ifndef	OS_WIN32
+
+	if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+	{
+		// MacOS X では仮想 LAN カードは増減できない
+		CiSetError(c, ERR_NOT_SUPPORTED);
+		return false;
+	}
+
+	// 指定した名前の仮想 LAN カードが 1 つ以上のアカウントによって使用されていない
+	// かどうか確認する
+	used = false;
+	LockList(c->AccountList);
+	{
+		for (i = 0;i < LIST_NUM(c->AccountList);i++)
+		{
+			ACCOUNT *a = LIST_DATA(c->AccountList, i);
+			if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0)
+			{
+				Lock(a->lock);
+				{
+					if (a->ClientSession != NULL)
+					{
+						used = true;
+					}
+				}
+				Unlock(a->lock);
+			}
+		}
+	}
+	UnlockList(c->AccountList);
+
+	// 仮想 LAN カードを検索する
+	LockList(c->UnixVLanList);
+	{
+		UNIX_VLAN *v, t;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName);
+
+		v = Search(c->UnixVLanList, &t);
+		if (v == NULL)
+		{
+			UnlockList(c->UnixVLanList);
+			CiSetError(c, ERR_OBJECT_NOT_FOUND);
+			return false;
+		}
+
+		// 停止する
+		v->Enabled = false;
+	}
+	UnlockList(c->UnixVLanList);
+
+	CiSaveConfigurationFile(c);
+	CiNotify(c);
+
+	return true;
+
+#else	// OS_WIN32
+
+	// 指定した名前の仮想 LAN カードが 1 つ以上のアカウントによって使用されていない
+	// かどうか確認する
+	used = false;
+	LockList(c->AccountList);
+	{
+		for (i = 0;i < LIST_NUM(c->AccountList);i++)
+		{
+			ACCOUNT *a = LIST_DATA(c->AccountList, i);
+			if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0)
+			{
+				Lock(a->lock);
+				{
+					if (a->ClientSession != NULL)
+					{
+						used = true;
+					}
+				}
+				Unlock(a->lock);
+			}
+		}
+	}
+	UnlockList(c->AccountList);
+
+#if	0
+	if (used)
+	{
+		// 使用中
+		CiSetError(c, ERR_VLAN_IS_USED);
+		return false;
+	}
+#endif
+
+
+	// 仮想 LAN カードが存在しているかチェック
+	if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false)
+	{
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+		CiNotify(c);
+		return false;
+	}
+
+
+	if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+	{
+		// Windows は 64 bit だがこのコードは 32 bit であるので
+		// driver_installer を起動して処理を実行する
+		char tmp[MAX_SIZE];
+
+		Format(tmp, sizeof(tmp), "disablevlan %s", vlan->DeviceName);
+
+		if (MsExecDriverInstaller(tmp) == false)
+		{
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+	else
+	{
+		// 仮想 LAN カードを停止
+		if (MsDisableVLan(vlan->DeviceName) == false)
+		{
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+
+	CiNotify(c);
+
+	return true;
+
+#endif	// OS_WIN32
+
+}
+
+// 仮想 LAN カードの開始
+bool CtEnableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+	// 引数チェック
+	if (c == NULL || vlan == NULL)
+	{
+		return false;
+	}
+
+#ifndef	OS_WIN32
+
+	if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+	{
+		// MacOS X では仮想 LAN カードは増減できない
+		CiSetError(c, ERR_NOT_SUPPORTED);
+		return false;
+	}
+
+	// 仮想 LAN カードを検索する
+	LockList(c->UnixVLanList);
+	{
+		UNIX_VLAN *v, t;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName);
+
+		v = Search(c->UnixVLanList, &t);
+		if (v == NULL)
+		{
+			UnlockList(c->UnixVLanList);
+			CiSetError(c, ERR_OBJECT_NOT_FOUND);
+			return false;
+		}
+
+		// 有効にする
+		v->Enabled = true;
+	}
+	UnlockList(c->UnixVLanList);
+
+	CiSaveConfigurationFile(c);
+	CiNotify(c);
+
+	return true;
+
+#else	// OS_WIN32
+
+	// 仮想 LAN カードが存在しているかチェック
+	if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false)
+	{
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+		CiNotify(c);
+		return false;
+	}
+
+	if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+	{
+		// Windows は 64 bit だがこのコードは 32 bit であるので
+		// driver_installer を起動して処理を実行する
+		char tmp[MAX_SIZE];
+
+		Format(tmp, sizeof(tmp), "enablevlan %s", vlan->DeviceName);
+
+		if (MsExecDriverInstaller(tmp) == false)
+		{
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+	else
+	{
+		// 仮想 LAN カードを開始
+		if (MsEnableVLan(vlan->DeviceName) == false)
+		{
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+
+	CiNotify(c);
+
+	return true;
+
+#endif	// OS_WIN32
+
+}
+
+// 仮想 LAN カードの削除
+bool CtDeleteVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *d)
+{
+	UINT i;
+	bool used;
+	// 引数チェック
+	if (c == NULL || d == NULL)
+	{
+		return false;
+	}
+
+#ifndef	OS_WIN32
+
+	if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+	{
+		// MacOS X では仮想 LAN カードは増減できない
+		CiSetError(c, ERR_NOT_SUPPORTED);
+		return false;
+	}
+
+	// 指定した名前の仮想 LAN カードが 1 つ以上のアカウントによって使用されていない
+	// かどうか確認する
+	used = false;
+	LockList(c->AccountList);
+	{
+		for (i = 0;i < LIST_NUM(c->AccountList);i++)
+		{
+			ACCOUNT *a = LIST_DATA(c->AccountList, i);
+			if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0)
+			{
+				used = true;
+			}
+		}
+	}
+	UnlockList(c->AccountList);
+
+#if	0
+	if (used)
+	{
+		// 使用中
+		CiSetError(c, ERR_VLAN_IS_USED);
+		return false;
+	}
+#endif
+
+	// 仮想 LAN カードを検索する
+	LockList(c->UnixVLanList);
+	{
+		UNIX_VLAN *v, t;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), d->DeviceName);
+
+		v = Search(c->UnixVLanList, &t);
+		if (v == NULL)
+		{
+			UnlockList(c->UnixVLanList);
+			CiSetError(c, ERR_OBJECT_NOT_FOUND);
+			return false;
+		}
+
+		// 削除する
+		if (Delete(c->UnixVLanList, v))
+		{
+			Free(v);
+		}
+
+		CLog(c, "LC_DELETE_VLAN", d->DeviceName);
+
+		UnixVLanDelete(d->DeviceName);
+	}
+	UnlockList(c->UnixVLanList);
+
+	CiNormalizeAccountVLan(c);
+
+	CiSaveConfigurationFile(c);
+	CiNotify(c);
+
+	return true;
+
+#else	// OS_WIN32
+
+	if (MsIsNt() == false)
+	{
+		// Win9x では使用できない
+		CiSetError(c, ERR_NOT_SUPPORTED);
+		return false;
+	}
+
+	// 仮想 LAN カードが存在しているかチェック
+	if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, d->DeviceName) == false)
+	{
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+		return false;
+	}
+
+	// 指定した名前の仮想 LAN カードが 1 つ以上のアカウントによって使用されていない
+	// かどうか確認する
+	used = false;
+	LockList(c->AccountList);
+	{
+		for (i = 0;i < LIST_NUM(c->AccountList);i++)
+		{
+			ACCOUNT *a = LIST_DATA(c->AccountList, i);
+			if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0)
+			{
+				used = true;
+			}
+		}
+	}
+	UnlockList(c->AccountList);
+
+#if	0
+	if (used)
+	{
+		// 使用中
+		CiSetError(c, ERR_VLAN_IS_USED);
+		return false;
+	}
+#endif
+
+	if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+	{
+		// Windows は 64 bit だがこのコードは 32 bit であるので
+		// driver_installer を起動して処理を実行する
+		char tmp[MAX_SIZE];
+
+		Format(tmp, sizeof(tmp), "uninstvlan %s", d->DeviceName);
+
+		if (MsExecDriverInstaller(tmp) == false)
+		{
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			return false;
+		}
+	}
+	else
+	{
+		// 仮想 LAN カードを直接削除
+		if (MsUninstallVLan(d->DeviceName) == false)
+		{
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+
+	CLog(c, "LC_DELETE_VLAN", d->DeviceName);
+
+	CiNormalizeAccountVLan(c);
+
+	CiNotify(c);
+
+	return true;
+
+#endif	// OS_WIN32
+
+}
+
+// 最初の VLAN の名前を取得
+char *CiGetFirstVLan(CLIENT *c)
+{
+	char *ret = NULL;
+	RPC_CLIENT_ENUM_VLAN t;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CtEnumVLan(c, &t) == false)
+	{
+		return NULL;
+	}
+
+	if (t.NumItem >= 1)
+	{
+		UINT i;
+		char *tmp = t.Items[0]->DeviceName;
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			if (t.Items[i]->Enabled)
+			{
+				tmp = t.Items[i]->DeviceName;
+			}
+		}
+
+		ret = CopyStr(tmp);
+	}
+
+	CiFreeClientEnumVLan(&t);
+
+	return ret;
+}
+
+// 仮想 LAN カードの列挙
+bool CtEnumVLan(CLIENT *c, RPC_CLIENT_ENUM_VLAN *e)
+{
+	UINT i;
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (c == NULL || e == NULL)
+	{
+		return false;
+	}
+
+#ifndef	OS_WIN32
+
+	LockList(c->UnixVLanList);
+	{
+		e->NumItem = LIST_NUM(c->UnixVLanList);
+		e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem);
+
+		for (i = 0;i < e->NumItem;i++)
+		{
+			RPC_CLIENT_ENUM_VLAN_ITEM *item;
+			UNIX_VLAN *v;
+
+			v = LIST_DATA(c->UnixVLanList, i);
+			e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+			item = e->Items[i];
+
+			item->Enabled = v->Enabled;
+			BinToStr(item->MacAddress, sizeof(item->MacAddress), v->MacAddress, 6);
+			StrCpy(item->DeviceName, sizeof(item->DeviceName), v->Name);
+			StrCpy(item->Version, sizeof(item->Version), c->Cedar->VerString);
+		}
+	}
+	UnlockList(c->UnixVLanList);
+
+	return true;
+
+#else	// OS_WIN32
+
+	// 列挙
+	t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");
+	if (t == NULL)
+	{
+		// 列挙失敗
+		e->NumItem = 0;
+		e->Items = ZeroMalloc(0);
+	}
+	else
+	{
+		// 列挙成功
+		e->NumItem = t->NumTokens;
+		e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem);
+
+		for (i = 0;i < e->NumItem;i++)
+		{
+			char *tmp;
+			RPC_CLIENT_ENUM_VLAN_ITEM *item;
+			e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+			item = e->Items[i];
+
+			StrCpy(item->DeviceName, sizeof(item->DeviceName), t->Token[i]);
+			item->Enabled = MsIsVLanEnabled(item->DeviceName);
+
+			tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, item->DeviceName);
+
+			StrCpy(item->MacAddress, sizeof(item->MacAddress), tmp);
+			Free(tmp);
+
+			tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, item->DeviceName);
+
+			StrCpy(item->Version, sizeof(item->Version), tmp);
+			Free(tmp);
+		}
+
+		FreeToken(t);
+	}
+
+	return true;
+
+#endif	// OS_WIN32
+}
+
+// 仮想 LAN カード列挙体の解放
+void CiFreeClientEnumVLan(RPC_CLIENT_ENUM_VLAN *e)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		Free(e->Items[i]);
+	}
+	Free(e->Items);
+}
+
+// 仮想 LAN カードに関する情報の設定
+bool CtSetVLan(CLIENT *c, RPC_CLIENT_SET_VLAN *set)
+{
+	// 引数チェック
+	if (c == NULL || set == NULL)
+	{
+		return false;
+	}
+
+#ifndef	OS_WIN32
+
+	LockList(c->UnixVLanList);
+	{
+		UNIX_VLAN t, *r;
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), set->DeviceName);
+
+		r = Search(c->UnixVLanList, &t);
+		if (r == NULL)
+		{
+			// 存在しない
+			CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+			UnlockList(c->UnixVLanList);
+			return false;
+		}
+
+		StrToMac(r->MacAddress, set->MacAddress);
+	}
+	UnlockList(c->UnixVLanList);
+
+	CiSaveConfigurationFile(c);
+	CiNotify(c);
+
+	return true;
+
+#else	// OS_WIN32
+
+	// 指定された名前の仮想 LAN カードが存在するかチェック
+	if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, set->DeviceName) == false)
+	{
+		// 存在していない
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+		return false;
+	}
+
+	// MAC アドレスの設定
+	MsSetMacAddress(VLAN_ADAPTER_NAME_TAG, set->DeviceName, set->MacAddress);
+
+	CiNotify(c);
+
+	return true;
+
+#endif	// OS_WIN32
+}
+
+// 仮想 LAN カードに関する情報の取得
+bool CtGetVLan(CLIENT *c, RPC_CLIENT_GET_VLAN *get)
+{
+	char *tmp;
+	// 引数チェック
+	if (c == NULL || get == NULL)
+	{
+		return false;
+	}
+
+#ifndef	OS_WIN32
+
+	// サポートされていない
+	CiSetError(c, ERR_NOT_SUPPORTED);
+	return false;
+
+#else	// OS_WIN32
+
+	// 指定された名前の仮想 LAN カードが存在するかチェック
+	if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, get->DeviceName) == false)
+	{
+		// 存在していない
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+		return false;
+	}
+
+	// 動作状況
+	get->Enabled = MsIsVLanEnabled(get->DeviceName);
+
+	// MAC アドレス
+	tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+	StrCpy(get->MacAddress, sizeof(get->MacAddress), tmp);
+	Free(tmp);
+
+	// バージョン
+	tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+	StrCpy(get->Version, sizeof(get->Version), tmp);
+	Free(tmp);
+
+	// ファイル名
+	tmp = MsGetDriverFileName(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+	StrCpy(get->FileName, sizeof(get->FileName), tmp);
+	Free(tmp);
+
+	// GUID
+	tmp = MsGetNetworkAdapterGuid(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+	StrCpy(get->Guid, sizeof(get->Guid), tmp);
+	Free(tmp);
+
+	return true;
+
+#endif	// OS_WIN32
+}
+
+// 仮想 LAN カードのアップグレード
+bool CtUpgradeVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create)
+{
+#ifdef	OS_WIN32
+	KAKUSHI *k = NULL;
+#endif	// OS_WIN32
+
+	// 引数チェック
+	if (c == NULL || create == NULL)
+	{
+		return false;
+	}
+
+#ifndef	OS_WIN32
+
+	// 常に成功
+	return true;
+
+#else	// OS_WIN32
+
+	if (MsIsNt() == false)
+	{
+		// Win9x では不可
+		CiSetError(c, ERR_NOT_SUPPORTED);
+		return false;
+	}
+
+	// 指定された名前の LAN カードがすでに存在していないかどうかチェックする
+	if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName) == false)
+	{
+		// 存在していない
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+		CiNotify(c);
+		return false;
+	}
+
+	if (MsIsVista() == false)
+	{
+		k = InitKakushi();	
+	}
+
+
+	if (MsIsVista() == false)
+	{
+		// インストールを行う (Windows Vista 以外)
+		if (MsUpgradeVLan(VLAN_ADAPTER_NAME_TAG,
+			VLAN_CONNECTION_NAME,
+			create->DeviceName) == false)
+		{
+			// インストール失敗
+			FreeKakushi(k);
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+	else
+	{
+		// インストールを行う (Windows Vista)
+		char tmp[MAX_SIZE];
+
+		Format(tmp, sizeof(tmp), "upgradevlan %s", create->DeviceName);
+
+		if (CncExecDriverInstaller(tmp) == false)
+		{
+			// インストール失敗
+			FreeKakushi(k);
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+
+	FreeKakushi(k);
+
+	CLog(c, "LC_UPDATE_VLAN", create->DeviceName);
+
+	CiNotify(c);
+
+	return true;
+
+#endif	// OS_WIN32
+}
+
+// 仮想 LAN カードの作成
+bool CtCreateVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create)
+{
+	TOKEN_LIST *t;
+	UINT max_len;
+
+#ifdef	OS_WIN32
+	KAKUSHI *k = NULL;
+#endif	// OS_WIN32
+
+	// 引数チェック
+	if (c == NULL || create == NULL)
+	{
+		return false;
+	}
+
+#ifndef	OS_WIN32
+
+	// Win32 以外
+	if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+	{
+		// MacOS X では仮想 LAN カードは増減できない
+		CiSetError(c, ERR_NOT_SUPPORTED);
+		return false;
+	}
+
+	// 指定された名前が有効かどうかチェックする
+	if (IsSafeStr(create->DeviceName) == false)
+	{
+		// 名前が不正
+		CiSetError(c, ERR_VLAN_INVALID_NAME);
+		return false;
+	}
+
+	// 指定した名前の LAN カードがすでに存在していないかどうかチェックする
+	LockList(c->UnixVLanList);
+	{
+		UNIX_VLAN t, *r;
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), create->DeviceName);
+
+		r = Search(c->UnixVLanList, &t);
+		if (r != NULL)
+		{
+			// すでに存在している
+			CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+			UnlockList(c->UnixVLanList);
+			return false;
+		}
+
+		// 登録する
+		r = ZeroMalloc(sizeof(UNIX_VLAN));
+		r->Enabled = true;
+		GenMacAddress(r->MacAddress);
+		StrCpy(r->Name, sizeof(r->Name), create->DeviceName);
+
+		// tap 作成
+		if (UnixVLanCreate(r->Name, r->MacAddress) == false)
+		{
+			// 失敗
+			Free(r);
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			UnlockList(c->UnixVLanList);
+			return false;
+		}
+
+		CLog(c, "LC_CREATE_VLAN", create->DeviceName);
+
+		Add(c->UnixVLanList, r);
+	}
+	UnlockList(c->UnixVLanList);
+
+	CiNormalizeAccountVLan(c);
+
+	CiNotify(c);
+	CiSaveConfigurationFile(c);
+
+	return true;
+
+#else	// OS_WIN32
+
+	if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+	{
+		// Win9x では LAN カードは 1 個しか作成できない
+		TOKEN_LIST *t;
+
+		t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");
+		if (t != NULL)
+		{
+			if (t->NumTokens >= 1)
+			{
+				FreeToken(t);
+				CiSetError(c, ERR_NOT_SUPPORTED);
+				return false;
+			}
+			FreeToken(t);
+		}
+	}
+
+	// 指定された名前が有効かどうかチェックする
+	if (IsSafeStr(create->DeviceName) == false)
+	{
+		// 名前が不正
+		CiSetError(c, ERR_VLAN_INVALID_NAME);
+		return false;
+	}
+
+	max_len = MsIsNt() ? MAX_DEVICE_NAME_LEN : MAX_DEVICE_NAME_LEN_9X;
+	if (StrLen(create->DeviceName) > max_len)
+	{
+		// 名前が長すぎる
+		CiSetError(c, ERR_VLAN_INVALID_NAME);
+		return false;
+	}
+
+	// 指定された名前の LAN カードがすでに存在していないかどうかチェックする
+	if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName))
+	{
+		// すでに存在している
+		CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+		return false;
+	}
+
+	if (MsIsNt())
+	{
+		if (MsIsVista() == false)
+		{
+			k = InitKakushi();
+		}
+	}
+
+	if (MsIsVista() == false)
+	{
+		// インストールを行う (Windows Vista 以外)
+		if (MsInstallVLan(VLAN_ADAPTER_NAME_TAG, VLAN_CONNECTION_NAME, create->DeviceName) == false)
+		{
+			// インストール失敗
+			FreeKakushi(k);
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+	else
+	{
+		// インストールを行う (Windows Vista)
+		char tmp[MAX_SIZE];
+
+		Format(tmp, sizeof(tmp), "instvlan %s", create->DeviceName);
+
+		if (CncExecDriverInstaller(tmp) == false)
+		{
+			// インストール失敗
+			FreeKakushi(k);
+			CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+			CiNotify(c);
+			return false;
+		}
+	}
+
+	FreeKakushi(k);
+
+	t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");
+	if (t->NumTokens == 1)
+	{
+		UINT i;
+		// インストールを行った結果、仮想 LAN カードが 1 つになった場合は
+		// 既存のすべてのアカウントの仮想 LAN カードをこの仮想 LAN カードにセットする
+		LockList(c->AccountList);
+		{
+			for (i = 0;i < LIST_NUM(c->AccountList);i++)
+			{
+				ACCOUNT *a = LIST_DATA(c->AccountList, i);
+				Lock(a->lock);
+				{
+					if (a->ClientOption != NULL)
+					{
+						StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), create->DeviceName);
+					}
+				}
+				Unlock(a->lock);
+			}
+		}
+		UnlockList(c->AccountList);
+	}
+	FreeToken(t);
+
+	CLog(c, "LC_CREATE_VLAN", create->DeviceName);
+
+	CiNormalizeAccountVLan(c);
+
+	CiNotify(c);
+
+	CiSaveConfigurationFile(c);
+
+	if (MsIsNt() == false)
+	{
+		if (GetOsInfo()->OsType == OSTYPE_WINDOWS_ME)
+		{
+			// Windows Me の場合は警告表示
+			MsgBox(NULL, 0x00000040L, _UU("CM_9X_VLAN_ME_MESSAGE"));
+		}
+
+		ReleaseThread(NewThread(Win9xRebootThread, NULL));
+	}
+
+	return true;
+
+#endif	// OS_WIN32
+}
+
+// セキュアデバイス内のオブジェクト列挙
+bool CtEnumObjectInSecure(CLIENT *c, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+	UINT i;
+	// 引数チェック
+	if (c == NULL || e == NULL)
+	{
+		return false;
+	}
+
+	e->NumItem = 5;
+	e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem);
+	e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem);
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		char tmp[MAX_SIZE];
+		Format(tmp, sizeof(tmp), "Test Object %u", i);
+		e->ItemName[i] = CopyStr(tmp);
+		e->ItemType[i] = (i % 2 == 0) ? false : true;
+	}
+
+	return true;
+}
+
+// 使用するセキュアデバイスの取得
+bool CtGetUseSecure(CLIENT *c, RPC_USE_SECURE *sec)
+{
+	// 引数チェック
+	if (c == NULL || sec == NULL)
+	{
+		return false;
+	}
+
+	sec->DeviceId = c->UseSecureDeviceId;
+
+	return true;
+}
+
+// 使用するセキュアデバイスの指定
+bool CtUseSecure(CLIENT *c, RPC_USE_SECURE *sec)
+{
+	// 引数チェック
+	if (c == NULL || sec == NULL)
+	{
+		return false;
+	}
+
+// クライアントマネージャに指定されたデバイスが存在するかどうかチェックしない
+/*	if (CheckSecureDeviceId(sec->DeviceId))
+	{
+		c->UseSecureDeviceId = sec->DeviceId;
+	}
+	else
+	{
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+		return false;
+	}
+*/
+	c->UseSecureDeviceId = sec->DeviceId;
+
+	CiSaveConfigurationFile(c);
+
+	return true;
+}
+
+// セキュアデバイスの列挙
+bool CtEnumSecure(CLIENT *c, RPC_CLIENT_ENUM_SECURE *e)
+{
+	LIST *o;
+	UINT i;
+	// 引数チェック
+	if (c == NULL || e == NULL)
+	{
+		return false;
+	}
+
+	o = GetSecureDeviceList();
+
+	e->NumItem = LIST_NUM(o);
+	e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		RPC_CLIENT_ENUM_SECURE_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM));
+		SECURE_DEVICE *s = LIST_DATA(o, i);
+
+		item->DeviceId = s->Id;
+		StrCpy(item->DeviceName, sizeof(item->DeviceName), s->DeviceName);
+		StrCpy(item->Manufacturer, sizeof(item->Manufacturer), s->Manufacturer);
+		item->Type = s->Type;
+
+		e->Items[i] = item;
+	}
+
+	return true;
+}
+
+// セキュアデバイス列挙体の解放
+void CiFreeClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		Free(e->Items[i]);
+	}
+	Free(e->Items);
+}
+
+// RPC_GET_ISSUER の解放
+void CiFreeGetIssuer(RPC_GET_ISSUER *a)
+{
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	if (a->issuer_x != NULL)
+	{
+		FreeX(a->issuer_x);
+	}
+	if (a->x != NULL)
+	{
+		FreeX(a->x);
+	}
+}
+
+// 署名者の取得
+bool CtGetIssuer(CLIENT *c, RPC_GET_ISSUER *a)
+{
+	X *x;
+	// 引数チェック
+	if (c == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	x = FindCaSignedX(c->Cedar->CaList, a->x);
+	if (x == NULL)
+	{
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);;
+		return false;
+	}
+	else
+	{
+		a->issuer_x = x;
+		if (a->x != NULL)
+		{
+			FreeX(a->x);
+			a->x = NULL;
+		}
+		return true;
+	}
+}
+
+// CA 証明書の取得
+bool CtGetCa(CLIENT *c, RPC_GET_CA *get)
+{
+	bool ret = true;
+	X *cert = NULL;
+	// 引数チェック
+	if (c == NULL || get == NULL)
+	{
+		return false;
+	}
+
+	LockList(c->Cedar->CaList);
+	{
+		UINT i;
+
+		for (i = 0;i < LIST_NUM(c->Cedar->CaList);i++)
+		{
+			X *x = LIST_DATA(c->Cedar->CaList, i);
+
+			if (POINTER_TO_KEY(x) == get->Key)
+			{
+				cert = CloneX(x);
+				break;
+			}
+		}
+	}
+	UnlockList(c->Cedar->CaList);
+
+	if (cert == NULL)
+	{
+		// 証明書は存在しない
+		ret = false;
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+	}
+	else
+	{
+		ret = true;
+		get->x = cert;
+	}
+
+	return ret;
+}
+
+// CA 証明書の削除
+bool CtDeleteCa(CLIENT *c, RPC_CLIENT_DELETE_CA *p)
+{
+	bool ret;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	ret = DeleteCa(c->Cedar, p->Key);
+
+	if (ret == false)
+	{
+		CiSetError(c, ERR_OBJECT_NOT_FOUND);
+	}
+
+	CiSaveConfigurationFile(c);
+
+	return ret;
+}
+
+// CA 証明書の追加
+bool CtAddCa(CLIENT *c, RPC_CERT *cert)
+{
+	// 引数チェック
+	if (c == NULL || cert == NULL)
+	{
+		return false;
+	}
+
+	if (cert->x->is_compatible_bit == false)
+	{
+		CiSetError(c, ERR_NOT_RSA_1024);
+		return false;
+	}
+
+	AddCa(c->Cedar, cert->x);
+
+	CiSaveConfigurationFile(c);
+
+	return true;
+}
+
+// 信頼する CA の列挙
+bool CtEnumCa(CLIENT *c, RPC_CLIENT_ENUM_CA *e)
+{
+	// 引数チェック
+	if (c == NULL || e == NULL)
+	{
+		return false;
+	}
+
+	Zero(e, sizeof(RPC_CLIENT_ENUM_CA));
+
+	LockList(c->Cedar->CaList);
+	{
+		UINT i;
+		e->NumItem = LIST_NUM(c->Cedar->CaList);
+		e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem);
+
+		for (i = 0;i < e->NumItem;i++)
+		{
+			X *x = LIST_DATA(c->Cedar->CaList, i);
+			e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM));
+			GetAllNameFromNameEx(e->Items[i]->SubjectName, sizeof(e->Items[i]->SubjectName), x->subject_name);
+			GetAllNameFromNameEx(e->Items[i]->IssuerName, sizeof(e->Items[i]->IssuerName), x->issuer_name);
+			e->Items[i]->Expires = x->notAfter;
+			e->Items[i]->Key = POINTER_TO_KEY(x);
+		}
+	}
+	UnlockList(c->Cedar->CaList);
+
+	return true;
+}
+
+// CA 列挙体を解放する
+void CiFreeClientEnumCa(RPC_CLIENT_ENUM_CA *e)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < e->NumItem;i++)
+	{
+		RPC_CLIENT_ENUM_CA_ITEM *ca = e->Items[i];
+		Free(ca);
+	}
+	Free(e->Items);
+}
+
+// パスワードの設定の取得
+bool CtGetPasswordSetting(CLIENT *c, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (c == NULL || a == NULL)
+	{
+		return false;
+	}
+
+	Hash(hash, "", 0, true);
+	if (Cmp(hash, c->EncryptedPassword, SHA1_SIZE) == 0)
+	{
+		a->IsPasswordPresented = false;
+	}
+	else
+	{
+		a->IsPasswordPresented = true;
+	}
+
+	a->PasswordRemoteOnly = c->PasswordRemoteOnly;
+
+	return true;
+}
+
+// パスワードの設定
+bool CtSetPassword(CLIENT *c, RPC_CLIENT_PASSWORD *pass)
+{
+	char *str;
+	if (c == NULL)
+	{
+		return false;
+	}
+	if (pass->Password == NULL)
+	{
+		str = "";
+	}
+	else
+	{
+		str = pass->Password;
+	}
+
+	if (StrCmp(str, "********") != 0)
+	{
+		// パスワードのハッシュ
+		Hash(c->EncryptedPassword, str, StrLen(str), true);
+	}
+
+	c->PasswordRemoteOnly = pass->PasswordRemoteOnly;
+
+	CLog(c, "LC_SET_PASSWORD");
+
+	CiSaveConfigurationFile(c);
+
+	return true;
+}
+
+// クライアントエラーコードの設定
+void CiSetError(CLIENT *c, UINT err)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->Err = err;
+}
+
+// UNIX 仮想 LAN カード比較関数
+int CiCompareUnixVLan(void *p1, void *p2)
+{
+	UNIX_VLAN *v1, *v2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	v1 = *(UNIX_VLAN **)p1;
+	v2 = *(UNIX_VLAN **)p2;
+	if (v1 == NULL || v2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(v1->Name, v2->Name);
+}
+
+// 不正な VLAN 名が指定されているアカウントの設定を修正する
+void CiNormalizeAccountVLan(CLIENT *c)
+{
+	bool b = false;
+	char *name;
+	UINT i;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	name = CiGetFirstVLan(c);
+
+	if (name != NULL)
+	{
+		LockList(c->AccountList);
+		{
+			for (i = 0;i < LIST_NUM(c->AccountList);i++)
+			{
+				ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+				Lock(a->lock);
+				{
+					if (a->ClientOption != NULL)
+					{
+						if (CiIsVLan(c, a->ClientOption->DeviceName) == false)
+						{
+							StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName),
+								name);
+							b = true;
+						}
+					}
+				}
+				Unlock(a->lock);
+			}
+		}
+		UnlockList(c->AccountList);
+
+		Free(name);
+	}
+
+	if (b)
+	{
+		CiNotify(c);
+		CiSaveConfigurationFile(c);
+	}
+}
+
+// 指定した名前の仮想 LAN カードが存在しているかどうか調べる
+bool CiIsVLan(CLIENT *c, char *name)
+{
+	// 引数チェック
+	if (c == NULL || name == NULL)
+	{
+		return false;
+	}
+
+#ifdef	OS_WIN32
+	{
+		TOKEN_LIST *t;
+		UINT i;
+
+		t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");
+		if (t == NULL)
+		{
+			return false;
+		}
+
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			if (StrCmpi(t->Token[i], name) == 0)
+			{
+				FreeToken(t);
+				return true;
+			}
+		}
+
+		FreeToken(t);
+
+		return false;
+	}
+#else	// OS_WIN32
+	{
+		UNIX_VLAN *v;
+		UINT i;
+		bool ret = false;
+
+		LockList(c->UnixVLanList);
+		{
+			for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+			{
+				v = (UNIX_VLAN *)LIST_DATA(c->UnixVLanList, i);
+				if (StrCmpi(v->Name, name) == 0)
+				{
+					ret = true;
+				}
+			}
+		}
+		UnlockList(c->UnixVLanList);
+
+		return ret;
+	}
+#endif	// OS_WIN32
+}
+
+// すべての接続アカウントにおいて、存在しない仮想 LAN カードが指定されている場合で
+// 現在の仮想 LAN カードが 1 枚だけの場合は、その仮想 LAN カードに指定しなおす
+void CiSetVLanToDefault(CLIENT *c)
+{
+	char device_name[MAX_SIZE];
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	{
+		TOKEN_LIST *t;
+
+		t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");
+		if (t == NULL)
+		{
+			return;
+		}
+		if (t->NumTokens != 1)
+		{
+			FreeToken(t);
+			return;
+		}
+		StrCpy(device_name, sizeof(device_name), t->Token[0]);
+		FreeToken(t);
+	}
+#else	// OS_WIN32
+	{
+		UINT i;
+		UNIX_VLAN *v;
+
+		LockList(c->UnixVLanList);
+
+		if (LIST_NUM(c->UnixVLanList) != 1)
+		{
+			UnlockList(c->UnixVLanList);
+			return;
+		}
+		v = LIST_DATA(c->UnixVLanList, 0);
+		StrCpy(device_name, sizeof(device_name), v->Name);
+
+		UnlockList(c->UnixVLanList);
+	}
+#endif	// OS_WIN32
+
+	{
+		UINT i;
+		LockList(c->AccountList);
+		{
+			for (i = 0;i < LIST_NUM(c->AccountList);i++)
+			{
+				ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+				Lock(a->lock);
+				{
+					if (CiIsVLan(c, a->ClientOption->DeviceName) == false)
+					{
+						StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName),
+							device_name);
+					}
+				}
+				Unlock(a->lock);
+			}
+		}
+		UnlockList(c->AccountList);
+	}
+}
+
+// 設定の初期化
+void CiInitConfiguration(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_UNIX
+	// VLAN 初期化
+	UnixVLanInit();
+#endif	 // OS_UNIX
+
+	// アカウントリスト
+	c->AccountList = NewList(CiCompareAccount);
+
+	// Unix 版 VLAN リスト
+	if (OS_IS_UNIX(GetOsInfo()->OsType))
+	{
+		c->UnixVLanList = NewList(CiCompareUnixVLan);
+	}
+
+	// 設定ファイルの読み込み
+	CLog(c, "LC_LOAD_CONFIG_1");
+	if (CiLoadConfigurationFile(c) == false)
+	{
+		CLog(c, "LC_LOAD_CONFIG_3");
+		// 設定ファイルが存在しないので初期設定を行う
+		// パスワードを空にする
+		Hash(c->EncryptedPassword, "", 0, true);
+		// クライアント設定を初期化
+		if (OS_IS_WINDOWS(GetOsInfo()->OsType))
+		{
+			// Windows の場合はリモートを禁止
+			c->Config.AllowRemoteConfig = false;
+		}
+		else
+		{
+			// UNIX の場合もリモートを禁止
+			c->Config.AllowRemoteConfig = false;
+		}
+		StrCpy(c->Config.KeepConnectHost, sizeof(c->Config.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);
+		c->Config.KeepConnectPort = CLIENT_DEFAULT_KEEPALIVE_PORT;
+		c->Config.KeepConnectProtocol = CONNECTION_UDP;
+		c->Config.KeepConnectInterval = CLIENT_DEFAULT_KEEPALIVE_INTERVAL;
+		c->Config.UseKeepConnect = false;	// Client ではデフォルトでは接続維持機能を使用しない
+		// 自動ファイル削除器
+		c->Eraser = NewEraser(c->Logger, 0);
+	}
+	else
+	{
+		CLog(c, "LC_LOAD_CONFIG_2");
+	}
+
+	// 仮想 LAN カードの適切な設定
+	CiSetVLanToDefault(c);
+}
+
+// 設定の解放
+void CiFreeConfiguration(CLIENT *c)
+{
+	UINT i;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	// 設定ファイルへ書き込み
+	CiSaveConfigurationFile(c);
+
+	// 設定ファイル解放
+	FreeCfgRw(c->CfgRw);
+
+	// アカウントリストの解放
+	for (i = 0;i < LIST_NUM(c->AccountList);i++)
+	{
+		ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+		CiFreeAccount(a);
+	}
+	ReleaseList(c->AccountList);
+
+	if (c->UnixVLanList != NULL)
+	{
+		// UNIX 版 VLAN リストの解放
+		for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+		{
+			UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i);
+			Free(v);
+		}
+		ReleaseList(c->UnixVLanList);
+	}
+	c->UnixVLanList = NULL;
+
+#ifdef	OS_UNIX
+	// VLAN 解放
+	UnixVLanFree();
+#endif	// OS_UNIX
+}
+
+// 証明書取得データの解放
+void CiFreeGetCa(RPC_GET_CA *a)
+{
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	FreeX(a->x);
+}
+
+// クライアント認証データの解放
+void CiFreeClientAuth(CLIENT_AUTH *auth)
+{
+	// 引数チェック
+	if (auth == NULL)
+	{
+		return;
+	}
+
+	if (auth->ClientX != NULL)
+	{
+		FreeX(auth->ClientX);
+	}
+	if (auth->ClientK != NULL)
+	{
+		FreeK(auth->ClientK);
+	}
+
+	Free(auth);
+}
+
+// アカウントの解放
+void CiFreeAccount(ACCOUNT *a)
+{
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	// ロック解放
+	DeleteLock(a->lock);
+
+	// クライアントオプションの解放
+	Free(a->ClientOption);
+
+	// クライアント認証データの解放
+	CiFreeClientAuth(a->ClientAuth);
+
+	if (a->ServerCert != NULL)
+	{
+		FreeX(a->ServerCert);
+	}
+
+	Free(a);
+}
+
+// アカウントのソート
+int CiCompareAccount(void *p1, void *p2)
+{
+	ACCOUNT *a1, *a2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	a1 = *(ACCOUNT **)p1;
+	a2 = *(ACCOUNT **)p2;
+	if (a1 == NULL || a2 == NULL)
+	{
+		return 0;
+	}
+
+	return UniStrCmpi(a1->ClientOption->AccountName, a2->ClientOption->AccountName);
+}
+
+// クライアントコンフィグレーションの読み込み
+void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f)
+{
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	c->UseKeepConnect = CfgGetBool(f, "UseKeepConnect");
+	CfgGetStr(f, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost));
+	c->KeepConnectPort = CfgGetInt(f, "KeepConnectPort");
+	c->KeepConnectProtocol = CfgGetInt(f, "KeepConnectProtocol");
+	c->AllowRemoteConfig = CfgGetBool(f, "AllowRemoteConfig");
+	c->KeepConnectInterval = MAKESURE(CfgGetInt(f, "KeepConnectInterval"), KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX);
+}
+
+// クライアント認証データの読み込み
+CLIENT_AUTH *CiLoadClientAuth(FOLDER *f)
+{
+	CLIENT_AUTH *a;
+	char *s;
+	BUF *b;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	a = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+	a->AuthType = CfgGetInt(f, "AuthType");
+	CfgGetStr(f, "Username", a->Username, sizeof(a->Username));
+
+	switch (a->AuthType)
+	{
+	case CLIENT_AUTHTYPE_ANONYMOUS:
+		break;
+
+	case CLIENT_AUTHTYPE_PASSWORD:
+		CfgGetByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE);
+		break;
+
+	case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+		b = CfgGetBuf(f, "EncryptedPassword");
+		if (b != NULL)
+		{
+			s = DecryptPassword(b);
+			StrCpy(a->PlainPassword, sizeof(a->PlainPassword), s);
+			Free(s);
+			FreeBuf(b);
+		}
+		break;
+
+	case CLIENT_AUTHTYPE_CERT:
+		b = CfgGetBuf(f, "ClientCert");
+		if (b != NULL)
+		{
+			a->ClientX = BufToX(b, false);
+		}
+		FreeBuf(b);
+		b = CfgGetBuf(f, "ClientKey");
+		if (b != NULL)
+		{
+			a->ClientK = BufToK(b, true, false, NULL);
+		}
+		FreeBuf(b);
+		break;
+
+	case CLIENT_AUTHTYPE_SECURE:
+		CfgGetStr(f, "SecurePublicCertName", a->SecurePublicCertName, sizeof(a->SecurePublicCertName));
+		CfgGetStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName, sizeof(a->SecurePrivateKeyName));
+		break;
+	}
+
+	return a;
+}
+
+// クライアントオプションの読み込み
+CLIENT_OPTION *CiLoadClientOption(FOLDER *f)
+{
+	CLIENT_OPTION *o;
+	char *s;
+	BUF *b;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	o = ZeroMalloc(sizeof(CLIENT_OPTION));
+
+	CfgGetUniStr(f, "AccountName", o->AccountName, sizeof(o->AccountName));
+	CfgGetStr(f, "Hostname", o->Hostname, sizeof(o->Hostname));
+	o->Port = CfgGetInt(f, "Port");
+	o->PortUDP = CfgGetInt(f, "PortUDP");
+	o->ProxyType = CfgGetInt(f, "ProxyType");
+	CfgGetStr(f, "ProxyName", o->ProxyName, sizeof(o->ProxyName));
+	o->ProxyPort = CfgGetInt(f, "ProxyPort");
+	CfgGetStr(f, "ProxyUsername", o->ProxyUsername, sizeof(o->ProxyUsername));
+	b = CfgGetBuf(f, "ProxyPassword");
+	s = DecryptPassword(b);
+	StrCpy(o->ProxyPassword, sizeof(o->ProxyPassword), s);
+	Free(s);
+	FreeBuf(b);
+	o->NumRetry = CfgGetInt(f, "NumRetry");
+	o->RetryInterval = CfgGetInt(f, "RetryInterval");
+	CfgGetStr(f, "HubName", o->HubName, sizeof(o->HubName));
+	o->MaxConnection = CfgGetInt(f, "MaxConnection");
+	o->UseEncrypt = CfgGetBool(f, "UseEncrypt");
+	o->UseCompress = CfgGetBool(f, "UseCompress");
+	o->HalfConnection = CfgGetBool(f, "HalfConnection");
+	o->NoRoutingTracking = CfgGetBool(f, "NoRoutingTracking");
+	CfgGetStr(f, "DeviceName", o->DeviceName, sizeof(o->DeviceName));
+	o->AdditionalConnectionInterval = CfgGetInt(f, "AdditionalConnectionInterval");
+	o->HideStatusWindow = CfgGetBool(f, "HideStatusWindow");
+	o->HideNicInfoWindow = CfgGetBool(f, "HideNicInfoWindow");
+	o->ConnectionDisconnectSpan = CfgGetInt(f, "ConnectionDisconnectSpan");
+	o->RequireMonitorMode = CfgGetBool(f, "RequireMonitorMode");
+	o->RequireBridgeRoutingMode = CfgGetBool(f, "RequireBridgeRoutingMode");
+	o->DisableQoS = CfgGetBool(f, "DisableQoS");
+	o->FromAdminPack = CfgGetBool(f, "FromAdminPack");
+	o->NoTls1 = CfgGetBool(f, "NoTls1");
+
+	return o;
+}
+
+// アカウントデータの読み込み
+ACCOUNT *CiLoadClientAccount(FOLDER *f)
+{
+	ACCOUNT *a;
+	FOLDER *client_option_folder, *client_auth_folder;
+	BUF *b;
+	char tmp[64];
+	// 引数チェック
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	client_option_folder = CfgGetFolder(f, "ClientOption");
+
+	if (client_option_folder != NULL)
+	{
+		// すでに登録されているアカウント名と一致するかどうか比較する
+	}
+
+	client_auth_folder = CfgGetFolder(f, "ClientAuth");
+
+	if (client_option_folder == NULL || client_auth_folder == NULL)
+	{
+		return NULL;
+	}
+
+	a = ZeroMalloc(sizeof(ACCOUNT));
+	a->lock = NewLock();
+
+	a->ClientOption = CiLoadClientOption(client_option_folder);
+	a->ClientAuth = CiLoadClientAuth(client_auth_folder);
+
+	a->StartupAccount = CfgGetBool(f, "StartupAccount");
+	a->CheckServerCert = CfgGetBool(f, "CheckServerCert");
+	a->CreateDateTime = CfgGetInt64(f, "CreateDateTime");
+	a->UpdateDateTime = CfgGetInt64(f, "UpdateDateTime");
+	a->LastConnectDateTime = CfgGetInt64(f, "LastConnectDateTime");
+
+	b = CfgGetBuf(f, "ServerCert");
+	if (b != NULL)
+	{
+		a->ServerCert = BufToX(b, false);
+		FreeBuf(b);
+	}
+
+	if (CfgGetStr(f, "ShortcutKey", tmp, sizeof(tmp)))
+	{
+		BUF *b = StrToBin(tmp);
+		if (b->Size == SHA1_SIZE)
+		{
+			Copy(a->ShortcutKey, b->Buf, SHA1_SIZE);
+		}
+		FreeBuf(b);
+	}
+
+	if (IsZero(a->ShortcutKey, SHA1_SIZE))
+	{
+		Rand(a->ShortcutKey, SHA1_SIZE);
+	}
+
+	return a;
+}
+
+// アカウントデータベースの読み込み
+void CiLoadAccountDatabase(CLIENT *c, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+	if (t == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		FOLDER *ff = CfgGetFolder(f, t->Token[i]);
+
+		if (ff != NULL)
+		{
+			ACCOUNT *a = CiLoadClientAccount(ff);
+			if (a != NULL)
+			{
+				Add(c->AccountList, a);
+			}
+		}
+	}
+
+	Sort(c->AccountList);
+
+	FreeToken(t);
+}
+
+// ルート CA 証明書を読み込む
+void CiLoadCACert(CLIENT *c, FOLDER *f)
+{
+	BUF *b;
+	X *x;
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	b = CfgGetBuf(f, "X509");
+	if (b == NULL)
+	{
+		return;
+	}
+
+	x = BufToX(b, false);
+
+	AddCa(c->Cedar, x);
+
+	FreeX(x);
+
+	FreeBuf(b);
+}
+
+// ルート CA リストを読み込む
+void CiLoadCAList(CLIENT *c, FOLDER *f)
+{
+	CEDAR *cedar;
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+
+	cedar = c->Cedar;
+
+	LockList(cedar->CaList);
+	{
+		UINT i;
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			FOLDER *folder = CfgGetFolder(f, t->Token[i]);
+			CiLoadCACert(c, folder);
+		}
+	}
+	UnlockList(cedar->CaList);
+
+	FreeToken(t);
+}
+
+// VLAN を読み込む
+void CiLoadVLan(CLIENT *c, FOLDER *f)
+{
+	char tmp[MAX_SIZE];
+	UCHAR addr[6];
+	BUF *b;
+	UNIX_VLAN *v;
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	if (CfgGetStr(f, "MacAddress", tmp, sizeof(tmp)) == false)
+	{
+		return;
+	}
+
+	b = StrToBin(tmp);
+	if (b == NULL)
+	{
+		return;
+	}
+
+	if (b->Size != 6)
+	{
+		FreeBuf(b);
+		return;
+	}
+
+	Copy(addr, b->Buf, 6);
+
+	FreeBuf(b);
+
+	if (IsZero(addr, 6))
+	{
+		return;
+	}
+
+	v = ZeroMalloc(sizeof(UNIX_VLAN));
+	Copy(v->MacAddress, addr, 6);
+	StrCpy(v->Name, sizeof(v->Name), f->Name);
+	v->Enabled = CfgGetBool(f, "Enabled");
+
+	Add(c->UnixVLanList, v);
+
+#ifdef	OS_UNIX
+	UnixVLanCreate(v->Name, v->MacAddress);
+#endif	// OS_UNIX
+}
+
+// VLAN リストを読み込む
+void CiLoadVLanList(CLIENT *c, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+
+	LockList(c->UnixVLanList);
+	{
+		UINT i;
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			FOLDER *folder = CfgGetFolder(f, t->Token[i]);
+			CiLoadVLan(c, folder);
+		}
+	}
+	UnlockList(c->UnixVLanList);
+
+	FreeToken(t);
+}
+
+// 設定ファイルから設定の読み込み
+bool CiReadSettingFromCfg(CLIENT *c, FOLDER *root)
+{
+	FOLDER *config;
+	FOLDER *cert;
+	FOLDER *db;
+	FOLDER *vlan;
+	FOLDER *cmsetting;
+	char user_agent[MAX_SIZE];
+	// 引数チェック
+	if (c == NULL || root == NULL)
+	{
+		return false;
+	}
+
+	// Config と AccountDatabase の両方が無い場合は設定を初期化する
+	config = CfgGetFolder(root, "Config");
+	if (config == NULL)
+	{
+		return false;
+	}
+
+	db = CfgGetFolder(root, "AccountDatabase");
+	if (db == NULL)
+	{
+		return false;
+	}
+
+	cmsetting = CfgGetFolder(root, "ClientManagerSetting");
+
+	CiLoadClientConfig(&c->Config, config);
+
+	// 自動ファイル削除器
+	c->Eraser = NewEraser(c->Logger, CfgGetInt64(config, "AutoDeleteCheckDiskFreeSpaceMin"));
+
+	if (OS_IS_UNIX(GetOsInfo()->OsType) && GetOsInfo()->OsType != OSTYPE_MACOS_X)
+	{
+		// Unix 版仮想 LAN カード一覧の読み込み (MacOS の場合はしない)
+		vlan = CfgGetFolder(root, "UnixVLan");
+		if (vlan != NULL)
+		{
+			CiLoadVLanList(c, vlan);
+		}
+	}
+
+	if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+	{
+#ifdef	OS_UNIX
+		UNIX_VLAN *uv;
+
+		// MacOS X の場合は Tap を作成する
+		if (UnixVLanCreate(CLIENT_MACOS_TAP_NAME, NULL) == false)
+		{
+			// 失敗 (強制終了)
+			CLog(c, "LC_TAP_NOT_FOUND");
+			Alert("tun/tap driver not found.", NULL);
+			exit(0);
+		}
+
+		uv = ZeroMalloc(sizeof(UNIX_VLAN));
+		uv->Enabled = true;
+		StrCpy(uv->Name, sizeof(uv->Name), CLIENT_MACOS_TAP_NAME);
+		Add(c->UnixVLanList, uv);
+#endif	// OS_UNIX
+	}
+
+	CiLoadAccountDatabase(c, db);
+
+	if (CfgGetByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE) == false)
+	{
+		Hash(c->EncryptedPassword, "", 0, true);
+	}
+
+	c->PasswordRemoteOnly = CfgGetBool(root, "PasswordRemoteOnly");
+	c->UseSecureDeviceId = CfgGetInt(root, "UseSecureDeviceId");
+
+	if (CfgGetStr(root, "UserAgent", user_agent, sizeof(user_agent)))
+	{
+		if (IsEmptyStr(user_agent) == false)
+		{
+			Free(c->Cedar->HttpUserAgent);
+			c->Cedar->HttpUserAgent = CopyStr(user_agent);
+		}
+	}
+
+	cert = CfgGetFolder(root, "RootCA");
+	if (cert != NULL)
+	{
+		CiLoadCAList(c, cert);
+	}
+
+	c->DontSavePassword = CfgGetBool(root, "DontSavePassword");
+
+	if (cmsetting != NULL)
+	{
+		UINT ostype = GetOsInfo()->OsType;
+		// CM_SETTING
+		CM_SETTING *s = c->CmSetting;
+
+		if (OS_IS_UNIX(ostype) || OS_IS_WINDOWS_NT(ostype))
+		{
+			s->EasyMode = CfgGetBool(cmsetting, "EasyMode");
+		}
+
+		s->LockMode = CfgGetBool(cmsetting, "LockMode");
+		CfgGetByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));
+	}
+
+	return true;
+}
+
+// 設定ファイルの読み込み
+bool CiLoadConfigurationFile(CLIENT *c)
+{
+	bool ret;
+	FOLDER *root;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	// 設定ファイルの読み込み
+	c->CfgRw = NewCfgRw(&root, CLIENT_CONFIG_FILE_NAME);
+
+	if (root == NULL)
+	{
+		return false;
+	}
+
+	ret = CiReadSettingFromCfg(c, root);
+
+	CfgDeleteFolder(root);
+
+	return ret;
+}
+
+// CLIENT_CONFIG を書き込む
+void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config)
+{
+	// 引数チェック
+	if (cc == NULL || config == NULL)
+	{
+		return;
+	}
+
+	CfgAddBool(cc, "UseKeepConnect", config->UseKeepConnect);
+	CfgAddStr(cc, "KeepConnectHost", config->KeepConnectHost);
+	CfgAddInt(cc, "KeepConnectPort", config->KeepConnectPort);
+	CfgAddInt(cc, "KeepConnectProtocol", config->KeepConnectProtocol);
+	CfgAddBool(cc, "AllowRemoteConfig", config->AllowRemoteConfig);
+	CfgAddInt(cc, "KeepConnectInterval", config->KeepConnectInterval);
+}
+
+// クライアント認証データを書き込む
+void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a)
+{
+	BUF *b;
+	// 引数チェック
+	if (f == NULL || a == NULL)
+	{
+		return;
+	}
+
+	CfgAddInt(f, "AuthType", a->AuthType);
+	CfgAddStr(f, "Username", a->Username);
+
+	switch (a->AuthType)
+	{
+	case CLIENT_AUTHTYPE_ANONYMOUS:
+		break;
+
+	case CLIENT_AUTHTYPE_PASSWORD:
+		CfgAddByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE);
+		break;
+
+	case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+		b = EncryptPassword(a->PlainPassword);
+		CfgAddByte(f, "EncryptedPassword", b->Buf, b->Size);
+		FreeBuf(b);
+		break;
+
+	case CLIENT_AUTHTYPE_CERT:
+		if (a->ClientK != NULL && a->ClientX != NULL)
+		{
+			b = XToBuf(a->ClientX, false);
+			CfgAddByte(f, "ClientCert", b->Buf, b->Size);
+			FreeBuf(b);
+
+			b = KToBuf(a->ClientK, false, NULL);
+			CfgAddByte(f, "ClientKey", b->Buf, b->Size);
+			FreeBuf(b);
+		}
+		break;
+
+	case CLIENT_AUTHTYPE_SECURE:
+		CfgAddStr(f, "SecurePublicCertName", a->SecurePublicCertName);
+		CfgAddStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName);
+		break;
+	}
+}
+
+// クライアントオプションを書き込む
+void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o)
+{
+	BUF *b;
+	// 引数チェック
+	if (f == NULL || o == NULL)
+	{
+		return;
+	}
+
+	CfgAddUniStr(f, "AccountName", o->AccountName);
+	CfgAddStr(f, "Hostname", o->Hostname);
+	CfgAddInt(f, "Port", o->Port);
+	CfgAddInt(f, "PortUDP", o->PortUDP);
+	CfgAddInt(f, "ProxyType", o->ProxyType);
+	CfgAddStr(f, "ProxyName", o->ProxyName);
+	CfgAddInt(f, "ProxyPort", o->ProxyPort);
+	CfgAddStr(f, "ProxyUsername", o->ProxyUsername);
+	b = EncryptPassword(o->ProxyPassword);
+	CfgAddByte(f, "ProxyPassword", b->Buf, b->Size);
+	FreeBuf(b);
+	CfgAddInt(f, "NumRetry", o->NumRetry);
+	CfgAddInt(f, "RetryInterval", o->RetryInterval);
+	CfgAddStr(f, "HubName", o->HubName);
+	CfgAddInt(f, "MaxConnection", o->MaxConnection);
+	CfgAddBool(f, "UseEncrypt", o->UseEncrypt);
+	CfgAddBool(f, "UseCompress", o->UseCompress);
+	CfgAddBool(f, "HalfConnection", o->HalfConnection);
+	CfgAddBool(f, "NoRoutingTracking", o->NoRoutingTracking);
+	CfgAddStr(f, "DeviceName", o->DeviceName);
+	CfgAddInt(f, "AdditionalConnectionInterval", o->AdditionalConnectionInterval);
+	CfgAddBool(f, "HideStatusWindow", o->HideStatusWindow);
+	CfgAddBool(f, "HideNicInfoWindow", o->HideNicInfoWindow);
+	CfgAddInt(f, "ConnectionDisconnectSpan", o->ConnectionDisconnectSpan);
+	CfgAddBool(f, "RequireMonitorMode", o->RequireMonitorMode);
+	CfgAddBool(f, "RequireBridgeRoutingMode", o->RequireBridgeRoutingMode);
+	CfgAddBool(f, "DisableQoS", o->DisableQoS);
+	CfgAddBool(f, "NoTls1", o->NoTls1);
+
+	if (o->FromAdminPack)
+	{
+		CfgAddBool(f, "FromAdminPack", o->FromAdminPack);
+	}
+}
+
+// パスワードの解読
+char *DecryptPassword(BUF *b)
+{
+	char *str;
+	char *key = "EncryptPassword";
+	CRYPT *c;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return CopyStr("");
+	}
+
+	str = ZeroMalloc(b->Size + 1);
+	c = NewCrypt(key, sizeof(key));
+	Encrypt(c, str, b->Buf, b->Size);
+	FreeCrypt(c);
+
+	str[b->Size] = 0;
+
+	return str;
+}
+
+// パスワードの暗号化
+BUF *EncryptPassword(char *password)
+{
+	UCHAR *tmp;
+	UINT size;
+	char *key = "EncryptPassword";
+	CRYPT *c;
+	BUF *b;
+	// 引数チェック
+	if (password == NULL)
+	{
+		password = "";
+	}
+
+	size = StrLen(password) + 1;
+	tmp = ZeroMalloc(size);
+
+	c = NewCrypt(key, sizeof(key));
+	Encrypt(c, tmp, password, size - 1);
+	FreeCrypt(c);
+
+	b = NewBuf();
+	WriteBuf(b, tmp, size - 1);
+	SeekBuf(b, 0, 0);
+	Free(tmp);
+
+	return b;
+}
+
+// アカウントデータを書き込む
+void CiWriteAccountData(FOLDER *f, ACCOUNT *a)
+{
+	// 引数チェック
+	if (f == NULL || a == NULL)
+	{
+		return;
+	}
+
+	// クライアントオプション
+	CiWriteClientOption(CfgCreateFolder(f, "ClientOption"), a->ClientOption);
+
+	// クライアント認証データ
+	CiWriteClientAuth(CfgCreateFolder(f, "ClientAuth"), a->ClientAuth);
+
+	// スタートアップアカウント
+	CfgAddBool(f, "StartupAccount", a->StartupAccount);
+
+	// サーバー証明書チェックフラグ
+	CfgAddBool(f, "CheckServerCert", a->CheckServerCert);
+
+	// 日時
+	CfgAddInt64(f, "CreateDateTime", a->CreateDateTime);
+	CfgAddInt64(f, "UpdateDateTime", a->UpdateDateTime);
+	CfgAddInt64(f, "LastConnectDateTime", a->LastConnectDateTime);
+
+	// サーバー証明書本体
+	if (a->ServerCert != NULL)
+	{
+		BUF *b = XToBuf(a->ServerCert, false);
+		if (b != NULL)
+		{
+			CfgAddBuf(f, "ServerCert", b);
+			FreeBuf(b);
+		}
+	}
+
+	// ショートカットキー
+	if (IsZero(a->ShortcutKey, SHA1_SIZE) == false)
+	{
+		char tmp[64];
+		BinToStr(tmp, sizeof(tmp), a->ShortcutKey, SHA1_SIZE);
+		CfgAddStr(f, "ShortcutKey", tmp);
+	}
+}
+
+// アカウントデータベースを書き込む
+void CiWriteAccountDatabase(CLIENT *c, FOLDER *f)
+{
+	char name[MAX_SIZE];
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	LockList(c->AccountList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(c->AccountList);i++)
+		{
+			ACCOUNT *a = LIST_DATA(c->AccountList, i);
+			Format(name, sizeof(name), "Account%u", i);
+			Lock(a->lock);
+			{
+				CiWriteAccountData(CfgCreateFolder(f, name), a);
+			}
+			Unlock(a->lock);
+		}
+	}
+	UnlockList(c->AccountList);
+}
+
+// CA 証明書を書き込む
+void CiWriteCACert(CLIENT *c, FOLDER *f, X *x)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || f == NULL || x == NULL)
+	{
+		return;
+	}
+
+	b = XToBuf(x, false);
+	CfgAddBuf(f, "X509", b);
+	FreeBuf(b);
+}
+
+// VLAN を書き込む
+void CiWriteVLan(CLIENT *c, FOLDER *f, UNIX_VLAN *v)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (c == NULL || f == NULL || v == NULL)
+	{
+		return;
+	}
+
+	MacToStr(tmp, sizeof(tmp), v->MacAddress);
+	CfgAddStr(f, "MacAddress", tmp);
+	CfgAddBool(f, "Enabled", v->Enabled);
+}
+
+// VLAN リストを書き込む
+void CiWriteVLanList(CLIENT *c, FOLDER *f)
+{
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	LockList(c->UnixVLanList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+		{
+			UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i);
+			CiWriteVLan(c, CfgCreateFolder(f, v->Name), v);
+		}
+	}
+	UnlockList(c->UnixVLanList);
+}
+
+// CA リストを書き込む
+void CiWriteCAList(CLIENT *c, FOLDER *f)
+{
+	CEDAR *cedar;
+	// 引数チェック
+	if (c == NULL || f == NULL)
+	{
+		return;
+	}
+
+	cedar = c->Cedar;
+
+	LockList(cedar->CaList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+		{
+			char tmp[MAX_SIZE];
+			X *x = LIST_DATA(cedar->CaList, i);
+			Format(tmp, sizeof(tmp), "Certificate%u", i);
+			CiWriteCACert(c, CfgCreateFolder(f, tmp), x);
+		}
+	}
+	UnlockList(cedar->CaList);
+}
+
+// 現在の設定を ROOT に書き込む
+void CiWriteSettingToCfg(CLIENT *c, FOLDER *root)
+{
+	FOLDER *cc;
+	FOLDER *account_database;
+	FOLDER *ca;
+	FOLDER *vlan;
+	FOLDER *cmsetting;
+	// 引数チェック
+	if (c == NULL || root == NULL)
+	{
+		return;
+	}
+
+	cmsetting = CfgCreateFolder(root, "ClientManagerSetting");
+
+	// CLIENT_CONFIG
+	cc = CfgCreateFolder(root, "Config");
+	CiWriteClientConfig(cc, &c->Config);
+
+	// 自動ファイル削除器
+	CfgAddInt64(cc, "AutoDeleteCheckDiskFreeSpaceMin", c->Eraser->MinFreeSpace);
+
+	// Account Database
+	account_database = CfgCreateFolder(root, "AccountDatabase");
+	CiWriteAccountDatabase(c, account_database);
+
+	// CA
+	ca = CfgCreateFolder(root, "RootCA");
+	CiWriteCAList(c, ca);
+
+	// VLAN
+	if (OS_IS_UNIX(GetOsInfo()->OsType) && GetOsInfo()->OsType != OSTYPE_MACOS_X)
+	{
+		vlan = CfgCreateFolder(root, "UnixVLan");
+		CiWriteVLanList(c, vlan);
+	}
+
+	// Password
+	CfgAddByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE);
+	CfgAddBool(root, "PasswordRemoteOnly", c->PasswordRemoteOnly);
+
+	// UseSecureDeviceId
+	CfgAddInt(root, "UseSecureDeviceId", c->UseSecureDeviceId);
+
+	// DontSavePassword
+	CfgAddBool(root, "DontSavePassword", c->DontSavePassword);
+
+	// UserAgent
+	if (c->Cedar != NULL)
+	{
+		CfgAddStr(root, "UserAgent", c->Cedar->HttpUserAgent);
+	}
+
+	if (cmsetting != NULL)
+	{
+		CM_SETTING *s = c->CmSetting;
+
+		CfgAddBool(cmsetting, "EasyMode", s->EasyMode);
+		CfgAddBool(cmsetting, "LockMode", s->LockMode);
+
+		if (IsZero(s->HashedPassword, sizeof(s->HashedPassword)) == false)
+		{
+			CfgAddByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));
+		}
+	}
+}
+
+// 設定ファイルへ書き込み
+void CiSaveConfigurationFile(CLIENT *c)
+{
+	FOLDER *root;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+	
+	// 設定ファイルを保存しない
+	if(c->NoSaveConfig)
+	{
+		return;
+	}
+
+	root = CfgCreateFolder(NULL, TAG_ROOT);
+	CiWriteSettingToCfg(c, root);
+
+	SaveCfgRw(c->CfgRw, root);
+
+	CfgDeleteFolder(root);
+}
+
+// CM_SETTING の設定
+bool CtSetCmSetting(CLIENT *c, CM_SETTING *s)
+{
+	// 引数チェック
+	if (c == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Copy(c->CmSetting, s, sizeof(CM_SETTING));
+
+	CiSaveConfigurationFile(c);
+
+	return true;
+}
+
+// CM_SETTING の取得
+bool CtGetCmSetting(CLIENT *c, CM_SETTING *s)
+{
+	// 引数チェック
+	if (c == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Copy(s, c->CmSetting, sizeof(CM_SETTING));
+	
+	return true;
+}
+
+// クライアントバージョンの取得
+bool CtGetClientVersion(CLIENT *c, RPC_CLIENT_VERSION *ver)
+{
+	// 引数チェック
+	if (ver == NULL)
+	{
+		return false;
+	}
+
+	Zero(ver, sizeof(RPC_CLIENT_VERSION));
+	StrCpy(ver->ClientProductName, sizeof(ver->ClientProductName), CEDAR_CLIENT_STR);
+	StrCpy(ver->ClientVersionString, sizeof(ver->ClientVersionString), c->Cedar->VerString);
+	StrCpy(ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString), c->Cedar->BuildInfo);
+	ver->ClientVerInt = c->Cedar->Version;
+	ver->ClientBuildInt = c->Cedar->Build;
+
+#ifdef	OS_WIN32
+	ver->ProcessId = MsGetProcessId();
+#endif	// OS_WIN32
+
+	ver->OsType = GetOsInfo()->OsType;
+
+	return true;
+}
+
+// クライアントオブジェクトの作成
+CLIENT *CiNewClient()
+{
+	CLIENT *c = ZeroMalloc(sizeof(CLIENT));
+
+//	StartCedarLog();
+
+	c->CmSetting = ZeroMalloc(sizeof(CM_SETTING));
+
+	c->SockList = NewSockList();
+
+	c->lock = NewLock();
+	c->lockForConnect = NewLock();
+	c->ref = NewRef();
+
+	c->Cedar = NewCedar(NULL, NULL);
+
+	c->Cedar->Client = c;
+
+	c->NotifyCancelList = NewList(NULL);
+
+	Hash(c->EncryptedPassword, "", 0, true);
+
+	// ログ設定
+	if(c->NoSaveLog == false)
+	{
+		MakeDir(CLIENT_LOG_DIR_NAME);
+		c->Logger = NewLog(CLIENT_LOG_DIR_NAME, CLIENT_LOG_PREFIX, LOG_SWITCH_DAY);
+	}
+
+	CLog(c, "L_LINE");
+	CLog(c, "LC_START_2", CEDAR_CLIENT_STR, c->Cedar->VerString);
+	CLog(c, "LC_START_3", c->Cedar->BuildInfo);
+	CLog(c, "LC_START_1");
+
+#ifdef	OS_WIN32
+	{
+		// Win32 UI の初期化
+		wchar_t tmp[MAX_SIZE];
+		StrToUni(tmp, sizeof(tmp), CEDAR_CLIENT_STR);
+
+		InitWinUi(tmp, _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+	}
+#endif	// OS_WIN32
+
+	// 設定の初期化
+	CiInitConfiguration(c);
+
+	// 優先順位を上げる
+	OSSetHighPriority();
+
+#ifdef	OS_WIN32
+	// Win9x の場合、すべての仮想 LAN カードの DHCP アドレスを解放する
+	if (MsIsNt() == false)
+	{
+		Win32ReleaseAllDhcp9x(true);
+	}
+#endif	// OS_WIN32
+
+	CiChangeAllVLanMacAddressIfMachineChanged(c);
+
+	return c;
+}
+
+// クライアントのクリーンアップ
+void CiCleanupClient(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	// 設定の解放
+	CiFreeConfiguration(c);
+
+#ifdef	OS_WIN32
+	// Win32 UI の解放
+	FreeWinUi();
+#endif	// OS_WIN32
+
+	CLog(c, "LC_END");
+	CLog(c, "L_LINE");
+	FreeEraser(c->Eraser);
+	FreeLog(c->Logger);
+	c->Logger = NULL;
+
+	ReleaseCedar(c->Cedar);
+
+	DeleteLock(c->lockForConnect);
+	DeleteLock(c->lock);
+
+	ReleaseList(c->NotifyCancelList);
+
+	FreeSockList(c->SockList);
+
+	Free(c->CmSetting);
+
+	Free(c);
+
+#ifdef	OS_WIN32
+	// Win9x の場合、すべての仮想 LAN カードの DHCP アドレスを解放する
+	if (MsIsNt() == false)
+	{
+		Win32ReleaseAllDhcp9x(true);
+	}
+#endif	// OS_WIN32
+
+	StopCedarLog();
+}
+
+// クライアントの解放
+void CtReleaseClient(CLIENT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	if (Release(c->ref) == 0)
+	{
+		CiCleanupClient(c);
+	}
+}
+
+// クライアントプログラムの動作開始
+void CtStartClient()
+{
+	UINT i;
+	LIST *o;
+	if (client != NULL)
+	{
+		// すでに動作している
+		return;
+	}
+
+	// OS チェック
+	CiCheckOs();
+
+#ifdef	OS_WIN32
+	RegistWindowsFirewallAll();
+#endif
+
+	// クライアントの作成
+	client = CiNewClient();
+
+	// Keep を開始
+	CiInitKeep(client);
+
+	// RPC サーバーを開始
+	CiStartRpcServer(client);
+
+	// 設定データ自動保存を開始
+	CiInitSaver(client);
+
+	// スタートアップ接続を開始する
+	o = NewListFast(NULL);
+	LockList(client->AccountList);
+	{
+		for (i = 0;i < LIST_NUM(client->AccountList);i++)
+		{
+			ACCOUNT *a = LIST_DATA(client->AccountList, i);
+			Lock(a->lock);
+			{
+				if (a->StartupAccount)
+				{
+					Add(o, CopyUniStr(a->ClientOption->AccountName));
+				}
+			}
+			Unlock(a->lock);
+		}
+	}
+	UnlockList(client->AccountList);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t *s = LIST_DATA(o, i);
+		RPC_CLIENT_CONNECT c;
+		Zero(&c, sizeof(c));
+		UniStrCpy(c.AccountName, sizeof(c.AccountName), s);
+		CtConnect(client, &c);
+		Free(s);
+	}
+	ReleaseList(o);
+}
+
+// クライアントプログラムの動作終了
+void CtStopClient()
+{
+	UINT i, num;
+	ACCOUNT **account_list;
+	if (client == NULL)
+	{
+		// まだ動作していない
+		return;
+	}
+
+	// 停止フラグ
+	client->Halt = true;
+
+	// RPC をすべて切断
+	CiStopRpcServer(client);
+
+	// クライアント通知サービスを終了
+	CncExit();
+
+	// Keep を終了
+	CiFreeKeep(client);
+
+	// 接続中のアカウントをすべて切断
+	LockList(client->AccountList);
+	{
+		num = LIST_NUM(client->AccountList);
+		account_list = ToArray(client->AccountList);
+	}
+	UnlockList(client->AccountList);
+
+	for (i = 0;i < num;i++)
+	{
+		ACCOUNT *a = account_list[i];
+		SESSION *s = NULL;
+
+		Lock(a->lock);
+		{
+			if (a->ClientSession != NULL)
+			{
+				s = a->ClientSession;
+				AddRef(s->ref);
+			}
+		}
+		Unlock(a->lock);
+
+		if (s != NULL)
+		{
+			StopSession(s);
+			ReleaseSession(s);
+			Lock(a->lock);
+			{
+				if (a->ClientSession != NULL)
+				{
+					ReleaseSession(a->ClientSession);
+					a->ClientSession = NULL;
+				}
+			}
+			Unlock(a->lock);
+		}
+	}
+
+	Free(account_list);
+
+	// 設定データ自動保存を停止
+	CiFreeSaver(client);
+
+	// クライアントの解放
+	CtReleaseClient(client);
+	client = NULL;
+}
+
+// OS チェック
+void CiCheckOs()
+{
+	// OS の種類の取得
+	OS_INFO *info = GetOsInfo();
+
+	if (OS_IS_WINDOWS(info->OsType))
+	{
+		bool ok = IS_CLIENT_SUPPORTED_OS(info->OsType);
+
+		if (ok == false)
+		{
+			Alert(
+				"SoftEther UT-VPN Client doesn't support this Windows Operating System.\n"
+				"SoftEther UT-VPN Client requires Windows 98 SE, Windows Me, Windows 2000, Windows XP, Windows Server 2003 or Greater.\n\n"
+				"Please contact your system administrator.", "SoftEther UT-VPN Client");
+			exit(0);
+		}
+	}
+}
+
+// クライアントオブジェクトの取得
+CLIENT *CtGetClient()
+{
+	if (client == NULL)
+	{
+		return NULL;
+	}
+
+	AddRef(client->ref);
+
+	return client;
+}
+
+// クライアントステータス表示器
+void CiClientStatusPrinter(SESSION *s, wchar_t *status)
+{
+#ifdef	OS_WIN32
+	ACCOUNT *a;
+	// 引数チェック
+	if (s == NULL || status == NULL)
+	{
+		return;
+	}
+
+	a = s->Account;
+	if (a == NULL)
+	{
+		return;
+	}
+
+	if (UniStrCmpi(status, L"init") == 0)
+	{
+		if (a->StatusWindow == NULL && s->Win32HideConnectWindow == false)
+		{
+			a->StatusWindow = CncStatusPrinterWindowStart(s);
+		}
+	}
+	else if (UniStrCmpi(status, L"free") == 0)
+	{
+		if (a->StatusWindow != NULL)
+		{
+			CncStatusPrinterWindowStop(a->StatusWindow);
+			a->StatusWindow = NULL;
+		}
+	}
+	else
+	{
+		if (a->StatusWindow != NULL)
+		{
+			CncStatusPrinterWindowPrint(a->StatusWindow, status);
+		}
+	}
+#else	// OS_WIN32
+	UniPrint(L"Status: %s\n", status);
+#endif	// OS_WIN32
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Client.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Client.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Client.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,787 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Client.h
+// Client.c のヘッダ
+
+#ifndef	CLIENT_H
+#define	CLIENT_H
+
+#define	CLIENT_CONFIG_PORT					9930		// クライアントポート番号
+#define	CLIENT_NOTIFY_PORT					9983		// クライアント通知ポート番号
+#define CLIENT_WAIT_CN_READY_TIMEOUT		(10 * 1000)	// クライアント通知サービスが起動するまでの待機時間
+
+
+// クライアントが指定された OS_TYPE で稼動するかどうかチェック
+#define	IS_CLIENT_SUPPORTED_OS(t)			\
+	((OS_IS_WINDOWS_NT(t) && GET_KETA(t, 100) >= 2) || (OS_IS_WINDOWS_9X(t)))
+
+
+// 定数
+#define	CLIENT_CONFIG_FILE_NAME				"@vpn_client.config"
+#define	CLIENT_DEFAULT_KEEPALIVE_HOST		"keepalive.utvpn.tsukuba.ac.jp"
+#define	CLIENT_DEFAULT_KEEPALIVE_PORT		80
+#define	CLIENT_DEFAULT_KEEPALIVE_INTERVAL	KEEP_INTERVAL_DEFAULT
+
+#define	CLIENT_RPC_MODE_NOTIFY				0
+#define	CLIENT_RPC_MODE_MANAGEMENT			1
+#define	CLIENT_RPC_MODE_SHORTCUT			2
+#define	CLIENT_RPC_MODE_SHORTCUT_DISCONNECT	3
+
+#define	CLIENT_MACOS_TAP_NAME				"tap0"
+
+#define	CLIENT_SAVER_INTERVAL				(30 * 1000)
+
+#define	CLIENT_NOTIFY_SERVICE_INSTANCENAME	"utvpnclient_uihelper"
+
+#define	CLIENT_WIN32_EXE_FILENAME			"utvpnclient.exe"
+#define	CLIENT_WIN32_EXE_FILENAME_X64		"utvpnclient_x64.exe"
+#define	CLIENT_WIN32_EXE_FILENAME_IA64		"utvpnclient_ia64.exe"
+
+#define CLIENT_CUSTOM_INI_FILENAME			"@custom.ini"
+
+
+// UNIX における仮想 LAN カードの一覧
+struct UNIX_VLAN
+{
+	bool Enabled;							// 有効フラグ
+	char Name[MAX_SIZE];					// 名前
+	UCHAR MacAddress[6];					// MAC アドレス
+	UCHAR Padding[2];
+};
+
+// アカウント
+struct ACCOUNT
+{
+	// 静的データ
+	CLIENT_OPTION *ClientOption;			// クライアント オプション
+	CLIENT_AUTH *ClientAuth;				// クライアント認証データ
+	bool CheckServerCert;					// サーバー証明書をチェックする
+	X *ServerCert;							// サーバー証明書
+	bool StartupAccount;					// スタートアップアカウントにする
+	UCHAR ShortcutKey[SHA1_SIZE];			// キー
+	UINT64 CreateDateTime;					// 作成日時
+	UINT64 UpdateDateTime;					// 更新日時
+	UINT64 LastConnectDateTime;				// 最終接続日時
+
+	// 動的データ
+	LOCK *lock;								// ロック
+	SESSION *ClientSession;					// クライアントセッション
+	CLIENT_STATUS_PRINTER *StatusPrinter;	// ステータス表示器
+
+	SOCK *StatusWindow;						// ステータスウインドウ
+};
+
+// クライアント設定
+struct CLIENT_CONFIG
+{
+	bool AllowRemoteConfig;					// リモート設定を許可する
+	bool UseKeepConnect;					// インターネットへの接続を維持
+	char KeepConnectHost[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	UINT KeepConnectPort;					// ポート番号
+	UINT KeepConnectProtocol;				// プロトコル
+	UINT KeepConnectInterval;				// 間隔
+};
+
+// バージョン取得
+struct RPC_CLIENT_VERSION
+{
+	char ClientProductName[128];		// クライアント製品名
+	char ClientVersionString[128];		// クライアントバージョン文字列
+	char ClientBuildInfoString[128];	// クライアントビルド情報文字列
+	UINT ClientVerInt;					// クライアントバージョン整数値
+	UINT ClientBuildInt;				// クライアントビルド番号整数値
+	UINT ProcessId;						// プロセス ID
+	UINT OsType;						// OS の種類
+};
+
+// パスワード設定
+struct RPC_CLIENT_PASSWORD
+{
+	char Password[MAX_PASSWORD_LEN + 1];	// パスワード
+	bool PasswordRemoteOnly;				// パスワードはリモートのみ必要
+};
+
+// パスワード設定の取得
+struct RPC_CLIENT_PASSWORD_SETTING
+{
+	bool IsPasswordPresented;				// パスワードが存在する
+	bool PasswordRemoteOnly;				// パスワードはリモートのみ必要
+};
+
+// 証明書列挙項目
+struct RPC_CLIENT_ENUM_CA_ITEM
+{
+	UINT Key;								// 証明書キー
+	wchar_t SubjectName[MAX_SIZE];			// 発行先
+	wchar_t IssuerName[MAX_SIZE];			// 発行者
+	UINT64 Expires;							// 有効期限
+};
+
+// 証明書列挙
+struct RPC_CLIENT_ENUM_CA
+{
+	UINT NumItem;							// 項目数
+	RPC_CLIENT_ENUM_CA_ITEM **Items;		// 項目
+};
+
+// 証明書項目
+struct RPC_CERT
+{
+	X *x;									// 証明書
+};
+
+// 証明書削除
+struct RPC_CLIENT_DELETE_CA
+{
+	UINT Key;								// 証明書キー
+};
+
+// 証明書の取得
+struct RPC_GET_CA
+{
+	UINT Key;								// 証明書キー
+	X *x;									// 証明書
+};
+
+// 署名者の取得
+struct RPC_GET_ISSUER
+{
+	X *x;									// 証明書
+	X *issuer_x;							// 署名者
+};
+
+// セキュアデバイス列挙項目
+struct RPC_CLIENT_ENUM_SECURE_ITEM
+{
+	UINT DeviceId;							// デバイス ID
+	UINT Type;								// 種別
+	char DeviceName[MAX_SIZE];				// デバイス名
+	char Manufacturer[MAX_SIZE];			// 製造元
+};
+
+// セキュアデバイスの列挙
+struct RPC_CLIENT_ENUM_SECURE
+{
+	UINT NumItem;							// 項目数
+	RPC_CLIENT_ENUM_SECURE_ITEM **Items;	// 項目
+};
+
+// セキュアデバイス指定
+struct RPC_USE_SECURE
+{
+	UINT DeviceId;							// デバイス ID
+};
+
+// セキュアデバイス内オブジェクト列挙
+struct RPC_ENUM_OBJECT_IN_SECURE
+{
+	UINT hWnd;								// ウインドウハンドル
+	UINT NumItem;							// 項目数
+	char **ItemName;						// 項目名
+	bool *ItemType;							// 種類 (true=秘密鍵, false=公開鍵)
+};
+
+// 仮想 LAN の作成
+struct RPC_CLIENT_CREATE_VLAN
+{
+	char DeviceName[MAX_SIZE];				// デバイス名
+};
+
+// 仮想 LAN 情報の取得
+struct RPC_CLIENT_GET_VLAN
+{
+	char DeviceName[MAX_SIZE];				// デバイス名
+	bool Enabled;							// 動作しているかどうかのフラグ
+	char MacAddress[MAX_SIZE];				// MAC アドレス
+	char Version[MAX_SIZE];					// バージョン
+	char FileName[MAX_SIZE];				// ドライバファイル名
+	char Guid[MAX_SIZE];					// GUID
+};
+
+// 仮想 LAN 情報の設定
+struct RPC_CLIENT_SET_VLAN
+{
+	char DeviceName[MAX_SIZE];				// デバイス名
+	char MacAddress[MAX_SIZE];				// MAC アドレス
+};
+
+// 仮想 LAN 列挙アイテム
+struct RPC_CLIENT_ENUM_VLAN_ITEM
+{
+	char DeviceName[MAX_SIZE];				// デバイス名
+	bool Enabled;							// 動作フラグ
+	char MacAddress[MAX_SIZE];				// MAC アドレス
+	char Version[MAX_SIZE];					// バージョン
+};
+
+// 仮想 LAN の列挙
+struct RPC_CLIENT_ENUM_VLAN
+{
+	UINT NumItem;							// アイテム数
+	RPC_CLIENT_ENUM_VLAN_ITEM **Items;		// アイテム
+};
+
+// アカウントの作成
+struct RPC_CLIENT_CREATE_ACCOUNT
+{
+	CLIENT_OPTION *ClientOption;			// クライアント オプション
+	CLIENT_AUTH *ClientAuth;				// クライアント認証データ
+	bool StartupAccount;					// スタートアップアカウント
+	bool CheckServerCert;					// サーバー証明書をチェックする
+	X *ServerCert;							// サーバー証明書
+	UCHAR ShortcutKey[SHA1_SIZE];			// ショートカットキー
+};
+
+// アカウントの列挙アイテム
+struct RPC_CLIENT_ENUM_ACCOUNT_ITEM
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+	char UserName[MAX_USERNAME_LEN + 1];	//  ユーザー名
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	char DeviceName[MAX_DEVICE_NAME_LEN + 1];	// デバイス名
+	UINT ProxyType;							// プロキシ接続の種類
+	char ProxyName[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	bool Active;							// 動作フラグ
+	bool Connected;							// 接続完了フラグ
+	bool StartupAccount;					// スタートアップアカウント
+	UINT Port;								// ポート番号 (Ver 3.0 以降)
+	char HubName[MAX_HUBNAME_LEN + 1];		// 仮想 HUB 名 (Ver 3.0 以降)
+	UINT64 CreateDateTime;					// 作成日時 (Ver 3.0 以降)
+	UINT64 UpdateDateTime;					// 更新日時 (Ver 3.0 以降)
+	UINT64 LastConnectDateTime;				// 最終接続日時 (Ver 3.0 以降)
+	UINT tmp1;								// 一時データ
+};
+
+// アカウントの列挙
+struct RPC_CLIENT_ENUM_ACCOUNT
+{
+	UINT NumItem;							// アイテム数
+	RPC_CLIENT_ENUM_ACCOUNT_ITEM **Items;	// アイテム
+};
+
+// アカウントの削除
+struct RPC_CLIENT_DELETE_ACCOUNT
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+};
+
+// アカウント名の変更
+struct RPC_RENAME_ACCOUNT
+{
+	wchar_t OldName[MAX_ACCOUNT_NAME_LEN + 1];		// 古い名前
+	wchar_t NewName[MAX_ACCOUNT_NAME_LEN + 1];		// 新しい名前
+};
+
+// アカウントの取得
+struct RPC_CLIENT_GET_ACCOUNT
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+	CLIENT_OPTION *ClientOption;			// クライアント オプション
+	CLIENT_AUTH *ClientAuth;				// クライアント認証データ
+	bool StartupAccount;					// スタートアップアカウント
+	bool CheckServerCert;					// サーバー証明書をチェックする
+	X *ServerCert;							// サーバー証明書
+	UCHAR ShortcutKey[SHA1_SIZE];			// ショートカットキー
+	UINT64 CreateDateTime;					// 作成日時 (Ver 3.0 以降)
+	UINT64 UpdateDateTime;					// 更新日時 (Ver 3.0 以降)
+	UINT64 LastConnectDateTime;				// 最終接続日時 (Ver 3.0 以降)
+};
+
+// 接続
+struct RPC_CLIENT_CONNECT
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+};
+
+// コネクション状況の取得
+struct RPC_CLIENT_GET_CONNECTION_STATUS
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+	bool Active;							// 動作フラグ
+	bool Connected;							// 接続済みフラグ
+	UINT SessionStatus;						// セッションステータス
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	UINT ServerPort;						// サーバーのポート番号
+	char ServerProductName[MAX_SIZE];		// サーバー製品名
+	UINT ServerProductVer;					// サーバー製品バージョン
+	UINT ServerProductBuild;				// サーバー製品ビルド番号
+	X *ServerX;								// サーバーの証明書
+	X *ClientX;								// クライアントの証明書
+	UINT64 StartTime;						// 接続開始時刻
+	UINT64 FirstConnectionEstablisiedTime;	// 最初のコネクションの接続完了時刻
+	UINT64 CurrentConnectionEstablishTime;	// このコネクションの接続完了時刻
+	UINT NumConnectionsEatablished;			// これまでに確立したコネクション数
+	bool HalfConnection;					// ハーフコネクション
+	bool QoS;								// VoIP / QoS
+	UINT MaxTcpConnections;					// 最大の TCP コネクション数
+	UINT NumTcpConnections;					// 現在の TCP コネクション数
+	UINT NumTcpConnectionsUpload;			// 上りコネクション数
+	UINT NumTcpConnectionsDownload;			// 下りコネクション数
+	bool UseEncrypt;						// 暗号化の使用
+	char CipherName[32];					// 暗号化アルゴリズム名
+	bool UseCompress;						// 圧縮の使用
+	char SessionName[MAX_SESSION_NAME_LEN + 1];	// セッション名
+	char ConnectionName[MAX_CONNECTION_NAME_LEN + 1];	// コネクション名
+	UCHAR SessionKey[SHA1_SIZE];			// セッションキー
+	POLICY Policy;							// ポリシー
+	UINT64 TotalSendSize;					// 合計送信データサイズ
+	UINT64 TotalRecvSize;					// 合計受信データサイズ
+	UINT64 TotalSendSizeReal;				// 合計送信データサイズ (無圧縮)
+	UINT64 TotalRecvSizeReal;				// 合計受信データサイズ (無圧縮)
+	TRAFFIC Traffic;						// トラフィックデータ
+	bool IsBridgeMode;						// ブリッジモード
+	bool IsMonitorMode;						// モニタモード
+	UINT VLanId;							// VLAN ID
+};
+
+
+// RPC コネクション
+struct CLIENT_RPC_CONNECTION
+{
+	struct CLIENT *Client;					// クライアント
+	bool RpcMode;							// true: RPC モード, false: 通知モード
+	THREAD *Thread;							// 処理スレッド
+	SOCK *Sock;								// ソケット
+};
+
+// クライアント オブジェクト
+struct CLIENT
+{
+	LOCK *lock;								// ロック
+	LOCK *lockForConnect;					// CtConnect 内部で使用するロック
+	REF *ref;								// 参照カウンタ
+	CEDAR *Cedar;							// Cedar
+	volatile bool Halt;						// 停止フラグ
+	UINT Err;								// エラーコード
+	CFG_RW *CfgRw;							// 設定ファイル R/W
+	LIST *AccountList;						// アカウントリスト
+	UCHAR EncryptedPassword[SHA1_SIZE];		// パスワード
+	bool PasswordRemoteOnly;				// パスワードはリモート接続のみ必要とする
+	UINT UseSecureDeviceId;					// 使用するセキュアデバイス ID
+	CLIENT_CONFIG Config;					// クライアント設定
+	LIST *RpcConnectionList;				// RPC コネクションリスト
+	SOCK *RpcListener;						// RPC リスナ
+	THREAD *RpcThread;						// RPC スレッド
+	LOCK *HelperLock;						// 補助ロック
+	THREAD *SaverThread;					// 設定データ自動保存スレッド
+	EVENT *SaverHalter;						// 設定データ自動保存スレッド停止用イベント
+	LIST *NotifyCancelList;					// 通知イベントリスト
+	KEEP *Keep;								// Keep Connection
+	LIST *UnixVLanList;						// UNIX における仮想 LAN カードのリスト
+	LOG *Logger;							// ロガー
+	bool DontSavePassword;					// パスワードを保存しないフラグ
+	ERASER *Eraser;							// 自動ファイル削除器
+	SOCKLIST *SockList;						// ソケットリスト
+	CM_SETTING *CmSetting;					// CM 設定
+	bool NoSaveLog;							// ログ保存をしない
+	bool NoSaveConfig;						// 設定を保存しない
+};
+
+// リモートクライアントへの通知
+struct RPC_CLIENT_NOTIFY
+{
+	UINT NotifyCode;						// コード
+};
+
+// 通知の種類
+#define	CLIENT_NOTIFY_ACCOUNT_CHANGED	1	// アカウント変化通知
+#define	CLIENT_NOTIFY_VLAN_CHANGED		2	// 仮想 LAN カード変化通知
+
+// リモートクライアント
+struct REMOTE_CLIENT
+{
+	RPC *Rpc;
+	UINT OsType;
+	bool Unix;
+	bool Win9x;
+	UINT ProcessId;
+	UINT ClientBuildInt;
+};
+
+// 通知クライアント
+struct NOTIFY_CLIENT
+{
+	SOCK *Sock;
+};
+
+// CM 設定
+struct CM_SETTING
+{
+	bool EasyMode;							// 簡易モード
+	bool LockMode;							// 設定ロックモード
+	UCHAR HashedPassword[SHA1_SIZE];		// パスワード
+};
+
+
+
+
+// 関数プロトタイプ
+REMOTE_CLIENT *CcConnectRpc(char *server_name, char *password, bool *bad_pass, bool *no_remote, UINT wait_retry);
+REMOTE_CLIENT *CcConnectRpcEx(char *server_name, char *password, bool *bad_pass, bool *no_remote, UCHAR *key, UINT *key_error_code, bool shortcut_disconnect, UINT wait_retry);
+UINT CcShortcut(UCHAR *key);
+UINT CcShortcutDisconnect(UCHAR *key);
+void CcDisconnectRpc(REMOTE_CLIENT *rc);
+NOTIFY_CLIENT *CcConnectNotify(REMOTE_CLIENT *rc);
+void CcDisconnectNotify(NOTIFY_CLIENT *n);
+void CcStopNotify(NOTIFY_CLIENT *n);
+bool CcWaitNotify(NOTIFY_CLIENT *n);
+UINT CcGetClientVersion(REMOTE_CLIENT *r, RPC_CLIENT_VERSION *a);
+UINT CcSetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a);
+UINT CcGetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a);
+UINT CcSetPassword(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD *pass);
+UINT CcGetPasswordSetting(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD_SETTING *a);
+UINT CcEnumCa(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_CA *e);
+UINT CcAddCa(REMOTE_CLIENT *r, RPC_CERT *cert);
+UINT CcDeleteCa(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_CA *p);
+UINT CcGetCa(REMOTE_CLIENT *r, RPC_GET_CA *get);
+UINT CcEnumSecure(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_SECURE *e);
+UINT CcUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec);
+UINT CcGetUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec);
+UINT CcEnumObjectInSecure(REMOTE_CLIENT *r, RPC_ENUM_OBJECT_IN_SECURE *e);
+UINT CcCreateVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create);
+UINT CcUpgradeVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create);
+UINT CcGetVLan(REMOTE_CLIENT *r, RPC_CLIENT_GET_VLAN *get);
+UINT CcSetVLan(REMOTE_CLIENT *r, RPC_CLIENT_SET_VLAN *set);
+UINT CcEnumVLan(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_VLAN *e);
+UINT CcDeleteVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *d);
+UINT CcEnableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan);
+UINT CcDisableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan);
+UINT CcCreateAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a);
+UINT CcEnumAccount(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_ACCOUNT *e);
+UINT CcDeleteAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcSetAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a);
+UINT CcGetAccount(REMOTE_CLIENT *r, RPC_CLIENT_GET_ACCOUNT *a);
+UINT CcRenameAccount(REMOTE_CLIENT *r, RPC_RENAME_ACCOUNT *rename);
+UINT CcSetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o);
+UINT CcGetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o);
+UINT CcConnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect);
+UINT CcDisconnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect);
+UINT CcGetAccountStatus(REMOTE_CLIENT *r, RPC_CLIENT_GET_CONNECTION_STATUS *st);
+UINT CcSetStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcRemoveStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcGetIssuer(REMOTE_CLIENT *r, RPC_GET_ISSUER *a);
+void CcSetServiceToForegroundProcess(REMOTE_CLIENT *r);
+char *CiGetFirstVLan(CLIENT *c);
+void CiNormalizeAccountVLan(CLIENT *c);
+
+
+void CnStart();
+void CnListenerProc(THREAD *thread, void *param);
+
+void CnReleaseSocket(SOCK *s, PACK *p);
+
+void CnStatusPrinter(SOCK *s, PACK *p);
+void Win32CnStatusPrinter(SOCK *s, PACK *p);
+
+void CnConnectErrorDlg(SOCK *s, PACK *p);
+void Win32CnConnectErrorDlg(SOCK *s, PACK *p);
+void Win32CnConnectErrorDlgThreadProc(THREAD *thread, void *param);
+
+void CnPasswordDlg(SOCK *s, PACK *p);
+void Win32CnPasswordDlg(SOCK *s, PACK *p);
+void Win32CnPasswordDlgThreadProc(THREAD *thread, void *param);
+
+void CnMsgDlg(SOCK *s, PACK *p);
+void Win32CnMsgDlg(SOCK *s, PACK *p);
+void Win32CnMsgDlgThreadProc(THREAD *thread, void *param);
+
+void CnNicInfo(SOCK *s, PACK *p);
+void Win32CnNicInfo(SOCK *s, PACK *p);
+void Win32CnNicInfoThreadProc(THREAD *thread, void *param);
+
+void CnCheckCert(SOCK *s, PACK *p);
+void Win32CnCheckCert(SOCK *s, PACK *p);
+void Win32CnCheckCertThreadProc(THREAD *thread, void *param);
+
+void CnExecDriverInstaller(SOCK *s, PACK *p);
+void Win32CnExecDriverInstaller(SOCK *s, PACK *p);
+
+bool CnCheckAlreadyExists(bool lock);
+bool CnIsCnServiceReady();
+void CnWaitForCnServiceReady();
+
+void CnSecureSign(SOCK *s, PACK *p);
+
+SOCK *CncConnect();
+SOCK *CncConnectEx(UINT timeout);
+void CncReleaseSocket();
+void CncExit();
+UINT CncGetSessionId();
+bool CncExecDriverInstaller(char *arg);
+SOCK *CncStatusPrinterWindowStart(SESSION *s);
+void CncStatusPrinterWindowPrint(SOCK *s, wchar_t *str);
+void CncStatusPrinterWindowStop(SOCK *s);
+void CncStatusPrinterWindowThreadProc(THREAD *thread, void *param);
+bool CncConnectErrorDlg(SESSION *session, UI_CONNECTERROR_DLG *dlg);
+void CncConnectErrorDlgHaltThread(THREAD *thread, void *param);
+bool CncPasswordDlg(SESSION *session, UI_PASSWORD_DLG *dlg);
+void CncPasswordDlgHaltThread(THREAD *thread, void *param);
+void CncCheckCert(SESSION *session, UI_CHECKCERT *dlg);
+void CncCheckCertHaltThread(THREAD *thread, void *param);
+bool CncSecureSignDlg(SECURE_SIGN *sign);
+SOCK *CncMsgDlg(UI_MSG_DLG *dlg);
+void CndMsgDlgFree(SOCK *s);
+SOCK *CncNicInfo(UI_NICINFO *info);
+void CncNicInfoFree(SOCK *s);
+
+void CtStartClient();
+void CtStopClient();
+CLIENT *CtGetClient();
+void CtReleaseClient(CLIENT *c);
+bool CtGetClientVersion(CLIENT *c, RPC_CLIENT_VERSION *ver);
+bool CtGetCmSetting(CLIENT *c, CM_SETTING *s);
+bool CtSetCmSetting(CLIENT *c, CM_SETTING *s);
+bool CtSetPassword(CLIENT *c, RPC_CLIENT_PASSWORD *pass);
+bool CtGetPasswordSetting(CLIENT *c, RPC_CLIENT_PASSWORD_SETTING *a);
+bool CtEnumCa(CLIENT *c, RPC_CLIENT_ENUM_CA *e);
+bool CtAddCa(CLIENT *c, RPC_CERT *cert);
+bool CtDeleteCa(CLIENT *c, RPC_CLIENT_DELETE_CA *p);
+bool CtGetCa(CLIENT *c, RPC_GET_CA *get);
+bool CtEnumSecure(CLIENT *c, RPC_CLIENT_ENUM_SECURE *e);
+bool CtUseSecure(CLIENT *c, RPC_USE_SECURE *sec);
+bool CtGetUseSecure(CLIENT *c, RPC_USE_SECURE *sec);
+bool CtEnumObjectInSecure(CLIENT *c, RPC_ENUM_OBJECT_IN_SECURE *e);
+bool CtCreateVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create);
+bool CtUpgradeVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create);
+bool CtGetVLan(CLIENT *c, RPC_CLIENT_GET_VLAN *get);
+bool CtSetVLan(CLIENT *c, RPC_CLIENT_SET_VLAN *set);
+bool CtEnumVLan(CLIENT *c, RPC_CLIENT_ENUM_VLAN *e);
+bool CtDeleteVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *d);
+bool CtEnableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan);
+bool CtDisableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan);
+bool CtCreateAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a);
+bool CtEnumAccount(CLIENT *c, RPC_CLIENT_ENUM_ACCOUNT *e);
+bool CtDeleteAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a);
+bool CtSetAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a);
+bool CtGetAccount(CLIENT *c, RPC_CLIENT_GET_ACCOUNT *a);
+bool CtRenameAccount(CLIENT *c, RPC_RENAME_ACCOUNT *rename);
+bool CtSetClientConfig(CLIENT *c, CLIENT_CONFIG *o);
+bool CtGetClientConfig(CLIENT *c, CLIENT_CONFIG *o);
+bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect);
+bool CtDisconnect(CLIENT *c, RPC_CLIENT_CONNECT *connect);
+bool CtGetAccountStatus(CLIENT *c, RPC_CLIENT_GET_CONNECTION_STATUS *st);
+bool CtSetStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a);
+bool CtRemoveStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a);
+bool CtGetIssuer(CLIENT *c, RPC_GET_ISSUER *a);
+
+
+
+
+
+// 内部関数プロトタイプ
+char *CiGetVpnClientExeFileName();
+void CiServerThread(THREAD *t, void *param);
+void CiInitSaver(CLIENT *c);
+void CiFreeSaver(CLIENT *c);
+void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s);
+PACK *CiRpcDispatch(RPC *rpc, char *name, PACK *p);
+void CiRpcAccepted(CLIENT *c, SOCK *s);
+void CiNotifyMain(CLIENT *c, SOCK *s);
+void CiRpcAcceptThread(THREAD *thread, void *param);
+void CiRpcServerThread(THREAD *thread, void *param);
+void CiStartRpcServer(CLIENT *c);
+void CiStopRpcServer(CLIENT *c);
+CLIENT_OPTION *CiLoadClientOption(FOLDER *f);
+CLIENT_AUTH *CiLoadClientAuth(FOLDER *f);
+ACCOUNT *CiLoadClientAccount(FOLDER *f);
+void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f);
+void CiLoadAccountDatabase(CLIENT *c, FOLDER *f);
+void CiLoadCAList(CLIENT *c, FOLDER *f);
+void CiLoadCACert(CLIENT *c, FOLDER *f);
+void CiLoadVLanList(CLIENT *c, FOLDER *f);
+void CiLoadVLan(CLIENT *c, FOLDER *f);
+bool CiReadSettingFromCfg(CLIENT *c, FOLDER *root);
+void CiWriteAccountDatabase(CLIENT *c, FOLDER *f);
+void CiWriteAccountData(FOLDER *f, ACCOUNT *a);
+void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o);
+void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a);
+void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config);
+void CiWriteSettingToCfg(CLIENT *c, FOLDER *root);
+void CiWriteCAList(CLIENT *c, FOLDER *f);
+void CiWriteCACert(CLIENT *c, FOLDER *f, X *x);
+void CiWriteVLanList(CLIENT *c, FOLDER *f);
+void CiWriteVLan(CLIENT *c, FOLDER *f, UNIX_VLAN *v);
+void CiFreeClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st);
+bool CiCheckCertProc(SESSION *s, CONNECTION *c, X *server_x, bool *expired);
+bool CiSecureSignProc(SESSION *s, CONNECTION *c, SECURE_SIGN *sign);
+bool Win32CiSecureSign(SECURE_SIGN *sign);
+void CiFreeClientAuth(CLIENT_AUTH *auth);
+void CiFreeClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *a);
+void CiFreeClientGetAccount(RPC_CLIENT_GET_ACCOUNT *a);
+void CiFreeClientEnumVLan(RPC_CLIENT_ENUM_VLAN *e);
+void CiFreeClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e);
+void CiFreeClientEnumCa(RPC_CLIENT_ENUM_CA *e);
+void CiFreeEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *a);
+void CiFreeGetCa(RPC_GET_CA *a);
+void CiFreeGetIssuer(RPC_GET_ISSUER *a);
+void CiFreeClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *a);
+void CiSetError(CLIENT *c, UINT err);
+void CiCheckOs();
+CLIENT *CiNewClient();
+void CiCleanupClient(CLIENT *c);
+bool CiLoadConfigurationFile(CLIENT *c);
+void CiSaveConfigurationFile(CLIENT *c);
+void CiInitConfiguration(CLIENT *c);
+void CiSetVLanToDefault(CLIENT *c);
+bool CiIsVLan(CLIENT *c, char *name);
+void CiFreeConfiguration(CLIENT *c);
+int CiCompareAccount(void *p1, void *p2);
+void CiFreeAccount(ACCOUNT *a);
+void CiNotify(CLIENT *c);
+void CiClientStatusPrinter(SESSION *s, wchar_t *status);
+void CiInitKeep(CLIENT *c);
+void CiFreeKeep(CLIENT *c);
+int CiCompareUnixVLan(void *p1, void *p2);
+BUF *CiAccountToCfg(RPC_CLIENT_CREATE_ACCOUNT *t);
+RPC_CLIENT_CREATE_ACCOUNT *CiCfgToAccount(BUF *b);
+void CiChangeAllVLanMacAddress(CLIENT *c);
+void CiChangeAllVLanMacAddressIfMachineChanged(CLIENT *c);
+bool CiReadLastMachineHash(void *data);
+bool CiWriteLastMachineHash(void *data);
+void CiGetCurrentMachineHash(void *data);
+void CiGetCurrentMachineHashOld(void *data);
+int CiCompareClientAccountEnumItemByLastConnectDateTime(void *p1, void *p2);
+
+BUF *EncryptPassword(char *password);
+char *DecryptPassword(BUF *b);
+
+void InRpcGetIssuer(RPC_GET_ISSUER *c, PACK *p);
+void OutRpcGetIssuer(PACK *p, RPC_GET_ISSUER *c);
+void InRpcClientVersion(RPC_CLIENT_VERSION *ver, PACK *p);
+void OutRpcClientVersion(PACK *p, RPC_CLIENT_VERSION *ver);
+void InRpcClientPassword(RPC_CLIENT_PASSWORD *pw, PACK *p);
+void OutRpcClientPassword(PACK *p, RPC_CLIENT_PASSWORD *pw);
+void InRpcClientEnumCa(RPC_CLIENT_ENUM_CA *e, PACK *p);
+void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e);
+void InRpcCert(RPC_CERT *c, PACK *p);
+void OutRpcCert(PACK *p, RPC_CERT *c);
+void InRpcClientDeleteCa(RPC_CLIENT_DELETE_CA *c, PACK *p);
+void OutRpcClientDeleteCa(PACK *p, RPC_CLIENT_DELETE_CA *c);
+void InRpcGetCa(RPC_GET_CA *c, PACK *p);
+void OutRpcGetCa(PACK *p, RPC_GET_CA *c);
+void InRpcClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e, PACK *p);
+void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e);
+void InRpcUseSecure(RPC_USE_SECURE *u, PACK *p);
+void OutRpcUseSecure(PACK *p, RPC_USE_SECURE *u);
+void InRpcEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *e, PACK *p);
+void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e);
+void InRpcCreateVLan(RPC_CLIENT_CREATE_VLAN *v, PACK *p);
+void OutRpcCreateVLan(PACK *p, RPC_CLIENT_CREATE_VLAN *v);
+void InRpcClientGetVLan(RPC_CLIENT_GET_VLAN *v, PACK *p);
+void OutRpcClientGetVLan(PACK *p, RPC_CLIENT_GET_VLAN *v);
+void InRpcClientSetVLan(RPC_CLIENT_SET_VLAN *v, PACK *p);
+void OutRpcClientSetVLan(PACK *p, RPC_CLIENT_SET_VLAN *v);
+void InRpcClientEnumVLan(RPC_CLIENT_ENUM_VLAN *v, PACK *p);
+void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v);
+void InRpcClientOption(CLIENT_OPTION *c, PACK *p);
+void OutRpcClientOption(PACK *p, CLIENT_OPTION *c);
+void InRpcClientAuth(CLIENT_AUTH *c, PACK *p);
+void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c);
+void InRpcClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *c, PACK *p);
+void OutRpcClientCreateAccount(PACK *p, RPC_CLIENT_CREATE_ACCOUNT *c);
+void InRpcClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *e, PACK *p);
+void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e);
+void InRpcClientDeleteAccount(RPC_CLIENT_DELETE_ACCOUNT *a, PACK *p);
+void OutRpcClientDeleteAccount(PACK *p, RPC_CLIENT_DELETE_ACCOUNT *a);
+void InRpcRenameAccount(RPC_RENAME_ACCOUNT *a, PACK *p);
+void OutRpcRenameAccount(PACK *p, RPC_RENAME_ACCOUNT *a);
+void InRpcClientGetAccount(RPC_CLIENT_GET_ACCOUNT *c, PACK *p);
+void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c);
+void InRpcClientConnect(RPC_CLIENT_CONNECT *c, PACK *p);
+void OutRpcClientConnect(PACK *p, RPC_CLIENT_CONNECT *c);
+void InRpcPolicy(POLICY *o, PACK *p);
+void OutRpcPolicy(PACK *p, POLICY *o);
+void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p);
+void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *c);
+void InRpcClientNotify(RPC_CLIENT_NOTIFY *n, PACK *p);
+void OutRpcClientNotify(PACK *p, RPC_CLIENT_NOTIFY *n);
+void InRpcClientConfig(CLIENT_CONFIG *c, PACK *p);
+void OutRpcClientConfig(PACK *p, CLIENT_CONFIG *c);
+void InRpcClientPasswordSetting(RPC_CLIENT_PASSWORD_SETTING *a, PACK *p);
+void OutRpcClientPasswordSetting(PACK *p, RPC_CLIENT_PASSWORD_SETTING *a);
+void InRpcTraffic(TRAFFIC *t, PACK *p);
+void OutRpcTraffic(PACK *p, TRAFFIC *t);
+void InRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i);
+void OutRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i, UINT num);
+void OutRpcCmSetting(PACK *p, CM_SETTING *c);
+void InRpcCmSetting(CM_SETTING *c, PACK *p);
+
+
+#endif	// CLIENT_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Command.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Command.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Command.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,22416 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Command.c
+// vpncmd コマンドライン管理ユーティリティ
+
+#include "CedarPch.h"
+
+// システムチェッカ定義
+typedef bool (CHECKER_PROC_DEF)();
+typedef struct CHECKER_PROC
+{
+	char *Title;
+	CHECKER_PROC_DEF *Proc;
+} CHECKER_PROC;
+
+static CHECKER_PROC checker_procs[] =
+{
+	{"CHECK_PROC_KERNEL", CheckKernel},
+	{"CHECK_PROC_MEMORY", CheckMemory},
+	{"CHECK_PROC_STRINGS", CheckStrings},
+	{"CHECK_PROC_FILESYSTEM", CheckFileSystem},
+	{"CHECK_PROC_THREAD", CheckThread},
+	{"CHECK_PROC_NETWORK", CheckNetwork},
+};
+
+typedef struct CHECK_NETWORK_1
+{
+	SOCK *ListenSocket;
+} CHECK_NETWORK_1;
+
+typedef struct CHECK_NETWORK_2
+{
+	SOCK *s;
+	X *x;
+	K *k;
+} CHECK_NETWORK_2;
+
+
+// TT_RESULT を RPC に変換
+void OutRpcTtResult(PACK *p, TT_RESULT *t)
+{
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddBool(p, "Raw", t->Raw);
+	PackAddBool(p, "Double", t->Double);
+	PackAddInt64(p, "NumBytesUpload", t->NumBytesUpload);
+	PackAddInt64(p, "NumBytesDownload", t->NumBytesDownload);
+	PackAddInt64(p, "NumBytesTotal", t->NumBytesTotal);
+	PackAddInt64(p, "Span", t->Span);
+	PackAddInt64(p, "BpsUpload", t->BpsUpload);
+	PackAddInt64(p, "BpsDownload", t->BpsDownload);
+	PackAddInt64(p, "BpsTotal", t->BpsTotal);
+}
+
+// RPC を TT_RESULT に変換
+void InRpcTtResult(PACK *p, TT_RESULT *t)
+{
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(TT_RESULT));
+
+	t->Raw = PackGetBool(p, "Raw");
+	t->Double = PackGetBool(p, "Double");
+	t->NumBytesUpload = PackGetInt64(p, "NumBytesUpload");
+	t->NumBytesDownload = PackGetInt64(p, "NumBytesDownload");
+	t->NumBytesTotal = PackGetInt64(p, "NumBytesTotal");
+	t->Span = PackGetInt64(p, "Span");
+	t->BpsUpload = PackGetInt64(p, "BpsUpload");
+	t->BpsDownload = PackGetInt64(p, "BpsDownload");
+	t->BpsTotal = PackGetInt64(p, "BpsTotal");
+}
+
+// Accept スレッド
+void CheckNetworkAcceptThread(THREAD *thread, void *param)
+{
+	CHECK_NETWORK_2 *c = (CHECK_NETWORK_2 *)param;
+	SOCK *s = c->s;
+	UINT i = 0;
+
+	if (StartSSL(s, c->x, c->k))
+	{
+		while (true)
+		{
+			i++;
+			if (Send(s, &i, sizeof(UINT), true) == 0)
+			{
+				break;
+			}
+		}
+	}
+
+	Disconnect(s);
+	ReleaseSock(s);
+}
+
+
+// Listen スレッド
+void CheckNetworkListenThread(THREAD *thread, void *param)
+{
+	CHECK_NETWORK_1 *c = (CHECK_NETWORK_1 *)param;
+	SOCK *s;
+	UINT i;
+	K *pub, *pri;
+	X *x;
+	LIST *o = NewList(NULL);
+	NAME *name = NewName(L"Test", L"Test", L"Test", L"JP", L"Ibaraki", L"Tsukuba");
+
+	RsaGen(&pri, &pub, 1024);
+	x = NewRootX(pub, pri, name, 1000, NULL);
+
+	FreeName(name);
+
+	for (i = 1025;;i++)
+	{
+		s = Listen(i);
+		if (s != NULL)
+		{
+			break;
+		}
+	}
+
+	c->ListenSocket = s;
+	AddRef(s->ref);
+
+	NoticeThreadInit(thread);
+
+	while (true)
+	{
+		SOCK *new_sock = Accept(s);
+
+		if (new_sock == NULL)
+		{
+			break;
+		}
+		else
+		{
+			CHECK_NETWORK_2 c;
+			THREAD *t;
+
+			Zero(&c, sizeof(c));
+			c.s = new_sock;
+			c.k = pri;
+			c.x = x;
+
+			t = NewThread(CheckNetworkAcceptThread, &c);
+			Insert(o, t);
+		}
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		THREAD *t = LIST_DATA(o, i);
+		WaitThread(t, INFINITE);
+		ReleaseThread(t);
+	}
+
+	FreeK(pri);
+	FreeK(pub);
+
+	FreeX(x);
+
+	ReleaseSock(s);
+	ReleaseList(o);
+}
+
+// ネットワーク機能チェック
+bool CheckNetwork()
+{
+	CHECK_NETWORK_1 c;
+	THREAD *t;
+	SOCK *listen_socket;
+	UINT port;
+	UINT i, num;
+	bool ok = true;
+	SOCK **socks;
+	SOCK_EVENT *se = NewSockEvent();
+
+	Zero(&c, sizeof(c));
+	t = NewThread(CheckNetworkListenThread, &c);
+	WaitThreadInit(t);
+
+	listen_socket = c.ListenSocket;
+
+	port = listen_socket->LocalPort;
+
+	num = 8;
+	socks = ZeroMalloc(sizeof(SOCK *) * num);
+	for (i = 0;i < num;i++)
+	{
+		socks[i] = Connect("localhost", port);
+		if (socks[i] == NULL)
+		{
+			Print("Connect Failed. (%u)\n", i);
+			ok = false;
+			num = i;
+			break;
+		}
+		if (StartSSL(socks[i], NULL, NULL) == false)
+		{
+			ReleaseSock(socks[i]);
+			Print("Connect Failed. (%u)\n", i);
+			ok = false;
+			num = i;
+			break;
+		}
+
+		JoinSockToSockEvent(socks[i], se);
+	}
+
+	if (ok)
+	{
+		while (true)
+		{
+			UINT i;
+			bool end = false;
+			bool all_blocked = true;
+
+			for (i = 0;i < num;i++)
+			{
+				UINT n;
+				UINT ret;
+
+				n = 0;
+				ret = Recv(socks[i], &n, sizeof(UINT), true);
+				if (ret == 0)
+				{
+					Print("Recv Failed (Disconnected).\n", ret);
+					end = true;
+					ok = false;
+				}
+				if (ret != SOCK_LATER)
+				{
+					all_blocked = false;
+				}
+
+				if (n >= 128)
+				{
+					end = true;
+				}
+			}
+
+			if (end)
+			{
+				break;
+			}
+
+			if (all_blocked)
+			{
+				WaitSockEvent(se, INFINITE);
+			}
+		}
+	}
+
+	for (i = 0;i < num;i++)
+	{
+		Disconnect(socks[i]);
+		ReleaseSock(socks[i]);
+	}
+	Free(socks);
+
+	Disconnect(listen_socket);
+
+	WaitThread(t, INFINITE);
+	ReleaseThread(t);
+
+	ReleaseSock(listen_socket);
+
+	ReleaseSockEvent(se);
+
+	return ok;
+}
+
+typedef struct CHECK_THREAD_1
+{
+	UINT num;
+	LOCK *lock;
+	THREAD *wait_thread;
+} CHECK_THREAD_1;
+
+static UINT check_thread_global_1 = 0;
+
+#define	CHECK_THREAD_INCREMENT_COUNT		32
+
+// テストスレッド 1
+void CheckThread1(THREAD *thread, void *param)
+{
+	CHECK_THREAD_1 *ct1 = (CHECK_THREAD_1 *)param;
+	UINT i;
+	UINT num = CHECK_THREAD_INCREMENT_COUNT;
+
+	WaitThread(ct1->wait_thread, INFINITE);
+
+	for (i = 0;i < num;i++)
+	{
+		Lock(ct1->lock);
+		check_thread_global_1 = ct1->num;
+		InputToNull((void *)check_thread_global_1);
+		check_thread_global_1 = check_thread_global_1 + 1 + RetZero();
+		ct1->num = check_thread_global_1;
+		Unlock(ct1->lock);
+	}
+}
+
+// テストスレッド 2
+void CheckThread2(THREAD *thread, void *param)
+{
+	EVENT *e = (EVENT *)param;
+	Wait(e, INFINITE);
+}
+
+typedef struct CHECK_THREAD_3
+{
+	UINT num, a;
+} CHECK_THREAD_3;
+
+// テストスレッド 3
+void CheckThread3(THREAD *thread, void *param)
+{
+	CHECK_THREAD_3 *c = (CHECK_THREAD_3 *)param;
+	THREAD *t;
+
+	if (c->num == 0)
+	{
+		return;
+	}
+	c->num--;
+	c->a++;
+
+	t = NewThread(CheckThread3, c);
+	WaitThread(t, INFINITE);
+	ReleaseThread(t);
+}
+
+// スレッドチェック
+bool CheckThread()
+{
+	bool ok = true;
+	CHECK_THREAD_1 ct1;
+	UINT num = 32;
+	UINT i;
+	THREAD **threads;
+	EVENT *e;
+	THREAD *t2;
+	THREAD *t;
+	CHECK_THREAD_3 c;
+
+	e = NewEvent();
+
+	Zero(&ct1, sizeof(ct1));
+	ct1.lock = NewLock();
+
+	t2 = NewThread(CheckThread2, e);
+	ct1.wait_thread = t2;
+
+	threads = ZeroMalloc(sizeof(THREAD *) * num);
+	for (i = 0;i < num;i++)
+	{
+		threads[i] = NewThread(CheckThread1, &ct1);
+		if (threads[i] == NULL)
+		{
+			Print("Thread %u Create Failed.\n", i);
+			ok = false;
+		}
+	}
+
+	Set(e);
+
+	for (i = 0;i < num;i++)
+	{
+		WaitThread(threads[i], INFINITE);
+		ReleaseThread(threads[i]);
+	}
+
+	Free(threads);
+
+	if (ct1.num != (num * CHECK_THREAD_INCREMENT_COUNT))
+	{
+		Print("Threading: %u != %u\n", ct1.num, num * CHECK_THREAD_INCREMENT_COUNT);
+		ok = false;
+	}
+
+	DeleteLock(ct1.lock);
+
+	WaitThread(t2, INFINITE);
+	ReleaseThread(t2);
+
+	ReleaseEvent(e);
+
+	num = 32;
+
+	Zero(&c, sizeof(c));
+	c.num = num;
+	t = NewThread(CheckThread3, &c);
+	WaitThread(t, INFINITE);
+	ReleaseThread(t);
+
+	if (c.a != num)
+	{
+		Print("Threading: %u != %u\n", c.a, num);
+		ok = false;
+	}
+
+	return ok;
+}
+
+// ファイルシステムチェック
+bool CheckFileSystem()
+{
+	bool ok = true;
+	char exe[MAX_PATH];
+	char exe_dir[MAX_PATH];
+	DIRLIST *dirs;
+	UINT i;
+
+	GetExeName(exe, sizeof(exe));
+	GetExeDir(exe_dir, sizeof(exe_dir));
+
+	ok = false;
+	dirs = EnumDir(exe_dir);
+	for (i = 0;i < dirs->NumFiles;i++)
+	{
+		if (EndWith(exe, dirs->File[i]->FileName))
+		{
+			ok = true;
+			break;
+		}
+	}
+	FreeDir(dirs);
+
+	if (ok == false)
+	{
+		Print("EnumDir Failed.\n");
+		return false;
+	}
+	else
+	{
+		UINT size = 1234567;
+		UCHAR *buf;
+		IO *io;
+#ifndef	OS_WIN32
+		wchar_t *filename = L"/tmp/vpn_checker_tmp";
+#else	// OS_WIN32
+		wchar_t filename[MAX_PATH];
+		CombinePathW(filename, sizeof(filename), MsGetMyTempDirW(), L"vpn_checker_tmp");
+#endif	// OS_WIN32
+
+		buf = Malloc(size);
+		for (i = 0;i < size;i++)
+		{
+			buf[i] = i % 256;
+		}
+
+		io = FileCreateW(filename);
+		if (io == NULL)
+		{
+			Print("FileCreate Failed.\n");
+			Free(buf);
+			return false;
+		}
+		else
+		{
+			FileWrite(io, buf, size);
+			Free(buf);
+			FileClose(io);
+
+			io = FileOpenW(filename, false);
+			if (FileSize(io) != 1234567)
+			{
+				Print("FileSize Failed.\n");
+				FileClose(io);
+				return false;
+			}
+			else
+			{
+				BUF *b;
+
+				FileClose(io);
+				b = ReadDumpW(filename);
+
+				for (i = 0;i < b->Size;i++)
+				{
+					UCHAR c = ((UCHAR *)b->Buf)[i];
+
+					if (c != (i % 256))
+					{
+						Print("FileToBuf Failed.\n");
+						FreeBuf(b);
+						return false;
+					}
+				}
+
+				FreeBuf(b);
+			}
+		}
+
+		FileDeleteW(filename);
+	}
+
+	return ok;
+}
+
+// 文字列チェック
+bool CheckStrings()
+{
+	wchar_t *numstr = _UU("CHECK_TEST_123456789");
+	char tmp[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	UINT i;
+	UINT sum, sum2;
+	UNI_TOKEN_LIST *t;
+
+	UniStrCpy(tmp2, sizeof(tmp2), L"");
+
+	sum2 = 0;
+	for (i = 0;i < 64;i++)
+	{
+		sum2 += i;
+		UniFormat(tmp2, sizeof(tmp2), L"%s,%u", tmp2, i);
+	}
+
+	t = UniParseToken(tmp2, L",");
+
+	sum = 0;
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		wchar_t *s = t->Token[i];
+		UINT n = UniToInt(s);
+
+		sum += n;
+	}
+
+	UniFreeToken(t);
+
+	if (sum != sum2)
+	{
+		Print("UniParseToken Failed.\n");
+		return false;
+	}
+
+	if (UniToInt(numstr) != 123456789)
+	{
+		Print("UniToInt Failed.\n");
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), numstr);
+	if (ToInt(tmp) != 123456789)
+	{
+		Print("UniToStr Failed.\n");
+		return false;
+	}
+
+	StrToUni(tmp2, sizeof(tmp2), _SS("CHECK_TEST_TESTSTR"));
+	if (UniStrCmp(_UU("CHECK_TEST_TESTSTR"), tmp2) != 0)
+	{
+		Print("StrToUni Failed.\n");
+		printf("[%S] [%S]\n", tmp2, _UU("CHECK_TEST_TESTSTR"));
+		return false;
+	}
+
+	ReplaceStrEx(tmp, sizeof(tmp), _SS("CHECK_TEST_REPLACE1"), _SS("CHECK_TEST_REPLACE3"),
+		_SS("CHECK_TEST_REPLACE4"), false);
+
+	if (StrCmp(tmp, _SS("CHECK_TEST_REPLACE2")) != 0)
+	{
+		Print("ReplaceStrEx Failed.\n");
+		return false;
+	}
+
+	UniReplaceStrEx(tmp2, sizeof(tmp2), _UU("CHECK_TEST_REPLACE1"), _UU("CHECK_TEST_REPLACE3"),
+		_UU("CHECK_TEST_REPLACE4"), false);
+
+	if (UniStrCmp(tmp2, _UU("CHECK_TEST_REPLACE2")) != 0)
+	{
+		Print("UniReplaceStrEx Failed.\n");
+		return false;
+	}
+
+	return true;
+}
+
+// メモリチェック
+bool CheckMemory()
+{
+	UINT i, num, size, j;
+	void **pp;
+	bool ok = true;
+	UINT old_size;
+
+	num = 2000;
+	size = 1000;
+	pp = ZeroMalloc(sizeof(void *) * num);
+	for (i = 0;i < num;i++)
+	{
+		pp[i] = ZeroMalloc(size);
+		InputToNull(pp[i]);
+		for (j = 0;j < size;j++)
+		{
+			((UCHAR *)pp[i])[j] = j % 256;
+		}
+	}
+	old_size = size;
+	size = size * 3;
+	for (i = 0;i < num;i++)
+	{
+		pp[i] = ReAlloc(pp[i], size);
+		for (j = old_size;j < size;j++)
+		{
+			InputToNull((void *)(UINT)(((UCHAR *)pp[i])[j] = j % 256));
+		}
+	}
+	for (i = 0;i < num;i++)
+	{
+		for (j = 0;j < size;j++)
+		{
+			if (((UCHAR *)pp[i])[j] != (j % 256))
+			{
+				ok = false;
+			}
+		}
+		Free(pp[i]);
+	}
+	Free(pp);
+
+	return ok;
+}
+
+// 何もしない関数
+void InputToNull(void *p)
+{
+	// 意味不明！
+	if (RetZero() == 1)
+	{
+		UCHAR *c = (UCHAR *)p;
+		c[0] = 0x32;
+	}
+}
+
+// 0 を返す関数
+UINT RetZero()
+{
+	// 意味不明！
+	if (g_debug == 0x123455)
+	{
+		return 1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+
+// カーネルチェック
+bool CheckKernel()
+{
+	UINT num = 10, i;
+	UINT64 s = Tick64();
+	UINT64 t = Tick64();
+
+	for (i = 0;i < num;i++)
+	{
+		UINT64 q = Tick64();
+		if (t > q)
+		{
+			Print("Tick64 #1 Failed.\n");
+			return false;
+		}
+
+		t = q;
+
+		SleepThread(100);
+	}
+
+	t = (Tick64() - s);
+	if (t <= 500 || t >= 2000)
+	{
+		Print("Tick64 #2 Failed.\n");
+		return false;
+	}
+	else if (false)
+	{
+		UINT64 tick1 = Tick64();
+		UINT64 time1;
+		UINT64 tick2, time2;
+
+		SleepThread(1000);
+
+		tick2 = Tick64();
+		time2 = LocalTime64();
+		time1 = SystemToLocal64(TickToTime(tick1));
+
+		if (time2 > time1)
+		{
+			s = time2 - time1;
+		}
+		else
+		{
+			s = time1 - time2;
+		}
+
+		if (s <= 500 || s >= 2000)
+		{
+			Print("TickToTime Failed.\n");
+			return false;
+		}
+	}
+
+#ifdef	OS_UNIX
+	{
+		// 子プロセスのテスト
+		UINT pid;
+		char exe[MAX_SIZE];
+
+		GetExeName(exe, sizeof(exe));
+
+		pid = fork();
+
+		if (pid == -1)
+		{
+			Print("fork Failed.\n");
+			return false;
+		}
+
+		if (pid == 0)
+		{
+			char *param = UNIX_ARG_EXIT;
+			char **args;
+
+			args = ZeroMalloc(sizeof(char *) * 3);
+			args[0] = exe;
+			args[1] = param;
+			args[2] = NULL;
+
+			setsid();
+
+			// 標準入出力をクローズする
+			UnixCloseIO();
+
+			// 不要なシグナルを停止する
+			signal(SIGHUP, SIG_IGN);
+
+			execvp(exe, args);
+			AbortExit();
+		}
+		else
+		{
+			int status = 0, ret;
+
+			// 子プロセスの終了を待機する
+			ret = waitpid(pid, &status, 0);
+
+			if (WIFEXITED(status) == 0)
+			{
+				// 異常終了した
+				Print("waitpid Failed: 0x%x\n", ret);
+				return false;
+			}
+		}
+	}
+#endif	// OS_UNIX
+
+	return true;
+}
+
+// システムチェッカ
+bool SystemCheck()
+{
+	UINT i;
+	bool ng = false;
+
+	UniPrint(_UU("CHECK_TITLE"));
+	UniPrint(_UU("CHECK_NOTE"));
+	for (i = 0;i < sizeof(checker_procs) / sizeof(checker_procs[0]);i++)
+	{
+		wchar_t *title;
+		bool ret = false;
+		CHECKER_PROC *p = &checker_procs[i];
+
+		title = _UU(p->Title);
+
+		UniPrint(_UU("CHECK_EXEC_TAG"), title);
+
+		ret = p->Proc();
+
+		if (ret == false)
+		{
+			ng = true;
+		}
+
+		UniPrint(L"              %s\n", ret ? _UU("CHECK_PASS") : _UU("CHECK_FAIL"));
+	}
+
+	UniPrint(L"\n");
+	if (ng == false)
+	{
+		UniPrint(L"%s\n\n", _UU("CHECK_RESULT_1"));
+	}
+	else
+	{
+		UniPrint(L"%s\n\n", _UU("CHECK_RESULT_2"));
+	}
+
+	return true;
+}
+
+
+// 動作チェッカ
+UINT PtCheck(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	UINT ret = ERR_NO_ERROR;
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (SystemCheck() == false)
+	{
+		ret = ERR_INTERNAL_ERROR;
+	}
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN Tools メイン関数
+void PtMain(PT *pt)
+{
+	char prompt[MAX_SIZE];
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (pt == NULL)
+	{
+		return;
+	}
+
+	// 起動が完了したメッセージを表示する
+	UniFormat(tmp, sizeof(tmp), _UU("CMD_UTVPNCMD_TOOLS_CONNECTED"));
+	pt->Console->Write(pt->Console, tmp);
+	pt->Console->Write(pt->Console, L"");
+
+	while (true)
+	{
+		// コマンドの定義
+		CMD cmd[] =
+		{
+			{"About", PsAbout},
+			{"MakeCert", PtMakeCert},
+			{"TrafficClient", PtTrafficClient},
+			{"TrafficServer", PtTrafficServer},
+			{"Check", PtCheck},
+		};
+
+		// プロンプトの生成
+		StrCpy(prompt, sizeof(prompt), "VPN Tools>");
+
+		if (DispatchNextCmdEx(pt->Console, pt->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), pt) == false)
+		{
+			break;
+		}
+		pt->LastError = pt->Console->RetCode;
+
+		if (pt->LastError == ERR_NO_ERROR && pt->Console->ConsoleType != CONSOLE_CSV)
+		{
+			pt->Console->Write(pt->Console, _UU("CMD_MSG_OK"));
+			pt->Console->Write(pt->Console, L"");
+		}
+
+		if (pt->CmdLine != NULL)
+		{
+			break;
+		}
+	}
+}
+
+// VPN Tools コンテキストの作成
+PT *NewPt(CONSOLE *c, wchar_t *cmdline)
+{
+	PT *pt;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	if (UniIsEmptyStr(cmdline))
+	{
+		cmdline = NULL;
+	}
+
+	pt = ZeroMalloc(sizeof(PT));
+	pt->Console = c;
+	pt->CmdLine = CopyUniStr(cmdline);
+
+	return pt;
+}
+
+// VPN Tools コンテキストの解放
+void FreePt(PT *pt)
+{
+	// 引数チェック
+	if (pt == NULL)
+	{
+		return;
+	}
+
+	Free(pt->CmdLine);
+	Free(pt);
+}
+
+// VPN Tools 開始
+UINT PtConnect(CONSOLE *c, wchar_t *cmdline)
+{
+	PT *pt;
+	UINT ret = 0;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	pt = NewPt(c, cmdline);
+
+	PtMain(pt);
+
+	ret = pt->LastError;
+
+	FreePt(pt);
+
+	return ret;
+}
+
+// vpncmd コマンドの起動パス情報の初期化
+void VpnCmdInitBootPath()
+{
+#ifdef	OS_WIN32
+	char exe_path[MAX_PATH];
+	char tmp[MAX_PATH];
+	GetExeName(exe_path, sizeof(exe_path));
+
+	if (SearchStrEx(exe_path, "ham.exe", 0, false) != INFINITE || SearchStrEx(exe_path, "ham_x64.exe", 0, false) != INFINITE || SearchStrEx(exe_path, "ham_ia64.exe", 0, false) != INFINITE)
+	{
+		return;
+	}
+
+	if (MsIsAdmin())
+	{
+		UINT current_ver;
+
+		// 現在インストールされている vpncmd のバージョンの取得
+		current_ver = MsRegReadInt(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER);
+
+		if ((CEDAR_BUILD >= current_ver) ||
+			MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+		{
+			char *src_filename;
+			bool b = false;
+			// vpncmdsys.exe を system32 にコピーする
+			if (MsIsNt())
+			{
+				Format(tmp, sizeof(tmp), "%s\\utvpncmd.exe", MsGetSystem32Dir());
+			}
+			else
+			{
+				Format(tmp, sizeof(tmp), "%s\\utvpncmd.exe", MsGetWindowsDir());
+			}
+
+			src_filename = VPNCMD_BOOTSTRAP_FILENAME;
+
+			if (IsX64())
+			{
+				src_filename = VPNCMD_BOOTSTRAP_FILENAME_X64;
+			}
+
+			if (IsIA64())
+			{
+				src_filename = VPNCMD_BOOTSTRAP_FILENAME_IA64;
+			}
+
+			b = true;
+
+			if (MsIs64BitWindows() == false || Is64())
+			{
+				if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+				{
+					b = FileCopy(src_filename, tmp);
+				}
+			}
+			else
+			{
+				void *wow;
+
+				wow = MsDisableWow64FileSystemRedirection();
+
+				if (true)
+				{
+					if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+					{
+						b = FileCopy(src_filename, tmp);
+					}
+				}
+
+				MsRestoreWow64FileSystemRedirection(wow);
+
+				if (true)
+				{
+					if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+					{
+						b = FileCopy(src_filename, tmp);
+					}
+				}
+			}
+
+			// 現在実行しているプロンプトのほうがバージョンが新しいのでレジストリを上書きする
+			if (MsIs64BitWindows() == false)
+			{
+				MsRegWriteStr(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path);
+				MsRegWriteInt(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD);
+			}
+			else
+			{
+				MsRegWriteStrEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path, true, false);
+				MsRegWriteIntEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD, true, false);
+
+				MsRegWriteStrEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path, false, true);
+				MsRegWriteIntEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD, false, true);
+			}
+		}
+	}
+#endif	// OS_WIN32
+}
+
+// 文字列の表示
+void TtPrint(void *param, TT_PRINT_PROC *print_proc, wchar_t *str)
+{
+	// 引数チェック
+	if (print_proc == NULL || str == NULL)
+	{
+		return;
+	}
+
+	print_proc(param, str);
+}
+
+// 新しいランダムデータの生成
+void TtGenerateRandomData(UCHAR **buf, UINT *size)
+{
+	UCHAR *tmp;
+	UINT sz;
+	UINT i;
+	// 引数チェック
+	if (buf == NULL || size == NULL)
+	{
+		return;
+	}
+
+	sz = TRAFFIC_BUF_SIZE;
+	tmp = Malloc(sz);
+	for (i = 0;i < sz;i++)
+	{
+		tmp[i] = rand() % 256;
+
+		if (tmp[i] == '!')
+		{
+			tmp[i] = '_';
+		}
+	}
+
+	*buf = tmp;
+	*size = sz;
+}
+
+// 通信スループット測定サーバーワーカースレッド
+void TtsWorkerThread(THREAD *thread, void *param)
+{
+	TTS *tts;
+	UINT buf_size;
+	UCHAR *send_buf_data, *recv_buf_data;
+	bool all_sockets_blocked = false;
+	UINT64 tmp64;
+	LIST *o;
+	UINT i;
+	wchar_t tmp[MAX_SIZE];
+	bool dont_block_next_time = false;
+	char *ver_str = TRAFFIC_VER_STR;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// データ領域の確保
+	TtGenerateRandomData(&send_buf_data, &buf_size);
+	TtGenerateRandomData(&recv_buf_data, &buf_size);
+
+	tts = (TTS *)param;
+
+	// ソケットイベントの準備
+	tts->SockEvent = NewSockEvent();
+	AddRef(tts->SockEvent->ref);
+
+	// サーバーソケットリストの準備
+	tts->TtsSockList = NewList(NULL);
+
+	// 親スレッドに準備完了を伝える
+	NoticeThreadInit(thread);
+
+	o = NewList(NULL);
+
+	while (tts->Halt == false)
+	{
+		// すべてのソケットを待機する
+		if (dont_block_next_time == false)
+		{
+			WaitSockEvent(tts->SockEvent, 50);
+		}
+		dont_block_next_time = false;
+
+		// 現在登録されているソケットについて処理する
+		LockList(tts->TtsSockList);
+		{
+			UINT i;
+
+			all_sockets_blocked = false;
+
+			// すべてのソケットがブロック状態にならない限り
+			// データの送受信を続ける
+			while (all_sockets_blocked == false)
+			{
+				all_sockets_blocked = true;
+
+				for (i = 0;i < LIST_NUM(tts->TtsSockList);i++)
+				{
+					UINT ret = SOCK_LATER;
+					UCHAR *send_data = NULL, *recv_data = NULL;
+					UINT send_size = 0, recv_size = 0;
+					TTS_SOCK *ts = LIST_DATA(tts->TtsSockList, i);
+					bool blocked_for_this_socket = false;
+
+					if (ts->SockJoined == false)
+					{
+						JoinSockToSockEvent(ts->Sock, tts->SockEvent);
+						ts->SockJoined = true;
+					}
+
+					switch (ts->State)
+					{
+					case 0:
+						// バージョン文字列を返す
+						ret = Send(ts->Sock, ver_str, TRAFFIC_VER_STR_SIZE, false);
+						if (ret != 0 && ret != SOCK_LATER)
+						{
+							ts->State = 5;
+						}
+						break;
+
+					case 5:
+						// クライアントから方向を受信する
+						ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+						if (ret != 0 && ret != SOCK_LATER)
+						{
+							UCHAR c;
+
+							// 受信した 1 バイト目にデータの方向が入っている
+							c = recv_buf_data[0];
+
+							if (c == 0)
+							{
+								// 0 の場合はクライアント -> サーバー
+								ts->State = 1;
+							}
+							else
+							{
+								// それ以外の場合はサーバー -> クライアント
+								ts->State = 2;
+							}
+						}
+						break;
+
+					case 1:
+						// クライアント -> サーバー
+						ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+
+						if (ret != 0 && ret != SOCK_LATER)
+						{
+							// 受信した 1 バイト目を検査する
+							UCHAR c = recv_buf_data[0];
+
+							if (c == '!')
+							{
+								// サーバーからクライアントにサイズ情報を通知
+								ts->State = 3;
+								Debug("!");
+							}
+						}
+						break;
+
+					case 2:
+						// サーバー -> クライアント
+						ret = Send(ts->Sock, send_buf_data, buf_size, false);
+						break;
+
+					case 3:
+						// サーバー -> クライアントにサイズ情報を通知する
+						tmp64 = Endian64(ts->NumBytes);
+
+						Recv(ts->Sock, recv_buf_data, buf_size, false);
+
+						if (ts->LastWaitTick == 0 || ts->LastWaitTick <= Tick64())
+						{
+							ret = Send(ts->Sock, &tmp64, sizeof(tmp64), false);
+
+							if (ret != SOCK_LATER)
+							{
+								ts->LastWaitTick = Tick64() + 100;
+							}
+						}
+						break;
+					}
+
+					if (ret == 0)
+					{
+						// 切断されたのでこのソケットを削除としてマークする
+						Insert(o, ts);
+					}
+					else if (ret == SOCK_LATER)
+					{
+						// 遅延が発生した
+						blocked_for_this_socket = true;
+						dont_block_next_time = false;
+					}
+					else
+					{
+						if (ts->State == 1)
+						{
+							ts->NumBytes += (UINT64)ret;
+						}
+					}
+
+					if (blocked_for_this_socket == false)
+					{
+						all_sockets_blocked = false;
+					}
+				}
+
+				if (LIST_NUM(o) != 0)
+				{
+					UINT i;
+					// 1 つ以上のソケットが切断された
+					for (i = 0;i < LIST_NUM(o);i++)
+					{
+						TTS_SOCK *ts = LIST_DATA(o, i);
+
+						UniFormat(tmp, sizeof(tmp), _UU("TTS_DISCONNECTED"), ts->Id, ts->Sock->RemoteHostname);
+						TtPrint(tts->Param, tts->Print, tmp);
+
+						Disconnect(ts->Sock);
+						ReleaseSock(ts->Sock);
+
+						Delete(tts->TtsSockList, ts);
+
+						Free(ts);
+					}
+
+					DeleteAll(o);
+				}
+
+				if (tts->NewSocketArrived || tts->Halt)
+				{
+					tts->NewSocketArrived = false;
+					all_sockets_blocked = true;
+					dont_block_next_time = true;
+				}
+			}
+		}
+		UnlockList(tts->TtsSockList);
+	}
+
+	LockList(tts->TtsSockList);
+	{
+		// 残留しているすべてのソケットを解放する
+		for (i = 0;i < LIST_NUM(tts->TtsSockList);i++)
+		{
+			TTS_SOCK *ts = LIST_DATA(tts->TtsSockList, i);
+
+			UniFormat(tmp, sizeof(tmp), _UU("TTS_DISCONNECT"), ts->Id, ts->Sock->RemoteHostname);
+			TtPrint(tts->Param, tts->Print, tmp);
+
+			Disconnect(ts->Sock);
+			ReleaseSock(ts->Sock);
+
+			Free(ts);
+		}
+	}
+	UnlockList(tts->TtsSockList);
+
+	// クリーンアップ
+	ReleaseList(o);
+	ReleaseList(tts->TtsSockList);
+	ReleaseSockEvent(tts->SockEvent);
+	Free(send_buf_data);
+	Free(recv_buf_data);
+}
+
+// IPv6 用 Accept スレッド
+void TtsIPv6AcceptThread(THREAD *thread, void *param)
+{
+	TTS *tts = (TTS *)param;
+	// 引数チェック
+	if (tts == NULL || param == NULL)
+	{
+		return;
+	}
+
+	TtsAcceptProc(tts, tts->ListenSocketV6);
+}
+
+// Accept プロシージャ
+void TtsAcceptProc(TTS *tts, SOCK *listen_socket)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (tts == NULL || listen_socket == NULL)
+	{
+		return;
+	}
+
+	while (tts->Halt == false)
+	{
+		SOCK *s;
+		// Accept する
+		s = Accept(listen_socket);
+
+		if (s == NULL)
+		{
+			if (tts->Halt == false)
+			{
+				SleepThread(10);
+			}
+			continue;
+		}
+		else
+		{
+			// クライアントから接続された
+			AcceptInit(s);
+			tts->NewSocketArrived = true;
+			LockList(tts->TtsSockList);
+			{
+				TTS_SOCK *ts = ZeroMalloc(sizeof(TTS_SOCK));
+
+				ts->Id = (++tts->IdSeed);
+				ts->Sock = s;
+
+				UniFormat(tmp, sizeof(tmp), _UU("TTS_ACCEPTED"), ts->Id,
+					s->RemoteHostname, s->RemotePort);
+				TtPrint(tts->Param, tts->Print, tmp);
+
+				Insert(tts->TtsSockList, ts);
+				tts->NewSocketArrived = true;
+			}
+			UnlockList(tts->TtsSockList);
+		}
+	}
+}
+
+// 通信スループット測定サーバー待機スレッド
+void TtsListenThread(THREAD *thread, void *param)
+{
+	TTS *tts;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	tts = (TTS *)param;
+
+	tts->ListenSocket = NULL;
+	tts->ListenSocket = Listen(tts->Port);
+	tts->ListenSocketV6 = Listen6(tts->Port);
+
+	if (tts->ListenSocket == NULL && tts->ListenSocketV6 == NULL)
+	{
+		// Listen に失敗した
+		UniFormat(tmp, sizeof(tmp), _UU("TT_LISTEN_FAILED"), tts->Port);
+		TtPrint(tts->Param, tts->Print, tmp);
+
+		// 親スレッドに準備完了を伝える
+		NoticeThreadInit(thread);
+
+		tts->ErrorCode = ERR_INTERNAL_ERROR;
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_STARTED"), tts->Port);
+		TtPrint(tts->Param, tts->Print, tmp);
+
+		if (tts->ListenSocketV6 != NULL)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_STARTED_V6"), tts->Port);
+			TtPrint(tts->Param, tts->Print, tmp);
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_FAILED_V6"), tts->Port);
+			TtPrint(tts->Param, tts->Print, tmp);
+		}
+
+		if (tts->ListenSocket != NULL)
+		{
+			AddRef(tts->ListenSocket->ref);
+		}
+		if (tts->ListenSocketV6 != NULL)
+		{
+			AddRef(tts->ListenSocketV6->ref);
+		}
+
+		// ワーカースレッドを開始する
+		tts->WorkThread = NewThread(TtsWorkerThread, tts);
+		WaitThreadInit(tts->WorkThread);
+
+		// 親スレッドに準備完了を伝える
+		NoticeThreadInit(thread);
+
+		// IPv6 用 Accept スレッドを準備
+		tts->IPv6AcceptThread = NULL;
+		if (tts->ListenSocketV6 != NULL)
+		{
+			tts->IPv6AcceptThread = NewThread(TtsIPv6AcceptThread, tts);
+		}
+
+		TtsAcceptProc(tts, tts->ListenSocket);
+
+		if (tts->IPv6AcceptThread != NULL)
+		{
+			WaitThread(tts->IPv6AcceptThread, INFINITE);
+			ReleaseThread(tts->IPv6AcceptThread);
+		}
+
+		TtPrint(tts->Param, tts->Print, _UU("TTS_LISTEN_STOP"));
+
+		ReleaseSock(tts->ListenSocket);
+		ReleaseSock(tts->ListenSocketV6);
+		SetSockEvent(tts->SockEvent);
+
+		// ワーカースレッドの停止を待機する
+		WaitThread(tts->WorkThread, INFINITE);
+		ReleaseThread(tts->WorkThread);
+		ReleaseSockEvent(tts->SockEvent);
+	}
+}
+
+// データが流れる方向の文字列
+wchar_t *GetTtcTypeStr(UINT type)
+{
+	switch (type)
+	{
+	case TRAFFIC_TYPE_DOWNLOAD:
+		return _UU("TTC_TYPE_DOWNLOAD");
+
+	case TRAFFIC_TYPE_UPLOAD:
+		return _UU("TTC_TYPE_UPLOAD");
+
+	default:
+		return _UU("TTC_TYPE_FULL");
+	}
+}
+
+// サマリーの表示
+void TtcPrintSummary(TTC *ttc)
+{
+	wchar_t tmp[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	wchar_t *tag = L"%-35s %s";
+	// 引数チェック
+	if (ttc == NULL)
+	{
+		return;
+	}
+
+	TtPrint(ttc->Param, ttc->Print, L"");
+	TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_BAR"));
+	TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_TITLE"));
+	TtPrint(ttc->Param, ttc->Print, L"");
+
+	// 接続先のホスト名
+	StrToUni(tmp2, sizeof(tmp2), ttc->Host);
+	UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_HOST"), tmp2);
+	TtPrint(ttc->Param, ttc->Print, tmp);
+
+	// 接続先の TCP ポート番号
+	UniToStru(tmp2, ttc->Port);
+	UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_PORT"), tmp2);
+	TtPrint(ttc->Param, ttc->Print, tmp);
+
+	// 確立する TCP コネクション数
+	UniToStru(tmp2, ttc->NumTcp);
+	UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_NUMTCP"), tmp2);
+	TtPrint(ttc->Param, ttc->Print, tmp);
+
+	// データ伝送方向
+	UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_TYPE"), GetTtcTypeStr(ttc->Type));
+	TtPrint(ttc->Param, ttc->Print, tmp);
+
+	// データ伝送時間
+	UniFormat(tmp2, sizeof(tmp2), _UU("TTC_SPAN_STR"), (double)(ttc->Span) / 1000.0);
+	UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_SPAN"), tmp2);
+	TtPrint(ttc->Param, ttc->Print, tmp);
+
+	// Ethernet フレーム用にデータ補正
+	UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_ETHER"), ttc->Raw ? _UU("SEC_NO") : _UU("SEC_YES"));
+	TtPrint(ttc->Param, ttc->Print, tmp);
+
+	// 中継機器の入出力合計スループット計測
+	UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_DOUBLE"), ttc->Double ? _UU("SEC_YES") : _UU("SEC_NO"));
+	TtPrint(ttc->Param, ttc->Print, tmp);
+
+	TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_BAR"));
+	TtPrint(ttc->Param, ttc->Print, L"");
+}
+
+// 通信スループット測定クライアントの停止
+void StopTtc(TTC *ttc)
+{
+	// 引数チェック
+	if (ttc == NULL)
+	{
+		return;
+	}
+
+	TtPrint(ttc->Param, ttc->Print, _UU("TTC_STOPPING"));
+
+	ttc->Halt = true;
+	SetSockEvent(ttc->SockEvent);
+}
+
+// 結果を生成
+void TtcGenerateResult(TTC *ttc)
+{
+	TT_RESULT *res;
+	UINT i;
+	// 引数チェック
+	if (ttc == NULL)
+	{
+		return;
+	}
+
+	res = &ttc->Result;
+
+	Zero(res, sizeof(TT_RESULT));
+
+	res->Raw = ttc->Raw;
+	res->Double = ttc->Double;
+	res->Span = ttc->RealSpan;
+
+	for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+	{
+		TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+		if (ts->Download == false)
+		{
+			// アップロード
+			res->NumBytesUpload += ts->NumBytes;
+		}
+		else
+		{
+			// ダウンロード
+			res->NumBytesDownload += ts->NumBytes;
+		}
+	}
+
+	if (res->Raw == false)
+	{
+		// Ethernet に合わせて補正する
+		// (1 個の Ethernet フレーム中の最大の TCP ペイロードサイズは 1460 である。)
+		res->NumBytesDownload = (UINT64)((double)res->NumBytesDownload * 1514.0 / 1460.0);
+		res->NumBytesUpload = (UINT64)((double)res->NumBytesUpload * 1514.0 / 1460.0);
+	}
+
+	res->NumBytesTotal = res->NumBytesDownload + res->NumBytesUpload;
+
+	// スループットを計測する
+	if (res->Span != 0)
+	{
+		res->BpsUpload = (UINT64)((double)res->NumBytesUpload * 8.0 / ((double)res->Span / 1000.0));
+		res->BpsDownload = (UINT64)((double)res->NumBytesDownload * 8.0 / ((double)res->Span / 1000.0));
+	}
+
+	if (res->Double)
+	{
+		res->BpsUpload *= 2ULL;
+		res->BpsDownload *= 2ULL;
+	}
+
+	res->BpsTotal = res->BpsUpload + res->BpsDownload;
+}
+
+// クライアントスレッド
+void TtcThread(THREAD *thread, void *param)
+{
+	TTC *ttc;
+	UINT i;
+	wchar_t tmp[MAX_SIZE];
+	bool ok = false;
+	UINT buf_size;
+	UCHAR *send_buf_data, *recv_buf_data;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// データ領域の確保
+	TtGenerateRandomData(&send_buf_data, &buf_size);
+	TtGenerateRandomData(&recv_buf_data, &buf_size);
+
+	ttc = (TTC *)param;
+
+	ttc->SockEvent = NewSockEvent();
+	AddRef(ttc->SockEvent->ref);
+
+	// 準備完了
+	NoticeThreadInit(thread);
+
+	TtcPrintSummary(ttc);
+
+	UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_START"),
+		ttc->Host, ttc->Port, ttc->NumTcp);
+	TtPrint(ttc->Param, ttc->Print, tmp);
+
+	// クライアントへのすべてのコネクションを確立する
+	ttc->ItcSockList = NewList(NULL);
+
+	ok = true;
+
+	for (i = 0;i < ttc->NumTcp;i++)
+	{
+		SOCK *s;
+		TTC_SOCK *ts = ZeroMalloc(sizeof(TTC_SOCK));
+
+		ts->Id = i + 1;
+
+		if (ttc->Type == TRAFFIC_TYPE_DOWNLOAD)
+		{
+			ts->Download = true;
+		}
+		else if (ttc->Type == TRAFFIC_TYPE_UPLOAD)
+		{
+			ts->Download = false;
+		}
+		else
+		{
+			ts->Download = ((i % 2) == 0) ? true : false;
+		}
+
+		s = Connect(ttc->Host, ttc->Port);
+
+		if (s == NULL)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_FAILED"), i + 1);
+			TtPrint(ttc->Param, ttc->Print, tmp);
+			ok = false;
+			Free(ts);
+			break;
+		}
+		else
+		{
+			char buffer[TRAFFIC_VER_STR_SIZE];
+
+			SetTimeout(s, 5000);
+
+			Zero(buffer, sizeof(buffer));
+			if (Recv(s, buffer, sizeof(buffer), false) != sizeof(buffer) || Cmp(buffer, TRAFFIC_VER_STR, TRAFFIC_VER_STR_SIZE) != 0)
+			{
+				TtPrint(ttc->Param, ttc->Print, _UU("TTC_CONNECT_NOT_SERVER"));
+				ok = false;
+				ReleaseSock(s);
+				Free(ts);
+				break;
+			}
+
+			UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_OK"), i + 1);
+			TtPrint(ttc->Param, ttc->Print, tmp);
+
+			UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_OK_2"), GetTtcTypeStr(ts->Download ? TRAFFIC_TYPE_DOWNLOAD : TRAFFIC_TYPE_UPLOAD));
+			TtPrint(ttc->Param, ttc->Print, tmp);
+
+			ts->Sock = s;
+
+			SetTimeout(s, TIMEOUT_INFINITE);
+
+			JoinSockToSockEvent(s, ttc->SockEvent);
+		}
+
+		Insert(ttc->ItcSockList, ts);
+	}
+
+	Set(ttc->InitedEvent);
+
+	if (ttc->StartEvent != NULL)
+	{
+		Wait(ttc->StartEvent, INFINITE);
+		SleepThread(500);
+	}
+
+	if (ok)
+	{
+		bool all_sockets_blocked;
+		bool dont_block_next_time = false;
+		bool halt_flag = false;
+		UINT64 start_tick, end_tick;
+		UINT64 halt_timeout = 0;
+		wchar_t tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+		UINT check_clock_seed = 0;
+		bool halting = false;
+		UINT64 tmp64;
+
+		// 現在時刻を記録
+		start_tick = Tick64();
+		end_tick = start_tick + ttc->Span;
+
+		// 開始メッセージを表示
+		GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(TickToTime(start_tick)), NULL);
+		GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(TickToTime(end_tick)), NULL);
+		UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_START"), tmp1, tmp2);
+		TtPrint(ttc->Param, ttc->Print, tmp);
+
+		// メインループ
+		while (true)
+		{
+			UINT i;
+
+			if (dont_block_next_time == false)
+			{
+				WaitSockEvent(ttc->SockEvent, 50);
+			}
+
+			dont_block_next_time = false;
+
+			if (ttc->AbnormalTerminated)
+			{
+				// 異常終了が発生した
+				break;
+			}
+
+			if (ttc->Halt || end_tick <= Tick64())
+			{
+				// 計測終了
+				if (halting == false)
+				{
+					if (ttc->Halt)
+					{
+						// ユーザーキャンセル
+						TtPrint(ttc->Param, ttc->Print, _UU("TTC_COMM_USER_CANCEL"));
+					}
+					else
+					{
+						// 時間経過
+						UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_END"),
+							(double)ttc->Span / 1000.0);
+						TtPrint(ttc->Param, ttc->Print, tmp);
+					}
+
+					ttc->RealSpan = Tick64() - start_tick;
+
+					halting = true;
+
+					// サーバーからの報告データを待つ
+					halt_timeout = Tick64() + 60000ULL;
+				}
+			}
+
+			if (halt_timeout != 0)
+			{
+				bool ok = true;
+
+				// すべての TCP コネクションが処理を完了するまで待機する
+				for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+				{
+					TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+					if (ts->Download == false)
+					{
+						if (ts->ServerUploadReportReceived == false)
+						{
+							ok = false;
+						}
+					}
+				}
+
+				if (ok)
+				{
+					// 測定完了
+					// 結果を表示する
+					TtcGenerateResult(ttc);
+					break;
+				}
+				else
+				{
+					if (halt_timeout <= Tick64())
+					{
+						// 異常発生
+						ttc->AbnormalTerminated = true;
+						ttc->ErrorCode = ERR_PROTOCOL_ERROR;
+						break;
+					}
+				}
+			}
+
+			all_sockets_blocked = false;
+
+			// すべてのソケットがブロック状態にならない限り
+			// データの送受信を続ける
+			while (all_sockets_blocked == false)
+			{
+				all_sockets_blocked = true;
+
+				for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+				{
+					UINT ret = SOCK_LATER;
+					TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+					bool blocked_for_this_socket = false;
+					UCHAR c = 0;
+
+					if (halt_timeout != 0)
+					{
+						if (ts->State != 3 && ts->State != 4)
+						{
+							if (ts->Download == false)
+							{
+								if (ts->State != 0)
+								{
+									ts->State = 3;
+								}
+								else
+								{
+									ts->ServerUploadReportReceived = true;
+									ts->State = 4;
+								}
+							}
+							else
+							{
+								ts->State = 4;
+							}
+						}
+					}
+
+					switch (ts->State)
+					{
+					case 0:
+						// 初期状態: クライアント／サーバー間のデータの流れの
+						// 方向を指定する
+						if (ts->Download)
+						{
+							c = 1;
+						}
+						else
+						{
+							c = 0;
+						}
+
+						ret = Send(ts->Sock, &c, 1, false);
+
+						if (ret != 0 && ret != SOCK_LATER)
+						{
+							if (ts->Download)
+							{
+								ts->State = 1;
+							}
+							else
+							{
+								ts->State = 2;
+							}
+						}
+						break;
+
+					case 1:
+						// サーバー -> クライアント (ダウンロード)
+						ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+						break;
+
+					case 2:
+						// クライアント -> サーバー (アップロード)
+						ret = Send(ts->Sock, send_buf_data, buf_size, false);
+						break;
+
+					case 3:
+						// クライアント -> サーバー (アップロード) の送信完了
+						// データサイズの要求処理
+						if (ts->NextSendRequestReportTick == 0 ||
+							(Tick64() >= ts->NextSendRequestReportTick))
+						{
+							UCHAR suprise[MAX_SIZE];
+							UINT i;
+
+							ts->NextSendRequestReportTick = Tick64() + 200ULL;
+
+							for (i = 0;i < sizeof(suprise);i++)
+							{
+								suprise[i] = '!';
+							}
+
+							ret = Send(ts->Sock, suprise, sizeof(suprise), false);
+						}
+
+						ret = Recv(ts->Sock, &tmp64, sizeof(tmp64), false);
+						if (ret != 0 && ret != SOCK_LATER && ret == sizeof(tmp64))
+						{
+							ts->NumBytes = Endian64(tmp64);
+
+							ts->ServerUploadReportReceived = true;
+
+							ts->State = 4;
+						}
+						break;
+
+					case 4:
+						// 何もしない
+						if (Recv(ts->Sock, recv_buf_data, buf_size, false) == SOCK_LATER)
+						{
+							ret = SOCK_LATER;
+						}
+						break;
+					}
+
+					if (ret == 0)
+					{
+						// ソケットが切断された
+						ttc->AbnormalTerminated = true;
+						ttc->ErrorCode = ERR_PROTOCOL_ERROR;
+						blocked_for_this_socket = true;
+						dont_block_next_time = false;
+
+						UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_DISCONNECTED"), ts->Id);
+						TtPrint(ttc->Param, ttc->Print, tmp);
+					}
+					else if (ret == SOCK_LATER)
+					{
+						// 遅延が発生した
+						blocked_for_this_socket = true;
+						dont_block_next_time = false;
+					}
+					else
+					{
+						if (ts->Download)
+						{
+							ts->NumBytes += (UINT64)ret;
+						}
+					}
+
+					if (blocked_for_this_socket == false)
+					{
+						all_sockets_blocked = false;
+					}
+				}
+
+				if (ttc->Halt)
+				{
+					all_sockets_blocked = true;
+					dont_block_next_time = true;
+				}
+
+				if (end_tick <= Tick64())
+				{
+					all_sockets_blocked = true;
+					dont_block_next_time = true;
+				}
+			}
+		}
+	}
+	else
+	{
+		// 中止
+		TtPrint(ttc->Param, ttc->Print, _UU("TTC_ERROR_ABORTED"));
+		ttc->ErrorCode = ERR_CONNECT_FAILED;
+	}
+
+	// クリーンアップ
+	for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+	{
+		TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+		Disconnect(ts->Sock);
+		ReleaseSock(ts->Sock);
+		Free(ts);
+	}
+
+	ReleaseSockEvent(ttc->SockEvent);
+	ReleaseList(ttc->ItcSockList);
+	Free(send_buf_data);
+	Free(recv_buf_data);
+}
+
+// 通信スループット測定クライアントの開始
+TTC *NewTtc(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param)
+{
+	return NewTtcEx(host, port, numtcp, type, span, dbl, raw, print_proc, param, NULL);
+}
+TTC *NewTtcEx(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param, EVENT *start_event)
+{
+	TTC *ttc;
+
+	ttc = ZeroMalloc(sizeof(TTC));
+	ttc->InitedEvent = NewEvent();
+	ttc->Port = port;
+	StrCpy(ttc->Host, sizeof(ttc->Host), host);
+	ttc->NumTcp = numtcp;
+	ttc->Type = type;
+	ttc->Span = span;
+	ttc->Double = dbl;
+	ttc->Raw = raw;
+	ttc->StartEvent = start_event;
+
+	if (ttc->Type == TRAFFIC_TYPE_FULL && ttc->NumTcp < 2)
+	{
+		ttc->NumTcp = 2;
+	}
+
+	ttc->Print = print_proc;
+	ttc->Param = param;
+	ttc->ErrorCode = ERR_NO_ERROR;
+
+	TtPrint(ttc->Param, ttc->Print, _UU("TTC_INIT"));
+
+	ttc->Thread = NewThread(TtcThread, ttc);
+	WaitThreadInit(ttc->Thread);
+
+	return ttc;
+}
+
+// 通信スループット測定クライアントの終了を待機
+UINT FreeTtc(TTC *ttc, TT_RESULT *result)
+{
+	UINT ret;
+	// 引数チェック
+	if (ttc == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	WaitThread(ttc->Thread, INFINITE);
+	ReleaseThread(ttc->Thread);
+
+	TtPrint(ttc->Param, ttc->Print, _UU("TTC_FREE"));
+
+	ret = ttc->ErrorCode;
+
+	if (ret == ERR_NO_ERROR)
+	{
+		if (result != NULL)
+		{
+			Copy(result, &ttc->Result, sizeof(TT_RESULT));
+		}
+	}
+
+	ReleaseSockEvent(ttc->SockEvent);
+	ReleaseEvent(ttc->InitedEvent);
+
+	Free(ttc);
+
+	return ret;
+}
+
+// 通信スループット測定サーバーの開始
+TTS *NewTts(UINT port, void *param, TT_PRINT_PROC *print_proc)
+{
+	TTS *tts;
+	THREAD *t;
+
+	tts = ZeroMalloc(sizeof(TTS));
+	tts->Port = port;
+	tts->Param = param;
+	tts->Print = print_proc;
+
+	TtPrint(param, print_proc, _UU("TTS_INIT"));
+
+	// スレッドの作成
+	t = NewThread(TtsListenThread, tts);
+	WaitThreadInit(t);
+
+	tts->Thread = t;
+
+	return tts;
+}
+
+// 通信スループット測定サーバーの終了を待機
+UINT FreeTts(TTS *tts)
+{
+	UINT ret;
+	// 引数チェック
+	if (tts == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	TtPrint(tts->Param, tts->Print, _UU("TTS_STOP_INIT"));
+
+	tts->Halt = true;
+	Disconnect(tts->ListenSocket);
+	ReleaseSock(tts->ListenSocket);
+	Disconnect(tts->ListenSocketV6);
+	ReleaseSock(tts->ListenSocketV6);
+
+	// スレッドの終了を待機
+	WaitThread(tts->Thread, INFINITE);
+
+	ReleaseThread(tts->Thread);
+
+	TtPrint(tts->Param, tts->Print, _UU("TTS_STOP_FINISHED"));
+
+	ret = tts->ErrorCode;
+
+	Free(tts);
+
+	return ret;
+}
+
+// 測定ツールプロンプトの表示
+void PtTrafficPrintProc(void *param, wchar_t *str)
+{
+	CONSOLE *c;
+	// 引数チェック
+	if (param == NULL || str == NULL)
+	{
+		return;
+	}
+
+	c = (CONSOLE *)param;
+
+	if (c->ConsoleType == CONSOLE_LOCAL)
+	{
+		wchar_t tmp[MAX_SIZE];
+
+		// ローカルコンソールの場合のみ表示する (それ以外の場合はマルチスレッドの同期
+		//  がとれないので表示できない？)
+		UniStrCpy(tmp, sizeof(tmp), str);
+		if (UniEndWith(str, L"\n") == false)
+		{
+			UniStrCat(tmp, sizeof(tmp), L"\n");
+		}
+		UniPrint(L"%s", tmp);
+	}
+}
+
+// 通信スループット結果の表示
+void TtcPrintResult(CONSOLE *c, TT_RESULT *res)
+{
+	CT *ct;
+	wchar_t tmp[MAX_SIZE];
+	wchar_t tmp1[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (c == NULL || res == NULL)
+	{
+		return;
+	}
+
+	c->Write(c, _UU("TTC_RES_TITLE"));
+
+	ct = CtNew();
+	CtInsertColumn(ct, _UU("TTC_RES_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("TTC_RES_COLUMN_2"), true);
+	CtInsertColumn(ct, _UU("TTC_RES_COLUMN_3"), true);
+
+	// 測定に使用した時間
+	GetSpanStrMilli(str, sizeof(str), res->Span);
+	StrToUni(tmp, sizeof(tmp), str);
+	CtInsert(ct, _UU("TTC_RES_SPAN"), tmp, L"");
+
+	// Ethernet フレーム用にデータ補正
+	CtInsert(ct, _UU("TTC_RES_ETHER"), res->Raw ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+	// ダウンロード方向の通信データ量
+	ToStr3(str, sizeof(str), res->NumBytesDownload);
+	UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+	ToStrByte1000(str, sizeof(str), res->NumBytesDownload);
+	StrToUni(tmp2, sizeof(tmp2), str);
+	CtInsert(ct, _UU("TTC_RES_BYTES_DOWNLOAD"), tmp1, tmp2);
+
+	// アップロード方向の通信データ量
+	ToStr3(str, sizeof(str), res->NumBytesUpload);
+	UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+	ToStrByte1000(str, sizeof(str), res->NumBytesUpload);
+	StrToUni(tmp2, sizeof(tmp2), str);
+	CtInsert(ct, _UU("TTC_RES_BYTES_UPLOAD"), tmp1, tmp2);
+
+	// 合計通信データ量
+	ToStr3(str, sizeof(str), res->NumBytesTotal);
+	UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+	ToStrByte1000(str, sizeof(str), res->NumBytesTotal);
+	StrToUni(tmp2, sizeof(tmp2), str);
+	CtInsert(ct, _UU("TTC_RES_BYTES_TOTAL"), tmp1, tmp2);
+
+	// 中継機器入出力合計スループット算出
+	CtInsert(ct, _UU("TTC_RES_DOUBLE"), (res->Double == false) ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+	// ダウンロード方向の平均スループット
+	ToStr3(str, sizeof(str), res->BpsDownload);
+	UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+	ToStrByte1000(str, sizeof(str), res->BpsDownload);
+	ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+	StrToUni(tmp2, sizeof(tmp2), str);
+	CtInsert(ct, _UU("TTC_RES_BPS_DOWNLOAD"), tmp1, tmp2);
+
+	// アップロード方向の平均スループット
+	ToStr3(str, sizeof(str), res->BpsUpload);
+	UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+	ToStrByte1000(str, sizeof(str), res->BpsUpload);
+	ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+	StrToUni(tmp2, sizeof(tmp2), str);
+	CtInsert(ct, _UU("TTC_RES_BPS_UPLOAD"), tmp1, tmp2);
+
+	// 合計平均スループット
+	ToStr3(str, sizeof(str), res->BpsTotal);
+	UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+	ToStrByte1000(str, sizeof(str), res->BpsTotal);
+	ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+	StrToUni(tmp2, sizeof(tmp2), str);
+	CtInsert(ct, _UU("TTC_RES_BPS_TOTAL"), tmp1, tmp2);
+
+	CtFree(ct, c);
+}
+
+// 通信スループット測定ツールサーバーの実行
+UINT PtTrafficServer(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	UINT ret = ERR_NO_ERROR;
+	UINT port;
+	TTS *tts;
+	PARAM args[] =
+	{
+		{"[port]", NULL, NULL, NULL, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	port = GetParamInt(o, "[port]");
+	if (port == 0)
+	{
+		port = TRAFFIC_DEFAULT_PORT;
+	}
+
+	tts = NewTts(port, c, PtTrafficPrintProc);
+
+	c->Write(c, _UU("TTS_ENTER_TO_EXIT"));
+
+	Free(c->ReadLine(c, L"", true));
+
+	ret = tts->ErrorCode;
+
+	FreeTts(tts);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 通信スループット測定ツールクライアントの実行
+UINT PtTrafficClient(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	TTC *ttc;
+	LIST *o;
+	UINT ret = ERR_NO_ERROR;
+	char *host = NULL;
+	UINT port;
+	UINT num, type;
+	bool dbl = false, raw = false;
+	UINT64 span;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX minmax =
+	{
+		"CMD_TrafficClient_EVAL_NUMTCP",
+		0, TRAFFIC_NUMTCP_MAX,
+	};
+	PARAM args[] =
+	{
+		{"[host:port]", CmdPrompt, _UU("CMD_TrafficClient_PROMPT_HOST"), CmdEvalNotEmpty, NULL},
+		{"NUMTCP", NULL, NULL, CmdEvalMinMax, &minmax},
+		{"TYPE", NULL, NULL, NULL, NULL},
+		{"SPAN", NULL, NULL, NULL, NULL},
+		{"DOUBLE", NULL, NULL, NULL, NULL},
+		{"RAW", NULL, NULL, NULL, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (ParseHostPort(GetParamStr(o, "[host:port]"), &host, &port, TRAFFIC_DEFAULT_PORT) == false)
+	{
+		c->Write(c, _UU("CMD_TrafficClient_ERROR_HOSTPORT"));
+		ret = ERR_INVALID_PARAMETER;
+	}
+	else
+	{
+		char *s;
+		UINT i;
+
+		Trim(host);
+
+		num = GetParamInt(o, "NUMTCP");
+		if (num == 0)
+		{
+			num = TRAFFIC_NUMTCP_DEFAULT;
+		}
+		s = GetParamStr(o, "TYPE");
+
+		if (StartWith("download", s))
+		{
+			type = TRAFFIC_TYPE_DOWNLOAD;
+		}
+		else if (StartWith("upload", s))
+		{
+			type = TRAFFIC_TYPE_UPLOAD;
+		}
+		else
+		{
+			type = TRAFFIC_TYPE_FULL;
+		}
+
+		i = GetParamInt(o, "SPAN");
+
+		if (i == 0)
+		{
+			i = TRAFFIC_SPAN_DEFAULT;
+		}
+
+		span = (UINT64)i * 1000ULL;
+
+		dbl = GetParamYes(o, "DOUBLE");
+		raw = GetParamYes(o, "RAW");
+
+		if (type == TRAFFIC_TYPE_FULL)
+		{
+			if ((num % 2) != 0)
+			{
+				ret = ERR_INVALID_PARAMETER;
+				c->Write(c, _UU("CMD_TrafficClient_ERROR_NUMTCP"));
+			}
+		}
+
+		if (ret == ERR_NO_ERROR)
+		{
+			TT_RESULT result;
+			ttc = NewTtc(host, port, num, type, span, dbl, raw, PtTrafficPrintProc, c);
+
+			if (c->ConsoleType == CONSOLE_LOCAL)
+			{
+				if (c->Param != NULL && (((LOCAL_CONSOLE_PARAM *)c->Param)->InBuf == NULL))
+				{
+//					c->Write(c, _UU("TTC_ENTER_TO_EXIT"));
+//					GetLine(NULL, 0);
+//					StopTtc(ttc);
+				}
+			}
+
+
+			Zero(&result, sizeof(result));
+			ret = FreeTtc(ttc, &result);
+
+			if (ret == ERR_NO_ERROR)
+			{
+				TtcPrintResult(c, &result);
+			}
+		}
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	Free(host);
+
+	return ret;
+}
+
+// 証明書簡易作成ツール
+UINT PtMakeCert(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	UINT ret = ERR_NO_ERROR;
+	X *x = NULL;
+	K *pub = NULL;
+	K *pri = NULL;
+	NAME *n;
+	X_SERIAL *x_serial = NULL;
+	BUF *buf;
+	UINT days;
+	X *root_x = NULL;
+	K *root_k = NULL;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX minmax =
+	{
+		"CMD_MakeCert_EVAL_EXPIRES",
+		0,
+		10950,
+	};
+	PARAM args[] =
+	{
+		{"CN", CmdPrompt, _UU("CMD_MakeCert_PROMPT_CN"), NULL, NULL},
+		{"O", CmdPrompt, _UU("CMD_MakeCert_PROMPT_O"), NULL, NULL},
+		{"OU", CmdPrompt, _UU("CMD_MakeCert_PROMPT_OU"), NULL, NULL},
+		{"C", CmdPrompt, _UU("CMD_MakeCert_PROMPT_C"), NULL, NULL},
+		{"ST", CmdPrompt, _UU("CMD_MakeCert_PROMPT_ST"), NULL, NULL},
+		{"L", CmdPrompt, _UU("CMD_MakeCert_PROMPT_L"), NULL, NULL},
+		{"SERIAL", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SERIAL"), NULL, NULL},
+		{"EXPIRES", CmdPrompt, _UU("CMD_MakeCert_PROMPT_EXPIRES"), CmdEvalMinMax, &minmax},
+		{"SIGNCERT", NULL, NULL, CmdEvalIsFile, NULL},
+		{"SIGNKEY", NULL, NULL, CmdEvalIsFile, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+		{"SAVEKEY", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SAVEKEY"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (IsEmptyStr(GetParamStr(o, "SIGNCERT")) == false && IsEmptyStr(GetParamStr(o, "SIGNKEY")) == false)
+	{
+		root_x = FileToX(GetParamStr(o, "SIGNCERT"));
+		root_k = FileToK(GetParamStr(o, "SIGNKEY"), true, NULL);
+
+		if (root_x == NULL || root_k == NULL || CheckXandK(root_x, root_k) == false)
+		{
+			ret = ERR_INTERNAL_ERROR;
+
+			c->Write(c, _UU("CMD_MakeCert_ERROR_SIGNKEY"));
+		}
+	}
+
+	if (ret == ERR_NO_ERROR)
+	{
+		buf = StrToBin(GetParamStr(o, "SERIAL"));
+		if (buf != NULL && buf->Size >= 1)
+		{
+			x_serial = NewXSerial(buf->Buf, buf->Size);
+		}
+		FreeBuf(buf);
+
+		n = NewName(GetParamUniStr(o, "CN"), GetParamUniStr(o, "O"), GetParamUniStr(o, "OU"), 
+			GetParamUniStr(o, "C"), GetParamUniStr(o, "ST"), GetParamUniStr(o, "L"));
+
+		days = GetParamInt(o, "EXPIRES");
+		if (days == 0)
+		{
+			days = 3650;
+		}
+
+		RsaGen(&pri, &pub, 1024);
+
+		if (root_x == NULL)
+		{
+			x = NewRootX(pub, pri, n, days, x_serial);
+		}
+		else
+		{
+			x = NewX(pub, root_k, root_x, n, days, x_serial);
+		}
+
+		FreeXSerial(x_serial);
+		FreeName(n);
+
+		if (x == NULL)
+		{
+			ret = ERR_INTERNAL_ERROR;
+			c->Write(c, _UU("CMD_MakeCert_ERROR_GEN_FAILED"));
+		}
+		else
+		{
+			if (XToFile(x, GetParamStr(o, "SAVECERT"), true) == false)
+			{
+				c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+			}
+			else if (KToFile(pri, GetParamStr(o, "SAVEKEY"), true, NULL) == false)
+			{
+				c->Write(c, _UU("CMD_SAVEKEY_FAILED"));
+			}
+		}
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	FreeX(root_x);
+	FreeK(root_k);
+
+	FreeX(x);
+	FreeK(pri);
+	FreeK(pub);
+
+	return ret;
+}
+
+
+// クライアント管理ツールメイン
+void PcMain(PC *pc)
+{
+	char prompt[MAX_SIZE];
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (pc == NULL)
+	{
+		return;
+	}
+
+	// 接続が完了したメッセージを表示する
+	UniFormat(tmp, sizeof(tmp), _UU("CMD_UTVPNCMD_CLIENT_CONNECTED"),
+		pc->ServerName);
+	pc->Console->Write(pc->Console, tmp);
+	pc->Console->Write(pc->Console, L"");
+
+	while (true)
+	{
+		// コマンドの定義
+		CMD cmd[] =
+		{
+			{"About", PsAbout},
+			{"Check", PtCheck},
+			{"VersionGet", PcVersionGet},
+			{"PasswordSet", PcPasswordSet},
+			{"PasswordGet", PcPasswordGet},
+			{"CertList", PcCertList},
+			{"CertAdd", PcCertAdd},
+			{"CertDelete", PcCertDelete},
+			{"CertGet", PcCertGet},
+			{"SecureList", PcSecureList},
+			{"SecureSelect", PcSecureSelect},
+			{"SecureGet", PcSecureGet},
+			{"NicCreate", PcNicCreate},
+			{"NicDelete", PcNicDelete},
+			{"NicUpgrade", PcNicUpgrade},
+			{"NicGetSetting", PcNicGetSetting},
+			{"NicSetSetting", PcNicSetSetting},
+			{"NicEnable", PcNicEnable},
+			{"NicDisable", PcNicDisable},
+			{"NicList", PcNicList},
+			{"AccountList", PcAccountList},
+			{"AccountCreate", PcAccountCreate},
+			{"AccountSet", PcAccountSet},
+			{"AccountGet", PcAccountGet},
+			{"AccountDelete", PcAccountDelete},
+			{"AccountUsernameSet", PcAccountUsernameSet},
+			{"AccountAnonymousSet", PcAccountAnonymousSet},
+			{"AccountPasswordSet", PcAccountPasswordSet},
+			{"AccountCertSet", PcAccountCertSet},
+			{"AccountCertGet", PcAccountCertGet},
+			{"AccountEncryptDisable", PcAccountEncryptDisable},
+			{"AccountEncryptEnable", PcAccountEncryptEnable},
+			{"AccountCompressEnable", PcAccountCompressEnable},
+			{"AccountCompressDisable", PcAccountCompressDisable},
+			{"AccountProxyNone", PcAccountProxyNone},
+			{"AccountProxyHttp", PcAccountProxyHttp},
+			{"AccountProxySocks", PcAccountProxySocks},
+			{"AccountServerCertEnable", PcAccountServerCertEnable},
+			{"AccountServerCertDisable", PcAccountServerCertDisable},
+			{"AccountServerCertSet", PcAccountServerCertSet},
+			{"AccountServerCertDelete", PcAccountServerCertDelete},
+			{"AccountServerCertGet", PcAccountServerCertGet},
+			{"AccountDetailSet", PcAccountDetailSet},
+			{"AccountRename", PcAccountRename},
+			{"AccountConnect", PcAccountConnect},
+			{"AccountDisconnect", PcAccountDisconnect},
+			{"AccountStatusGet", PcAccountStatusGet},
+			{"AccountNicSet", PcAccountNicSet},
+			{"AccountStatusShow", PcAccountStatusShow},
+			{"AccountStatusHide", PcAccountStatusHide},
+			{"AccountSecureCertSet", PcAccountSecureCertSet},
+			{"AccountRetrySet", PcAccountRetrySet},
+			{"AccountStartupSet", PcAccountStartupSet},
+			{"AccountStartupRemove", PcAccountStartupRemove},
+			{"AccountExport", PcAccountExport},
+			{"AccountImport", PcAccountImport},
+			{"RemoteEnable", PcRemoteEnable},
+			{"RemoteDisable", PcRemoteDisable},
+			{"KeepEnable", PcKeepEnable},
+			{"KeepDisable", PcKeepDisable},
+			{"KeepSet", PcKeepSet},
+			{"KeepGet", PcKeepGet},
+			{"MakeCert", PtMakeCert},
+			{"TrafficClient", PtTrafficClient},
+			{"TrafficServer", PtTrafficServer},
+		};
+
+		// プロンプトの生成
+		StrCpy(prompt, sizeof(prompt), "VPN Client>");
+
+		if (DispatchNextCmdEx(pc->Console, pc->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), pc) == false)
+		{
+			break;
+		}
+		pc->LastError = pc->Console->RetCode;
+
+		if (pc->LastError == ERR_NO_ERROR && pc->Console->ConsoleType != CONSOLE_CSV)
+		{
+			pc->Console->Write(pc->Console, _UU("CMD_MSG_OK"));
+			pc->Console->Write(pc->Console, L"");
+		}
+
+		if (pc->CmdLine != NULL)
+		{
+			break;
+		}
+	}
+}
+
+// VPN Client サービスのバージョン情報の取得
+UINT PcVersionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_VERSION t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetClientVersion(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		wchar_t tmp[MAX_SIZE];
+		CT *ct;
+
+		// 成功
+		ct = CtNewStandard();
+
+		StrToUni(tmp, sizeof(tmp), t.ClientProductName);
+		CtInsert(ct, _UU("CMD_VersionGet_1"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), t.ClientVersionString);
+		CtInsert(ct, _UU("CMD_VersionGet_2"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), t.ClientBuildInfoString);
+		CtInsert(ct, _UU("CMD_VersionGet_3"), tmp);
+
+		UniToStru(tmp, t.ProcessId);
+		CtInsert(ct, _UU("CMD_VersionGet_4"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), OsTypeToStr(t.OsType));
+		CtInsert(ct, _UU("CMD_VersionGet_5"), tmp);
+
+		CtFree(ct, c);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN Client サービスに接続するためのパスワードの設定
+UINT PcPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_PASSWORD t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+		{"REMOTEONLY", NULL, NULL, NULL, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	StrCpy(t.Password, sizeof(t.Password), GetParamStr(o, "[password]"));
+	t.PasswordRemoteOnly = GetParamYes(o, "REMOTEONLY");
+
+	ret = CcSetPassword(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN Client サービスに接続するためのパスワードの設定の取得
+UINT PcPasswordGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_PASSWORD_SETTING t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetPasswordSetting(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+		CT *ct = CtNewStandard();
+
+		CtInsert(ct, _UU("CMD_PasswordGet_1"),
+			t.IsPasswordPresented ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		CtInsert(ct, _UU("CMD_PasswordGet_2"),
+			t.PasswordRemoteOnly ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		CtFree(ct, c);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 信頼する証明機関の証明書一覧の取得
+UINT PcCertList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_ENUM_CA t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcEnumCa(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+		UINT i;
+		CT *ct = CtNewStandard();
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			wchar_t tmp[MAX_SIZE];
+			wchar_t tmp2[64];
+			RPC_CLIENT_ENUM_CA_ITEM *e = t.Items[i];
+
+			GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(e->Expires), NULL);
+
+			UniToStru(tmp2, e->Key);
+
+			CtInsert(ct, _UU("CMD_CAList_COLUMN_ID"), tmp2);
+			CtInsert(ct, _UU("CM_CERT_COLUMN_1"), e->SubjectName);
+			CtInsert(ct, _UU("CM_CERT_COLUMN_2"), e->IssuerName);
+			CtInsert(ct, _UU("CM_CERT_COLUMN_3"), tmp);
+
+			if (i != (t.NumItem - 1))
+			{
+				CtInsert(ct, L"---", L"---");
+			}
+		}
+
+		CtFree(ct, c);
+
+		CiFreeClientEnumCa(&t);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 信頼する証明機関の証明書の追加
+UINT PcCertAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CERT t;
+	X *x;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[path]", CmdPrompt, _UU("CMD_CAAdd_PROMPT_PATH"), CmdEvalIsFile, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+
+	x = FileToX(GetParamStr(o, "[path]"));
+
+	if (x == NULL)
+	{
+		FreeParamValueList(o);
+		c->Write(c, _UU("CMD_MSG_LOAD_CERT_FAILED"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	t.x = x;
+
+	ret = CcAddCa(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	FreeX(x);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 信頼する証明機関の証明書の削除
+UINT PcCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_DELETE_CA t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[id]", CmdPrompt, _UU("CMD_CADelete_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	t.Key = GetParamInt(o, "[id]");
+
+	ret = CcDeleteCa(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 信頼する証明機関の証明書の取得
+UINT PcCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_GET_CA t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[id]", CmdPrompt, _UU("CMD_CAGet_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_CAGet_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	t.Key = GetParamInt(o, "[id]");
+
+	ret = CcGetCa(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+		if (XToFile(t.x, GetParamStr(o, "SAVECERT"), true))
+		{
+			// 成功
+		}
+		else
+		{
+			// 失敗
+			ret = ERR_INTERNAL_ERROR;
+			c->Write(c, _UU("CMD_MSG_SAVE_CERT_FAILED"));
+		}
+
+		CiFreeGetCa(&t);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 使用できるスマートカードの種類の一覧の取得
+UINT PcSecureList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_ENUM_SECURE t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcEnumSecure(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		CT *ct;
+		UINT i;
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp4[MAX_SIZE];
+		wchar_t *tmp3;
+
+		// 成功
+		ct = CtNew();
+		CtInsertColumn(ct, _UU("SEC_COLUMN1"), false);
+		CtInsertColumn(ct, _UU("SEC_COLUMN2"), false);
+		CtInsertColumn(ct, _UU("SEC_COLUMN3"), false);
+		CtInsertColumn(ct, _UU("SEC_COLUMN4"), false);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_CLIENT_ENUM_SECURE_ITEM *e = t.Items[i];
+
+			// ID
+			UniToStru(tmp1, e->DeviceId);
+
+			// デバイス名
+			StrToUni(tmp2, sizeof(tmp2), e->DeviceName);
+
+			// 種類
+			tmp3 = (e->Type == SECURE_IC_CARD) ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN");
+
+			// 製造元
+			StrToUni(tmp4, sizeof(tmp4), e->Manufacturer);
+
+			CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+		}
+
+		CtFreeEx(ct, c, true);
+
+		CiFreeClientEnumSecure(&t);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 使用するスマートカードの種類の選択
+UINT PcSecureSelect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_USE_SECURE t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[id]", CmdPrompt, _UU("CMD_SecureSelect_PROMPT_ID"), NULL, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	t.DeviceId = GetParamInt(o, "[id]");
+
+	ret = CcUseSecure(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 使用するスマートカードの種類の ID の取得
+UINT PcSecureGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_USE_SECURE t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetUseSecure(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+		wchar_t tmp[MAX_SIZE];
+
+		if (t.DeviceId != 0)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CMD_SecureGet_Print"), t.DeviceId);
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CMD_SecureGet_NoPrint"));
+		}
+		c->Write(c, tmp);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 新規仮想 LAN カードの作成
+UINT PcNicCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_CREATE_VLAN t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+	ret = CcCreateVLan(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 仮想 LAN カードの削除
+UINT PcNicDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_CREATE_VLAN t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+	ret = CcDeleteVLan(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 仮想 LAN カードのデバイスドライバのアップグレード
+UINT PcNicUpgrade(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_CREATE_VLAN t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+	ret = CcUpgradeVLan(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 仮想 LAN カードの設定の取得
+UINT PcNicGetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_VLAN t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+	ret = CcGetVLan(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+		CT *ct = CtNewStandard();
+		wchar_t tmp[MAX_SIZE];
+
+		StrToUni(tmp, sizeof(tmp), t.DeviceName);
+		CtInsert(ct, _UU("CMD_NicGetSetting_1"), tmp);
+
+		CtInsert(ct, _UU("CMD_NicGetSetting_2"), t.Enabled ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		StrToUni(tmp, sizeof(tmp), t.MacAddress);
+		CtInsert(ct, _UU("CMD_NicGetSetting_3"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), t.Version);
+		CtInsert(ct, _UU("CMD_NicGetSetting_4"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), t.FileName);
+		CtInsert(ct, _UU("CMD_NicGetSetting_5"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), t.Guid);
+		CtInsert(ct, _UU("CMD_NicGetSetting_6"), tmp);
+
+		CtFree(ct, c);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 仮想 LAN カードの設定の変更
+UINT PcNicSetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_SET_VLAN t;
+	UCHAR mac_address[6];
+	BUF *b;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"MAC", CmdPrompt, _UU("CMD_NicSetSetting_PROMPT_MAC"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// MAC アドレスの検査
+	Zero(mac_address, sizeof(mac_address));
+	b = StrToBin(GetParamStr(o, "MAC"));
+	if (b != NULL && b->Size == 6)
+	{
+		Copy(mac_address, b->Buf, 6);
+	}
+	FreeBuf(b);
+
+	if (IsZero(mac_address, 6))
+	{
+		// MAC アドレスが不正
+		FreeParamValueList(o);
+
+		CmdPrintError(c, ERR_INVALID_PARAMETER);
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+	NormalizeMacAddress(t.MacAddress, sizeof(t.MacAddress), GetParamStr(o, "MAC"));
+
+	ret = CcSetVLan(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 仮想 LAN カードの有効化
+UINT PcNicEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_CREATE_VLAN t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+	ret = CcEnableVLan(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 仮想 LAN カードの無効化
+UINT PcNicDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_CREATE_VLAN t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+	ret = CcDisableVLan(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 仮想 LAN カード一覧の取得
+UINT PcNicList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_ENUM_VLAN t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcEnumVLan(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		CT *ct;
+		UINT i;
+
+		// 成功
+		ct = CtNew();
+		CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_2"), false);
+		CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_4"), false);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			wchar_t name[MAX_SIZE];
+			wchar_t mac[MAX_SIZE];
+			wchar_t ver[MAX_SIZE];
+			wchar_t *status;
+			RPC_CLIENT_ENUM_VLAN_ITEM *v = t.Items[i];
+
+			// デバイス名
+			StrToUni(name, sizeof(name), v->DeviceName);
+
+			// 状態
+			status = v->Enabled ? _UU("CM_VLAN_ENABLED") : _UU("CM_VLAN_DISABLED");
+
+			// MAC アドレス
+			StrToUni(mac, sizeof(mac), v->MacAddress);
+
+			// バージョン
+			StrToUni(ver, sizeof(ver), v->Version);
+
+			CtInsert(ct,
+				name, status, mac, ver);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientEnumVLan(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// プロトコル名文字列を取得
+wchar_t *GetProtocolName(UINT n)
+{
+	switch (n)
+	{
+	case PROXY_DIRECT:
+		return _UU("PROTO_DIRECT_TCP");
+	case PROXY_HTTP:
+		return _UU("PROTO_HTTP_PROXY");
+	case PROXY_SOCKS:
+		return _UU("PROTO_SOCKS_PROXY");
+	}
+
+	return _UU("PROTO_UNKNOWN");
+}
+
+// 接続設定一覧の取得
+UINT PcAccountList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_ENUM_ACCOUNT t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcEnumAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		UINT i;
+		CT *ct;
+
+		// 成功
+		ct = CtNew();
+		CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_2"), false);
+		CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_3_2"), false);
+		CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_4"), false);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_CLIENT_ENUM_ACCOUNT_ITEM *e = t.Items[i];
+			wchar_t tmp[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			wchar_t tmp4[MAX_SIZE];
+			IP ip;
+			char ip_str[MAX_SIZE];
+
+			// IPv6 アドレスの場合の特別処理
+			if (StrToIP6(&ip, e->ServerName) && StartWith(e->ServerName, "[") == false)
+			{
+				Format(ip_str, sizeof(ip_str),
+					"[%s]", e->ServerName);
+			}
+			else
+			{
+				StrCpy(ip_str, sizeof(ip_str), e->ServerName);
+			}
+
+			if (e->Port == 0)
+			{
+				// ポート番号不明
+				UniFormat(tmp2, sizeof(tmp2), L"%S (%s)", ip_str, GetProtocolName(e->ProxyType));
+			}
+			else
+			{
+				// ポート番号併記
+				UniFormat(tmp2, sizeof(tmp2), L"%S:%u (%s)", ip_str, e->Port, GetProtocolName(e->ProxyType));
+			}
+
+			// 仮想 HUB 名
+			StrToUni(tmp4, sizeof(tmp4), e->HubName);
+
+			// 追加
+			StrToUni(tmp, sizeof(tmp), e->DeviceName);
+
+			CtInsert(ct,
+				e->AccountName,
+				e->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+				(e->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+				tmp2, tmp4,
+				tmp);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	CiFreeClientEnumAccount(&t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 新しい接続設定の作成
+UINT PcAccountCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_CREATE_ACCOUNT t;
+	UINT port = 443;
+	char *host = NULL;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SERVER", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+		{"HUB", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+		{"USERNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+		{"NICNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Nicname"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+	t.ClientOption->Port = port;
+	StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+	StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+	t.ClientOption->NumRetry = INFINITE;
+	t.ClientOption->RetryInterval = 15;
+	t.ClientOption->MaxConnection = 1;
+	t.ClientOption->UseEncrypt = true;
+	t.ClientOption->AdditionalConnectionInterval = 1;
+	StrCpy(t.ClientOption->DeviceName, sizeof(t.ClientOption->DeviceName), GetParamStr(o, "NICNAME"));
+
+	t.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+	t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+	StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+	Free(host);
+
+	ret = CcCreateAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	CiFreeClientCreateAccount(&t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の接続先の設定
+UINT PcAccountSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	char *host = NULL;
+	UINT port = 443;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SERVER", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+		{"HUB", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+	Zero(&t, sizeof(t));
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT c;
+		// 成功
+		t.ClientOption->Port = port;
+		StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+		StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+
+		Zero(&c, sizeof(c));
+
+		c.ClientAuth = t.ClientAuth;
+		c.ClientOption = t.ClientOption;
+		c.CheckServerCert = t.CheckServerCert;
+		c.ServerCert = t.ServerCert;
+		c.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &c);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	Free(host);
+
+	return ret;
+}
+
+// 接続設定の設定の取得
+UINT PcAccountGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 接続設定の内容を表示
+		wchar_t tmp[MAX_SIZE];
+
+		CT *ct = CtNewStandard();
+
+		// 接続設定名
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NAME"), t.ClientOption->AccountName);
+
+		// 接続先 VPN Server のホスト名
+		StrToUni(tmp, sizeof(tmp), t.ClientOption->Hostname);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HOSTNAME"), tmp);
+
+		// 接続先 VPN Server のポート番号
+		UniToStru(tmp, t.ClientOption->Port);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PORT"), tmp);
+
+		// 接続先 VPN Server の仮想 HUB 名
+		StrToUni(tmp, sizeof(tmp), t.ClientOption->HubName);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HUBNAME"), tmp);
+
+		// 経由するプロキシ サーバーの種類
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_TYPE"), GetProxyTypeStr(t.ClientOption->ProxyType));
+
+		if (t.ClientOption->ProxyType != PROXY_DIRECT)
+		{
+			// プロキシ サーバーのホスト名
+			StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyName);
+			CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_HOSTNAME"), tmp);
+
+			// プロキシ サーバーのポート番号
+			UniToStru(tmp, t.ClientOption->ProxyPort);
+			CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_PORT"), tmp);
+
+			// プロキシ サーバーのユーザー名
+			StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyUsername);
+			CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_USERNAME"), tmp);
+		}
+
+		// サーバー証明書の検証
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_USE"),
+			t.CheckServerCert ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// 登録されている固有証明書
+		if (t.ServerCert != NULL)
+		{
+			GetAllNameFromX(tmp, sizeof(tmp), t.ServerCert);
+			CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_NAME"), tmp);
+		}
+
+		// 接続に使用するデバイス名
+		StrToUni(tmp, sizeof(tmp), t.ClientOption->DeviceName);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_DEVICE_NAME"), tmp);
+
+		// 認証の種類
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_TYPE"), GetClientAuthTypeStr(t.ClientAuth->AuthType));
+
+		// ユーザー名
+		StrToUni(tmp, sizeof(tmp), t.ClientAuth->Username);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_USERNAME"), tmp);
+
+		if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+		{
+			if (t.ClientAuth->ClientX != NULL)
+			{
+				// クライアント証明書名
+				GetAllNameFromX(tmp, sizeof(tmp), t.ClientAuth->ClientX);
+				CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_CERT_NAME"), tmp);
+			}
+		}
+
+		// VPN 通信に使用する TCP コネクション数
+		UniToStru(tmp, t.ClientOption->MaxConnection);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NUMTCP"), tmp);
+
+		// 各 TCP コネクションの確立間隔
+		UniToStru(tmp, t.ClientOption->AdditionalConnectionInterval);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_INTERVAL"), tmp);
+
+		// 各 TCP コネクションの寿命
+		if (t.ClientOption->ConnectionDisconnectSpan != 0)
+		{
+			UniToStru(tmp, t.ClientOption->ConnectionDisconnectSpan);
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+		}
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_TTL"), tmp);
+
+		// 半二重モードの使用
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_HALF"),
+			t.ClientOption->HalfConnection ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// SSL による暗号化
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_ENCRYPT"),
+			t.ClientOption->UseEncrypt ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// データ圧縮
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_COMPRESS"),
+			t.ClientOption->UseCompress ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// ブリッジ / ルータモードで接続
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_BRIDGE_ROUTER"),
+			t.ClientOption->RequireBridgeRoutingMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// モニタリングモードで接続
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_MONITOR"),
+			t.ClientOption->RequireMonitorMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// ルーティング テーブルを書き換えない
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NO_TRACKING"),
+			t.ClientOption->NoRoutingTracking ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// QoS制御を無効化する
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_QOS_DISABLE"),
+			t.ClientOption->DisableQoS ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		CtFree(ct, c);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の削除
+UINT PcAccountDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_DELETE_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcDeleteAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の接続に使用するユーザー名の設定
+UINT PcAccountUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"USERNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+		if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+		{
+			c->Write(c, _UU("CMD_AccountUsername_Notice"));
+		}
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のユーザー認証の種類を匿名認証に設定
+UINT PcAccountAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のユーザー認証の種類をパスワード認証に設定
+UINT PcAccountPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+		{"TYPE", CmdPrompt, _UU("CMD_CascadePasswordSet_Prompt_Type"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		char *typestr = GetParamStr(o, "TYPE");
+		RPC_CLIENT_CREATE_ACCOUNT z;
+
+		// 設定変更
+		if (StartWith("standard", typestr))
+		{
+			t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+			HashPassword(t.ClientAuth->HashedPassword, t.ClientAuth->Username,
+				GetParamStr(o, "PASSWORD"));
+		}
+		else if (StartWith("radius", typestr) || StartWith("ntdomain", typestr))
+		{
+			t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PLAIN_PASSWORD;
+
+			StrCpy(t.ClientAuth->PlainPassword, sizeof(t.ClientAuth->PlainPassword),
+				GetParamStr(o, "PASSWORD"));
+		}
+		else
+		{
+			// エラー発生
+			c->Write(c, _UU("CMD_CascadePasswordSet_Type_Invalid"));
+			ret = ERR_INVALID_PARAMETER;
+		}
+
+		if (ret == ERR_NO_ERROR)
+		{
+			Zero(&z, sizeof(z));
+			z.CheckServerCert = t.CheckServerCert;
+			z.ClientAuth = t.ClientAuth;
+			z.ClientOption = t.ClientOption;
+			z.ServerCert = t.ServerCert;
+			z.StartupAccount = t.StartupAccount;
+
+			ret = CcSetAccount(pc->RemoteClient, &z);
+		}
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のユーザー認証の種類をクライアント証明書認証に設定
+UINT PcAccountCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	X *x;
+	K *k;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+		{"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (CmdLoadCertAndKey(c, &x, &k, GetParamStr(o, "LOADCERT"), GetParamStr(o, "LOADKEY")) == false)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+
+		t.ClientAuth->AuthType = CLIENT_AUTHTYPE_CERT;
+		if (t.ClientAuth->ClientX != NULL)
+		{
+			FreeX(t.ClientAuth->ClientX);
+		}
+		if (t.ClientAuth->ClientK != NULL)
+		{
+			FreeK(t.ClientAuth->ClientK);
+		}
+
+		t.ClientAuth->ClientX = CloneX(x);
+		t.ClientAuth->ClientK = CloneK(k);
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	FreeX(x);
+	FreeK(k);
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定に用いるクライアント証明書の取得
+UINT PcAccountCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		if (t.ClientAuth->AuthType != CLIENT_AUTHTYPE_CERT)
+		{
+			c->Write(c, _UU("CMD_CascadeCertSet_Not_Auth_Cert"));
+			ret = ERR_INTERNAL_ERROR;
+		}
+		else if (t.ClientAuth->ClientX == NULL)
+		{
+			c->Write(c, _UU("CMD_CascadeCertSet_Cert_Not_Exists"));
+			ret = ERR_INTERNAL_ERROR;
+		}
+		else
+		{
+			XToFile(t.ClientAuth->ClientX, GetParamStr(o, "SAVECERT"), true);
+		}
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の通信時の暗号化の無効化
+UINT PcAccountEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientOption->UseEncrypt = false;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の通信時の暗号化の有効化
+UINT PcAccountEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientOption->UseEncrypt = true;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の通信時のデータ圧縮の有効化
+UINT PcAccountCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientOption->UseCompress = true;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の通信時のデータ圧縮の無効化
+UINT PcAccountCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientOption->UseCompress = false;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の接続方法を直接 TCP/IP 接続に設定
+UINT PcAccountProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientOption->ProxyType = PROXY_DIRECT;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の接続方法を HTTP プロキシサーバー経由接続に設定
+UINT PcAccountProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SERVER", CmdPrompt, _UU("CMD_AccountProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+		{"USERNAME", NULL, NULL, NULL, NULL},
+		{"PASSWORD", NULL, NULL, NULL, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		char *host;
+		UINT port;
+
+		// データ変更
+		if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+		{
+			t.ClientOption->ProxyType = PROXY_HTTP;
+			StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+			t.ClientOption->ProxyPort = port;
+			StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+			StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+			Free(host);
+		}
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の接続方法を SOCKS プロキシサーバー経由接続に設定
+UINT PcAccountProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SERVER", CmdPrompt, _UU("CMD_AccountProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+		{"USERNAME", NULL, NULL, NULL, NULL},
+		{"PASSWORD", NULL, NULL, NULL, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		char *host;
+		UINT port;
+
+		// データ変更
+		if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+		{
+			t.ClientOption->ProxyType = PROXY_SOCKS;
+			StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+			t.ClientOption->ProxyPort = port;
+			StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+			StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+			Free(host);
+		}
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のサーバー証明書の検証オプションの有効化
+UINT PcAccountServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.CheckServerCert = true;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のサーバー証明書の検証オプションの無効化
+UINT PcAccountServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.CheckServerCert = false;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のサーバー固有証明書の設定
+UINT PcAccountServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	X *x;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	x = FileToX(GetParamStr(o, "LOADCERT"));
+	if (x == NULL)
+	{
+		FreeParamValueList(o);
+		c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+		return ERR_INTERNAL_ERROR;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		if (t.ServerCert != NULL)
+		{
+			FreeX(t.ServerCert);
+		}
+		t.ServerCert = CloneX(x);
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	FreeX(x);
+
+	return ret;
+}
+
+// 接続設定のサーバー固有証明書の削除
+UINT PcAccountServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		if (t.ServerCert != NULL)
+		{
+			FreeX(t.ServerCert);
+		}
+		t.ServerCert = NULL;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のサーバー固有証明書の取得
+UINT PcAccountServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		if (t.ServerCert != NULL)
+		{
+			FreeX(t.ServerCert);
+		}
+		t.ServerCert = NULL;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の高度な通信設定の設定
+UINT PcAccountDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	CMD_EVAL_MIN_MAX mm_maxtcp =
+	{
+		"CMD_CascadeDetailSet_Eval_MaxTcp", 1, 32
+	};
+	CMD_EVAL_MIN_MAX mm_interval =
+	{
+		"CMD_CascadeDetailSet_Eval_Interval", 1, 4294967295UL
+	};
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"MAXTCP", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_MaxTcp"), CmdEvalMinMax, &mm_maxtcp},
+		{"INTERVAL", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_Interval"), CmdEvalMinMax, &mm_interval},
+		{"TTL", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_TTL"), NULL, NULL},
+		{"HALF", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_HALF"), NULL, NULL},
+		{"BRIDGE", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_BRIDGE"), NULL, NULL},
+		{"MONITOR", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_MONITOR"), NULL, NULL},
+		{"NOTRACK", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOTRACK"), NULL, NULL},
+		{"NOQOS", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOQOS"), NULL, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// データ変更
+		t.ClientOption->MaxConnection = GetParamInt(o, "MAXTCP");
+		t.ClientOption->AdditionalConnectionInterval = GetParamInt(o, "INTERVAL");
+		t.ClientOption->ConnectionDisconnectSpan = GetParamInt(o, "TTL");
+		t.ClientOption->HalfConnection = GetParamYes(o, "HALF");
+		t.ClientOption->RequireBridgeRoutingMode = GetParamYes(o, "BRIDGE");
+		t.ClientOption->RequireMonitorMode = GetParamYes(o, "MONITOR");
+		t.ClientOption->NoRoutingTracking = GetParamYes(o, "NOTRACK");
+		t.ClientOption->DisableQoS = GetParamYes(o, "NOQOS");
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の名前の変更
+UINT PcAccountRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_RENAME_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountRename_PROMPT_OLD"), CmdEvalNotEmpty, NULL},
+		{"NEW", CmdPrompt, _UU("CMD_AccountRename_PROMPT_NEW"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	UniStrCpy(t.NewName, sizeof(t.NewName), GetParamUniStr(o, "NEW"));
+	UniStrCpy(t.OldName, sizeof(t.OldName), GetParamUniStr(o, "[name]"));
+
+	ret = CcRenameAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定を使用して VPN Server へ接続を開始
+UINT PcAccountConnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_CONNECT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcConnect(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続中の接続設定の切断
+UINT PcAccountDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_CONNECT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcDisconnect(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の現在の状態の取得
+UINT PcAccountStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_CONNECTION_STATUS t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccountStatus(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		if (t.Active == false)
+		{
+			// 切断されている
+			ret = ERR_ACCOUNT_INACTIVE;
+		}
+		else
+		{
+			CT *ct = CtNewStandard();
+
+			CmdPrintStatusToListView(ct, &t);
+
+			CtFree(ct, c);
+		}
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetConnectionStatus(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定で使用する仮想 LAN カードの設定
+UINT PcAccountNicSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"NICNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Nicname"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	Zero(&t, sizeof(t));
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT c;
+		// 成功
+		StrCpy(t.ClientOption->DeviceName, sizeof(t.ClientOption->DeviceName),
+			GetParamStr(o, "NICNAME"));
+
+		Zero(&c, sizeof(c));
+
+		c.ClientAuth = t.ClientAuth;
+		c.ClientOption = t.ClientOption;
+		c.CheckServerCert = t.CheckServerCert;
+		c.ServerCert = t.ServerCert;
+		c.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &c);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN Server への接続中に接続状況やエラー画面を表示するように設定
+UINT PcAccountStatusShow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientOption->HideStatusWindow = false;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN Server への接続中に接続状況やエラー画面を表示しないように設定
+UINT PcAccountStatusHide(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientOption->HideStatusWindow = true;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のユーザー認証の種類をスマートカード認証に設定
+UINT PcAccountSecureCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"CERTNAME", CmdPrompt, _UU("CMD_AccountSecureCertSet_PROMPT_CERTNAME"), CmdEvalNotEmpty, NULL},
+		{"KEYNAME", CmdPrompt, _UU("CMD_AccountSecureCertSet_PROMPT_KEYNAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.ClientAuth->AuthType = CLIENT_AUTHTYPE_SECURE;
+		StrCpy(t.ClientAuth->SecurePublicCertName, sizeof(t.ClientAuth->SecurePublicCertName),
+			GetParamStr(o, "CERTNAME"));
+		StrCpy(t.ClientAuth->SecurePrivateKeyName, sizeof(t.ClientAuth->SecurePrivateKeyName),
+			GetParamStr(o, "KEYNAME"));
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定の接続失敗または切断時の再試行回数と間隔の設定
+UINT PcAccountRetrySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX minmax =
+	{
+		"CMD_AccountRetrySet_EVAL_INTERVAL",
+		5,
+		4294967295UL,
+	};
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"NUM", CmdPrompt, _UU("CMD_AccountRetrySet_PROMPT_NUM"), CmdEvalNotEmpty, NULL},
+		{"INTERVAL", CmdPrompt, _UU("CMD_AccountRetrySet_PROMPY_INTERVAL"), CmdEvalMinMax, &minmax},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		UINT num = GetParamInt(o, "NUM");
+		UINT interval = GetParamInt(o, "INTERVAL");
+
+		t.ClientOption->NumRetry = (num == 999) ? INFINITE : num;
+		t.ClientOption->RetryInterval = interval;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+
+// 接続設定をスタートアップ接続に設定
+UINT PcAccountStartupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.StartupAccount = true;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のスタートアップ接続を解除
+UINT PcAccountStartupRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		// 設定変更
+		t.StartupAccount = false;
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		ret = CcSetAccount(pc->RemoteClient, &z);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 接続設定のエクスポート
+UINT PcAccountExport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	RPC_CLIENT_GET_ACCOUNT t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SAVEPATH", CmdPrompt, _UU("CMD_AccountExport_PROMPT_SAVEPATH"), CmdEvalNotEmpty, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = CcGetAccount(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		RPC_CLIENT_CREATE_ACCOUNT z;
+		BUF *b;
+		BUF *b2;
+		char tmp[MAX_SIZE];
+		UCHAR *buf;
+		UINT buf_size;
+		UCHAR bom[] = {0xef, 0xbb, 0xbf, };
+
+		Zero(&z, sizeof(z));
+		z.CheckServerCert = t.CheckServerCert;
+		z.ClientAuth = t.ClientAuth;
+		z.ClientOption = t.ClientOption;
+		z.ServerCert = t.ServerCert;
+		z.StartupAccount = t.StartupAccount;
+
+		b = CiAccountToCfg(&z);
+
+		StrCpy(tmp, sizeof(tmp), GetParamStr(o, "SAVEPATH"));
+		b2 = NewBuf();
+
+		WriteBuf(b2, bom, sizeof(bom));
+
+		// ヘッダ部分を付加する
+		buf_size = CalcUniToUtf8(_UU("CM_ACCOUNT_FILE_BANNER"));
+		buf = ZeroMalloc(buf_size + 32);
+		UniToUtf8(buf, buf_size, _UU("CM_ACCOUNT_FILE_BANNER"));
+
+		WriteBuf(b2, buf, StrLen((char *)buf));
+		WriteBuf(b2, b->Buf, b->Size);
+		SeekBuf(b2, 0, 0);
+
+		FreeBuf(b);
+
+		if (DumpBuf(b2, tmp) == false)
+		{
+			c->Write(c, _UU("CMD_SAVEFILE_FAILED"));
+			ret = ERR_INTERNAL_ERROR;
+		}
+
+		FreeBuf(b2);
+		Free(buf);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	CiFreeClientGetAccount(&t);
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 指定されたアカウント名が存在するかチェックする
+bool CmdIsAccountName(REMOTE_CLIENT *r, wchar_t *name)
+{
+	UINT i;
+	RPC_CLIENT_ENUM_ACCOUNT t;
+	wchar_t tmp[MAX_SIZE];
+	bool b = false;
+	// 引数チェック
+	if (r == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	if (CcEnumAccount(r, &t) != ERR_NO_ERROR)
+	{
+		return false;
+	}
+
+	UniStrCpy(tmp, sizeof(tmp), name);
+	UniTrim(tmp);
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		if (UniStrCmpi(t.Items[i]->AccountName, tmp) == 0)
+		{
+			b = true;
+			break;
+		}
+	}
+
+	CiFreeClientEnumAccount(&t);
+
+	return b;
+}
+
+// インポート名の生成
+void CmdGenerateImportName(REMOTE_CLIENT *r, wchar_t *name, UINT size, wchar_t *old_name)
+{
+	UINT i;
+	// 引数チェック
+	if (r == NULL || name == NULL || old_name == NULL)
+	{
+		return;
+	}
+
+	for (i = 1;;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		if (i == 1)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_1"), old_name);
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_2"), old_name, i);
+		}
+
+		if (CmdIsAccountName(r, tmp) == false)
+		{
+			UniStrCpy(name, size, tmp);
+			return;
+		}
+	}
+}
+
+// 接続設定のインポート
+UINT PcAccountImport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	BUF *b;
+	wchar_t name[MAX_SIZE];
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[path]", CmdPrompt, _UU("CMD_AccountImport_PROMPT_PATH"), CmdEvalIsFile, NULL},
+	};
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// ファイルを読み込む
+	b = ReadDump(GetParamStr(o, "[path]"));
+
+	if (b == NULL)
+	{
+		// 読み込み失敗
+		c->Write(c, _UU("CMD_LOADFILE_FAILED"));
+		ret = ERR_INTERNAL_ERROR;
+	}
+	else
+	{
+		RPC_CLIENT_CREATE_ACCOUNT *t;
+
+		t = CiCfgToAccount(b);
+
+		if (t == NULL)
+		{
+			// パースに失敗
+			c->Write(c, _UU("CMD_AccountImport_FAILED_PARSE"));
+			ret = ERR_INTERNAL_ERROR;
+		}
+		else
+		{
+			CmdGenerateImportName(pc->RemoteClient, name, sizeof(name), t->ClientOption->AccountName);
+			UniStrCpy(t->ClientOption->AccountName, sizeof(t->ClientOption->AccountName), name);
+
+			ret = CcCreateAccount(pc->RemoteClient, t);
+
+			if (ret == ERR_NO_ERROR)
+			{
+				wchar_t tmp[MAX_SIZE];
+
+				UniFormat(tmp, sizeof(tmp), _UU("CMD_AccountImport_OK"), name);
+				c->Write(c, tmp);
+			}
+
+			CiFreeClientCreateAccount(t);
+			Free(t);
+		}
+
+		FreeBuf(b);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN Client サービスのリモート管理の許可
+UINT PcRemoteEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	CLIENT_CONFIG t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		t.AllowRemoteConfig = true;
+		ret = CcSetClientConfig(pc->RemoteClient, &t);
+	}
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN Client サービスのリモート管理の禁止
+UINT PcRemoteDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	CLIENT_CONFIG t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		t.AllowRemoteConfig = false;
+		ret = CcSetClientConfig(pc->RemoteClient, &t);
+	}
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// インターネット接続の維持機能の有効化
+UINT PcKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	CLIENT_CONFIG t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 設定変更
+		t.UseKeepConnect = true;
+		ret = CcSetClientConfig(pc->RemoteClient, &t);
+	}
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// インターネット接続の維持機能の無効化
+UINT PcKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	CLIENT_CONFIG t;
+
+	// パラメータリストの取得
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 設定変更
+		t.UseKeepConnect = false;
+		ret = CcSetClientConfig(pc->RemoteClient, &t);
+	}
+
+	if (ret == ERR_NO_ERROR)
+	{
+		// 成功
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// インターネット接続の維持機能の設定
+UINT PcKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	CLIENT_CONFIG t;
+	char *host;
+	UINT port;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"HOST", CmdPrompt, _UU("CMD_KeepSet_PROMPT_HOST"), CmdEvalHostAndPort, NULL},
+		{"PROTOCOL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_PROTOCOL"), CmdEvalTcpOrUdp, NULL},
+		{"INTERVAL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_INTERVAL"), NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, 0))
+		{
+			StrCpy(t.KeepConnectHost, sizeof(t.KeepConnectHost), host);
+			t.KeepConnectPort = port;
+			t.KeepConnectInterval = GetParamInt(o, "INTERVAL");
+			t.KeepConnectProtocol = (StrCmpi(GetParamStr(o, "PROTOCOL"), "tcp") == 0) ? 0 : 1;
+			Free(host);
+
+			ret = CcSetClientConfig(pc->RemoteClient, &t);
+		}
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// インターネット接続の維持機能の取得
+UINT PcKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PC *pc = (PC *)param;
+	UINT ret = ERR_NO_ERROR;
+	CLIENT_CONFIG t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	Zero(&t, sizeof(t));
+
+	ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+	if (ret == ERR_NO_ERROR)
+	{
+		wchar_t tmp[MAX_SIZE];
+		CT *ct = CtNewStandard();
+
+		StrToUni(tmp, sizeof(tmp), t.KeepConnectHost);
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_1"), tmp);
+
+		UniToStru(tmp, t.KeepConnectPort);
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_2"), tmp);
+
+		UniToStru(tmp, t.KeepConnectInterval);
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_3"), tmp);
+
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_4"),
+			t.KeepConnectProtocol == 0 ? L"TCP/IP" : L"UDP/IP");
+
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_5"),
+			t.UseKeepConnect ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"));
+
+		CtFree(ct, c);
+	}
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラーが発生した
+		CmdPrintError(c, ret);
+	}
+
+	// パラメータリストの解放
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+
+// 新しいクライアント管理ツールコンテキストの作成
+PC *NewPc(CONSOLE *c, REMOTE_CLIENT *remote_client, char *servername, wchar_t *cmdline)
+{
+	PC *pc;
+	// 引数チェック
+	if (c == NULL || remote_client == NULL || servername == NULL)
+	{
+		return NULL;
+	}
+	if (UniIsEmptyStr(cmdline))
+	{
+		cmdline = NULL;
+	}
+
+	pc = ZeroMalloc(sizeof(PC));
+	pc->ConsoleForServer = false;
+	pc->ServerName = CopyStr(servername);
+	pc->Console = c;
+	pc->LastError = 0;
+	pc->RemoteClient = remote_client;
+	pc->CmdLine = CopyUniStr(cmdline);
+
+	return pc;
+}
+
+// クライアント管理ツールコンテキストの解放
+void FreePc(PC *pc)
+{
+	// 引数チェック
+	if (pc == NULL)
+	{
+		return;
+	}
+
+	Free(pc->ServerName);
+	Free(pc->CmdLine);
+	Free(pc);
+}
+
+// クライアント管理ツール
+UINT PcConnect(CONSOLE *c, char *target, wchar_t *cmdline, char *password)
+{
+	CEDAR *cedar;
+	REMOTE_CLIENT *client;
+	bool bad_pass;
+	bool no_remote;
+	char pass[MAX_SIZE];
+	UINT ret = 0;
+	// 引数チェック
+	if (c == NULL || target == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	StrCpy(pass, sizeof(pass), password);
+
+	cedar = NewCedar(NULL, NULL);
+
+RETRY:
+	client = CcConnectRpc(target, pass, &bad_pass, &no_remote, 0);
+
+	if (client == NULL)
+	{
+		if (no_remote)
+		{
+			// リモート接続拒否
+			c->Write(c, _UU("CMD_UTVPNCMD_CLIENT_NO_REMODE"));
+			ReleaseCedar(cedar);
+			return ERR_INTERNAL_ERROR;
+		}
+		else if (bad_pass)
+		{
+			char *tmp;
+			// パスワード違い
+			c->Write(c, _UU("CMD_UTVPNCMD_PASSWORD_1"));
+			tmp = c->ReadPassword(c, _UU("CMD_UTVPNCMD_PASSWORD_2"));
+			c->Write(c, L"");
+
+			if (tmp == NULL)
+			{
+				// キャンセル
+				ReleaseCedar(cedar);
+				return ERR_ACCESS_DENIED;
+			}
+			else
+			{
+				StrCpy(pass, sizeof(pass), tmp);
+				Free(tmp);
+			}
+
+			goto RETRY;
+		}
+		else
+		{
+			// 接続失敗
+			CmdPrintError(c, ERR_CONNECT_FAILED);
+			ReleaseCedar(cedar);
+			return ERR_CONNECT_FAILED;
+		}
+	}
+	else
+	{
+		// 接続完了
+		PC *pc = NewPc(c, client, target, cmdline);
+		PcMain(pc);
+		ret = pc->LastError;
+		FreePc(pc);
+	}
+
+	CcDisconnectRpc(client);
+
+	ReleaseCedar(cedar);
+
+	return ret;
+}
+
+
+// サーバー管理ツールプロセッサメイン
+void PsMain(PS *ps)
+{
+	char prompt[MAX_SIZE];
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (ps == NULL)
+	{
+		return;
+	}
+
+	// CSV モードでなければ、接続が完了したメッセージを表示する
+	if(ps->Console->ConsoleType != CONSOLE_CSV)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CMD_UTVPNCMD_SERVER_CONNECTED"),
+			ps->ServerName, ps->ServerPort);
+		ps->Console->Write(ps->Console, tmp);
+		ps->Console->Write(ps->Console, L"");
+
+		if (ps->HubName == NULL)
+		{
+			// サーバー管理モード
+			ps->Console->Write(ps->Console, _UU("CMD_UTVPNCMD_SERVER_CONNECTED_1"));
+		}
+		else
+		{
+			// 仮想 HUB 管理モード
+			UniFormat(tmp, sizeof(tmp), _UU("CMD_UTVPNCMD_SERVER_CONNECTED_2"),
+				ps->HubName);
+			ps->Console->Write(ps->Console, tmp);
+		}
+		ps->Console->Write(ps->Console, L"");
+	}
+
+	// Caps を取得
+	ps->CapsList = ScGetCapsEx(ps->Rpc);
+
+	if (ps->AdminHub != NULL)
+	{
+		RPC_HUB_STATUS t;
+		UINT ret;
+		wchar_t tmp[MAX_SIZE];
+
+		// ADMINHUB で指定された仮想 HUB を選択する
+		Zero(&t, sizeof(t));
+
+		StrCpy(t.HubName, sizeof(t.HubName), ps->AdminHub);
+
+		ret = ScGetHubStatus(ps->Rpc, &t);
+		if (ret == ERR_NO_ERROR)
+		{
+			// 成功
+			UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Selected"), t.HubName);
+
+			if (ps->HubName != NULL)
+			{
+				Free(ps->HubName);
+			}
+			ps->HubName = CopyStr(t.HubName);
+
+			if( ps->Console->ConsoleType != CONSOLE_CSV)
+			{
+				ps->Console->Write(ps->Console, tmp);
+			}
+		}
+		else
+		{
+			// 失敗
+			UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Select_Failed"), ps->AdminHub);
+
+			ps->Console->Write(ps->Console, tmp);
+			CmdPrintError(ps->Console, ret);
+		}
+	}
+
+	while (true)
+	{
+		// コマンドの定義
+		CMD cmd[] =
+		{
+			{"About", PsAbout},
+			{"Check", PtCheck},
+			{"Crash", PsCrash},
+			{"Flush", PsFlush},
+			{"Debug", PsDebug},
+			{"ServerInfoGet", PsServerInfoGet},
+			{"ServerStatusGet", PsServerStatusGet},
+			{"ListenerCreate", PsListenerCreate},
+			{"ListenerDelete", PsListenerDelete},
+			{"ListenerList", PsListenerList},
+			{"ListenerEnable", PsListenerEnable},
+			{"ListenerDisable", PsListenerDisable},
+			{"ServerPasswordSet", PsServerPasswordSet},
+			{"ClusterSettingGet", PsClusterSettingGet},
+			{"ClusterSettingStandalone", PsClusterSettingStandalone},
+			{"ClusterSettingController", PsClusterSettingController},
+			{"ClusterSettingMember", PsClusterSettingMember},
+			{"ClusterMemberList", PsClusterMemberList},
+			{"ClusterMemberInfoGet", PsClusterMemberInfoGet},
+			{"ClusterMemberCertGet", PsClusterMemberCertGet},
+			{"ClusterConnectionStatusGet", PsClusterConnectionStatusGet},
+			{"ServerCertGet", PsServerCertGet},
+			{"ServerKeyGet", PsServerKeyGet},
+			{"ServerCertSet", PsServerCertSet},
+			{"ServerCipherGet", PsServerCipherGet},
+			{"ServerCipherSet", PsServerCipherSet},
+			{"KeepEnable", PsKeepEnable},
+			{"KeepDisable", PsKeepDisable},
+			{"KeepSet", PsKeepSet},
+			{"KeepGet", PsKeepGet},
+			{"SyslogGet", PsSyslogGet},
+			{"SyslogDisable", PsSyslogDisable},
+			{"SyslogEnable", PsSyslogEnable},
+			{"ConnectionList", PsConnectionList},
+			{"ConnectionGet", PsConnectionGet},
+			{"ConnectionDisconnect", PsConnectionDisconnect},
+			{"BridgeDeviceList", PsBridgeDeviceList},
+			{"BridgeList", PsBridgeList},
+			{"BridgeCreate", PsBridgeCreate},
+			{"BridgeDelete", PsBridgeDelete},
+			{"Caps", PsCaps},
+			{"Reboot", PsReboot},
+			{"ConfigGet", PsConfigGet},
+			{"ConfigSet", PsConfigSet},
+			{"RouterList", PsRouterList},
+			{"RouterAdd", PsRouterAdd},
+			{"RouterDelete", PsRouterDelete},
+			{"RouterStart", PsRouterStart},
+			{"RouterStop", PsRouterStop},
+			{"RouterIfList", PsRouterIfList},
+			{"RouterIfAdd", PsRouterIfAdd},
+			{"RouterIfDel", PsRouterIfDel},
+			{"RouterTableList", PsRouterTableList},
+			{"RouterTableAdd", PsRouterTableAdd},
+			{"RouterTableDel", PsRouterTableDel},
+			{"LogFileList", PsLogFileList},
+			{"LogFileGet", PsLogFileGet},
+			{"HubCreate", PsHubCreate},
+			{"HubCreateDynamic", PsHubCreateDynamic},
+			{"HubCreateStatic", PsHubCreateStatic},
+			{"HubDelete", PsHubDelete},
+			{"HubSetStatic", PsHubSetStatic},
+			{"HubSetDynamic", PsHubSetDynamic},
+			{"HubList", PsHubList},
+			{"Hub", PsHub},
+			{"Online", PsOnline},
+			{"Offline", PsOffline},
+			{"SetMaxSession", PsSetMaxSession},
+			{"SetHubPassword", PsSetHubPassword},
+			{"SetEnumAllow", PsSetEnumAllow},
+			{"SetEnumDeny", PsSetEnumDeny},
+			{"OptionsGet", PsOptionsGet},
+			{"RadiusServerSet", PsRadiusServerSet},
+			{"RadiusServerDelete", PsRadiusServerDelete},
+			{"RadiusServerGet", PsRadiusServerGet},
+			{"StatusGet", PsStatusGet},
+			{"LogGet", PsLogGet},
+			{"LogEnable", PsLogEnable},
+			{"LogDisable", PsLogDisable},
+			{"LogSwitchSet", PsLogSwitchSet},
+			{"LogPacketSaveType", PsLogPacketSaveType},
+			{"CAList", PsCAList},
+			{"CAAdd", PsCAAdd},
+			{"CADelete", PsCADelete},
+			{"CAGet", PsCAGet},
+			{"CascadeList", PsCascadeList},
+			{"CascadeCreate", PsCascadeCreate},
+			{"CascadeSet", PsCascadeSet},
+			{"CascadeGet", PsCascadeGet},
+			{"CascadeDelete", PsCascadeDelete},
+			{"CascadeUsernameSet", PsCascadeUsernameSet},
+			{"CascadeAnonymousSet", PsCascadeAnonymousSet},
+			{"CascadePasswordSet", PsCascadePasswordSet},
+			{"CascadeCertSet", PsCascadeCertSet},
+			{"CascadeCertGet", PsCascadeCertGet},
+			{"CascadeEncryptEnable", PsCascadeEncryptEnable},
+			{"CascadeEncryptDisable", PsCascadeEncryptDisable},
+			{"CascadeCompressEnable", PsCascadeCompressEnable},
+			{"CascadeCompressDisable", PsCascadeCompressDisable},
+			{"CascadeProxyNone", PsCascadeProxyNone},
+			{"CascadeProxyHttp", PsCascadeProxyHttp},
+			{"CascadeProxySocks", PsCascadeProxySocks},
+			{"CascadeServerCertEnable", PsCascadeServerCertEnable},
+			{"CascadeServerCertDisable", PsCascadeServerCertDisable},
+			{"CascadeServerCertSet", PsCascadeServerCertSet},
+			{"CascadeServerCertDelete", PsCascadeServerCertDelete},
+			{"CascadeServerCertGet", PsCascadeServerCertGet},
+			{"CascadeDetailSet", PsCascadeDetailSet},
+			{"CascadePolicySet", PsCascadePolicySet},
+			{"PolicyList", PsPolicyList},
+			{"CascadeStatusGet", PsCascadeStatusGet},
+			{"CascadeRename", PsCascadeRename},
+			{"CascadeOnline", PsCascadeOnline},
+			{"CascadeOffline", PsCascadeOffline},
+			{"AccessAdd", PsAccessAdd},
+			{"AccessAddEx", PsAccessAddEx},
+			{"AccessAdd6", PsAccessAdd6},
+			{"AccessAddEx6", PsAccessAddEx6},
+			{"AccessList", PsAccessList},
+			{"AccessDelete", PsAccessDelete},
+			{"AccessEnable", PsAccessEnable},
+			{"AccessDisable", PsAccessDisable},
+			{"UserList", PsUserList},
+			{"UserCreate", PsUserCreate},
+			{"UserSet", PsUserSet},
+			{"UserDelete", PsUserDelete},
+			{"UserGet", PsUserGet},
+			{"UserAnonymousSet", PsUserAnonymousSet},
+			{"UserPasswordSet", PsUserPasswordSet},
+			{"UserCertSet", PsUserCertSet},
+			{"UserCertGet", PsUserCertGet},
+			{"UserSignedSet", PsUserSignedSet},
+			{"UserRadiusSet", PsUserRadiusSet},
+			{"UserNTLMSet", PsUserNTLMSet},
+			{"UserPolicyRemove", PsUserPolicyRemove},
+			{"UserPolicySet", PsUserPolicySet},
+			{"UserExpiresSet", PsUserExpiresSet},
+			{"GroupList", PsGroupList},
+			{"GroupCreate", PsGroupCreate},
+			{"GroupSet", PsGroupSet},
+			{"GroupDelete", PsGroupDelete},
+			{"GroupGet", PsGroupGet},
+			{"GroupJoin", PsGroupJoin},
+			{"GroupUnjoin", PsGroupUnjoin},
+			{"GroupPolicyRemove", PsGroupPolicyRemove},
+			{"GroupPolicySet", PsGroupPolicySet},
+			{"SessionList", PsSessionList},
+			{"SessionGet", PsSessionGet},
+			{"SessionDisconnect", PsSessionDisconnect},
+			{"MacTable", PsMacTable},
+			{"MacDelete", PsMacDelete},
+			{"IpTable", PsIpTable},
+			{"IpDelete", PsIpDelete},
+			{"SecureNatEnable", PsSecureNatEnable},
+			{"SecureNatDisable", PsSecureNatDisable},
+			{"SecureNatStatusGet", PsSecureNatStatusGet},
+			{"SecureNatHostGet", PsSecureNatHostGet},
+			{"SecureNatHostSet", PsSecureNatHostSet},
+			{"NatGet", PsNatGet},
+			{"NatEnable", PsNatEnable},
+			{"NatDisable", PsNatDisable},
+			{"NatSet", PsNatSet},
+			{"NatTable", PsNatTable},
+			{"DhcpGet", PsDhcpGet},
+			{"DhcpEnable", PsDhcpEnable},
+			{"DhcpDisable", PsDhcpDisable},
+			{"DhcpSet", PsDhcpSet},
+			{"DhcpTable", PsDhcpTable},
+			{"AdminOptionList", PsAdminOptionList},
+			{"AdminOptionSet", PsAdminOptionSet},
+			{"ExtOptionList", PsExtOptionList},
+			{"ExtOptionSet", PsExtOptionSet},
+			{"CrlList", PsCrlList},
+			{"CrlAdd", PsCrlAdd},
+			{"CrlDel", PsCrlDel},
+			{"CrlGet", PsCrlGet},
+			{"AcList", PsAcList},
+			{"AcAdd", PsAcAdd},
+			{"AcAdd6", PsAcAdd6},
+			{"AcDel", PsAcDel},
+			{"MakeCert", PtMakeCert},
+			{"TrafficClient", PtTrafficClient},
+			{"TrafficServer", PtTrafficServer},
+			{"LicenseAdd", PsLicenseAdd},
+			{"LicenseDel", PsLicenseDel},
+			{"LicenseList", PsLicenseList},
+			{"LicenseStatus", PsLicenseStatus},
+		};
+
+		// プロンプトの生成
+		if (ps->HubName == NULL)
+		{
+			Format(prompt, sizeof(prompt), "VPN Server>");
+		}
+		else
+		{
+			Format(prompt, sizeof(prompt), "VPN Server/%s>", ps->HubName);
+		}
+
+		if (DispatchNextCmdEx(ps->Console, ps->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), ps) == false)
+		{
+			break;
+		}
+		ps->LastError = ps->Console->RetCode;
+
+		if (ps->LastError == ERR_NO_ERROR && ps->Console->ConsoleType != CONSOLE_CSV)
+		{
+			ps->Console->Write(ps->Console, _UU("CMD_MSG_OK"));
+			ps->Console->Write(ps->Console, L"");
+		}
+
+		if (ps->CmdLine != NULL)
+		{
+			break;
+		}
+	}
+
+	// Caps を解放
+	FreeCapsList(ps->CapsList);
+	ps->CapsList = NULL;
+}
+
+// 新しいコマンド関数のテンプレート
+UINT PsXxx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_LISTENER t;
+	PARAM args[] =
+	{
+		{"[port]", CmdPromptPort, _UU("CMD_ListenerCreate_PortPrompt"), CmdEvalPort, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Enable = true;
+	t.Port = ToInt(GetParamStr(o, "[port]"));
+
+	ret = ScCreateListener(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// スタンドアロンモードに設定
+UINT PsClusterSettingStandalone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_FARM t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.ServerType = SERVER_TYPE_STANDALONE;
+
+	// RPC 呼び出し
+	ret = ScSetFarmSetting(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// クラスタコントローラモードに設定
+UINT PsClusterSettingController(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_FARM t;
+	UINT weight;
+	PARAM args[] =
+	{
+		{"WEIGHT", NULL, NULL, NULL, NULL},
+		{"ONLY", NULL, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	weight = GetParamInt(o, "WEIGHT");
+	if (weight == 0)
+	{
+		weight = FARM_DEFAULT_WEIGHT;
+	}
+
+	Zero(&t, sizeof(t));
+	t.ServerType = SERVER_TYPE_FARM_CONTROLLER;
+	t.Weight = weight;
+	t.ControllerOnly = GetParamYes(o, "ONLY");
+
+	// RPC 呼び出し
+	ret = ScSetFarmSetting(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// IP アドレスの評価
+bool CmdEvalIp(CONSOLE *c, wchar_t *str, void *param)
+{
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	if (UniIsEmptyStr(str))
+	{
+		return true;
+	}
+
+	if (UniStrToIP32(str) == 0 && UniStrCmpi(str, L"0.0.0.0") != 0)
+	{
+		wchar_t *msg = (param == NULL) ? _UU("CMD_IP_EVAL_FAILED") : (wchar_t *)param;
+		c->Write(c, msg);
+		return false;
+	}
+
+	return true;
+}
+
+// 文字列をポートリストに変換
+LIST *StrToPortList(char *str)
+{
+	LIST *o;
+	TOKEN_LIST *t;
+	UINT i;
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	// トークンに変換
+	t = ParseToken(str, ", ");
+	if (t == NULL)
+	{
+		return NULL;
+	}
+	if (t->NumTokens == 0)
+	{
+		FreeToken(t);
+		return NULL;
+	}
+
+	o = NewListFast(NULL);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *s = t->Token[i];
+		UINT n;
+		if (IsNum(s) == false)
+		{
+			ReleaseList(o);
+			FreeToken(t);
+			return NULL;
+		}
+		n = ToInt(s);
+		if (n == 0 || n >= 65536)
+		{
+			ReleaseList(o);
+			FreeToken(t);
+			return NULL;
+		}
+		if (IsInList(o, (void *)n))
+		{
+			ReleaseList(o);
+			FreeToken(t);
+			return NULL;
+		}
+		Add(o, (void *)n);
+	}
+
+	FreeToken(t);
+
+	if (LIST_NUM(o) > MAX_PUBLIC_PORT_NUM)
+	{
+		ReleaseList(o);
+		return NULL;
+	}
+
+	return o;
+}
+
+// クラスタメンバモードに設定
+UINT PsClusterSettingMember(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_FARM t;
+	char *host_and_port;
+	char *host;
+	UINT port;
+	UINT weight;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[server:port]", CmdPrompt, _UU("CMD_ClusterSettingMember_Prompt_HOST_1"), CmdEvalHostAndPort, NULL},
+		{"IP", PsClusterSettingMemberPromptIp, NULL, CmdEvalIp, NULL},
+		{"PORTS", PsClusterSettingMemberPromptPorts, NULL, CmdEvalPortList, NULL},
+		{"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+		{"WEIGHT", NULL, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	weight = GetParamInt(o, "WEIGHT");
+
+	if (weight == 0)
+	{
+		weight = FARM_DEFAULT_WEIGHT;
+	}
+
+	Zero(&t, sizeof(t));
+	host_and_port = GetParamStr(o, "[server:port]");
+	if (ParseHostPort(host_and_port, &host, &port, 0))
+	{
+		char *pw;
+		char *ports_str;
+		LIST *ports;
+		UINT i;
+
+		StrCpy(t.ControllerName, sizeof(t.ControllerName), host);
+		t.ControllerPort = port;
+		Free(host);
+
+		pw = GetParamStr(o, "PASSWORD");
+
+		Hash(t.MemberPassword, pw, StrLen(pw), true);
+		t.PublicIp = StrToIP32(GetParamStr(o, "IP"));
+		t.ServerType = SERVER_TYPE_FARM_MEMBER;
+
+		ports_str = GetParamStr(o, "PORTS");
+
+		ports = StrToPortList(ports_str);
+
+		t.NumPort = LIST_NUM(ports);
+		t.Ports = ZeroMalloc(sizeof(UINT) * t.NumPort);
+
+		for (i = 0;i < t.NumPort;i++)
+		{
+			t.Ports[i] = (UINT)LIST_DATA(ports, i);
+		}
+
+		t.Weight = weight;
+
+		ReleaseList(ports);
+
+		// RPC 呼び出し
+		ret = ScSetFarmSetting(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcFarm(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ポート一覧の評価
+bool CmdEvalPortList(CONSOLE *c, wchar_t *str, void *param)
+{
+	char *s;
+	bool ret = false;
+	LIST *o;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	s = CopyUniToStr(str);
+
+	o = StrToPortList(s);
+
+	if (o != NULL)
+	{
+		ret = true;
+	}
+
+	ReleaseList(o);
+
+	Free(s);
+
+	if (ret == false)
+	{
+		c->Write(c, _UU("CMD_PORTLIST_EVAL_FAILED"));
+	}
+
+	return ret;
+}
+
+// ホスト名とポート番号の形式の文字列のチェック
+bool CmdEvalHostAndPort(CONSOLE *c, wchar_t *str, void *param)
+{
+	char *tmp;
+	bool ret = false;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	tmp = CopyUniToStr(str);
+
+	ret = ParseHostPort(tmp, NULL, NULL, (UINT)param);
+
+	if (ret == false)
+	{
+		c->Write(c, param == NULL ? _UU("CMD_HOSTPORT_EVAL_FAILED") : (wchar_t *)param);
+	}
+
+	Free(tmp);
+
+	return ret;
+}
+
+// 公開 ポート番号の入力
+wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param)
+{
+	wchar_t *ret;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	c->Write(c, _UU("CMD_ClusterSettingMember_Prompt_PORT_1"));
+	c->Write(c, L"");
+
+	ret = c->ReadLine(c, _UU("CMD_ClusterSettingMember_Prompt_PORT_2"), true);
+
+	return ret;
+}
+
+// 公開 IP アドレスの入力
+wchar_t *PsClusterSettingMemberPromptIp(CONSOLE *c, void *param)
+{
+	wchar_t *ret;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	c->Write(c, _UU("CMD_ClusterSettingMember_Prompt_IP_1"));
+	c->Write(c, L"");
+
+	ret = c->ReadLine(c, _UU("CMD_ClusterSettingMember_Prompt_IP_2"), true);
+
+	return ret;
+}
+
+// クラスタメンバリストの表示
+UINT PsClusterMemberList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_FARM t;
+	CT *ct;
+	UINT i;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScEnumFarmMember(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNew();
+
+	CtInsertColumn(ct, _UU("CMD_ID"), true);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_2"), false);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_3"), false);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_4"), true);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_5"), true);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_6"), true);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_7"), true);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_8"), true);
+	CtInsertColumn(ct, _UU("SM_FM_COLUMN_9"), true);
+
+	for (i = 0;i < t.NumFarm;i++)
+	{
+		RPC_ENUM_FARM_ITEM *e = &t.Farms[i];
+		wchar_t tmp0[64];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp3[64];
+		wchar_t tmp4[64];
+		wchar_t tmp5[64];
+		wchar_t tmp6[64];
+		wchar_t tmp7[64];
+		wchar_t tmp8[64];
+
+		GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+		StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+		UniToStru(tmp3, e->Point);
+		UniToStru(tmp4, e->NumSessions);
+		UniToStru(tmp5, e->NumTcpConnections);
+		UniToStru(tmp6, e->NumHubs);
+		UniToStru(tmp7, e->AssignedClientLicense);
+		UniToStru(tmp8, e->AssignedBridgeLicense);
+
+		UniToStru(tmp0, e->Id);
+
+		CtInsert(ct, tmp0,
+			e->Controller ? _UU("SM_FM_CONTROLLER") : _UU("SM_FM_MEMBER"),
+			tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8);
+	}
+
+	CtFree(ct, c);
+
+	FreeRpcEnumFarm(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// クラスタ メンバの情報の取得
+UINT PsClusterMemberInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_FARM_INFO t;
+	CT *ct;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_ClusterMemberInfoGet_PROMPT_ID"), NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Id = UniToInt(GetParamUniStr(o, "[id]"));
+
+	// RPC 呼び出し
+	ret = ScGetFarmInfo(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNewStandard();
+
+	{
+		wchar_t tmp[MAX_SIZE];
+		char str[MAX_SIZE];
+		UINT i;
+
+		CtInsert(ct, _UU("SM_FMINFO_TYPE"),
+			t.Controller ? _UU("SM_FARM_CONTROLLER") : _UU("SM_FARM_MEMBER"));
+
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+		CtInsert(ct, _UU("SM_FMINFO_CONNECT_TIME"), tmp);
+
+		IPToStr32(str, sizeof(str), t.Ip);
+		StrToUni(tmp, sizeof(tmp), str);
+		CtInsert(ct, _UU("SM_FMINFO_IP"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), t.Hostname);
+		CtInsert(ct, _UU("SM_FMINFO_HOSTNAME"), tmp);
+
+		UniToStru(tmp, t.Point);
+		CtInsert(ct, _UU("SM_FMINFO_POINT"), tmp);
+
+		UniToStru(tmp, t.Weight);
+		CtInsert(ct, _UU("SM_FMINFO_WEIGHT"), tmp);
+
+		UniToStru(tmp, t.NumPort);
+		CtInsert(ct, _UU("SM_FMINFO_NUM_PORT"), tmp);
+
+		for (i = 0;i < t.NumPort;i++)
+		{
+			wchar_t tmp2[MAX_SIZE];
+			UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_PORT"), i + 1);
+			UniToStru(tmp2, t.Ports[i]);
+			CtInsert(ct, tmp, tmp2);
+		}
+
+		UniToStru(tmp, t.NumFarmHub);
+		CtInsert(ct, _UU("SM_FMINFO_NUM_HUB"), tmp);
+
+		for (i = 0;i < t.NumFarmHub;i++)
+		{
+			wchar_t tmp2[MAX_SIZE];
+			UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_HUB"), i + 1);
+			UniFormat(tmp2, sizeof(tmp2),
+				t.FarmHubs[i].DynamicHub ? _UU("SM_FMINFO_HUB_TAG_2") : _UU("SM_FMINFO_HUB_TAG_1"),
+				t.FarmHubs[i].HubName);
+			CtInsert(ct, tmp, tmp2);
+		}
+
+		UniToStru(tmp, t.NumSessions);
+		CtInsert(ct, _UU("SM_FMINFO_NUM_SESSION"), tmp);
+
+		UniToStru(tmp, t.NumTcpConnections);
+		CtInsert(ct, _UU("SM_FMINFO_NUN_CONNECTION"), tmp);
+	}
+
+	CtFree(ct, c);
+
+	FreeRpcFarmInfo(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// クラスタ メンバの証明書の取得
+UINT PsClusterMemberCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_FARM_INFO t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_ClusterMemberCertGet_PROMPT_ID"), NULL, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	t.Id = UniToInt(GetParamUniStr(o, "[id]"));
+
+	// RPC 呼び出し
+	ret = ScGetFarmInfo(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		X *x = t.ServerCert;
+		char *filename = GetParamStr(o, "SAVECERT");
+
+		if (XToFile(x, filename, true) == false)
+		{
+			c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+
+			ret = ERR_INTERNAL_ERROR;
+		}
+	}
+
+	FreeRpcFarmInfo(&t);
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// クラスタ コントローラへの接続状態の取得
+UINT PsClusterConnectionStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_FARM_CONNECTION_STATUS t;
+	wchar_t tmp[MAX_SIZE];
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetFarmConnectionStatus(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNewStandard();
+		char str[MAX_SIZE];
+
+		if (t.Online == false)
+		{
+			CtInsert(ct, _UU("SM_FC_IP"), _UU("SM_FC_NOT_CONNECTED"));
+
+			CtInsert(ct, _UU("SM_FC_PORT"), _UU("SM_FC_NOT_CONNECTED"));
+		}
+		else
+		{
+			IPToStr32(str, sizeof(str), t.Ip);
+			StrToUni(tmp, sizeof(tmp), str);
+			CtInsert(ct, _UU("SM_FC_IP"), tmp);
+
+			UniToStru(tmp, t.Port);
+			CtInsert(ct, _UU("SM_FC_PORT"), tmp);
+		}
+
+		CtInsert(ct,
+			_UU("SM_FC_STATUS"),
+			t.Online ? _UU("SM_FC_ONLINE") : _UU("SM_FC_OFFLINE"));
+
+		if (t.Online == false)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("SM_FC_ERROR_TAG"), _E(t.LastError), t.LastError);
+			CtInsert(ct,
+				_UU("SM_FC_LAST_ERROR"), tmp);
+		}
+
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartedTime), NULL);
+		CtInsert(ct, _UU("SM_FC_START_TIME"), tmp);
+
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.FirstConnectedTime), NULL);
+		CtInsert(ct, _UU("SM_FC_FIRST_TIME"), tmp);
+
+		//if (t.Online == false)
+		{
+			GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CurrentConnectedTime), NULL);
+			CtInsert(ct, _UU("SM_FC_CURRENT_TIME"), tmp);
+		}
+
+		UniToStru(tmp, t.NumTry);
+		CtInsert(ct, _UU("SM_FC_NUM_TRY"), tmp);
+
+		UniToStru(tmp, t.NumConnected);
+		CtInsert(ct, _UU("SM_FC_NUM_CONNECTED"), tmp);
+
+		UniToStru(tmp, t.NumFailed);
+		CtInsert(ct, _UU("SM_FC_NUM_FAILED"), tmp);
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// VPN Server の SSL 証明書の取得
+UINT PsServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_KEY_PAIR t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[cert]", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetServerCert(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	if (XToFile(t.Cert, GetParamStr(o, "[cert]"), true) == false)
+	{
+		c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+	}
+
+	FreeRpcKeyPair(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// VPN Server の SSL 証明書の秘密鍵の取得
+UINT PsServerKeyGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_KEY_PAIR t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[key]", CmdPrompt, _UU("CMD_SAVEKEYPATH"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetServerCert(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	if (t.Key != NULL)
+	{
+		if (KToFile(t.Key, GetParamStr(o, "[key]"), true, NULL) == false)
+		{
+			c->Write(c, _UU("CMD_SAVEKEY_FAILED"));
+		}
+	}
+	else
+	{
+		ret = ERR_NOT_ENOUGH_RIGHT;
+		CmdPrintError(c, ret);
+	}
+
+	FreeRpcKeyPair(&t);
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 証明書と秘密鍵の読み込み
+bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, char *cert_filename, char *key_filename)
+{
+	X *x;
+	K *k;
+	// 引数チェック
+	if (c == NULL || cert_filename == NULL || key_filename == NULL || xx == NULL || kk == NULL)
+	{
+		return false;
+	}
+
+	x = FileToX(cert_filename);
+	if (x == NULL)
+	{
+		c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+		return false;
+	}
+
+	k = CmdLoadKey(c, key_filename);
+	if (k == NULL)
+	{
+		c->Write(c, _UU("CMD_LOADKEY_FAILED"));
+		FreeX(x);
+		return false;
+	}
+
+	if (CheckXandK(x, k) == false)
+	{
+		c->Write(c, _UU("CMD_KEYPAIR_FAILED"));
+		FreeX(x);
+		FreeK(k);
+
+		return false;
+	}
+
+	*xx = x;
+	*kk = k;
+
+	return true;
+}
+
+// 秘密鍵の読み込み
+K *CmdLoadKey(CONSOLE *c, char *filename)
+{
+	BUF *b;
+	// 引数チェック
+	if (c == NULL || filename == NULL)
+	{
+		return NULL;
+	}
+
+	b = ReadDump(filename);
+	if (b == NULL)
+	{
+		c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+		return NULL;
+	}
+	else
+	{
+		K *key;
+		if (IsEncryptedK(b, true) == false)
+		{
+			key = BufToK(b, true, IsBase64(b), NULL);
+		}
+		else
+		{
+			c->Write(c, _UU("CMD_LOADKEY_ENCRYPTED_1"));
+
+			while (true)
+			{
+				char *pass = c->ReadPassword(c, _UU("CMD_LOADKEY_ENCRYPTED_2"));
+
+				if (pass == NULL)
+				{
+					FreeBuf(b);
+					return NULL;
+				}
+
+				key = BufToK(b, true, IsBase64(b), pass);
+				Free(pass);
+
+				if (key != NULL)
+				{
+					break;
+				}
+
+				c->Write(c, _UU("CMD_LOADKEY_ENCRYPTED_3"));
+			}
+		}
+
+		FreeBuf(b);
+
+		return key;
+	}
+}
+
+// VPN Server の SSL 証明書と秘密鍵の設定
+UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_KEY_PAIR t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+		{"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	if (CmdLoadCertAndKey(c, &t.Cert, &t.Key,
+		GetParamStr(o, "LOADCERT"),
+		GetParamStr(o, "LOADKEY")))
+	{
+		// RPC 呼び出し
+		ret = ScSetServerCert(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcKeyPair(&t);
+	}
+	else
+	{
+		ret = ERR_INTERNAL_ERROR;
+	}
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN 通信で使用される暗号化アルゴリズムの取得
+UINT PsServerCipherGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_STR t;
+	TOKEN_LIST *ciphers;
+	UINT i;
+	wchar_t tmp[MAX_SIZE];
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetServerCipher(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ciphers = GetCipherList();
+
+	c->Write(c, _UU("CMD_ServerCipherGet_SERVER"));
+
+	UniFormat(tmp, sizeof(tmp), L" %S", t.String);
+	c->Write(c, tmp);
+
+	c->Write(c, L"");
+	c->Write(c, _UU("CMD_ServerCipherGet_CIPHERS"));
+
+	for (i = 0;i < ciphers->NumTokens;i++)
+	{
+		UniFormat(tmp, sizeof(tmp), L" %S", ciphers->Token[i]);
+		c->Write(c, tmp);
+	}
+
+	FreeRpcStr(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// VPN 通信で使用される暗号化アルゴリズムの設定
+UINT PsServerCipherSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_STR t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_ServerCipherSet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.String = CopyStr(GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScSetServerCipher(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcStr(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// インターネット接続の維持機能の有効化
+UINT PsKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_KEEP t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetKeep(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	t.UseKeepConnect = true;
+
+	ret = ScSetKeep(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// インターネット接続の維持機能の無効化
+UINT PsKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_KEEP t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetKeep(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	t.UseKeepConnect = false;
+
+	ret = ScSetKeep(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// tcp または udp の評価
+bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param)
+{
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	if (UniStrCmpi(str, L"tcp") == 0 || UniStrCmpi(str, L"udp") == 0)
+	{
+		return true;
+	}
+
+	c->Write(c, _UU("CMD_KeepSet_EVAL_TCP_UDP"));
+
+	return false;
+}
+
+// syslog 設定の有効化
+UINT PsSyslogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	SYSLOG_SETTING t;
+	CMD_EVAL_MIN_MAX minmax = {"CMD_SyslogEnable_MINMAX", 1, 3};
+	char *host;
+	UINT port;
+
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[1|2|3]", CmdPrompt, _UU("CMD_SyslogEnable_Prompt_123"), CmdEvalMinMax, &minmax},
+		{"HOST", CmdPrompt, _UU("CMD_SyslogEnable_Prompt_HOST"), CmdEvalHostAndPort, (void *)SYSLOG_PORT},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, SYSLOG_PORT))
+	{
+		StrCpy(t.Hostname, sizeof(t.Hostname), host);
+		t.Port = port;
+		t.SaveType = GetParamInt(o, "[1|2|3]");
+
+		Free(host);
+
+		// RPC 呼び出し
+		ret = ScSetSysLog(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// syslog 設定の無効化
+UINT PsSyslogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	SYSLOG_SETTING t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetSysLog(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	t.SaveType = SYSLOG_NONE;
+
+	// RPC 呼び出し
+	ret = ScSetSysLog(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// syslog 設定の取得
+UINT PsSyslogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	SYSLOG_SETTING t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetSysLog(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		CT *ct = CtNewStandard();
+
+		CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_1"), GetSyslogSettingName(t.SaveType));
+
+		if (t.SaveType != SYSLOG_NONE)
+		{
+			StrToUni(tmp, sizeof(tmp), t.Hostname);
+			CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_2"), tmp);
+
+			UniToStru(tmp, t.Port);
+			CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_3"), tmp);
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// syslog 設定名を取得
+wchar_t *GetSyslogSettingName(UINT n)
+{
+	char tmp[MAX_PATH];
+
+	Format(tmp, sizeof(tmp), "SM_SYSLOG_%u", n);
+
+	return _UU(tmp);
+}
+
+// インターネット接続の維持機能の設定
+UINT PsKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_KEEP t;
+	char *host;
+	UINT port;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"HOST", CmdPrompt, _UU("CMD_KeepSet_PROMPT_HOST"), CmdEvalHostAndPort, NULL},
+		{"PROTOCOL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_PROTOCOL"), CmdEvalTcpOrUdp, NULL},
+		{"INTERVAL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_INTERVAL"), NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetKeep(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, 0))
+	{
+		StrCpy(t.KeepConnectHost, sizeof(t.KeepConnectHost), host);
+		t.KeepConnectPort = port;
+		t.KeepConnectInterval = GetParamInt(o, "INTERVAL");
+		t.KeepConnectProtocol = (StrCmpi(GetParamStr(o, "PROTOCOL"), "tcp") == 0) ? 0 : 1;
+		Free(host);
+
+		// RPC 呼び出し
+		ret = ScSetKeep(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// インターネット接続の維持機能の取得
+UINT PsKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_KEEP t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetKeep(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		CT *ct = CtNewStandard();
+
+		StrToUni(tmp, sizeof(tmp), t.KeepConnectHost);
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_1"), tmp);
+
+		UniToStru(tmp, t.KeepConnectPort);
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_2"), tmp);
+
+		UniToStru(tmp, t.KeepConnectInterval);
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_3"), tmp);
+
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_4"),
+			t.KeepConnectProtocol == 0 ? L"TCP/IP" : L"UDP/IP");
+
+		CtInsert(ct, _UU("CMD_KeepGet_COLUMN_5"),
+			t.UseKeepConnect ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"));
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// コネクション種類文字列の取得
+wchar_t *GetConnectionTypeStr(UINT type)
+{
+	char tmp[MAX_SIZE];
+	Format(tmp, sizeof(tmp), "SM_CONNECTION_TYPE_%u", type);
+
+	return _UU(tmp);
+}
+
+// VPN Server に接続中の TCP コネクション一覧の取得
+UINT PsConnectionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_CONNECTION t;
+	UINT i;
+	CT *ct;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScEnumConnection(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNew();
+	CtInsertColumn(ct, _UU("SM_CONN_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("SM_CONN_COLUMN_2"), false);
+	CtInsertColumn(ct, _UU("SM_CONN_COLUMN_3"), false);
+	CtInsertColumn(ct, _UU("SM_CONN_COLUMN_4"), false);
+
+	for (i = 0;i < t.NumConnection;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		wchar_t name[MAX_SIZE];
+		wchar_t datetime[MAX_SIZE];
+		RPC_ENUM_CONNECTION_ITEM *e = &t.Connections[i];
+
+		StrToUni(name, sizeof(name), e->Name);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_HOSTNAME_AND_PORT"), e->Hostname, e->Port);
+		GetDateTimeStrEx64(datetime, sizeof(datetime), SystemToLocal64(e->ConnectedTime), NULL);
+
+		CtInsert(ct, name, tmp, datetime,
+			GetConnectionTypeStr(e->Type));
+	}
+
+	CtFree(ct, c);
+
+	FreeRpcEnumConnetion(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// VPN Server に接続中の TCP コネクションの情報の取得
+UINT PsConnectionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CONNECTION_INFO t;
+	CT *ct;
+	wchar_t tmp[MAX_SIZE];
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_ConnectionGet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetConnectionInfo(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		ct = CtNewStandard();
+
+		StrToUni(tmp, sizeof(tmp), t.Name);
+		CtInsert(ct, _UU("SM_CONNINFO_NAME"), tmp);
+
+		CtInsert(ct, _UU("SM_CONNINFO_TYPE"), GetConnectionTypeStr(t.Type));
+
+		StrToUni(tmp, sizeof(tmp), t.Hostname);
+		CtInsert(ct, _UU("SM_CONNINFO_HOSTNAME"), tmp);
+
+		UniToStru(tmp, t.Port);
+		CtInsert(ct, _UU("SM_CONNINFO_PORT"), tmp);
+
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+		CtInsert(ct, _UU("SM_CONNINFO_TIME"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), t.ServerStr);
+		CtInsert(ct, _UU("SM_CONNINFO_SERVER_STR"), tmp);
+
+		UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ServerVer / 100, t.ServerVer % 100);
+		CtInsert(ct, _UU("SM_CONNINFO_SERVER_VER"), tmp);
+
+		UniToStru(tmp, t.ServerBuild);
+		CtInsert(ct, _UU("SM_CONNINFO_SERVER_BUILD"), tmp);
+
+		if (StrLen(t.ClientStr) != 0)
+		{
+			StrToUni(tmp, sizeof(tmp), t.ClientStr);
+			CtInsert(ct, _UU("SM_CONNINFO_CLIENT_STR"), tmp);
+
+			UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ClientVer / 100, t.ClientVer % 100);
+			CtInsert(ct, _UU("SM_CONNINFO_CLIENT_VER"), tmp);
+
+			UniToStru(tmp, t.ClientBuild);
+			CtInsert(ct, _UU("SM_CONNINFO_CLIENT_BUILD"), tmp);
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// VPN Server に接続中の TCP コネクションの切断
+UINT PsConnectionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_DISCONNECT_CONNECTION t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_ConnectionDisconnect_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScDisconnectConnection(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ローカル ブリッジに使用できる LAN カード一覧の取得
+UINT PsBridgeDeviceList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_ETH t;
+	UINT i;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScEnumEthernet(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_ETH_ITEM *item = &t.Items[i];
+		wchar_t tmp[MAX_SIZE * 2];
+
+		if(UniIsEmptyStr(item->NetworkConnectionName) == false)
+		{
+			UniFormat(tmp, sizeof(tmp), BRIDGE_NETWORK_CONNECTION_STR, item->NetworkConnectionName, item->DeviceName);
+		}
+		else
+		{
+			StrToUni(tmp, sizeof(tmp), item->DeviceName);
+		}
+		c->Write(c, tmp);
+	}
+
+	FreeRpcEnumEth(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ローカル ブリッジ接続の一覧の取得
+UINT PsBridgeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_LOCALBRIDGE t;
+	UINT i;
+	CT *ct;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScEnumLocalBridge(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNew();
+
+	CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_2"), false);
+	CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_3"), false);
+	CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_4"), false);
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_LOCALBRIDGE *e = &t.Items[i];
+		wchar_t name[MAX_SIZE];
+		wchar_t nic[MAX_SIZE];
+		wchar_t hub[MAX_SIZE];
+		wchar_t *status = _UU("SM_BRIDGE_OFFLINE");
+
+		UniToStru(name, i + 1);
+		StrToUni(nic, sizeof(nic), e->DeviceName);
+		StrToUni(hub, sizeof(hub), e->HubName);
+
+		if (e->Online)
+		{
+			status = e->Active ? _UU("SM_BRIDGE_ONLINE") : _UU("SM_BRIDGE_ERROR");
+		}
+
+		CtInsert(ct, name, hub, nic, status);
+	}
+
+	CtFree(ct, c);
+
+	FreeRpcEnumLocalBridge(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ローカル ブリッジ接続の作成
+UINT PsBridgeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_LOCALBRIDGE t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[hubname]", CmdPrompt, _UU("CMD_BridgeCreate_PROMPT_HUBNAME"), CmdEvalNotEmpty, NULL},
+		{"DEVICE", CmdPrompt, _UU("CMD_BridgeCreate_PROMPT_DEVICE"), CmdEvalNotEmpty, NULL},
+		{"TAP", NULL, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	t.Active = true;
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "DEVICE"));
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[hubname]"));
+	t.Online = true;
+	t.TapMode = GetParamYes(o, "TAP");
+
+	// RPC 呼び出し
+	ret = ScAddLocalBridge(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		c->Write(c, _UU("SM_BRIDGE_INTEL"));
+		c->Write(c, L"");
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ローカル ブリッジ接続の削除
+UINT PsBridgeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_LOCALBRIDGE t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[hubname]", CmdPrompt, _UU("CMD_BridgeDelete_PROMPT_HUBNAME"), CmdEvalNotEmpty, NULL},
+		{"DEVICE", CmdPrompt, _UU("CMD_BridgeDelete_PROMPT_DEVICE"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "DEVICE"));
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[hubname]"));
+
+	// RPC 呼び出し
+	ret = ScDeleteLocalBridge(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// サーバーの機能・能力一覧の取得
+UINT PsCaps(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	CAPSLIST *t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// RPC 呼び出し
+	t = ScGetCapsEx(ps->Rpc);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		CT *ct;
+
+		ct = CtNewStandard();
+
+		for (i = 0;i < LIST_NUM(t->CapsList);i++)
+		{
+			CAPS *c = LIST_DATA(t->CapsList, i);
+			wchar_t title[MAX_SIZE];
+			char name[256];
+
+			Format(name, sizeof(name), "CT_%s", c->Name);
+
+			UniStrCpy(title, sizeof(title), _UU(name));
+
+			if (UniIsEmptyStr(title))
+			{
+				UniFormat(title, sizeof(title), L"%S", (StrLen(c->Name) >= 2) ? c->Name + 2 : c->Name);
+			}
+
+			if (StartWith(c->Name, "b_"))
+			{
+				bool icon_pass = c->Value == 0 ? false : true;
+				if (StrCmpi(c->Name, "b_must_install_pcap") == 0)
+				{
+					// WinPcap の項目のみ反転する
+					icon_pass = !icon_pass;
+				}
+				CtInsert(ct, title, c->Value == 0 ? _UU("CAPS_NO") : _UU("CAPS_YES"));
+			}
+			else
+			{
+				wchar_t str[64];
+				UniToStru(str, c->Value);
+				CtInsert(ct, title, str);
+			}
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeCapsList(t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// VPN Server サービスの再起動
+UINT PsReboot(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_TEST t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"RESETCONFIG", NULL, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	t.IntValue = GetParamYes(o, "RESETCONFIG") ? 1 : 0;
+
+	// RPC 呼び出し
+	ret = ScRebootServer(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcTest(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// VPN Server の現在のコンフィグレーションの取得
+UINT PsConfigGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CONFIG t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[path]", NULL, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScGetConfig(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		char *filename = GetParamStr(o, "[path]");
+
+		if (IsEmptyStr(filename))
+		{
+			// 画面に表示
+			wchar_t tmp[MAX_SIZE];
+			UINT buf_size;
+			wchar_t *buf;
+
+			UniFormat(tmp, sizeof(tmp), _UU("CMD_ConfigGet_FILENAME"), t.FileName,
+				StrLen(t.FileData));
+			c->Write(c, tmp);
+			c->Write(c, L"");
+
+			buf_size = CalcUtf8ToUni((BYTE *)t.FileData, StrLen(t.FileData));
+			buf = ZeroMalloc(buf_size + 32);
+
+			Utf8ToUni(buf, buf_size, (BYTE *)t.FileData, StrLen(t.FileData));
+
+			c->Write(c, buf);
+			c->Write(c, L"");
+
+			Free(buf);
+		}
+		else
+		{
+			// ファイルに保存
+			IO *io = FileCreate(filename);
+
+			if (io == NULL)
+			{
+				c->Write(c, _UU("CMD_ConfigGet_FILE_SAVE_FAILED"));
+
+				ret = ERR_INTERNAL_ERROR;
+			}
+			else
+			{
+				FileWrite(io, t.FileData, StrLen(t.FileData));
+				FileClose(io);
+			}
+		}
+	}
+
+	FreeRpcConfig(&t);
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// VPN Server へのコンフィグレーションの書き込み
+UINT PsConfigSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CONFIG t;
+	char *filename;
+	BUF *buf;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[path]", CmdPrompt, _UU("CMD_ConfigSet_PROMPT_PATH"), CmdEvalIsFile, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	filename = GetParamStr(o, "[path]");
+
+	buf = ReadDump(filename);
+	if (buf == NULL)
+	{
+		c->Write(c, _UU("CMD_ConfigSet_FILE_LOAD_FAILED"));
+	}
+	else
+	{
+		Zero(&t, sizeof(t));
+
+		t.FileData = ZeroMalloc(buf->Size + 1);
+		Copy(t.FileData, buf->Buf, buf->Size);
+		FreeBuf(buf);
+
+		// RPC 呼び出し
+		ret = ScSetConfig(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcConfig(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチ一覧の取得
+UINT PsRouterList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_L3SW t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScEnumL3Switch(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+		UINT i;
+
+		CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN1"), false);
+		CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN2"), false);
+		CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN3"), true);
+		CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN4"), true);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+			wchar_t tmp1[MAX_SIZE], *tmp2, tmp3[64], tmp4[64];
+
+			StrToUni(tmp1, sizeof(tmp1), e->Name);
+			if (e->Active == false)
+			{
+				tmp2 = _UU("SM_L3_SW_ST_F_F");
+			}
+			else if (e->Online == false)
+			{
+				tmp2 = _UU("SM_L3_SW_ST_T_F");
+			}
+			else
+			{
+				tmp2 = _UU("SM_L3_SW_ST_T_T");
+			}
+			UniToStru(tmp3, e->NumInterfaces);
+			UniToStru(tmp4, e->NumTables);
+
+			CtInsert(ct,
+				tmp1, tmp2, tmp3, tmp4);
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeRpcEnumL3Sw(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 新しい仮想レイヤ 3 スイッチの定義
+UINT PsRouterAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_L3SW t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScAddL3Switch(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチの削除
+UINT PsRouterDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_L3SW t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterDelete_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScDelL3Switch(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチの動作の開始
+UINT PsRouterStart(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_L3SW t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterStart_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScStartL3Switch(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチの動作の停止
+UINT PsRouterStop(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_L3SW t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterStop_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScStopL3Switch(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチに登録されているインターフェイス一覧の取得
+UINT PsRouterIfList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_L3IF t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterIfList_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScEnumL3If(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp3[MAX_SIZE];
+		CT *ct = CtNew();
+
+		CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN1"), false);
+		CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN2"), false);
+		CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN3"), false);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_L3IF *e = &t.Items[i];
+
+			IPToUniStr32(tmp1, sizeof(tmp1), e->IpAddress);
+			IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+			StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+			CtInsert(ct, tmp1, tmp2, tmp3);
+		}
+
+
+		CtFree(ct, c);
+	}
+
+	FreeRpcEnumL3If(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// IP アドレスとマスクの評価
+bool CmdEvalIpAndMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[MAX_SIZE];
+	UINT ip, mask;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if (ParseIpAndMask4(tmp, &ip, &mask) == false)
+	{
+		c->Write(c, _UU("CMD_PARSE_IP_MASK_ERROR_1"));
+		return false;
+	}
+
+	return true;
+}
+bool CmdEvalIpAndMask6(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[MAX_SIZE];
+	IP ip, mask;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if (ParseIpAndMask6(tmp, &ip, &mask) == false)
+	{
+		c->Write(c, _UU("CMD_PARSE_IP_MASK_ERROR_1_6"));
+		return false;
+	}
+
+	return true;
+}
+bool CmdEvalIpAndMask46(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[MAX_SIZE];
+	TOKEN_LIST *t;
+	bool ret = false;
+
+	Zero(tmp, sizeof(tmp));
+	UniToStr(tmp, sizeof(tmp), str);
+
+	t = ParseToken(tmp, "/");
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	if (t->NumTokens >= 1)
+	{
+		Trim(t->Token[0]);
+
+		if (IsIpStr4(t->Token[0]))
+		{
+			ret = CmdEvalIpAndMask4(c, str, param);
+		}
+		else
+		{
+			ret = CmdEvalIpAndMask6(c, str, param);
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// ネットワークアドレスとサブネットマスクの評価
+bool CmdEvalNetworkAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[MAX_SIZE];
+	UINT ip, mask;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if (ParseIpAndSubnetMask4(tmp, &ip, &mask) == false)
+	{
+		c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1"));
+		return false;
+	}
+
+	if (IsNetworkAddress32(ip, mask) == false)
+	{
+		c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_2"));
+		return false;
+	}
+
+	return true;
+}
+bool CmdEvalNetworkAndSubnetMask6(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[MAX_SIZE];
+	IP ip, mask;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if (ParseIpAndSubnetMask6(tmp, &ip, &mask) == false)
+	{
+		c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1_6"));
+		return false;
+	}
+
+	if (IsNetworkPrefixAddress6(&ip, &mask) == false)
+	{
+		c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_3"));
+		return false;
+	}
+
+	return true;
+}
+bool CmdEvalNetworkAndSubnetMask46(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[MAX_SIZE];
+	TOKEN_LIST *t;
+	bool ret = false;
+
+	Zero(tmp, sizeof(tmp));
+	UniToStr(tmp, sizeof(tmp), str);
+
+	t = ParseToken(tmp, "/");
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	if (t->NumTokens >= 1)
+	{
+		Trim(t->Token[0]);
+
+		if (IsIpStr4(t->Token[0]))
+		{
+			ret = CmdEvalNetworkAndSubnetMask4(c, str, param);
+		}
+		else
+		{
+			ret = CmdEvalNetworkAndSubnetMask6(c, str, param);
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// IP アドレスとサブネットマスクの評価
+bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if (ParseIpAndSubnetMask4(tmp, NULL, NULL) == false)
+	{
+		c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1"));
+		return false;
+	}
+
+	return true;
+}
+
+// 仮想レイヤ 3 スイッチへの仮想インターフェイスの追加
+UINT PsRouterIfAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_L3IF t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"HUB", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_HUB"), CmdEvalNotEmpty, NULL},
+		{"IP", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_IP"), CmdEvalHostAndSubnetMask4, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+	ParseIpAndSubnetMask4(GetParamStr(o, "IP"), &t.IpAddress, &t.SubnetMask);
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "HUB"));
+
+	// RPC 呼び出し
+	ret = ScAddL3If(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチの仮想インターフェイスの削除
+UINT PsRouterIfDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_L3IF t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"HUB", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_HUB"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "HUB"));
+
+	// RPC 呼び出し
+	ret = ScDelL3If(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチのルーティング テーブル一覧の取得
+UINT PsRouterTableList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_L3TABLE t;
+	CT *ct;
+	wchar_t tmp1[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	wchar_t tmp3[MAX_SIZE];
+	wchar_t tmp4[MAX_SIZE];
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_RouterTableList_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScEnumL3Table(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+
+		ct = CtNew();
+
+		CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN1"), false);
+		CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN2"), false);
+		CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN3"), false);
+		CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN4"), true);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_L3TABLE *e = &t.Items[i];
+
+			IPToUniStr32(tmp1, sizeof(tmp1), e->NetworkAddress);
+			IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+			IPToUniStr32(tmp3, sizeof(tmp3), e->GatewayAddress);
+			UniToStru(tmp4, e->Metric);
+
+			CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeRpcEnumL3Table(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチへのルーティング テーブル エントリの追加
+UINT PsRouterTableAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_L3TABLE t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"NETWORK", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NETWORK"), CmdEvalNetworkAndSubnetMask4, NULL},
+		{"GATEWAY", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_GATEWAY"), CmdEvalIp, NULL},
+		{"METRIC", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_METRIC"), CmdEvalInt1, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+	ParseIpAndSubnetMask4(GetParamStr(o, "NETWORK"), &t.NetworkAddress, &t.SubnetMask);
+	t.Metric = GetParamInt(o, "METRIC");
+	t.GatewayAddress = StrToIP32(GetParamStr(o, "GATEWAY"));
+
+	// RPC 呼び出し
+	ret = ScAddL3Table(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想レイヤ 3 スイッチのルーティング テーブル エントリの削除
+UINT PsRouterTableDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_L3TABLE t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"NETWORK", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NETWORK"), CmdEvalNetworkAndSubnetMask4, NULL},
+		{"GATEWAY", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_GATEWAY"), CmdEvalIp, NULL},
+		{"METRIC", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_METRIC"), CmdEvalInt1, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+	ParseIpAndSubnetMask4(GetParamStr(o, "NETWORK"), &t.NetworkAddress, &t.SubnetMask);
+	t.Metric = GetParamInt(o, "METRIC");
+	t.GatewayAddress = StrToIP32(GetParamStr(o, "GATEWAY"));
+
+	// RPC 呼び出し
+	ret = ScDelL3Table(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ログ ファイル一覧の取得
+UINT PsLogFileList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_LOG_FILE t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	c->Write(c, _UU("CMD_LogFileList_START"));
+	c->Write(c, L"");
+
+	// RPC 呼び出し
+	ret = ScEnumLogFile(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		wchar_t tmp[MAX_SIZE];
+		CT *ct;
+
+		UniFormat(tmp, sizeof(tmp), _UU("CMD_LogFileList_NUM_LOGS"), t.NumItem);
+		c->Write(c, tmp);
+
+		ct = CtNew();
+
+		CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_2"), true);
+		CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_4"), false);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_ENUM_LOG_FILE_ITEM *e = &t.Items[i];
+			wchar_t tmp1[MAX_PATH], tmp2[128], tmp3[128], tmp4[MAX_HOST_NAME_LEN + 1];
+			char tmp[MAX_SIZE];
+
+			StrToUni(tmp1, sizeof(tmp1), e->FilePath);
+
+			ToStrByte(tmp, sizeof(tmp), e->FileSize);
+			StrToUni(tmp2, sizeof(tmp2), tmp);
+
+			GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->UpdatedTime));
+
+			StrToUni(tmp4, sizeof(tmp4), e->ServerName);
+
+			CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumLogFile(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ログ ファイルのダウンロード
+UINT PsLogFileGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	BUF *buf;
+	char *filename = NULL;
+	char *server_name;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_LogFileGet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"SERVER", NULL, NULL, NULL, NULL},
+		{"SAVEPATH", NULL, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	filename = GetParamStr(o, "SAVE");
+
+	c->Write(c, _UU("CMD_LogFileGet_START"));
+
+	server_name = GetParamStr(o, "SERVER");
+
+	buf = DownloadFileFromServer(ps->Rpc, server_name,
+		GetParamStr(o, "[name]"), 0, NULL, NULL);
+
+	if (buf == NULL)
+	{
+		c->Write(c, _UU("CMD_LogFileGet_FAILED"));
+
+		ret = ERR_INTERNAL_ERROR;
+	}
+	else
+	{
+		if (IsEmptyStr(filename) == false)
+		{
+			// ファイルに保存
+			if (DumpBuf(buf, filename) == false)
+			{
+				ret = ERR_INTERNAL_ERROR;
+				c->Write(c, _UU("CMD_LogFileGet_SAVE_FAILED"));
+			}
+		}
+		else
+		{
+			// 画面に表示
+			wchar_t tmp[MAX_SIZE];
+			UINT buf_size;
+			wchar_t *uni_buf;
+
+			UniFormat(tmp, sizeof(tmp), _UU("CMD_LogFileGet_FILESIZE"),
+				buf->Size);
+			c->Write(c, tmp);
+			c->Write(c, L"");
+
+			buf_size = CalcUtf8ToUni((BYTE *)buf->Buf, buf->Size);
+			uni_buf = ZeroMalloc(buf_size + 32);
+
+			Utf8ToUni(uni_buf, buf_size, (BYTE *)buf->Buf, buf->Size);
+
+			c->Write(c, uni_buf);
+			c->Write(c, L"");
+
+			Free(uni_buf);
+		}
+
+		FreeBuf(buf);
+	}
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 新しい仮想 HUB の作成
+UINT PsHubCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+	char *pass = "";
+	UINT hub_type = HUB_TYPE_STANDALONE;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+	else
+	{
+		RPC_SERVER_INFO t;
+		Zero(&t, sizeof(t));
+		if (ScGetServerInfo(ps->Rpc, &t) == ERR_NO_ERROR)
+		{
+			if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+			{
+				hub_type = HUB_TYPE_FARM_DYNAMIC;
+			}
+			FreeRpcServerInfo(&t);
+		}
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+	t.HubType = hub_type;
+
+	if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+	{
+		pass = GetParamStr(o, "PASSWORD");
+	}
+
+	Hash(t.HashedPassword, pass, StrLen(pass), true);
+	HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+	t.Online = true;
+
+	// RPC 呼び出し
+	ret = ScCreateHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 新しい仮想 HUB の作成 (ダイナミックモード)
+UINT PsHubCreateDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+	char *pass = "";
+	UINT hub_type = HUB_TYPE_FARM_DYNAMIC;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+	t.HubType = hub_type;
+
+	if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+	{
+		pass = GetParamStr(o, "PASSWORD");
+	}
+
+	Hash(t.HashedPassword, pass, StrLen(pass), true);
+	HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+	t.Online = true;
+
+	// RPC 呼び出し
+	ret = ScCreateHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 新しい仮想 HUB の作成 (スタティックモード)
+UINT PsHubCreateStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+	char *pass = "";
+	UINT hub_type = HUB_TYPE_FARM_STATIC;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+		{"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+	t.HubType = hub_type;
+
+	if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+	{
+		pass = GetParamStr(o, "PASSWORD");
+	}
+
+	Hash(t.HashedPassword, pass, StrLen(pass), true);
+	HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+	t.Online = true;
+
+	// RPC 呼び出し
+	ret = ScCreateHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB の削除
+UINT PsHubDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_DELETE_HUB t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_HubDelete_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScDeleteHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB をスタティックにする
+UINT PsHubSetStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_HubChange_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+	// まず現在の設定を取得する
+	ret = ScGetHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 設定を変更する
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+	t.HubType = HUB_TYPE_FARM_STATIC;
+
+	// 書き込む
+	ret = ScSetHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB の種類をダイナミック仮想 HUB に変更
+UINT PsHubSetDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_HubChange_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+	// まず現在の設定を取得する
+	ret = ScGetHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 設定を変更する
+	StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+	t.HubType = HUB_TYPE_FARM_DYNAMIC;
+
+	// 書き込む
+	ret = ScSetHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB の一覧の取得
+UINT PsHubList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_HUB t;
+	UINT i;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScEnumHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_2"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_4"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_5"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_6"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_7"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_8"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_9"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_10"), false);
+		CtInsertColumn(ct, _UU("SM_HUB_COLUMN_11"), false);
+
+		for (i = 0;i < t.NumHub;i++)
+		{
+			RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+			wchar_t name[MAX_HUBNAME_LEN + 1];
+			wchar_t s1[64], s2[64], s3[64], s4[64], s5[64];
+			wchar_t s6[64], s7[128], s8[128];
+			UniToStru(s1, e->NumUsers);
+			UniToStru(s2, e->NumGroups);
+			UniToStru(s3, e->NumSessions);
+			UniToStru(s4, e->NumMacTables);
+			UniToStru(s5, e->NumIpTables);
+
+			UniToStru(s6, e->NumLogin);
+
+			if (e->LastLoginTime != 0)
+			{
+				GetDateTimeStr64Uni(s7, sizeof(s7), SystemToLocal64(e->LastLoginTime));
+			}
+			else
+			{
+				UniStrCpy(s7, sizeof(s7), _UU("COMMON_UNKNOWN"));
+			}
+
+			if (e->LastCommTime != 0)
+			{
+				GetDateTimeStr64Uni(s8, sizeof(s8), SystemToLocal64(e->LastCommTime));
+			}
+			else
+			{
+				UniStrCpy(s8, sizeof(s8), _UU("COMMON_UNKNOWN"));
+			}
+
+			StrToUni(name, sizeof(name), e->HubName);
+
+			CtInsert(ct,
+				name,
+				e->Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"),
+				GetHubTypeStr(e->HubType),
+				s1, s2, s3, s4, s5, s6, s7, s8);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumHub(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 管理する仮想 HUB の選択
+UINT PsHub(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_STATUS t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", NULL, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (IsEmptyStr(GetParamStr(o, "[name]")) == false)
+	{
+		wchar_t tmp[MAX_SIZE];
+		Zero(&t, sizeof(t));
+
+		// 指定した仮想 HUB にアクセスできるかどうか調べる
+		StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+		// RPC 呼び出し
+		ret = ScGetHubStatus(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		// 選択を変更する
+		if (ps->HubName != NULL)
+		{
+			Free(ps->HubName);
+		}
+		ps->HubName = CopyStr(t.HubName);
+
+		UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Selected"), t.HubName);
+		c->Write(c, tmp);
+	}
+	else
+	{
+		// 選択を解除する
+		if (ps->HubName != NULL)
+		{
+			c->Write(c, _UU("CMD_Hub_Unselected"));
+			Free(ps->HubName);
+		}
+		ps->HubName = NULL;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB をオンラインにする
+UINT PsOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_HUB_ONLINE t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Online = true;
+
+	// RPC 呼び出し
+	ret = ScSetHubOnline(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB をオフラインにする
+UINT PsOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_HUB_ONLINE t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Online = false;
+
+	// RPC 呼び出し
+	ret = ScSetHubOnline(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB の最大同時接続セッション数を設定する
+UINT PsSetMaxSession(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[max_session]", CmdPrompt, _UU("CMD_SetMaxSession_Prompt"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// 現在の仮想 HUB の設定を取得
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	ret = ScGetHub(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	t.HubOption.MaxSession = GetParamInt(o, "[max_session]");
+
+	// 仮想 HUB の設定を書き込み
+	ret = ScSetHub(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB の管理パスワードを設定する
+UINT PsSetHubPassword(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+	char *pw;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// 現在の仮想 HUB の設定を取得
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	ret = ScGetHub(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 設定の変更
+	pw = GetParamStr(o, "[password]");
+	HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pw);
+	Hash(t.HashedPassword, pw, StrLen(pw), true);
+
+	// 仮想 HUB の設定を書き込み
+	ret = ScSetHub(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB の匿名ユーザーへの列挙の許可設定
+UINT PsSetEnumAllow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// 現在の仮想 HUB の設定を取得
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	ret = ScGetHub(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	t.HubOption.NoEnum = false;
+
+	// 仮想 HUB の設定を書き込み
+	ret = ScSetHub(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB の匿名ユーザーへの列挙の禁止設定
+UINT PsSetEnumDeny(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// 現在の仮想 HUB の設定を取得
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	ret = ScGetHub(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	t.HubOption.NoEnum = true;
+
+	// 仮想 HUB の設定を書き込み
+	ret = ScSetHub(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB のオプション設定の取得
+UINT PsOptionsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_HUB t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHub(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct;
+		wchar_t tmp[MAX_SIZE];
+
+		UniFormat(tmp, sizeof(tmp), _UU("CMD_OptionsGet_TITLE"), ps->HubName);
+		c->Write(c, tmp);
+
+		// 設定の表示
+		ct = CtNewStandard();
+
+		CtInsert(ct, _UU("CMD_OptionsGet_ENUM"),
+			t.HubOption.NoEnum ? _UU("CMD_MSG_DENY") : _UU("CMD_MSG_ALLOW"));
+
+		if (t.HubOption.MaxSession == 0)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+		}
+		else
+		{
+			UniToStru(tmp, t.HubOption.MaxSession);
+		}
+		CtInsert(ct, _UU("CMD_OptionsGet_MAXSESSIONS"), tmp);
+
+		CtInsert(ct, _UU("CMD_OptionsGet_STATUS"), t.Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"));
+
+		CtInsert(ct, _UU("CMD_OptionsGet_TYPE"), GetHubTypeStr(t.HubType));
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザー認証に使用する Radius サーバーの設定
+UINT PsRadiusServerSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_RADIUS t;
+	char *host;
+	UINT port;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX minmax =
+	{
+		"CMD_RadiusServerSet_EVAL_NUMINTERVAL", RADIUS_RETRY_INTERVAL, RADIUS_RETRY_TIMEOUT,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[server_name:port]", CmdPrompt, _UU("CMD_RadiusServerSet_Prompt_Host"), CmdEvalNotEmpty, NULL},
+		{"SECRET", CmdPromptChoosePassword, _UU("CMD_RadiusServerSet_Prompt_Secret"), NULL, NULL},
+		{"RETRY_INTERVAL", CmdPrompt, _UU("CMD_RadiusServerSet_Prompt_RetryInterval"), CmdEvalMinMax, &minmax},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (ParseHostPort(GetParamStr(o, "[server_name:port]"), &host, &port, 1812))
+	{
+		Zero(&t, sizeof(t));
+
+		StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+		t.RadiusPort = port;
+		StrCpy(t.RadiusServerName, sizeof(t.RadiusServerName), host);
+		StrCpy(t.RadiusSecret, sizeof(t.RadiusSecret), GetParamStr(o, "SECRET"));
+		t.RadiusRetryInterval = GetParamInt(o, "RETRY_INTERVAL");
+
+		Free(host);
+
+		// RPC 呼び出し
+		ret = ScSetHubRadius(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザー認証に使用する Radius サーバー設定の削除
+UINT PsRadiusServerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_RADIUS t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.RadiusPort = 1812;
+
+	// RPC 呼び出し
+	ret = ScSetHubRadius(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザー認証に使用する Radius サーバー設定の取得
+UINT PsRadiusServerGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_RADIUS t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubRadius(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct;
+		wchar_t tmp[MAX_SIZE];
+
+		ct = CtNewStandard();
+
+		if (IsEmptyStr(t.RadiusServerName))
+		{
+			CtInsert(ct, _UU("CMD_RadiusServerGet_STATUS"), _UU("CMD_MSG_DISABLE"));
+		}
+		else
+		{
+			CtInsert(ct, _UU("CMD_RadiusServerGet_STATUS"), _UU("CMD_MSG_ENABLE"));
+
+			StrToUni(tmp, sizeof(tmp), t.RadiusServerName);
+			CtInsert(ct, _UU("CMD_RadiusServerGet_HOST"), tmp);
+
+			UniToStri(tmp, t.RadiusPort);
+			CtInsert(ct, _UU("CMD_RadiusServerGet_PORT"), tmp);
+
+			StrToUni(tmp, sizeof(tmp), t.RadiusSecret);
+			CtInsert(ct, _UU("CMD_RadiusServerGet_SECRET"), tmp);
+
+			UniToStri(tmp, t.RadiusRetryInterval);
+			CtInsert(ct, _UU("CMD_RadiusServerGet_RetryInterval"), tmp);
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB の現在の状況の取得
+UINT PsStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_STATUS t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubStatus(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNewStandard();
+		wchar_t *s;
+		wchar_t tmp[MAX_SIZE];
+
+		// HUB 名
+		s = CopyStrToUni(t.HubName);
+		CtInsert(ct, _UU("SM_HUB_STATUS_HUBNAME"), s);
+		Free(s);
+
+		// オンライン
+		CtInsert(ct, _UU("SM_HUB_STATUS_ONLINE"),
+			t.Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"));
+
+		// HUB の種類
+		CtInsert(ct, _UU("SM_HUB_TYPE"),
+			GetHubTypeStr(t.HubType));
+
+		if (t.HubType == HUB_TYPE_STANDALONE)
+		{
+			// SecureNAT の有効/無効
+			CtInsert(ct, _UU("SM_HUB_SECURE_NAT"),
+				t.SecureNATEnabled ? _UU("SM_HUB_SECURE_NAT_YES") : _UU("SM_HUB_SECURE_NAT_NO"));
+		}
+
+		// その他の値
+		UniToStru(tmp, t.NumSessions);
+		CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS"), tmp);
+
+		if (t.NumSessionsClient != 0 || t.NumSessionsBridge != 0)
+		{
+			UniToStru(tmp, t.NumSessionsClient);
+			CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS_CLIENT"), tmp);
+			UniToStru(tmp, t.NumSessionsBridge);
+			CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS_BRIDGE"), tmp);
+		}
+
+		UniToStru(tmp, t.NumAccessLists);
+		CtInsert(ct, _UU("SM_HUB_NUM_ACCESSES"), tmp);
+
+		UniToStru(tmp, t.NumUsers);
+		CtInsert(ct, _UU("SM_HUB_NUM_USERS"), tmp);
+		UniToStru(tmp, t.NumGroups);
+		CtInsert(ct, _UU("SM_HUB_NUM_GROUPS"), tmp);
+
+		UniToStru(tmp, t.NumMacTables);
+		CtInsert(ct, _UU("SM_HUB_NUM_MAC_TABLES"), tmp);
+		UniToStru(tmp, t.NumIpTables);
+		CtInsert(ct, _UU("SM_HUB_NUM_IP_TABLES"), tmp);
+
+		// 利用状況
+		UniToStru(tmp, t.NumLogin);
+		CtInsert(ct, _UU("SM_HUB_NUM_LOGIN"), tmp);
+
+		if (t.LastLoginTime != 0)
+		{
+			GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastLoginTime));
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+		}
+		CtInsert(ct, _UU("SM_HUB_LAST_LOGIN_TIME"), tmp);
+
+		if (t.LastCommTime != 0)
+		{
+			GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastCommTime));
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+		}
+		CtInsert(ct, _UU("SM_HUB_LAST_COMM_TIME"), tmp);
+
+		if (t.CreatedTime != 0)
+		{
+			GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime));
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+		}
+		CtInsert(ct, _UU("SM_HUB_CREATED_TIME"), tmp);
+
+		// トラフィック情報
+		CmdInsertTrafficInfo(ct, &t.Traffic);
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ログ切り替え文字列の取得
+wchar_t *GetLogSwitchStr(UINT i)
+{
+	char tmp[64];
+
+	Format(tmp, sizeof(tmp), "SM_LOG_SWITCH_%u", i);
+
+	return _UU(tmp);
+}
+
+// パケットログ名文字列の取得
+wchar_t *GetPacketLogNameStr(UINT i)
+{
+	char tmp[64];
+
+	Format(tmp, sizeof(tmp), "CMD_Log_%u", i);
+
+	return _UU(tmp);
+}
+
+// 仮想 HUB のログ保存設定の取得
+UINT PsLogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_LOG t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubLog(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNewStandard();
+
+		CtInsert(ct, _UU("CMD_Log_SecurityLog"),
+			t.LogSetting.SaveSecurityLog ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+		if (t.LogSetting.SaveSecurityLog)
+		{
+			CtInsert(ct, _UU("CMD_Log_SwitchType"), GetLogSwitchStr(t.LogSetting.SecurityLogSwitchType));
+		}
+
+		CtInsert(ct, L"", L"");
+
+		CtInsert(ct, _UU("CMD_Log_PacketLog"),
+			t.LogSetting.SavePacketLog ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+		if (t.LogSetting.SavePacketLog)
+		{
+			UINT i;
+
+			CtInsert(ct, _UU("CMD_Log_SwitchType"), GetLogSwitchStr(t.LogSetting.PacketLogSwitchType));
+
+			for (i = 0;i <= 7;i++)
+			{
+				wchar_t *tmp = NULL;
+
+				switch (t.LogSetting.PacketLogConfig[i])
+				{
+				case PACKET_LOG_NONE:
+					tmp = _UU("D_SM_LOG@B_PACKET_0_0");
+					break;
+
+				case PACKET_LOG_HEADER:
+					tmp = _UU("D_SM_LOG@B_PACKET_0_1");
+					break;
+
+				case PACKET_LOG_ALL:
+					tmp = _UU("D_SM_LOG@B_PACKET_0_2");
+					break;
+				}
+
+				CtInsert(ct, GetPacketLogNameStr(i),
+					tmp);
+			}
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// LogEnable コマンド
+UINT PsLogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_LOG t;
+	bool packet_log = false;
+	char *tmp;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	tmp = GetParamStr(o, "[security|packet]");
+
+	if (StartWith(tmp, "p"))
+	{
+		packet_log = true;
+	}
+	else if (StartWith(tmp, "s") == false)
+	{
+		c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubLog(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	if (packet_log == false)
+	{
+		t.LogSetting.SaveSecurityLog = true;
+	}
+	else
+	{
+		t.LogSetting.SavePacketLog = true;
+	}
+
+	// RPC 呼び出し
+	ret = ScSetHubLog(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// セキュリティ ログまたはパケット ログの無効化
+UINT PsLogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_LOG t;
+	bool packet_log = false;
+	char *tmp;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	tmp = GetParamStr(o, "[security|packet]");
+
+	if (StartWith(tmp, "p"))
+	{
+		packet_log = true;
+	}
+	else if (StartWith(tmp, "s") == false)
+	{
+		c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+		FreeParamValueList(o);
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubLog(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	if (packet_log == false)
+	{
+		t.LogSetting.SaveSecurityLog = false;
+	}
+	else
+	{
+		t.LogSetting.SavePacketLog = false;
+	}
+
+	// RPC 呼び出し
+	ret = ScSetHubLog(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 文字列をログ切り替え種類に変換
+UINT StrToLogSwitchType(char *str)
+{
+	UINT ret = INFINITE;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return INFINITE;
+	}
+
+	if (IsEmptyStr(str) || StartWith("none", str))
+	{
+		ret = LOG_SWITCH_NO;
+	}
+	else if (StartWith("second", str))
+	{
+		ret = LOG_SWITCH_SECOND;
+	}
+	else if (StartWith("minute", str))
+	{
+		ret = LOG_SWITCH_MINUTE;
+	}
+	else if (StartWith("hour", str))
+	{
+		ret = LOG_SWITCH_HOUR;
+	}
+	else if (StartWith("day", str))
+	{
+		ret = LOG_SWITCH_DAY;
+	}
+	else if (StartWith("month", str))
+	{
+		ret = LOG_SWITCH_MONTH;
+	}
+
+	return ret;
+}
+
+// ログ ファイルの切り替え周期の設定
+UINT PsLogSwitchSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_LOG t;
+	bool packet_log = false;
+	char *tmp;
+	UINT new_switch_type = 0;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+		{"SWITCH", CmdPrompt, _UU("CMD_LogSwitchSet_Prompt"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	tmp = GetParamStr(o, "[security|packet]");
+
+	if (StartWith(tmp, "p"))
+	{
+		packet_log = true;
+	}
+	else if (StartWith(tmp, "s") == false)
+	{
+		c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+		FreeParamValueList(o);
+		return ERR_INVALID_PARAMETER;
+	}
+	
+	new_switch_type = StrToLogSwitchType(GetParamStr(o, "SWITCH"));
+
+	if (new_switch_type == INFINITE)
+	{
+		c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+		FreeParamValueList(o);
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubLog(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	if (packet_log == false)
+	{
+		t.LogSetting.SecurityLogSwitchType = new_switch_type;
+	}
+	else
+	{
+		t.LogSetting.PacketLogSwitchType = new_switch_type;
+	}
+
+	// RPC 呼び出し
+	ret = ScSetHubLog(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// パケットログのパケットの保存内容の文字列を整数に変換
+UINT StrToPacketLogSaveInfoType(char *str)
+{
+	UINT ret = INFINITE;
+	if (str == NULL)
+	{
+		return INFINITE;
+	}
+
+	if (StartWith("none", str) || IsEmptyStr(str))
+	{
+		ret = PACKET_LOG_NONE;
+	}
+	else if (StartWith("header", str))
+	{
+		ret = PACKET_LOG_HEADER;
+	}
+	else if (StartWith("full", str) || StartWith("all", str))
+	{
+		ret = PACKET_LOG_ALL;
+	}
+
+	return ret;
+}
+
+// パケットログのパケットの種類の文字列を整数に変換
+UINT StrToPacketLogType(char *str)
+{
+	UINT ret = INFINITE;
+	if (str == NULL || IsEmptyStr(str))
+	{
+		return INFINITE;
+	}
+
+	if (StartWith("tcpconn", str))
+	{
+		ret = PACKET_LOG_TCP_CONN;
+	}
+	else if (StartWith("tcpdata", str))
+	{
+		ret = PACKET_LOG_TCP;
+	}
+	else if (StartWith("dhcp", str))
+	{
+		ret = PACKET_LOG_DHCP;
+	}
+	else if (StartWith("udp", str))
+	{
+		ret = PACKET_LOG_UDP;
+	}
+	else if (StartWith("icmp", str))
+	{
+		ret = PACKET_LOG_ICMP;
+	}
+	else if (StartWith("ip", str))
+	{
+		ret = PACKET_LOG_IP;
+	}
+	else if (StartWith("arp", str))
+	{
+		ret = PACKET_LOG_ARP;
+	}
+	else if (StartWith("ethernet", str))
+	{
+		ret = PACKET_LOG_ETHERNET;
+	}
+
+	return ret;
+}
+
+// パケット ログに保存するパケットの種類と保存内容の設定
+UINT PsLogPacketSaveType(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_LOG t;
+	bool packet_log = false;
+	UINT packet_type = INFINITE;
+	UINT packet_save_info_type = INFINITE;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"TYPE", CmdPrompt, _UU("CMD_LogPacketSaveType_Prompt_TYPE"), NULL, NULL},
+		{"SAVE", CmdPrompt, _UU("CMD_LogPacketSaveType_Prompt_SAVE"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+	
+	packet_type = StrToPacketLogType(GetParamStr(o, "TYPE"));
+	packet_save_info_type = StrToPacketLogSaveInfoType(GetParamStr(o, "SAVE"));
+
+	if (packet_type == INFINITE || packet_save_info_type == INFINITE)
+	{
+		c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+		FreeParamValueList(o);
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubLog(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	t.LogSetting.PacketLogConfig[packet_type] = packet_save_info_type;
+
+	// RPC 呼び出し
+	ret = ScSetHubLog(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 信頼する証明機関の証明書一覧の取得
+UINT PsCAList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_ENUM_CA t;
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumCa(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		CT *ct = CtNewStandard();
+
+		for (i = 0;i < t.NumCa;i++)
+		{
+			wchar_t tmp[MAX_SIZE];
+			wchar_t tmp2[64];
+			RPC_HUB_ENUM_CA_ITEM *e = &t.Ca[i];
+
+			GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(e->Expires), NULL);
+
+			UniToStru(tmp2, e->Key);
+
+			CtInsert(ct, _UU("CMD_CAList_COLUMN_ID"), tmp2);
+			CtInsert(ct, _UU("CM_CERT_COLUMN_1"), e->SubjectName);
+			CtInsert(ct, _UU("CM_CERT_COLUMN_2"), e->IssuerName);
+			CtInsert(ct, _UU("CM_CERT_COLUMN_3"), tmp);
+
+			if (i != (t.NumCa - 1))
+			{
+				CtInsert(ct, L"---", L"---");
+			}
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeRpcHubEnumCa(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 信頼する証明機関の証明書の追加
+UINT PsCAAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_ADD_CA t;
+	X *x;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[path]", CmdPrompt, _UU("CMD_CAAdd_PROMPT_PATH"), CmdEvalIsFile, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	x = FileToX(GetParamStr(o, "[path]"));
+
+	if (x == NULL)
+	{
+		FreeParamValueList(o);
+		c->Write(c, _UU("CMD_MSG_LOAD_CERT_FAILED"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Cert = x;
+
+	// RPC 呼び出し
+	ret = ScAddCa(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcHubAddCa(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 信頼する証明機関の証明書の削除
+UINT PsCADelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_DELETE_CA t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_CADelete_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Key = GetParamInt(o, "[id]");
+
+	// RPC 呼び出し
+	ret = ScDeleteCa(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 信頼する証明機関の証明書の取得
+UINT PsCAGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB_GET_CA t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_CAGet_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_CAGet_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Key = GetParamInt(o, "[id]");
+
+	// RPC 呼び出し
+	ret = ScGetCa(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		if (XToFile(t.Cert, GetParamStr(o, "SAVECERT"), true))
+		{
+			// 成功
+		}
+		else
+		{
+			ret = ERR_INTERNAL_ERROR;
+			c->Write(c, _UU("CMD_MSG_SAVE_CERT_FAILED"));
+		}
+	}
+
+	FreeRpcHubGetCa(&t);
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// カスケード接続一覧の取得
+UINT PsCascadeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_LINK t;
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+		UINT i;
+
+		CtInsertColumn(ct, _UU("SM_LINK_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("SM_LINK_COLUMN_2"), false);
+		CtInsertColumn(ct, _UU("SM_LINK_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("SM_LINK_COLUMN_4"), false);
+		CtInsertColumn(ct, _UU("SM_LINK_COLUMN_5"), false);
+
+		for (i = 0;i < t.NumLink;i++)
+		{
+			RPC_ENUM_LINK_ITEM *e = &t.Links[i];
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			wchar_t tmp3[MAX_SIZE];
+			wchar_t tmp4[MAX_SIZE];
+
+			GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+			StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+			StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+			if (e->Online == false)
+			{
+				UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_OFFLINE"));
+			}
+			else
+			{
+				if (e->Connected)
+				{
+					UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ONLINE"));
+				}
+				else
+				{
+					if (e->LastError != 0)
+					{
+						UniFormat(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ERROR"), e->LastError, _E(e->LastError));
+					}
+					else
+					{
+						UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_CONNECTING"));
+					}
+				}
+			}
+
+			CtInsert(ct, e->AccountName, tmp4, tmp1, tmp2, tmp3);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumLink(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 新しいカスケード接続の作成
+UINT PsCascadeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	char *host = NULL;
+	UINT port = 443;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SERVER", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+		{"HUB", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+		{"USERNAME", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	t.Online = false;
+
+	Copy(&t.Policy, GetDefaultPolicy(), sizeof(POLICY));
+
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+	t.ClientOption->Port = port;
+	StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+	StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+	t.ClientOption->NumRetry = INFINITE;
+	t.ClientOption->RetryInterval = 15;
+	t.ClientOption->MaxConnection = 8;
+	t.ClientOption->UseEncrypt = true;
+	t.ClientOption->AdditionalConnectionInterval = 1;
+	t.ClientOption->RequireBridgeRoutingMode = true;
+
+	t.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+	t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+	StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+	Free(host);
+
+	// RPC 呼び出し
+	ret = ScCreateLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcCreateLink(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の接続先とユーザー名の設定
+UINT PsCascadeSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	char *host = NULL;
+	UINT port = 443;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SERVER", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+		{"HUB", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	ret = ScGetLink(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		Free(host);
+		return ret;
+	}
+
+	t.ClientOption->Port = port;
+	StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+	StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+
+	Free(host);
+
+	// RPC 呼び出し
+	ret = ScSetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcCreateLink(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// プロキシの種類文字列の取得
+wchar_t *GetProxyTypeStr(UINT i)
+{
+	switch (i)
+	{
+	case PROXY_DIRECT:
+
+		return _UU("PROTO_DIRECT_TCP");
+
+	case PROXY_HTTP:
+		return _UU("PROTO_HTTP_PROXY");
+
+	case PROXY_SOCKS:
+		return _UU("PROTO_SOCKS_PROXY");
+
+	default:
+		return _UU("PROTO_UNKNOWN");
+	}
+}
+
+// クライアントのユーザー認証の種類文字列の取得
+wchar_t *GetClientAuthTypeStr(UINT i)
+{
+	char tmp[MAX_SIZE];
+
+	Format(tmp, sizeof(tmp), "PW_TYPE_%u", i);
+
+	return _UU(tmp);
+}
+
+// カスケード接続の設定の取得
+UINT PsCascadeGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+		GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// 接続設定の内容を表示
+		wchar_t tmp[MAX_SIZE];
+
+		CT *ct = CtNewStandard();
+
+		// 接続設定名
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NAME"), t.ClientOption->AccountName);
+
+		// 接続先 VPN Server のホスト名
+		StrToUni(tmp, sizeof(tmp), t.ClientOption->Hostname);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HOSTNAME"), tmp);
+
+		// 接続先 VPN Server のポート番号
+		UniToStru(tmp, t.ClientOption->Port);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PORT"), tmp);
+
+		// 接続先 VPN Server の仮想 HUB 名
+		StrToUni(tmp, sizeof(tmp), t.ClientOption->HubName);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HUBNAME"), tmp);
+
+		// 経由するプロキシ サーバーの種類
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_TYPE"), GetProxyTypeStr(t.ClientOption->ProxyType));
+
+		if (t.ClientOption->ProxyType != PROXY_DIRECT)
+		{
+			// プロキシ サーバーのホスト名
+			StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyName);
+			CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_HOSTNAME"), tmp);
+
+			// プロキシ サーバーのポート番号
+			UniToStru(tmp, t.ClientOption->ProxyPort);
+			CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_PORT"), tmp);
+
+			// プロキシ サーバーのユーザー名
+			StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyUsername);
+			CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_USERNAME"), tmp);
+		}
+
+		// サーバー証明書の検証
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_USE"),
+			t.CheckServerCert ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// 登録されている固有証明書
+		if (t.ServerCert != NULL)
+		{
+			GetAllNameFromX(tmp, sizeof(tmp), t.ServerCert);
+			CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_NAME"), tmp);
+		}
+
+		// 接続に使用するデバイス名
+		StrToUni(tmp, sizeof(tmp), t.ClientOption->DeviceName);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_DEVICE_NAME"), tmp);
+
+		// 認証の種類
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_TYPE"), GetClientAuthTypeStr(t.ClientAuth->AuthType));
+
+		// ユーザー名
+		StrToUni(tmp, sizeof(tmp), t.ClientAuth->Username);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_USERNAME"), tmp);
+
+		if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+		{
+			if (t.ClientAuth->ClientX != NULL)
+			{
+				// クライアント証明書名
+				GetAllNameFromX(tmp, sizeof(tmp), t.ClientAuth->ClientX);
+				CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_CERT_NAME"), tmp);
+			}
+		}
+
+		// VPN 通信に使用する TCP コネクション数
+		UniToStru(tmp, t.ClientOption->MaxConnection);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NUMTCP"), tmp);
+
+		// 各 TCP コネクションの確立間隔
+		UniToStru(tmp, t.ClientOption->AdditionalConnectionInterval);
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_INTERVAL"), tmp);
+
+		// 各 TCP コネクションの寿命
+		if (t.ClientOption->ConnectionDisconnectSpan != 0)
+		{
+			UniToStru(tmp, t.ClientOption->ConnectionDisconnectSpan);
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+		}
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_TTL"), tmp);
+
+		// 半二重モードの使用
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_HALF"),
+			t.ClientOption->HalfConnection ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// SSL による暗号化
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_ENCRYPT"),
+			t.ClientOption->UseEncrypt ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// データ圧縮
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_COMPRESS"),
+			t.ClientOption->UseCompress ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// ブリッジ / ルータモードで接続
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_BRIDGE_ROUTER"),
+			t.ClientOption->RequireBridgeRoutingMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// モニタリングモードで接続
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_MONITOR"),
+			t.ClientOption->RequireMonitorMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// ルーティング テーブルを書き換えない
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NO_TRACKING"),
+			t.ClientOption->NoRoutingTracking ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		// QoS制御を無効化する
+		CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_QOS_DISABLE"),
+			t.ClientOption->DisableQoS ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+		CtFree(ct, c);
+
+		// セキュリティ ポリシー
+		c->Write(c, L"");
+		c->Write(c, _UU("CMD_CascadeGet_Policy"));
+		PrintPolicy(c, &t.Policy, true);
+	}
+
+	FreeRpcCreateLink(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の削除
+UINT PsCascadeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScDeleteLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の接続に使用するユーザー名の設定
+UINT PsCascadeUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"USERNAME", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// カスケード接続の設定の変更
+		StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username),
+			GetParamStr(o, "USERNAME"));
+
+		if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+		{
+			c->Write(c, _UU("CMD_CascadeUsername_Notice"));
+		}
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+//カスケード接続のユーザー認証の種類を匿名認証に設定
+UINT PsCascadeAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// カスケード接続の設定の変更
+		t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のユーザー認証の種類をパスワード認証に設定
+UINT PsCascadePasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+		{"TYPE", CmdPrompt, _UU("CMD_CascadePasswordSet_Prompt_Type"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// カスケード接続の設定の変更
+		char *typestr = GetParamStr(o, "TYPE");
+
+		if (StartWith("standard", typestr))
+		{
+			t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+			HashPassword(t.ClientAuth->HashedPassword, t.ClientAuth->Username,
+				GetParamStr(o, "PASSWORD"));
+		}
+		else if (StartWith("radius", typestr) || StartWith("ntdomain", typestr))
+		{
+			t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PLAIN_PASSWORD;
+
+			StrCpy(t.ClientAuth->PlainPassword, sizeof(t.ClientAuth->PlainPassword),
+				GetParamStr(o, "PASSWORD"));
+		}
+		else
+		{
+			// エラー発生
+			c->Write(c, _UU("CMD_CascadePasswordSet_Type_Invalid"));
+			FreeRpcCreateLink(&t);
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ERR_INTERNAL_ERROR;
+		}
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のユーザー認証の種類をクライアント証明書認証に設定
+UINT PsCascadeCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	X *x;
+	K *k;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+		{"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (CmdLoadCertAndKey(c, &x, &k, GetParamStr(o, "LOADCERT"), GetParamStr(o, "LOADKEY")) == false)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		FreeX(x);
+		FreeK(k);
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// 認証データ変更
+		t.ClientAuth->AuthType = CLIENT_AUTHTYPE_CERT;
+		if (t.ClientAuth->ClientX != NULL)
+		{
+			FreeX(t.ClientAuth->ClientX);
+		}
+		if (t.ClientAuth->ClientK != NULL)
+		{
+			FreeK(t.ClientAuth->ClientK);
+		}
+
+		t.ClientAuth->ClientX = x;
+		t.ClientAuth->ClientK = k;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続に用いるクライアント証明書の取得
+UINT PsCascadeCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		if (t.ClientAuth->AuthType != CLIENT_AUTHTYPE_CERT)
+		{
+			c->Write(c, _UU("CMD_CascadeCertSet_Not_Auth_Cert"));
+			ret = ERR_INTERNAL_ERROR;
+		}
+		else if (t.ClientAuth->ClientX == NULL)
+		{
+			c->Write(c, _UU("CMD_CascadeCertSet_Cert_Not_Exists"));
+			ret = ERR_INTERNAL_ERROR;
+		}
+		else
+		{
+			XToFile(t.ClientAuth->ClientX, GetParamStr(o, "SAVECERT"), true);
+		}
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// カスケード接続の通信時の暗号化の有効化
+UINT PsCascadeEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		t.ClientOption->UseEncrypt = true;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の通信時の暗号化の無効化
+UINT PsCascadeEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		t.ClientOption->UseEncrypt = false;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の通信時のデータ圧縮の有効化
+UINT PsCascadeCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		t.ClientOption->UseCompress = true;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の通信時のデータ圧縮の無効化
+UINT PsCascadeCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		t.ClientOption->UseCompress = false;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の接続方法を直接 TCP/IP 接続に設定
+UINT PsCascadeProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		t.ClientOption->ProxyType = PROXY_DIRECT;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の接続方法を HTTP プロキシサーバー経由接続に設定
+UINT PsCascadeProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SERVER", CmdPrompt, _UU("CMD_CascadeProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+		{"USERNAME", NULL, NULL, NULL, NULL},
+		{"PASSWORD", NULL, NULL, NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		char *host;
+		UINT port;
+
+		// データ変更
+		if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+		{
+			t.ClientOption->ProxyType = PROXY_HTTP;
+			StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+			t.ClientOption->ProxyPort = port;
+			StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+			StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+			Free(host);
+		}
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の接続方法を SOCKS プロキシサーバー経由接続に設定
+UINT PsCascadeProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SERVER", CmdPrompt, _UU("CMD_CascadeProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+		{"USERNAME", NULL, NULL, NULL, NULL},
+		{"PASSWORD", NULL, NULL, NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		char *host;
+		UINT port;
+
+		// データ変更
+		if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+		{
+			t.ClientOption->ProxyType = PROXY_SOCKS;
+			StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+			t.ClientOption->ProxyPort = port;
+			StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+			StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+			Free(host);
+		}
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のサーバー証明書の検証オプションの有効化
+UINT PsCascadeServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		t.CheckServerCert = true;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のサーバー証明書の検証オプションの無効化
+UINT PsCascadeServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		t.CheckServerCert = false;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のサーバー固有証明書の設定
+UINT PsCascadeServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	X *x;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	x = FileToX(GetParamStr(o, "LOADCERT"));
+	if (x == NULL)
+	{
+		FreeParamValueList(o);
+		c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+		return ERR_INTERNAL_ERROR;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		FreeX(x);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		if (t.ServerCert != NULL)
+		{
+			FreeX(t.ServerCert);
+		}
+		t.ServerCert = x;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のサーバー固有証明書の削除
+UINT PsCascadeServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		if (t.ServerCert != NULL)
+		{
+			FreeX(t.ServerCert);
+		}
+		t.ServerCert = NULL;
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のサーバー固有証明書の取得
+UINT PsCascadeServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// 証明書保存
+		if (t.ServerCert == NULL)
+		{
+			c->Write(c, _UU("CMD_CERT_NOT_EXISTS"));
+			ret = ERR_INTERNAL_ERROR;
+		}
+		else
+		{
+			if (XToFile(t.ServerCert, GetParamStr(o, "SAVECERT"), true) == false)
+			{
+				c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+				ret = ERR_INTERNAL_ERROR;
+			}
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// カスケード接続の高度な通信設定の設定
+UINT PsCascadeDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	CMD_EVAL_MIN_MAX mm_maxtcp =
+	{
+		"CMD_CascadeDetailSet_Eval_MaxTcp", 1, 32
+	};
+	CMD_EVAL_MIN_MAX mm_interval =
+	{
+		"CMD_CascadeDetailSet_Eval_Interval", 1, 4294967295UL
+	};
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"MAXTCP", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_MaxTcp"), CmdEvalMinMax, &mm_maxtcp},
+		{"INTERVAL", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_Interval"), CmdEvalMinMax, &mm_interval},
+		{"TTL", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_TTL"), NULL, NULL},
+		{"HALF", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_HALF"), NULL, NULL},
+		{"NOQOS", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOQOS"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// データ変更
+		t.ClientOption->MaxConnection = GetParamInt(o, "MAXTCP");
+		t.ClientOption->AdditionalConnectionInterval = GetParamInt(o, "INTERVAL");
+		t.ClientOption->ConnectionDisconnectSpan = GetParamInt(o, "TTL");
+		t.ClientOption->HalfConnection = GetParamYes(o, "HALF");
+		t.ClientOption->DisableQoS = GetParamYes(o, "NOQOS");
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// セキュリティ ポリシーを表示
+void PrintPolicy(CONSOLE *c, POLICY *pol, bool cascade_mode)
+{
+	UINT i;
+	CT *ct;
+	PACK *p;
+	// 引数チェック
+	if (c == NULL || pol == NULL)
+	{
+		return;
+	}
+
+	ct = CtNew();
+	CtInsertColumn(ct, _UU("CMD_PolicyList_Column_1"), false);
+	CtInsertColumn(ct, _UU("CMD_PolicyList_Column_2"), false);
+	CtInsertColumn(ct, _UU("CMD_PolicyList_Column_3"), false);
+
+	p = NewPack();
+	OutRpcPolicy(p, pol);
+
+	// すべてのポリシー一覧を表示する
+	for (i = 0; i < PolicyNum();i++)
+	{
+		char name[64];
+		wchar_t *tmp;
+
+		if (cascade_mode == false || PolicyIsSupportedForCascade(i))
+		{
+			wchar_t value_str[256];
+			UINT value;
+			char tmp2[256];
+
+			Format(tmp2, sizeof(tmp2), "policy:%s", PolicyIdToStr(i));
+			value = PackGetInt(p, tmp2);
+
+			tmp = CopyStrToUni(PolicyIdToStr(i));
+
+			FormatPolicyValue(value_str, sizeof(value_str),
+				i, value);
+
+			Format(name, sizeof(name), "POL_%u", i);
+			CtInsert(ct, tmp, _UU(name), value_str);
+
+			Free(tmp);
+		}
+	}
+
+	FreePack(p);
+
+	CtFree(ct, c);
+}
+
+// セキュリティ ポリシー リストを表示
+void PrintPolicyList(CONSOLE *c, char *name)
+{
+	UINT id;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+	if (IsEmptyStr(name))
+	{
+		name = NULL;
+	}
+
+	if (name != NULL)
+	{
+		id = PolicyStrToId(name);
+		if (id == INFINITE)
+		{
+			// 不正な ID
+			c->Write(c, _UU("CMD_PolicyList_Invalid_Name"));
+		}
+		else
+		{
+			wchar_t tmp[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			char name1[64], name2[64];
+			wchar_t *title, *descript;
+			wchar_t policy_name[MAX_SIZE];
+
+			Format(name1, sizeof(name1), "POL_%u", id);
+			Format(name2, sizeof(name2), "POL_EX_%u", id);
+
+			title = _UU(name1);
+			descript = _UU(name2);
+
+			StrToUni(policy_name, sizeof(policy_name), PolicyIdToStr(id));
+
+			// ポリシー名
+			c->Write(c, _UU("CMD_PolicyList_Help_1"));
+			UniFormat(tmp2, sizeof(tmp2), L" %s", policy_name);
+			c->Write(c, tmp2);
+			c->Write(c, L"");
+
+			// ポリシーの簡易説明
+			c->Write(c, _UU("CMD_PolicyList_Help_2"));
+			UniFormat(tmp2, sizeof(tmp2), L" %s", title);
+			c->Write(c, tmp2);
+			c->Write(c, L"");
+
+			// 設定できる値の範囲
+			GetPolicyValueRangeStr(tmp, sizeof(tmp), id);
+			c->Write(c, _UU("CMD_PolicyList_Help_3"));
+			UniFormat(tmp2, sizeof(tmp2), L" %s", tmp);
+			c->Write(c, tmp2);
+			c->Write(c, L"");
+
+			// デフォルト値
+			FormatPolicyValue(tmp, sizeof(tmp), id, GetPolicyItem(id)->DefaultValue);
+			c->Write(c, _UU("CMD_PolicyList_Help_4"));
+			UniFormat(tmp2, sizeof(tmp2), L" %s", tmp);
+			c->Write(c, tmp2);
+			c->Write(c, L"");
+
+			// ポリシーの詳細説明
+			c->Write(c, _UU("CMD_PolicyList_Help_5"));
+			c->Write(c, descript);
+			c->Write(c, L"");
+		}
+	}
+	else
+	{
+		UINT i;
+		CT *ct = CtNew();
+		CtInsertColumn(ct, _UU("CMD_PolicyList_Column_1"), false);
+		CtInsertColumn(ct, _UU("CMD_PolicyList_Column_2"), false);
+
+		// すべてのポリシー一覧を表示する
+		for (i = 0; i < PolicyNum();i++)
+		{
+			char name[64];
+			wchar_t *tmp;
+
+			tmp = CopyStrToUni(PolicyIdToStr(i));
+
+			Format(name, sizeof(name), "POL_%u", i);
+			CtInsert(ct, tmp, _UU(name));
+
+			Free(tmp);
+		}
+
+		CtFree(ct, c);
+	}
+}
+
+// ポリシーの内容の編集
+bool EditPolicy(CONSOLE *c, POLICY *pol, char *name, char *value, bool cascade_mode)
+{
+	PACK *p;
+	ELEMENT *e;
+	POLICY_ITEM *item;
+	UINT id;
+	wchar_t tmp[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	char pack_name[128];
+	// 引数チェック
+	if (c == NULL || pol == NULL || name == NULL || value == NULL)
+	{
+		return false;
+	}
+
+	p = NewPack();
+
+	OutRpcPolicy(p, pol);
+
+	Format(pack_name, sizeof(pack_name), "policy:%s", PolicyIdToStr(PolicyStrToId(name)));
+
+	if ((e = GetElement(p, pack_name, VALUE_INT)) == NULL || (id = PolicyStrToId(name)) == INFINITE)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CMD_CascadePolicySet_Invalid_Name"), name);
+		c->Write(c, tmp);
+		FreePack(p);
+		return false;
+	}
+
+	if (cascade_mode && (PolicyIsSupportedForCascade(id) == false))
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CMD_CascadePolicySet_Invalid_Name_For_Cadcade"), name);
+		c->Write(c, tmp);
+		FreePack(p);
+		return false;
+	}
+
+	item = GetPolicyItem(id);
+
+	if (item->TypeInt == false)
+	{
+		// bool 型
+		e->values[0]->IntValue = (
+			StartWith(value, "y") || StartWith(value, "t") ||
+			ToInt(value) != 0) ? 1 : 0;
+	}
+	else
+	{
+		UINT n = ToInt(value);
+		bool b = true;
+
+		// int 型
+		GetPolicyValueRangeStr(tmp, sizeof(tmp), id);
+
+		if (item->AllowZero == false)
+		{
+			if (n == 0)
+			{
+				b = false;
+			}
+		}
+
+		if (n != 0 && (n < item->MinValue || n > item->MaxValue))
+		{
+			b = false;
+		}
+
+		if (b == false)
+		{
+			UniFormat(tmp2, sizeof(tmp2), _UU("CMD_CascadePolicySet_Invalid_Range"), PolicyIdToStr(id), tmp);
+			c->Write(c, tmp2);
+			FreePack(p);
+			return false;
+		}
+
+		e->values[0]->IntValue = n;
+	}
+
+	Zero(pol, sizeof(POLICY));
+
+	InRpcPolicy(pol, p);
+
+	FreePack(p);
+
+	return true;
+}
+
+// セキュリティ ポリシーの種類と設定可能値の一覧を表示
+UINT PsPolicyList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", NULL, NULL, NULL, NULL}
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	PrintPolicyList(c, GetParamStr(o, "[name]"));
+
+	FreeParamValueList(o);
+
+	return ERR_NO_ERROR;
+}
+
+// カスケード接続セッションのセキュリティ ポリシーの設定
+UINT PsCascadePolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CREATE_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+		{"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+		{"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		if (EditPolicy(c, &t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), true) == false)
+		{
+			// エラー発生
+			FreeRpcCreateLink(&t);
+			FreeParamValueList(o);
+			return ERR_INTERNAL_ERROR;
+		}
+
+		ret = ScSetLink(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcCreateLink(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// セッションのステータス情報の表示
+void CmdPrintStatusToListView(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s)
+{
+	CmdPrintStatusToListViewEx(ct, s, false);
+}
+void CmdPrintStatusToListViewEx(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode)
+{
+	wchar_t tmp[MAX_SIZE];
+	char str[MAX_SIZE];
+	char vv[128];
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (server_mode == false)
+	{
+		CtInsert(ct, _UU("CM_ST_ACCOUNT_NAME"), s->AccountName);
+
+		if (s->Connected == false)
+		{
+			wchar_t *st = _UU("CM_ST_CONNECTED_FALSE");
+			switch (s->SessionStatus)
+			{
+			case CLIENT_STATUS_CONNECTING:
+				st = _UU("CM_ST_CONNECTING");
+				break;
+			case CLIENT_STATUS_NEGOTIATION:
+				st = _UU("CM_ST_NEGOTIATION");
+				break;
+			case CLIENT_STATUS_AUTH:
+				st = _UU("CM_ST_AUTH");
+				break;
+			case CLIENT_STATUS_ESTABLISHED:
+				st = _UU("CM_ST_ESTABLISHED");
+				break;
+			case CLIENT_STATUS_RETRY:
+				st = _UU("CM_ST_RETRY");
+				break;
+			case CLIENT_STATUS_IDLE:
+				st = _UU("CM_ST_IDLE");
+				break;
+			}
+			CtInsert(ct, _UU("CM_ST_CONNECTED"), st);
+		}
+		else
+		{
+			CtInsert(ct, _UU("CM_ST_CONNECTED"), _UU("CM_ST_CONNECTED_TRUE"));
+		}
+	}
+
+	if (s->Connected)
+	{
+		if (s->VLanId == 0)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_NO_VLAN"));
+		}
+		else
+		{
+			UniToStru(tmp, s->VLanId);
+		}
+
+		CtInsert(ct, _UU("CM_ST_VLAN_ID"), tmp);
+
+		if (server_mode == false)
+		{
+			StrToUni(tmp, sizeof(tmp), s->ServerName);
+			CtInsert(ct, _UU("CM_ST_SERVER_NAME"), tmp);
+
+			UniFormat(tmp, sizeof(tmp), _UU("CM_ST_PORT_TCP"), s->ServerPort);
+			CtInsert(ct, _UU("CM_ST_SERVER_PORT"), tmp);
+		}
+
+		StrToUni(tmp, sizeof(tmp), s->ServerProductName);
+		CtInsert(ct, _UU("CM_ST_SERVER_P_NAME"), tmp);
+
+		UniFormat(tmp, sizeof(tmp), L"%u.%02u", s->ServerProductVer / 100, s->ServerProductVer % 100);
+		CtInsert(ct, _UU("CM_ST_SERVER_P_VER"), tmp);
+		UniFormat(tmp, sizeof(tmp), L"Build %u", s->ServerProductBuild);
+		CtInsert(ct, _UU("CM_ST_SERVER_P_BUILD"), tmp);
+	}
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL);
+	CtInsert(ct, _UU("CM_ST_START_TIME"), tmp);
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablisiedTime), NULL);
+	CtInsert(ct, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablisiedTime == 0 ? _UU("CM_ST_NONE") : tmp);
+
+	if (s->Connected)
+	{
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->CurrentConnectionEstablishTime), NULL);
+		CtInsert(ct, _UU("CM_ST_CURR_ESTAB_TIME"), tmp);
+	}
+
+	if (server_mode == false)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_STR"), s->NumConnectionsEatablished);
+		CtInsert(ct, _UU("CM_ST_NUM_ESTABLISHED"), tmp);
+	}
+
+	if (s->Connected)
+	{
+		CtInsert(ct, _UU("CM_ST_HALF_CONNECTION"), s->HalfConnection ? _UU("CM_ST_HALF_TRUE") : _UU("CM_ST_HALF_FALSE"));
+
+		CtInsert(ct, _UU("CM_ST_QOS"), s->QoS ? _UU("CM_ST_QOS_TRUE") : _UU("CM_ST_QOS_FALSE"));
+
+		UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnections);
+		CtInsert(ct, _UU("CM_ST_NUM_TCP"), tmp);
+
+		if (s->HalfConnection)
+		{
+			UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsUpload);
+			CtInsert(ct, _UU("CM_ST_NUM_TCP_UPLOAD"), tmp);
+			UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsDownload);
+			CtInsert(ct, _UU("CM_ST_NUM_TCP_DOWNLOAD"), tmp);
+		}
+
+		UniFormat(tmp, sizeof(tmp), L"%u", s->MaxTcpConnections);
+		CtInsert(ct, _UU("CM_ST_MAX_TCP"), tmp);
+
+		if (s->UseEncrypt == false)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_FALSE"));
+		}
+		else
+		{
+			if (StrLen(s->CipherName) != 0)
+			{
+				UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE"), s->CipherName);
+			}
+			else
+			{
+				UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE2"));
+			}
+		}
+		CtInsert(ct, _UU("CM_ST_USE_ENCRYPT"), tmp);
+
+		if (s->UseCompress)
+		{
+			UINT percent = 0;
+			if ((s->TotalRecvSize + s->TotalSendSize) > 0)
+			{
+				percent = (UINT)((UINT64)100 - (UINT64)(s->TotalRecvSizeReal + s->TotalSendSizeReal) * (UINT64)100 /
+					(s->TotalRecvSize + s->TotalSendSize));
+				percent = MAKESURE(percent, 0, 100);
+			}
+
+			UniFormat(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_TRUE"), percent);
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_FALSE"));
+		}
+		CtInsert(ct, _UU("CM_ST_USE_COMPRESS"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), s->SessionName);
+		CtInsert(ct, _UU("CM_ST_SESSION_NAME"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), s->ConnectionName);
+		if (UniStrCmpi(tmp, L"INITING") != 0)
+		{
+			CtInsert(ct, _UU("CM_ST_CONNECTION_NAME"), tmp);
+		}
+
+		BinToStr(str, sizeof(str), s->SessionKey, sizeof(s->SessionKey));
+		StrToUni(tmp, sizeof(tmp), str);
+		CtInsert(ct, _UU("CM_ST_SESSION_KEY"), tmp);
+
+		CtInsert(ct, _UU("CM_ST_BRIDGE_MODE"), s->IsBridgeMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+		CtInsert(ct, _UU("CM_ST_MONITOR_MODE"), s->IsMonitorMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+		ToStr3(vv, sizeof(vv), s->TotalSendSize);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_SEND_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->TotalRecvSize);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_RECV_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastCount);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_SEND_UCAST_NUM"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastBytes);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_SEND_UCAST_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastCount);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_SEND_BCAST_NUM"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastBytes);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_SEND_BCAST_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastCount);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_RECV_UCAST_NUM"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastBytes);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_RECV_UCAST_SIZE"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastCount);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_RECV_BCAST_NUM"), tmp);
+
+		ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastBytes);
+		UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+		CtInsert(ct, _UU("CM_ST_RECV_BCAST_SIZE"), tmp);
+	}
+}
+
+// カスケード接続の現在の状態の取得
+UINT PsCascadeStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_LINK_STATUS t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetLinkStatus(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// カスケード接続状態の取得
+		CT *ct = CtNewStandard();
+
+		CmdPrintStatusToListView(ct, &t.Status);
+
+		CtFree(ct, c);
+
+		FreeRpcLinkStatus(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続の名前の変更
+UINT PsCascadeRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_RENAME_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeRename_PROMPT_OLD"), CmdEvalNotEmpty, NULL},
+		{"NEW", CmdPrompt, _UU("CMD_CascadeRename_PROMPT_NEW"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	UniStrCpy(t.NewAccountName, sizeof(t.NewAccountName), GetParamUniStr(o, "NEW"));
+	UniStrCpy(t.OldAccountName, sizeof(t.OldAccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScRenameLink(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のオンライン状態への設定
+UINT PsCascadeOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScSetLinkOnline(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// カスケード接続のオフライン状態への設定
+UINT PsCascadeOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_LINK t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+	};
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScSetLinkOffline(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 文字列を pass/discard に変換
+bool StrToPassOrDiscard(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	if (ToInt(str) != 0)
+	{
+		return true;
+	}
+
+	if (StartWith(str, "p") || StartWith(str, "y") || StartWith(str, "t"))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// 文字列をプロトコルに変換
+UINT StrToProtocol(char *str)
+{
+	if (IsEmptyStr(str))
+	{
+		return 0;
+	}
+
+	if (StartWith("ip", str))
+	{
+		return 0;
+	}
+	else if (StartWith("tcp", str))
+	{
+		return IP_PROTO_TCP;
+	}
+	else if (StartWith("udp", str))
+	{
+		return IP_PROTO_UDP;
+	}
+	else if (StartWith("icmpv4", str))
+	{
+		return IP_PROTO_ICMPV4;
+	}
+	else if (StartWith("icmpv6", str))
+	{
+		return IP_PROTO_ICMPV6;
+	}
+
+	if (ToInt(str) == 0)
+	{
+		if (StrCmpi(str, "0") == 0)
+		{
+			return 0;
+		}
+		else
+		{
+			return INFINITE;
+		}
+	}
+
+	if (ToInt(str) >= 256)
+	{
+		return INFINITE;
+	}
+
+	return ToInt(str);
+}
+
+// プロトコル名のチェック
+bool CmdEvalProtocol(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[64];
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if (StrToProtocol(tmp) == INFINITE)
+	{
+		c->Write(c, _UU("CMD_PROTOCOL_EVAL_FAILED"));
+		return false;
+	}
+
+	return true;
+}
+
+// ポート範囲のパース
+bool ParsePortRange(char *str, UINT *start, UINT *end)
+{
+	UINT a = 0, b = 0;
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	if (IsEmptyStr(str) == false)
+	{
+
+		t = ParseToken(str, "\t -");
+
+		if (t->NumTokens == 1)
+		{
+			a = b = ToInt(t->Token[0]);
+		}
+		else if (t->NumTokens == 2)
+		{
+			a = ToInt(t->Token[0]);
+			b = ToInt(t->Token[1]);
+		}
+
+		FreeToken(t);
+
+		if (a > b)
+		{
+			return false;
+		}
+
+		if (a >= 65536 || b >= 65536)
+		{
+			return false;
+		}
+
+		if (a == 0 && b != 0)
+		{
+			return false;
+		}
+	}
+
+	if (start != NULL)
+	{
+		*start = a;
+	}
+	if (end != NULL)
+	{
+		*end = b;
+	}
+
+	return true;
+}
+
+// ポート範囲のチェック
+bool CmdEvalPortRange(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[64];
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if (ParsePortRange(tmp, NULL, NULL) == false)
+	{
+		c->Write(c, _UU("CMD_PORT_RANGE_EVAL_FAILED"));
+		return false;
+	}
+
+	return true;
+}
+
+// MAC アドレスとマスクのパース
+bool ParseMacAddressAndMask(char *src, bool *check_mac, UCHAR *mac_bin, UCHAR *mask_bin)
+{
+	TOKEN_LIST *t;
+	char *macstr, *maskstr;
+	UCHAR mac[6], mask[6];
+	bool ok = false;
+
+	// 引数チェック
+	if (src == NULL)
+	{
+		return false;
+	}
+
+	//Zero(mac, sizeof(mac));
+	//Zero(mask, sizeof(mask));
+
+	if(check_mac != NULL && mac_bin != NULL && mask_bin != NULL)
+	{
+		ok = true;
+	}
+	if(IsEmptyStr(src) != false)
+	{
+		if(ok != false)
+		{
+			*check_mac = false;
+			Zero(mac_bin, 6);
+			Zero(mask_bin, 6);
+		}
+		return true;
+	}
+
+	t = ParseToken(src, "/");
+	if(t->NumTokens != 2)
+	{
+		FreeToken(t);
+		return false;
+	}
+
+	macstr = t->Token[0];
+	maskstr = t->Token[1];
+
+	Trim(macstr);
+	Trim(maskstr);
+
+	if(StrToMac(mac, macstr) == false || StrToMac(mask, maskstr) == false)
+	{
+		FreeToken(t);
+		return false;
+	}
+	else
+	{
+		if(ok != false)
+		{
+			Copy(mac_bin, mac, 6);
+			Copy(mask_bin, mask, 6);
+			*check_mac = true;
+		}
+	}
+	FreeToken(t);
+
+	return true;
+}
+
+// MAC アドレスとマスクのチェック
+bool CmdEvalMacAddressAndMask(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[64];
+	// 引数チェック
+	if(c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+
+	if(ParseMacAddressAndMask(tmp, NULL, NULL, NULL) == false)
+	{
+		c->Write(c, _UU("CMD_MAC_ADDRESS_AND_MASK_EVAL_FAILED"));
+		return false;
+	}
+
+	return true;
+}
+// TCP コネクションの状態パース
+bool ParseTcpState(char *src, bool *check_tcp_state, bool *established)
+{
+	bool ok = false;
+	// 引数チェック
+	if(src == NULL)
+	{
+		return false;
+	}
+
+	if(check_tcp_state != NULL && established != NULL)
+	{
+		ok = true;
+	}
+
+	if (IsEmptyStr(src) == false)
+	{
+		if (StartWith("Established", src) == 0)
+		{
+			if(ok != false)
+			{
+				*check_tcp_state = true;
+				*established = true;
+			}
+		}
+		else if (StartWith("Unestablished", src) == 0)
+		{
+			if(ok != false)
+			{
+				*check_tcp_state = true;
+				*established = false;
+			}
+		}
+		else
+		{
+			// 不正な文字列
+			return false;
+		}
+	}
+	else
+	{
+		if(ok != false)
+		{
+			*check_tcp_state = false;
+			*established = false;
+		}
+	}
+
+	return true;
+}
+// TCP コネクションの状態チェック
+bool CmdEvalTcpState(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[64];
+	// 引数チェック
+	if(c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if(ParseTcpState(tmp, NULL, NULL) == false)
+	{
+		c->Write(c, _UU("CMD_TCP_CONNECTION_STATE_EVAL_FAILED"));
+		return false;
+	}
+
+	return true;
+}
+
+// アクセス リストへのルールの追加 (標準、IPv4)
+UINT PsAccessAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ADD_ACCESS t;
+	ACCESS *a;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX minmax =
+	{
+		"CMD_AccessAdd_Eval_PRIORITY", 1, 4294967295UL,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+		{"MEMO", CmdPrompt, _UU("CMD_AccessAdd_Prompt_MEMO"), NULL, NULL},
+		{"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+		{"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCUSERNAME"), NULL, NULL},
+		{"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTUSERNAME"), NULL, NULL},
+		{"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+		{"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+		{"SRCIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCIP"), CmdEvalIpAndMask4, NULL},
+		{"DESTIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTIP"), CmdEvalIpAndMask4, NULL},
+		{"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+		{"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+		{"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+		{"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	a = &t.Access;
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+	a->Active = true;
+	a->Priority = GetParamInt(o, "PRIORITY");
+	a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+	StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+	StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+	ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+	ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+	ParseIpAndMask4(GetParamStr(o, "SRCIP"), &a->SrcIpAddress, &a->SrcSubnetMask);
+	ParseIpAndMask4(GetParamStr(o, "DESTIP"), &a->DestIpAddress, &a->DestSubnetMask);
+	a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+	ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+	ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+	ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+
+	// RPC 呼び出し
+	ret = ScAddAccess(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// アクセス リストへのルールの追加 (拡張、IPv4)
+UINT PsAccessAddEx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ADD_ACCESS t;
+	ACCESS *a;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX minmax =
+	{
+		"CMD_AccessAdd_Eval_PRIORITY", 1, 4294967295UL,
+	};
+	CMD_EVAL_MIN_MAX minmax_delay =
+	{
+		"CMD_AccessAddEx_Eval_DELAY", 0, HUB_ACCESSLIST_DELAY_MAX,
+	};
+	CMD_EVAL_MIN_MAX minmax_jitter =
+	{
+		"CMD_AccessAddEx_Eval_JITTER", 0, HUB_ACCESSLIST_JITTER_MAX,
+	};
+	CMD_EVAL_MIN_MAX minmax_loss =
+	{
+		"CMD_AccessAddEx_Eval_LOSS", 0, HUB_ACCESSLIST_LOSS_MAX,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+		{"MEMO", CmdPrompt, _UU("CMD_AccessAdd_Prompt_MEMO"), NULL, NULL},
+		{"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+		{"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCUSERNAME"), NULL, NULL},
+		{"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTUSERNAME"), NULL, NULL},
+		{"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+		{"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+		{"SRCIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCIP"), CmdEvalIpAndMask4, NULL},
+		{"DESTIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTIP"), CmdEvalIpAndMask4, NULL},
+		{"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+		{"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+		{"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+		{"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+		{"DELAY", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_DELAY"), CmdEvalMinMax, &minmax_delay},
+		{"JITTER", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_JITTER"), CmdEvalMinMax, &minmax_jitter},
+		{"LOSS", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_LOSS"), CmdEvalMinMax, &minmax_loss},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// サポートしているかどうかチェック
+	if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+	{
+		c->Write(c, _E(ERR_NOT_SUPPORTED));
+		return ERR_NOT_SUPPORTED;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	a = &t.Access;
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+	a->Active = true;
+	a->Priority = GetParamInt(o, "PRIORITY");
+	a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+	StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+	StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+	ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+	ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+	ParseIpAndMask4(GetParamStr(o, "SRCIP"), &a->SrcIpAddress, &a->SrcSubnetMask);
+	ParseIpAndMask4(GetParamStr(o, "DESTIP"), &a->DestIpAddress, &a->DestSubnetMask);
+	a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+	ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+	ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+	ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+	a->Delay = GetParamInt(o, "DELAY");
+	a->Jitter = GetParamInt(o, "JITTER");
+	a->Loss = GetParamInt(o, "LOSS");
+
+	// RPC 呼び出し
+	ret = ScAddAccess(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// アクセス リストへのルールの追加 (標準、IPv6)
+UINT PsAccessAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ADD_ACCESS t;
+	ACCESS *a;
+	IP ip, mask;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX minmax =
+	{
+		"CMD_AccessAdd6_Eval_PRIORITY", 1, 4294967295UL,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+		{"MEMO", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_MEMO"), NULL, NULL},
+		{"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+		{"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCUSERNAME"), NULL, NULL},
+		{"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTUSERNAME"), NULL, NULL},
+		{"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+		{"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+		{"SRCIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCIP"), CmdEvalIpAndMask6, NULL},
+		{"DESTIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTIP"), CmdEvalIpAndMask6, NULL},
+		{"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+		{"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+		{"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+		{"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// サポートしているかどうかチェック
+	if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+	{
+		c->Write(c, _E(ERR_NOT_SUPPORTED));
+		return ERR_NOT_SUPPORTED;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	a = &t.Access;
+
+	a->IsIPv6 = true;
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+	a->Active = true;
+	a->Priority = GetParamInt(o, "PRIORITY");
+	a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+	StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+	StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+	ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+	ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+
+	Zero(&ip, sizeof(ip));
+	Zero(&mask, sizeof(mask));
+
+	ParseIpAndMask6(GetParamStr(o, "SRCIP"), &ip, &mask);
+	IPToIPv6Addr(&a->SrcIpAddress6, &ip);
+	IPToIPv6Addr(&a->SrcSubnetMask6, &mask);
+
+	ParseIpAndMask6(GetParamStr(o, "DESTIP"), &ip, &mask);
+	IPToIPv6Addr(&a->DestIpAddress6, &ip);
+	IPToIPv6Addr(&a->DestSubnetMask6, &mask);
+
+	a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+	ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+	ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+	ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+
+	// RPC 呼び出し
+	ret = ScAddAccess(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// アクセス リストへのルールの追加 (拡張、IPv6)
+UINT PsAccessAddEx6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ADD_ACCESS t;
+	ACCESS *a;
+	IP ip, mask;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX minmax =
+	{
+		"CMD_AccessAdd6_Eval_PRIORITY", 1, 4294967295UL,
+	};
+	CMD_EVAL_MIN_MAX minmax_delay =
+	{
+		"CMD_AccessAddEx6_Eval_DELAY", 0, HUB_ACCESSLIST_DELAY_MAX,
+	};
+	CMD_EVAL_MIN_MAX minmax_jitter =
+	{
+		"CMD_AccessAddEx6_Eval_JITTER", 0, HUB_ACCESSLIST_JITTER_MAX,
+	};
+	CMD_EVAL_MIN_MAX minmax_loss =
+	{
+		"CMD_AccessAddEx6_Eval_LOSS", 0, HUB_ACCESSLIST_LOSS_MAX,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+		{"MEMO", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_MEMO"), NULL, NULL},
+		{"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+		{"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCUSERNAME"), NULL, NULL},
+		{"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTUSERNAME"), NULL, NULL},
+		{"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+		{"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+		{"SRCIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCIP"), CmdEvalIpAndMask6, NULL},
+		{"DESTIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTIP"), CmdEvalIpAndMask6, NULL},
+		{"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+		{"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+		{"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+		{"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+		{"DELAY", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_DELAY"), CmdEvalMinMax, &minmax_delay},
+		{"JITTER", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_JITTER"), CmdEvalMinMax, &minmax_jitter},
+		{"LOSS", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_LOSS"), CmdEvalMinMax, &minmax_loss},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// サポートしているかどうかチェック
+	if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+	{
+		c->Write(c, _E(ERR_NOT_SUPPORTED));
+		return ERR_NOT_SUPPORTED;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	a = &t.Access;
+
+	a->IsIPv6 = true;
+
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+	a->Active = true;
+	a->Priority = GetParamInt(o, "PRIORITY");
+	a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+	StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+	StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+	ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+	ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+
+	Zero(&ip, sizeof(ip));
+	Zero(&mask, sizeof(mask));
+
+	ParseIpAndMask6(GetParamStr(o, "SRCIP"), &ip, &mask);
+	IPToIPv6Addr(&a->SrcIpAddress6, &ip);
+	IPToIPv6Addr(&a->SrcSubnetMask6, &mask);
+
+	ParseIpAndMask6(GetParamStr(o, "DESTIP"), &ip, &mask);
+	IPToIPv6Addr(&a->DestIpAddress6, &ip);
+	IPToIPv6Addr(&a->DestSubnetMask6, &mask);
+
+	a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+	ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+	ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+	ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+	a->Delay = GetParamInt(o, "DELAY");
+	a->Jitter = GetParamInt(o, "JITTER");
+	a->Loss = GetParamInt(o, "LOSS");
+
+	// RPC 呼び出し
+	ret = ScAddAccess(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+
+// アクセス リストのルール一覧の取得
+UINT PsAccessList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_ACCESS_LIST t;
+	CT *ct;
+	UINT i;
+	
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumAccess(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNew();
+	CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_0"), true);
+	CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_1"), true);
+	CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_2"), true);
+	CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_3"), true);
+	CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_5"), false);
+	CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_4"), false);
+
+	for (i = 0;i < t.NumAccess;i++)
+	{
+		ACCESS *a = &t.Accesses[i];
+		char tmp[MAX_SIZE];
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+
+		GetAccessListStr(tmp, sizeof(tmp), a);
+		UniToStru(tmp1, a->Priority);
+		StrToUni(tmp2, sizeof(tmp2), tmp);
+
+		UniToStru(tmp3, a->Id);
+
+		CtInsert(ct,
+			tmp3,
+			a->Discard ? _UU("SM_ACCESS_DISCARD") : _UU("SM_ACCESS_PASS"),
+			a->Active ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"),
+			tmp1,
+			tmp2,
+			a->Note);
+	}
+
+	CtFreeEx(ct, c, true);
+
+	FreeRpcEnumAccessList(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// アクセス リストからルールを削除
+UINT PsAccessDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_DELETE_ACCESS t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Id = GetParamInt(o, "[id]");
+
+	// RPC 呼び出し
+	ret = ScDeleteAccess(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// アクセス リストのルールの有効化
+UINT PsAccessEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_ACCESS_LIST t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumAccess(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		bool b = false;
+		for (i = 0;i < t.NumAccess;i++)
+		{
+			ACCESS *a = &t.Accesses[i];
+
+			if (a->Id == GetParamInt(o, "[id]"))
+			{
+				b = true;
+
+				a->Active = true;
+			}
+		}
+
+		if (b == false)
+		{
+			// 指定した ID が見つからない
+			ret = ERR_OBJECT_NOT_FOUND;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			FreeRpcEnumAccessList(&t);
+			return ret;
+		}
+
+		ret = ScSetAccessList(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcEnumAccessList(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// アクセス リストのルールの無効化
+UINT PsAccessDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_ACCESS_LIST t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumAccess(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		bool b = false;
+		for (i = 0;i < t.NumAccess;i++)
+		{
+			ACCESS *a = &t.Accesses[i];
+
+			if (a->Id == GetParamInt(o, "[id]"))
+			{
+				b = true;
+
+				a->Active = false;
+			}
+		}
+
+		if (b == false)
+		{
+			// 指定した ID が見つからない
+			ret = ERR_OBJECT_NOT_FOUND;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			FreeRpcEnumAccessList(&t);
+			return ret;
+		}
+
+		ret = ScSetAccessList(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		FreeRpcEnumAccessList(&t);
+	}
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// ユーザー一覧の取得
+UINT PsUserList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_USER t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		CT *ct = CtNew();
+
+		CtInsertColumn(ct, _UU("SM_USER_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("SM_USER_COLUMN_2"), false);
+		CtInsertColumn(ct, _UU("SM_USER_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("SM_USER_COLUMN_4"), false);
+		CtInsertColumn(ct, _UU("SM_USER_COLUMN_5"), false);
+		CtInsertColumn(ct, _UU("SM_USER_COLUMN_6"), false);
+		CtInsertColumn(ct, _UU("SM_USER_COLUMN_7"), false);
+
+		for (i = 0;i < t.NumUser;i++)
+		{
+			RPC_ENUM_USER_ITEM *e = &t.Users[i];
+			wchar_t name[MAX_SIZE];
+			wchar_t group[MAX_SIZE];
+			wchar_t num[MAX_SIZE];
+			wchar_t time[MAX_SIZE];
+
+			StrToUni(name, sizeof(name), e->Name);
+
+			if (StrLen(e->GroupName) != 0)
+			{
+				StrToUni(group, sizeof(group), e->GroupName);
+			}
+			else
+			{
+				UniStrCpy(group, sizeof(group), _UU("SM_NO_GROUP"));
+			}
+
+			UniToStru(num, e->NumLogin);
+
+			GetDateTimeStrEx64(time, sizeof(time), SystemToLocal64(e->LastLoginTime), NULL);
+
+			CtInsert(ct,
+				name, e->Realname, group, e->Note, GetAuthTypeStr(e->AuthType),
+				num, time);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザー認証方法の文字列の取得
+wchar_t *GetAuthTypeStr(UINT id)
+{
+	char tmp[MAX_SIZE];
+	Format(tmp, sizeof(tmp), "SM_AUTHTYPE_%u", id);
+
+	return _UU(tmp);
+}
+
+// ユーザーの作成
+UINT PsUserCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"GROUP", CmdPrompt, _UU("CMD_UserCreate_Prompt_GROUP"), NULL, NULL},
+		{"REALNAME", CmdPrompt, _UU("CMD_UserCreate_Prompt_REALNAME"), NULL, NULL},
+		{"NOTE", CmdPrompt, _UU("CMD_UserCreate_Prompt_NOTE"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+	StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "GROUP"));
+	UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+	UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+	Trim(t.Name);
+	if (StrCmpi(t.Name, "*") == 0)
+	{
+		t.AuthType = AUTHTYPE_RADIUS;
+		t.AuthData = NewRadiusAuthData(NULL);
+	}
+	else
+	{
+		UCHAR random_pass[SHA1_SIZE];
+
+		Rand(random_pass, sizeof(random_pass));
+		t.AuthType = AUTHTYPE_PASSWORD;
+		t.AuthData = NewPasswordAuthDataRaw(random_pass);
+	}
+
+	// RPC 呼び出し
+	ret = ScCreateUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザー情報の変更
+UINT PsUserSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"GROUP", CmdPrompt, _UU("CMD_UserCreate_Prompt_GROUP"), NULL, NULL},
+		{"REALNAME", CmdPrompt, _UU("CMD_UserCreate_Prompt_REALNAME"), NULL, NULL},
+		{"NOTE", CmdPrompt, _UU("CMD_UserCreate_Prompt_NOTE"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 情報を更新する
+	StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "GROUP"));
+	UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+	UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザーの削除
+UINT PsUserDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_DELETE_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScDeleteUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザー情報の取得
+UINT PsUserGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		CT *ct;
+
+		// ユーザーデータを表示
+		ct = CtNewStandard();
+
+		// ユーザー名
+		StrToUni(tmp, sizeof(tmp), t.Name);
+		CtInsert(ct, _UU("CMD_UserGet_Column_Name"), tmp);
+
+		// 本名
+		CtInsert(ct, _UU("CMD_UserGet_Column_RealName"), t.Realname);
+
+		// 説明
+		CtInsert(ct, _UU("CMD_UserGet_Column_Note"), t.Note);
+
+		// グループ名
+		if (IsEmptyStr(t.GroupName) == false)
+		{
+			StrToUni(tmp, sizeof(tmp), t.GroupName);
+			CtInsert(ct, _UU("CMD_UserGet_Column_Group"), tmp);
+		}
+
+		// 有効期限
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ExpireTime), NULL);
+		CtInsert(ct, _UU("CMD_UserGet_Column_Expires"), tmp);
+
+		// 認証方法
+		CtInsert(ct, _UU("CMD_UserGet_Column_AuthType"), GetAuthTypeStr(t.AuthType));
+
+		switch (t.AuthType)
+		{
+		case AUTHTYPE_USERCERT:
+			if (t.AuthData != NULL)
+			{
+				AUTHUSERCERT *auc = (AUTHUSERCERT *)t.AuthData;
+
+				if (auc != NULL && auc->UserX != NULL)
+				{
+					// 登録済みユーザー固有証明書
+					GetAllNameFromX(tmp, sizeof(tmp), auc->UserX);
+					CtInsert(ct, _UU("CMD_UserGet_Column_UserCert"), tmp);
+				}
+			}
+			break;
+
+		case AUTHTYPE_ROOTCERT:
+			if (t.AuthData != NULL)
+			{
+				AUTHROOTCERT *arc = (AUTHROOTCERT *)t.AuthData;
+
+				if (IsEmptyUniStr(arc->CommonName) == false)
+				{
+					// 証明書の CN の値の限定
+					CtInsert(ct, _UU("CMD_UserGet_Column_RootCert_CN"), arc->CommonName);
+				}
+
+				if (arc->Serial != NULL && arc->Serial->size >= 1)
+				{
+					char tmp2[MAX_SIZE];
+
+					// 証明書のシリアル番号の限定
+					BinToStrEx(tmp2, sizeof(tmp2), arc->Serial->data, arc->Serial->size);
+					StrToUni(tmp, sizeof(tmp), tmp2);
+					CtInsert(ct, _UU("CMD_UserGet_Column_RootCert_SERIAL"), tmp);
+				}
+			}
+			break;
+
+		case AUTHTYPE_RADIUS:
+		case AUTHTYPE_NT:
+			if (t.AuthData != NULL)
+			{
+				AUTHRADIUS *ar = (AUTHRADIUS *)t.AuthData;
+
+				// 外部認証サーバーの認証ユーザー名
+				if (IsEmptyUniStr(ar->RadiusUsername) == false)
+				{
+					CtInsert(ct, _UU("CMD_UserGet_Column_RadiusAlias"), ar->RadiusUsername);
+				}
+			}
+			break;
+		}
+
+		CtInsert(ct, L"---", L"---");
+
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime), NULL);
+		CtInsert(ct, _UU("SM_USERINFO_CREATE"), tmp);
+
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.UpdatedTime), NULL);
+		CtInsert(ct, _UU("SM_USERINFO_UPDATE"), tmp);
+
+		CmdInsertTrafficInfo(ct, &t.Traffic);
+
+		UniToStru(tmp, t.NumLogin);
+		CtInsert(ct, _UU("SM_USERINFO_NUMLOGIN"), tmp);
+
+
+		CtFree(ct, c);
+
+		if (t.Policy != NULL)
+		{
+			c->Write(c, L"");
+			c->Write(c, _UU("CMD_UserGet_Policy"));
+			PrintPolicy(c, t.Policy, false);
+		}
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザーの認証方法を匿名認証に設定
+UINT PsUserAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 情報を更新する
+	FreeAuthData(t.AuthType, t.AuthData);
+
+	// 匿名認証に設定する
+	t.AuthType = AUTHTYPE_ANONYMOUS;
+	t.AuthData = NULL;
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザーの認証方法をパスワード認証に設定しパスワードを設定
+UINT PsUserPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 情報を更新する
+	FreeAuthData(t.AuthType, t.AuthData);
+
+	{
+		AUTHPASSWORD *pw;
+
+		pw = NewPasswordAuthData(t.Name, GetParamStr(o, "PASSWORD"));
+
+		// パスワード認証に設定する
+		t.AuthType = AUTHTYPE_PASSWORD;
+		t.AuthData = pw;
+	}
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザーの認証方法を固有証明書認証に設定し証明書を設定
+UINT PsUserCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	X *x;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// 証明書を読み込む
+	x = FileToX(GetParamStr(o, "LOADCERT"));
+	if (x == NULL)
+	{
+		c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+
+		FreeParamValueList(o);
+
+		return ERR_INTERNAL_ERROR;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		FreeX(x);
+		return ret;
+	}
+
+	// 情報を更新する
+	FreeAuthData(t.AuthType, t.AuthData);
+
+	{
+		AUTHUSERCERT *c;
+
+		c = NewUserCertAuthData(x);
+
+		FreeX(x);
+
+		// パスワード認証に設定する
+		t.AuthType = AUTHTYPE_USERCERT;
+		t.AuthData = c;
+	}
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 固有証明書認証のユーザーの登録されている証明書の取得
+UINT PsUserCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	AUTHUSERCERT *a;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	a = (AUTHUSERCERT *)t.AuthData;
+
+	if (t.AuthType != AUTHTYPE_USERCERT || a == NULL || a->UserX == NULL)
+	{
+		// ユーザーは固有証明書認証ではない
+		ret = ERR_INVALID_PARAMETER;
+
+		c->Write(c, _UU("CMD_UserCertGet_Not_Cert"));
+	}
+	else
+	{
+		if (XToFile(a->UserX, GetParamStr(o, "SAVECERT"), true) == false)
+		{
+			c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+		}
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// ユーザーの認証方法を署名済み証明書認証に設定
+UINT PsUserSignedSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"CN", CmdPrompt, _UU("CMD_UserSignedSet_Prompt_CN"), NULL, NULL},
+		{"SERIAL", CmdPrompt, _UU("CMD_UserSignedSet_Prompt_SERIAL"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 情報を更新する
+	FreeAuthData(t.AuthType, t.AuthData);
+
+	{
+		AUTHROOTCERT *c;
+		BUF *b;
+		X_SERIAL *serial = NULL;
+
+		b = StrToBin(GetParamStr(o, "SERIAL"));
+
+		if (b != NULL && b->Size >= 1)
+		{
+			serial = NewXSerial(b->Buf, b->Size);
+		}
+
+		FreeBuf(b);
+
+		c = NewRootCertAuthData(serial, GetParamUniStr(o, "CN"));
+
+		FreeXSerial(serial);
+
+		// パスワード認証に設定する
+		t.AuthType = AUTHTYPE_ROOTCERT;
+		t.AuthData = c;
+	}
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザーの認証方法を Radius 認証に設定
+UINT PsUserRadiusSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"ALIAS", CmdPrompt, _UU("CMD_UserRadiusSet_Prompt_ALIAS"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 情報を更新する
+	FreeAuthData(t.AuthType, t.AuthData);
+
+	{
+		AUTHRADIUS *a;
+
+		a = NewRadiusAuthData(GetParamUniStr(o, "ALIAS"));
+
+		// Radius 認証に設定する
+		t.AuthType = AUTHTYPE_RADIUS;
+		t.AuthData = a;
+	}
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザーの認証方法を NT ドメイン認証に設定
+UINT PsUserNTLMSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"ALIAS", CmdPrompt, _UU("CMD_UserRadiusSet_Prompt_ALIAS"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 情報を更新する
+	FreeAuthData(t.AuthType, t.AuthData);
+
+	{
+		AUTHRADIUS *a;
+
+		a = NewRadiusAuthData(GetParamUniStr(o, "ALIAS"));
+
+		// NT ドメイン認証に設定する
+		t.AuthType = AUTHTYPE_NT;
+		t.AuthData = a;
+	}
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザーのセキュリティ ポリシーの削除
+UINT PsUserPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 更新
+	if (t.Policy != NULL)
+	{
+		Free(t.Policy);
+		t.Policy = NULL;
+	}
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// ユーザーのセキュリティ ポリシーの設定
+UINT PsUserPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+		{"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 更新
+	if (t.Policy == NULL)
+	{
+		t.Policy = ClonePolicy(GetDefaultPolicy());
+	}
+
+	// 編集
+	if (EditPolicy(c, t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), false) == false)
+	{
+		ret = ERR_INVALID_PARAMETER;
+	}
+	else
+	{
+		// ユーザーオブジェクトを書き込み
+		ret = ScSetUser(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return ret;
+}
+
+// 文字列を日時に変換
+UINT64 StrToDateTime64(char *str)
+{
+	UINT64 ret = 0;
+	TOKEN_LIST *t;
+	UINT a, b, c, d, e, f;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return INFINITE;
+	}
+
+	if (IsEmptyStr(str) || StrCmpi(str, "none") == 0)
+	{
+		return 0;
+	}
+
+	t = ParseToken(str, ":/,. \"");
+	if (t->NumTokens != 6)
+	{
+		FreeToken(t);
+		return INFINITE;
+	}
+
+	a = ToInt(t->Token[0]);
+	b = ToInt(t->Token[1]);
+	c = ToInt(t->Token[2]);
+	d = ToInt(t->Token[3]);
+	e = ToInt(t->Token[4]);
+	f = ToInt(t->Token[5]);
+
+	ret = INFINITE;
+
+	if (a >= 1000 && a <= 9999 && b >= 1 && b <= 12 && c >= 1 && c <= 31 &&
+		d >= 0 && d <= 23 && e >= 0 && e <= 59 && f >= 0 && f <= 59)
+	{
+		SYSTEMTIME t;
+
+		Zero(&t, sizeof(t));
+		t.wYear = a;
+		t.wMonth = b;
+		t.wDay = c;
+		t.wHour = d;
+		t.wMinute = e;
+		t.wSecond = f;
+
+		ret = SystemToUINT64(&t);
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// 日時文字列の評価
+bool CmdEvalDateTime(CONSOLE *c, wchar_t *str, void *param)
+{
+	UINT64 ret;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	ret = StrToDateTime64(tmp);
+
+	if (ret == INFINITE)
+	{
+		c->Write(c, _UU("CMD_EVAL_DATE_TIME_FAILED"));
+		return false;
+	}
+
+	return true;
+}
+
+// ユーザーの有効期限の設定
+UINT PsUserExpiresSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	UINT64 expires;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"EXPIRES", CmdPrompt, _UU("CMD_UserExpiresSet_Prompt_EXPIRES"), CmdEvalDateTime, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	// ユーザーオブジェクトを取得
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	ret = ScGetUser(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 情報を更新する
+	expires = StrToDateTime64(GetParamStr(o, "EXPIRES"));
+
+	if (expires != 0)
+	{
+		expires = LocalToSystem64(expires);
+	}
+
+	t.ExpireTime = expires;
+
+	// ユーザーオブジェクトを書き込み
+	ret = ScSetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループ一覧の取得
+UINT PsGroupList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_GROUP t;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumGroup(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+		UINT i;
+
+		CtInsertColumn(ct, _UU("SM_GROUPLIST_NAME"), false);
+		CtInsertColumn(ct, _UU("SM_GROUPLIST_REALNAME"), false);
+		CtInsertColumn(ct, _UU("SM_GROUPLIST_NOTE"), false);
+		CtInsertColumn(ct, _UU("SM_GROUPLIST_NUMUSERS"), false);
+
+		for (i = 0;i < t.NumGroup;i++)
+		{
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			RPC_ENUM_GROUP_ITEM *e = &t.Groups[i];
+
+			StrToUni(tmp1, sizeof(tmp1), e->Name);
+			UniToStru(tmp2, e->NumUsers);
+
+			CtInsert(ct, tmp1, e->Realname, e->Note, tmp2);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumGroup(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループの作成
+UINT PsGroupCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_GROUP t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"REALNAME", CmdPrompt, _UU("CMD_GroupCreate_Prompt_REALNAME"), NULL, NULL},
+		{"NOTE", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NOTE"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+	UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+	UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+	// RPC 呼び出し
+	ret = ScCreateGroup(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetGroup(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループ情報の設定
+UINT PsGroupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_GROUP t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"REALNAME", CmdPrompt, _UU("CMD_GroupCreate_Prompt_REALNAME"), NULL, NULL},
+		{"NOTE", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NOTE"), NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetGroup(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	// 情報更新
+	UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+	UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+	// RPC 呼び出し
+	ret = ScSetGroup(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcSetGroup(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループの削除
+UINT PsGroupDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_DELETE_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScDeleteGroup(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループ情報と所属しているユーザー一覧の取得
+UINT PsGroupGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_GROUP t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetGroup(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		char groupname[MAX_USERNAME_LEN + 1];
+		CT *ct = CtNewStandard();
+
+		StrCpy(groupname, sizeof(groupname), t.Name);
+
+		StrToUni(tmp, sizeof(tmp), t.Name);
+		CtInsert(ct, _UU("CMD_GroupGet_Column_NAME"), tmp);
+		CtInsert(ct, _UU("CMD_GroupGet_Column_REALNAME"), t.Realname);
+		CtInsert(ct, _UU("CMD_GroupGet_Column_NOTE"), t.Note);
+
+		CtFree(ct, c);
+
+		if (t.Policy != NULL)
+		{
+			c->Write(c, L"");
+			c->Write(c, _UU("CMD_GroupGet_Column_POLICY"));
+
+			PrintPolicy(c, t.Policy, false);
+		}
+
+		{
+			RPC_ENUM_USER t;
+			bool b = false;
+
+			Zero(&t, sizeof(t));
+
+			StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+			if (ScEnumUser(ps->Rpc, &t) == ERR_NO_ERROR)
+			{
+				UINT i;
+
+				for (i = 0;i < t.NumUser;i++)
+				{
+					RPC_ENUM_USER_ITEM *u = &t.Users[i];
+
+					if (StrCmpi(u->GroupName, groupname) == 0)
+					{
+						if (b == false)
+						{
+							b = true;
+							c->Write(c, L"");
+							c->Write(c, _UU("CMD_GroupGet_Column_MEMBERS"));
+						}
+
+						UniFormat(tmp, sizeof(tmp), L" %S", u->Name);
+						c->Write(c, tmp);
+					}
+				}
+				FreeRpcEnumUser(&t);
+
+				if (b)
+				{
+					c->Write(c, L"");
+				}
+			}
+		}
+
+	}
+
+	FreeRpcSetGroup(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループにユーザーを追加
+UINT PsGroupJoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"USERNAME", CmdPrompt, _UU("CMD_GroupJoin_Prompt_USERNAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "USERNAME"));
+
+	// RPC 呼び出し
+	ret = ScGetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// グループの更新
+		StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "[name]"));
+
+		ret = ScSetUser(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループからユーザーを削除
+UINT PsGroupUnjoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_USER t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_GroupUnjoin_Prompt_name"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetUser(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// グループの更新
+		StrCpy(t.GroupName, sizeof(t.GroupName), "");
+
+		ret = ScSetUser(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeRpcSetUser(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループのセキュリティ ポリシーの削除
+UINT PsGroupPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_GROUP t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetGroup(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// 更新
+		if (t.Policy != NULL)
+		{
+			Free(t.Policy);
+			t.Policy = NULL;
+		}
+
+		ret = ScSetGroup(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeRpcSetGroup(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// グループのセキュリティ ポリシーの設定
+UINT PsGroupPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SET_GROUP t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+		{"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+		{"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetGroup(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// 更新
+		if (t.Policy == NULL)
+		{
+			t.Policy = ClonePolicy(GetDefaultPolicy());
+		}
+
+		if (EditPolicy(c, t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), false) == false)
+		{
+			// エラー発生
+			FreeRpcSetGroup(&t);
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ERR_INTERNAL_ERROR;
+		}
+
+		ret = ScSetGroup(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeRpcSetGroup(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 接続中のセッション一覧の取得
+UINT PsSessionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_SESSION t;
+	UINT server_type = 0;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	{
+		// サーバー種類の取得
+		RPC_SERVER_INFO t;
+
+		Zero(&t, sizeof(t));
+
+		if (ScGetServerInfo(ps->Rpc, &t) == ERR_NO_ERROR)
+		{
+			server_type = t.ServerType;
+
+			FreeRpcServerInfo(&t);
+		}
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumSession(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+		UINT i;
+
+		CtInsertColumn(ct, _UU("SM_SESS_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("SM_SESS_COLUMN_8"), false);
+		CtInsertColumn(ct, _UU("SM_SESS_COLUMN_2"), false);
+		CtInsertColumn(ct, _UU("SM_SESS_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("SM_SESS_COLUMN_4"), false);
+		CtInsertColumn(ct, _UU("SM_SESS_COLUMN_5"), true);
+		CtInsertColumn(ct, _UU("SM_SESS_COLUMN_6"), true);
+		CtInsertColumn(ct, _UU("SM_SESS_COLUMN_7"), true);
+
+		for (i = 0;i < t.NumSession;i++)
+		{
+			RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t *tmp2;
+			wchar_t tmp3[MAX_SIZE];
+			wchar_t tmp4[MAX_SIZE];
+			wchar_t tmp5[MAX_SIZE];
+			wchar_t tmp6[MAX_SIZE];
+			wchar_t tmp7[MAX_SIZE];
+			wchar_t tmp8[MAX_SIZE];
+			bool free_tmp2 = false;
+
+			StrToUni(tmp1, sizeof(tmp1), e->Name);
+
+			tmp2 = _UU("SM_SESS_NORMAL");
+			if (server_type != SERVER_TYPE_STANDALONE)
+			{
+				if (e->RemoteSession)
+				{
+					tmp2 = ZeroMalloc(MAX_SIZE);
+					UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_REMOTE"), e->RemoteHostname);
+					free_tmp2 = true;
+				}
+				else
+				{
+					if (StrLen(e->RemoteHostname) == 0)
+					{
+						tmp2 = _UU("SM_SESS_LOCAL");
+					}
+					else
+					{
+						tmp2 = ZeroMalloc(MAX_SIZE);
+						UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_LOCAL_2"), e->RemoteHostname);
+						free_tmp2 = true;
+					}
+				}
+			}
+			if (e->LinkMode)
+			{
+				if (free_tmp2)
+				{
+					Free(tmp2);
+					free_tmp2 = false;
+				}
+				tmp2 = _UU("SM_SESS_LINK");
+			}
+			else if (e->SecureNATMode)
+			{
+				/*if (free_tmp2)
+				{
+					Free(tmp2);
+					free_tmp2 = false;
+				}*/
+				tmp2 = _UU("SM_SESS_SNAT");
+			}
+
+			StrToUni(tmp3, sizeof(tmp3), e->Username);
+
+			StrToUni(tmp4, sizeof(tmp4), e->Hostname);
+			if (e->LinkMode)
+			{
+				UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LINK_HOSTNAME"));
+			}
+			else if (e->SecureNATMode)
+			{
+				UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_SNAT_HOSTNAME"));
+			}
+			else if (e->BridgeMode)
+			{
+				UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_BRIDGE_HOSTNAME"));
+			}
+			else if (StartWith(e->Username, L3_USERNAME))
+			{
+				UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LAYER3_HOSTNAME"));
+			}
+
+			UniFormat(tmp5, sizeof(tmp5), L"%u / %u", e->CurrentNumTcp, e->MaxNumTcp);
+			if (e->LinkMode)
+			{
+				UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_LINK_TCP"));
+			}
+			else if (e->SecureNATMode)
+			{
+				UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_SNAT_TCP"));
+			}
+			else if (e->BridgeMode)
+			{
+				UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_BRIDGE_TCP"));
+			}
+
+			UniToStr3(tmp6, sizeof(tmp6), e->PacketSize);
+			UniToStr3(tmp7, sizeof(tmp7), e->PacketNum);
+
+			if (e->VLanId == 0)
+			{
+				UniStrCpy(tmp8, sizeof(tmp8), _UU("CM_ST_NO_VLAN"));
+			}
+			else
+			{
+				UniToStru(tmp8, e->VLanId);
+			}
+
+			CtInsert(ct, tmp1, tmp8, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7);
+
+			if (free_tmp2)
+			{
+				Free(tmp2);
+			}
+		}
+
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumSession(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// NODE_INFO の表示
+void CmdPrintNodeInfo(CT *ct, NODE_INFO *info)
+{
+	wchar_t tmp[MAX_SIZE];
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (ct == NULL || info == NULL)
+	{
+		return;
+	}
+
+	StrToUni(tmp, sizeof(tmp), info->ClientProductName);
+	CtInsert(ct, _UU("SM_NODE_CLIENT_NAME"), tmp);
+
+	UniFormat(tmp, sizeof(tmp), L"%u.%02u", Endian32(info->ClientProductVer) / 100, Endian32(info->ClientProductVer) % 100);
+	CtInsert(ct, _UU("SM_NODE_CLIENT_VER"), tmp);
+
+	UniFormat(tmp, sizeof(tmp), L"Build %u", Endian32(info->ClientProductBuild));
+	CtInsert(ct, _UU("SM_NODE_CLIENT_BUILD"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ClientOsName);
+	CtInsert(ct, _UU("SM_NODE_CLIENT_OS_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ClientOsVer);
+	CtInsert(ct, _UU("SM_NODE_CLIENT_OS_VER"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ClientOsProductId);
+	CtInsert(ct, _UU("SM_NODE_CLIENT_OS_PID"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ClientHostname);
+	CtInsert(ct, _UU("SM_NODE_CLIENT_HOST"), tmp);
+
+	IPToStr4or6(str, sizeof(str), info->ClientIpAddress, info->ClientIpAddress6);
+	StrToUni(tmp, sizeof(tmp), str);
+	CtInsert(ct, _UU("SM_NODE_CLIENT_IP"), tmp);
+
+	UniToStru(tmp, Endian32(info->ClientPort));
+	CtInsert(ct, _UU("SM_NODE_CLIENT_PORT"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ServerHostname);
+	CtInsert(ct, _UU("SM_NODE_SERVER_HOST"), tmp);
+
+	IPToStr4or6(str, sizeof(str), info->ServerIpAddress, info->ServerIpAddress6);
+	StrToUni(tmp, sizeof(tmp), str);
+	CtInsert(ct, _UU("SM_NODE_SERVER_IP"), tmp);
+
+	UniToStru(tmp, Endian32(info->ServerPort));
+	CtInsert(ct, _UU("SM_NODE_SERVER_PORT"), tmp);
+
+	if (StrLen(info->ProxyHostname) != 0)
+	{
+		StrToUni(tmp, sizeof(tmp), info->ProxyHostname);
+		CtInsert(ct, _UU("SM_NODE_PROXY_HOSTNAME"), tmp);
+
+		IPToStr4or6(str, sizeof(str), info->ProxyIpAddress, info->ProxyIpAddress6);
+		StrToUni(tmp, sizeof(tmp), str);
+		CtInsert(ct, _UU("SM_NODE_PROXY_IP"), tmp);
+
+		UniToStru(tmp, Endian32(info->ProxyPort));
+		CtInsert(ct, _UU("SM_NODE_PROXY_PORT"), tmp);
+	}
+}
+
+// セッション情報の取得
+UINT PsSessionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_SESSION_STATUS t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_SessionGet_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScGetSessionStatus(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		char str[MAX_SIZE];
+		CT *ct = CtNewStandard();
+
+		if (t.ClientIp != 0)
+		{
+			IPToStr4or6(str, sizeof(str), t.ClientIp, t.ClientIp6);
+			StrToUni(tmp, sizeof(tmp), str);
+			CtInsert(ct, _UU("SM_CLIENT_IP"), tmp);
+		}
+
+		if (StrLen(t.ClientHostName) != 0)
+		{
+			StrToUni(tmp, sizeof(tmp), t.ClientHostName);
+			CtInsert(ct, _UU("SM_CLIENT_HOSTNAME"), tmp);
+		}
+
+		StrToUni(tmp, sizeof(tmp), t.Username);
+		CtInsert(ct, _UU("SM_SESS_STATUS_USERNAME"), tmp);
+
+		if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0)
+		{
+			StrToUni(tmp, sizeof(tmp), t.RealUsername);
+			CtInsert(ct, _UU("SM_SESS_STATUS_REALUSER"), tmp);
+		}
+
+		if (IsEmptyStr(t.GroupName) == false)
+		{
+			StrToUni(tmp, sizeof(tmp), t.GroupName);
+			CtInsert(ct, _UU("SM_SESS_STATUS_GROUPNAME"), tmp);
+		}
+
+
+		CmdPrintStatusToListViewEx(ct, &t.Status, true);
+
+		if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0 &&
+			StartWith(t.Username, L3_USERNAME) == false)
+		{
+			CmdPrintNodeInfo(ct, &t.NodeInfo);
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeRpcSessionStatus(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// セッションの切断
+UINT PsSessionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_DELETE_SESSION t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_SessionGet_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+	// RPC 呼び出し
+	ret = ScDeleteSession(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// MAC アドレス テーブル データベースの取得
+UINT PsMacTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_MAC_TABLE t;
+	UINT i;
+
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[session_name]", NULL, NULL, NULL, NULL,}
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumMacTable(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+		char *session_name = GetParamStr(o, "[session_name]");
+
+		if (IsEmptyStr(session_name))
+		{
+			session_name = NULL;
+		}
+
+		CtInsertColumn(ct, _UU("CMD_ID"), false);
+		CtInsertColumn(ct, _UU("SM_MAC_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("SM_MAC_COLUMN_1A"), false);
+		CtInsertColumn(ct, _UU("SM_MAC_COLUMN_2"), false);
+		CtInsertColumn(ct, _UU("SM_MAC_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("SM_MAC_COLUMN_4"), false);
+		CtInsertColumn(ct, _UU("SM_MAC_COLUMN_5"), false);
+
+		for (i = 0;i < t.NumMacTable;i++)
+		{
+			char str[MAX_SIZE];
+			wchar_t tmp0[128];
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			wchar_t tmp3[MAX_SIZE];
+			wchar_t tmp4[MAX_SIZE];
+			wchar_t tmp5[MAX_SIZE];
+			wchar_t tmp6[MAX_SIZE];
+
+			RPC_ENUM_MAC_TABLE_ITEM *e = &t.MacTables[i];
+
+			if (session_name == NULL || StrCmpi(e->SessionName, session_name) == 0)
+			{
+				UniToStru(tmp0, e->Key);
+
+				StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+				MacToStr(str, sizeof(str), e->MacAddress);
+				StrToUni(tmp2, sizeof(tmp2), str);
+
+				GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+				GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+				if (StrLen(e->RemoteHostname) == 0)
+				{
+					UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+				}
+				else
+				{
+					UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+				}
+
+				UniToStru(tmp6, e->VlanId);
+				if (e->VlanId == 0)
+				{
+					UniStrCpy(tmp6, sizeof(tmp6), _UU("CM_ST_NONE"));
+				}
+
+				CtInsert(ct,
+					tmp0, tmp1, tmp6, tmp2, tmp3, tmp4, tmp5);
+			}
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumMacTable(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// MAC アドレス テーブル エントリの削除
+UINT PsMacDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_DELETE_TABLE t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_MacDelete_Prompt"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Key = GetParamInt(o, "[id]");
+
+	// RPC 呼び出し
+	ret = ScDeleteMacTable(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// IP アドレス テーブル データベースの取得
+UINT PsIpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_IP_TABLE t;
+	UINT i;
+
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[session_name]", NULL, NULL, NULL, NULL,}
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumIpTable(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+		char *session_name = GetParamStr(o, "[session_name]");
+
+		if (IsEmptyStr(session_name))
+		{
+			session_name = NULL;
+		}
+
+		CtInsertColumn(ct, _UU("CMD_ID"), false);
+		CtInsertColumn(ct, _UU("SM_IP_COLUMN_1"), false);
+		CtInsertColumn(ct, _UU("SM_IP_COLUMN_2"), false);
+		CtInsertColumn(ct, _UU("SM_IP_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("SM_IP_COLUMN_4"), false);
+		CtInsertColumn(ct, _UU("SM_IP_COLUMN_5"), false);
+
+		for (i = 0;i < t.NumIpTable;i++)
+		{
+			char str[MAX_SIZE];
+			wchar_t tmp0[128];
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			wchar_t tmp3[MAX_SIZE];
+			wchar_t tmp4[MAX_SIZE];
+			wchar_t tmp5[MAX_SIZE];
+			RPC_ENUM_IP_TABLE_ITEM *e = &t.IpTables[i];
+
+			if (session_name == NULL || StrCmpi(e->SessionName, session_name) == 0)
+			{
+				UniToStru(tmp0, e->Key);
+
+				StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+				if (e->DhcpAllocated == false)
+				{
+					IPToStr(str, sizeof(str), &e->IpV6);
+					StrToUni(tmp2, sizeof(tmp2), str);
+				}
+				else
+				{
+					IPToStr(str, sizeof(str), &e->IpV6);
+					UniFormat(tmp2, sizeof(tmp2), _UU("SM_MAC_IP_DHCP"), str);
+				}
+
+				GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+				GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+				if (StrLen(e->RemoteHostname) == 0)
+				{
+					UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+				}
+				else
+				{
+					UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+				}
+
+				CtInsert(ct,
+					tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+			}
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumIpTable(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// IP アドレス テーブル エントリの削除
+UINT PsIpDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_DELETE_TABLE t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_MacDelete_Prompt"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Key = GetParamInt(o, "[id]");
+
+	// RPC 呼び出し
+	ret = ScDeleteIpTable(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 NAT および DHCP サーバー機能 (SecureNAT 機能) の有効化
+UINT PsSecureNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnableSecureNAT(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 NAT および DHCP サーバー機能 (SecureNAT 機能) の無効化
+UINT PsSecureNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_HUB t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScDisableSecureNAT(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 NAT および DHCP サーバー機能 (SecureNAT 機能) の動作状況の取得
+UINT PsSecureNatStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_NAT_STATUS t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATStatus(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		CT *ct = CtNewStandard();
+
+		StrToUni(tmp, sizeof(tmp), ps->HubName);
+		CtInsert(ct, _UU("SM_HUB_COLUMN_1"), tmp);
+
+		UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumTcpSessions);
+		CtInsert(ct, _UU("NM_STATUS_TCP"), tmp);
+
+		UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumUdpSessions);
+		CtInsert(ct, _UU("NM_STATUS_UDP"), tmp);
+
+		UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_CLIENT"), t.NumDhcpClients);
+		CtInsert(ct, _UU("NM_STATUS_DHCP"), tmp);
+
+		CtFree(ct, c);
+	}
+
+	FreeRpcNatStatus(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想ホストのネットワーク インターフェイス設定の取得
+UINT PsSecureNatHostGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		char str[MAX_SIZE];
+		CT *ct = CtNewStandard();
+
+		// 使用フラグ
+		// MAC アドレス
+		MacToStr(str, sizeof(str), t.MacAddress);
+		StrToUni(tmp, sizeof(tmp), str);
+		CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_MAC"), tmp);
+
+		// IP アドレス
+		IPToUniStr(tmp, sizeof(tmp), &t.Ip);
+		CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_IP"), tmp);
+
+		// サブネット マスク
+		IPToUniStr(tmp, sizeof(tmp), &t.Mask);
+		CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_MASK"), tmp);
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想ホストのネットワーク インターフェイス設定の変更
+UINT PsSecureNatHostSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"MAC", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_MAC"), NULL, NULL},
+		{"IP", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_IP"), CmdEvalIp, NULL},
+		{"MASK", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_MASK"), CmdEvalIp, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		char *mac, *ip, *mask;
+		bool ok = true;
+
+		StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+		mac = GetParamStr(o, "MAC");
+		ip = GetParamStr(o, "IP");
+		mask = GetParamStr(o, "MASK");
+
+		if (IsEmptyStr(mac) == false)
+		{
+			BUF *b = StrToBin(mac);
+
+			if (b == NULL || b->Size != 6)
+			{
+				ok = false;
+			}
+			else
+			{
+				Copy(t.MacAddress, b->Buf, 6);
+			}
+
+			FreeBuf(b);
+		}
+
+		if (IsEmptyStr(ip) == false)
+		{
+			if (IsIpStr4(ip) == false)
+			{
+				ok = false;
+			}
+			else
+			{
+				UINT u = StrToIP32(ip);
+
+				if (u == 0 || u == 0xffffffff)
+				{
+					ok = false;
+				}
+				else
+				{
+					UINTToIP(&t.Ip, u);
+				}
+			}
+		}
+
+		if (IsEmptyStr(mask) == false)
+		{
+			if (IsIpStr4(mask) == false)
+			{
+				ok = false;
+			}
+			else
+			{
+				StrToIP(&t.Mask, mask);
+			}
+		}
+
+		if (ok == false)
+		{
+			// パラメータが不正
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+		else
+		{
+			ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 NAT 機能の設定の取得
+UINT PsNatGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		CT *ct = CtNewStandard();
+
+		// 仮想 NAT 機能を使用する
+		CtInsert(ct, _UU("CMD_NatGet_Column_USE"), t.UseNat ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+		// MTU 値
+		UniToStru(tmp, t.Mtu);
+		CtInsert(ct, _UU("CMD_NetGet_Column_MTU"), tmp);
+
+		// TCP セッションのタイムアウト (秒)
+		UniToStru(tmp, t.NatTcpTimeout);
+		CtInsert(ct, _UU("CMD_NatGet_Column_TCP"), tmp);
+
+		// UDP セッションのタイムアウト (秒)
+		UniToStru(tmp, t.NatUdpTimeout);
+		CtInsert(ct, _UU("CMD_NatGet_Column_UDP"), tmp);
+
+		// ログ保存
+		CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_LOG"), t.SaveLog ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 NAT 機能の有効化
+UINT PsNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		bool ok = true;
+
+		t.UseNat = true;
+
+		if (ok == false)
+		{
+			// パラメータが不正
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+		else
+		{
+			StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+			ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 NAT 機能の無効化
+UINT PsNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		bool ok = true;
+
+		t.UseNat = false;
+
+		if (ok == false)
+		{
+			// パラメータが不正
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+		else
+		{
+			StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+			ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 NAT 機能の設定の変更
+UINT PsNatSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX mtu_mm =
+	{
+		"CMD_NatSet_Eval_MTU", TCP_HEADER_SIZE + IP_HEADER_SIZE + MAC_HEADER_SIZE + 8, MAX_L3_DATA_SIZE,
+	};
+	CMD_EVAL_MIN_MAX tcp_mm =
+	{
+		"CMD_NatSet_Eval_TCP", NAT_TCP_MIN_TIMEOUT / 1000, NAT_TCP_MAX_TIMEOUT / 1000,
+	};
+	CMD_EVAL_MIN_MAX udp_mm =
+	{
+		"CMD_NatSet_Eval_UDP", NAT_UDP_MIN_TIMEOUT / 1000, NAT_UDP_MAX_TIMEOUT / 1000,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"MTU", CmdPrompt, _UU("CMD_NatSet_Prompt_MTU"), CmdEvalMinMax, &mtu_mm},
+		{"TCPTIMEOUT", CmdPrompt, _UU("CMD_NatSet_Prompt_TCPTIMEOUT"), CmdEvalMinMax, &tcp_mm},
+		{"UDPTIMEOUT", CmdPrompt, _UU("CMD_NatSet_Prompt_UDPTIMEOUT"), CmdEvalMinMax, &udp_mm},
+		{"LOG", CmdPrompt, _UU("CMD_NatSet_Prompt_LOG"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		bool ok = true;
+
+		t.Mtu = GetParamInt(o, "MTU");
+		t.NatTcpTimeout = GetParamInt(o, "TCPTIMEOUT");
+		t.NatUdpTimeout = GetParamInt(o, "UDPTIMEOUT");
+		t.SaveLog = GetParamYes(o, "LOG");
+
+		if (ok == false)
+		{
+			// パラメータが不正
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+		else
+		{
+			StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+			ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 NAT 機能のセッション テーブルの取得
+UINT PsNatTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_NAT t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumNAT(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+		UINT i;
+
+		CtInsertColumn(ct, _UU("NM_NAT_ID"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_PROTOCOL"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_SRC_HOST"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_SRC_PORT"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_DST_HOST"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_DST_PORT"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_CREATED"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_LAST_COMM"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_SIZE"), false);
+		CtInsertColumn(ct, _UU("NM_NAT_TCP_STATUS"), false);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_ENUM_NAT_ITEM *e = &t.Items[i];
+			wchar_t tmp0[MAX_SIZE];
+			wchar_t *tmp1 = L"";
+			wchar_t tmp2[MAX_SIZE];
+			wchar_t tmp3[MAX_SIZE];
+			wchar_t tmp4[MAX_SIZE];
+			wchar_t tmp5[MAX_SIZE];
+			wchar_t tmp6[MAX_SIZE];
+			wchar_t tmp7[MAX_SIZE];
+			wchar_t tmp8[MAX_SIZE];
+			wchar_t *tmp9 = L"";
+			char v1[128], v2[128];
+
+			// ID
+			UniToStru(tmp0, e->Id);
+
+			// プロトコル
+			switch (e->Protocol)
+			{
+			case NAT_TCP:
+				tmp1 = _UU("NM_NAT_PROTO_TCP");
+				break;
+			case NAT_UDP:
+				tmp1 = _UU("NM_NAT_PROTO_UDP");
+				break;
+			case NAT_DNS:
+				tmp1 = _UU("NM_NAT_PROTO_DNS");
+				break;
+			}
+
+			// 接続元ホスト
+			StrToUni(tmp2, sizeof(tmp2), e->SrcHost);
+
+			// 接続元ポート
+			UniToStru(tmp3, e->SrcPort);
+
+			// 接続先ホスト
+			StrToUni(tmp4, sizeof(tmp4), e->DestHost);
+
+			// 接続先ポート
+			UniToStru(tmp5, e->DestPort);
+
+			// セッション作成日時
+			GetDateTimeStrEx64(tmp6, sizeof(tmp6), SystemToLocal64(e->CreatedTime), NULL);
+
+			// 最終通信日時
+			GetDateTimeStrEx64(tmp7, sizeof(tmp7), SystemToLocal64(e->LastCommTime), NULL);
+
+			// 通信量
+			ToStr3(v1, sizeof(v1), e->RecvSize);
+			ToStr3(v2, sizeof(v2), e->SendSize);
+			UniFormat(tmp8, sizeof(tmp8), L"%S / %S", v1, v2);
+
+			// TCP 状態
+			if (e->Protocol == NAT_TCP)
+			{
+				switch (e->TcpStatus)
+				{
+				case NAT_TCP_CONNECTING:
+					tmp9 = _UU("NAT_TCP_CONNECTING");
+					break;
+				case NAT_TCP_SEND_RESET:
+					tmp9 = _UU("NAT_TCP_SEND_RESET");
+					break;
+				case NAT_TCP_CONNECTED:
+					tmp9 = _UU("NAT_TCP_CONNECTED");
+					break;
+				case NAT_TCP_ESTABLISHED:
+					tmp9 = _UU("NAT_TCP_ESTABLISHED");
+					break;
+				case NAT_TCP_WAIT_DISCONNECT:
+					tmp9 = _UU("NAT_TCP_WAIT_DISCONNECT");
+					break;
+				}
+			}
+
+			CtInsert(ct,
+				tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumNat(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 DHCP サーバー機能の設定の取得
+UINT PsDhcpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		CT *ct = CtNewStandard();
+
+		// 仮想 DHCP 機能を使用する
+		CtInsert(ct, _UU("CMD_DhcpGet_Column_USE"), t.UseDhcp ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+		// 配布アドレス帯の開始
+		IPToUniStr(tmp, sizeof(tmp), &t.DhcpLeaseIPStart);
+		CtInsert(ct, _UU("CMD_DhcpGet_Column_IP1"), tmp);
+
+		// 配布アドレス帯の終了
+		IPToUniStr(tmp, sizeof(tmp), &t.DhcpLeaseIPEnd);
+		CtInsert(ct, _UU("CMD_DhcpGet_Column_IP2"), tmp);
+
+		// サブネット マスク
+		IPToUniStr(tmp, sizeof(tmp), &t.DhcpSubnetMask);
+		CtInsert(ct, _UU("CMD_DhcpGet_Column_MASK"), tmp);
+
+		// リース期限 (秒)
+		UniToStru(tmp, t.DhcpExpireTimeSpan);
+		CtInsert(ct, _UU("CMD_DhcpGet_Column_LEASE"), tmp);
+
+		// デフォルトゲートウェイアドレス
+		UniStrCpy(tmp, sizeof(tmp), _UU("SEC_NONE"));
+		if (IPToUINT(&t.DhcpGatewayAddress) != 0)
+		{
+			IPToUniStr(tmp, sizeof(tmp), &t.DhcpGatewayAddress);
+		}
+		CtInsert(ct, _UU("CMD_DhcpGet_Column_GW"), tmp);
+
+		// DNS サーバー アドレス
+		UniStrCpy(tmp, sizeof(tmp), _UU("SEC_NONE"));
+		if (IPToUINT(&t.DhcpDnsServerAddress) != 0)
+		{
+			IPToUniStr(tmp, sizeof(tmp), &t.DhcpDnsServerAddress);
+		}
+		CtInsert(ct, _UU("CMD_DhcpGet_Column_DNS"), tmp);
+
+		// ドメイン名
+		StrToUni(tmp, sizeof(tmp), t.DhcpDomainName);
+		CtInsert(ct, _UU("CMD_DhcpGet_Column_DOMAIN"), tmp);
+
+		// ログ保存
+		CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_LOG"), t.SaveLog ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+		CtFree(ct, c);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 DHCP サーバー機能の有効化
+UINT PsDhcpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		bool ok = true;
+
+		t.UseDhcp = true;
+
+		if (ok == false)
+		{
+			// パラメータが不正
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+		else
+		{
+			StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+			ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 DHCP サーバー機能の無効化
+UINT PsDhcpDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		bool ok = true;
+
+		t.UseDhcp = false;
+
+		if (ok == false)
+		{
+			// パラメータが不正
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+		else
+		{
+			ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 DHCP サーバー機能の設定の変更
+UINT PsDhcpSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	VH_OPTION t;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX mm =
+	{
+		"CMD_NatSet_Eval_UDP", NAT_UDP_MIN_TIMEOUT / 1000, NAT_UDP_MAX_TIMEOUT / 1000,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"START", CmdPrompt, _UU("CMD_DhcpSet_Prompt_START"), CmdEvalIp, NULL},
+		{"END", CmdPrompt, _UU("CMD_DhcpSet_Prompt_END"), CmdEvalIp, NULL},
+		{"MASK", CmdPrompt, _UU("CMD_DhcpSet_Prompt_MASK"), CmdEvalIp, NULL},
+		{"EXPIRE", CmdPrompt, _UU("CMD_DhcpSet_Prompt_EXPIRE"), CmdEvalMinMax, &mm},
+		{"GW", CmdPrompt, _UU("CMD_DhcpSet_Prompt_GW"), CmdEvalIp, NULL},
+		{"DNS", CmdPrompt, _UU("CMD_DhcpSet_Prompt_DNS"), CmdEvalIp, NULL},
+		{"DOMAIN", CmdPrompt, _UU("CMD_DhcpSet_Prompt_DOMAIN"), NULL, NULL},
+		{"LOG", CmdPrompt, _UU("CMD_NatSet_Prompt_LOG"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		bool ok = true;
+
+		StrToIP(&t.DhcpLeaseIPStart, GetParamStr(o, "START"));
+		StrToIP(&t.DhcpLeaseIPEnd, GetParamStr(o, "END"));
+		StrToIP(&t.DhcpSubnetMask, GetParamStr(o, "MASK"));
+		t.DhcpExpireTimeSpan = GetParamInt(o, "EXPIRE");
+		StrToIP(&t.DhcpGatewayAddress, GetParamStr(o, "GW"));
+		StrToIP(&t.DhcpDnsServerAddress, GetParamStr(o, "DNS"));
+		StrCpy(t.DhcpDomainName, sizeof(t.DhcpDomainName), GetParamStr(o, "DOMAIN"));
+		t.SaveLog = GetParamYes(o, "LOG");
+
+		if (ok == false)
+		{
+			// パラメータが不正
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+		else
+		{
+			StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+			ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// SecureNAT 機能の仮想 DHCP サーバー機能のリース テーブルの取得
+UINT PsDhcpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_DHCP t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumDHCP(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNew();
+		UINT i;
+
+		CtInsertColumn(ct, _UU("DHCP_DHCP_ID"), false);
+		CtInsertColumn(ct, _UU("DHCP_LEASED_TIME"), false);
+		CtInsertColumn(ct, _UU("DHCP_EXPIRE_TIME"), false);
+		CtInsertColumn(ct, _UU("DHCP_MAC_ADDRESS"), false);
+		CtInsertColumn(ct, _UU("DHCP_IP_ADDRESS"), false);
+		CtInsertColumn(ct, _UU("DHCP_HOSTNAME"), false);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_ENUM_DHCP_ITEM *e = &t.Items[i];
+			wchar_t tmp0[MAX_SIZE];
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			wchar_t tmp3[MAX_SIZE];
+			wchar_t tmp4[MAX_SIZE];
+			wchar_t tmp5[MAX_SIZE];
+			char str[MAX_SIZE];
+
+			// ID
+			UniToStru(tmp0, e->Id);
+
+			// 時刻
+			GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->LeasedTime), NULL);
+			GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(e->ExpireTime), NULL);
+
+			MacToStr(str, sizeof(str), e->MacAddress);
+			StrToUni(tmp3, sizeof(tmp3), str);
+
+			IPToStr32(str, sizeof(str), e->IpAddress);
+			StrToUni(tmp4, sizeof(tmp4), str);
+
+			StrToUni(tmp5, sizeof(tmp5), e->Hostname);
+
+			CtInsert(ct,
+				tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumDhcp(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB 管理オプションの一覧の取得
+UINT PsAdminOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ADMIN_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubAdminOptions(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNewStandardEx();
+		UINT i;
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			ADMIN_OPTION *e = &t.Items[i];
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+
+			StrToUni(tmp1, sizeof(tmp1), e->Name);
+			UniToStru(tmp2, e->Value);
+
+			CtInsert(ct, tmp1, tmp2, GetHubAdminOptionHelpString(e->Name));
+				
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcAdminOption(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB 管理オプションの値の設定
+UINT PsAdminOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ADMIN_OPTION t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_name"), CmdEvalNotEmpty, NULL},
+		{"VALUE", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_VALUE"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubAdminOptions(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		bool b = false;
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			if (StrCmpi(t.Items[i].Name, GetParamStr(o, "[name]")) == 0)
+			{
+				t.Items[i].Value = GetParamInt(o, "VALUE");
+				b = true;
+			}
+		}
+
+		if (b == false)
+		{
+			// エラー発生
+			ret = ERR_OBJECT_NOT_FOUND;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			FreeRpcAdminOption(&t);
+			return ret;
+		}
+		else
+		{
+			StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+			ret = ScSetHubAdminOptions(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeRpcAdminOption(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB 拡張オプションの一覧の取得
+UINT PsExtOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ADMIN_OPTION t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubExtOptions(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		CT *ct = CtNewStandardEx();
+		UINT i;
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			ADMIN_OPTION *e = &t.Items[i];
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+
+			StrToUni(tmp1, sizeof(tmp1), e->Name);
+			UniToStru(tmp2, e->Value);
+
+			CtInsert(ct, tmp1, tmp2, GetHubAdminOptionHelpString(e->Name));
+
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcAdminOption(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 仮想 HUB 拡張オプションの値の設定
+UINT PsExtOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ADMIN_OPTION t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[name]", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_name"), CmdEvalNotEmpty, NULL},
+		{"VALUE", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_VALUE"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetHubExtOptions(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		bool b = false;
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			if (StrCmpi(t.Items[i].Name, GetParamStr(o, "[name]")) == 0)
+			{
+				t.Items[i].Value = GetParamInt(o, "VALUE");
+				b = true;
+			}
+		}
+
+		if (b == false)
+		{
+			// エラー発生
+			ret = ERR_OBJECT_NOT_FOUND;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			FreeRpcAdminOption(&t);
+			return ret;
+		}
+		else
+		{
+			StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+			ret = ScSetHubExtOptions(ps->Rpc, &t);
+
+			if (ret != ERR_NO_ERROR)
+			{
+				// エラー発生
+				CmdPrintError(c, ret);
+				FreeParamValueList(o);
+				return ret;
+			}
+		}
+	}
+
+	FreeRpcAdminOption(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 無効な証明書リストの一覧の取得
+UINT PsCrlList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_CRL t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScEnumCrl(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		CT *ct = CtNew();
+
+		CtInsertColumn(ct, _UU("CMD_ID"), false);
+		CtInsertColumn(ct, _UU("SM_CRL_COLUMN_1"), false);
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			wchar_t tmp[64];
+			RPC_ENUM_CRL_ITEM *e = &t.Items[i];
+
+			UniToStru(tmp, e->Key);
+			CtInsert(ct, tmp, e->CrlInfo);
+		}
+
+		CtFreeEx(ct, c, true);
+	}
+
+	FreeRpcEnumCrl(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 無効な証明書の追加
+UINT PsCrlAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CRL t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		{"SERIAL", NULL, NULL, NULL, NULL},
+		{"MD5", NULL, NULL, NULL, NULL},
+		{"SHA1", NULL, NULL, NULL, NULL},
+		{"CN", NULL, NULL, NULL, NULL},
+		{"O", NULL, NULL, NULL, NULL},
+		{"OU", NULL, NULL, NULL, NULL},
+		{"C", NULL, NULL, NULL, NULL},
+		{"ST", NULL, NULL, NULL, NULL},
+		{"L", NULL, NULL, NULL, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	{
+		bool param_exists = false;
+		CRL *crl = ZeroMalloc(sizeof(CRL));
+		NAME *n;
+		n = crl->Name = ZeroMalloc(sizeof(NAME));
+
+		if (IsEmptyStr(GetParamStr(o, "CN")) == false)
+		{
+			n->CommonName = CopyUniStr(GetParamUniStr(o, "CN"));
+			param_exists = true;
+		}
+
+		if (IsEmptyStr(GetParamStr(o, "O")) == false)
+		{
+			n->CommonName = CopyUniStr(GetParamUniStr(o, "O"));
+			param_exists = true;
+		}
+
+		if (IsEmptyStr(GetParamStr(o, "OU")) == false)
+		{
+			n->CommonName = CopyUniStr(GetParamUniStr(o, "OU"));
+			param_exists = true;
+		}
+
+		if (IsEmptyStr(GetParamStr(o, "C")) == false)
+		{
+			n->CommonName = CopyUniStr(GetParamUniStr(o, "C"));
+			param_exists = true;
+		}
+
+		if (IsEmptyStr(GetParamStr(o, "ST")) == false)
+		{
+			n->CommonName = CopyUniStr(GetParamUniStr(o, "ST"));
+			param_exists = true;
+		}
+
+		if (IsEmptyStr(GetParamStr(o, "L")) == false)
+		{
+			n->CommonName = CopyUniStr(GetParamUniStr(o, "L"));
+			param_exists = true;
+		}
+
+		if (IsEmptyStr(GetParamStr(o, "SERIAL")) == false)
+		{
+			BUF *b;
+
+			b = StrToBin(GetParamStr(o, "SERIAL"));
+
+			if (b != NULL && b->Size >= 1)
+			{
+				crl->Serial = NewXSerial(b->Buf, b->Size);
+				param_exists = true;
+			}
+
+			FreeBuf(b);
+		}
+
+		if (IsEmptyStr(GetParamStr(o, "MD5")) == false)
+		{
+			BUF *b;
+
+			b = StrToBin(GetParamStr(o, "MD5"));
+
+			if (b != NULL && b->Size == MD5_SIZE)
+			{
+				Copy(crl->DigestMD5, b->Buf, MD5_SIZE);
+				param_exists = true;
+			}
+
+			FreeBuf(b);
+		}
+
+		if (IsEmptyStr(GetParamStr(o, "SHA1")) == false)
+		{
+			BUF *b;
+
+			b = StrToBin(GetParamStr(o, "SHA1"));
+
+			if (b != NULL && b->Size == SHA1_SIZE)
+			{
+				Copy(crl->DigestSHA1, b->Buf, SHA1_SIZE);
+				param_exists = true;
+			}
+
+			FreeBuf(b);
+		}
+
+		t.Crl = crl;
+
+		if (param_exists == false)
+		{
+			FreeRpcCrl(&t);
+			ret = ERR_INVALID_PARAMETER;
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	// RPC 呼び出し
+	ret = ScAddCrl(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcCrl(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 無効な証明書の削除
+UINT PsCrlDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CRL t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_CrlDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Key = GetParamInt(o, "[id]");
+
+	// RPC 呼び出し
+	ret = ScDelCrl(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeRpcCrl(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 無効な証明書の取得
+UINT PsCrlGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_CRL t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_CrlGet_Prompt_ID"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+	t.Key = GetParamInt(o, "[id]");
+
+	// RPC 呼び出し
+	ret = ScGetCrl(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// 内容の表示
+		CT *ct = CtNewStandard();
+		CRL *crl = t.Crl;
+		NAME *n;
+
+		if (crl != NULL)
+		{
+			n = crl->Name;
+
+			if (n != NULL)
+			{
+				if (UniIsEmptyStr(n->CommonName) == false)
+				{
+					CtInsert(ct, _UU("CMD_CrlGet_CN"), n->CommonName);
+				}
+				if (UniIsEmptyStr(n->Organization) == false)
+				{
+					CtInsert(ct, _UU("CMD_CrlGet_O"), n->Organization);
+				}
+				if (UniIsEmptyStr(n->Unit) == false)
+				{
+					CtInsert(ct, _UU("CMD_CrlGet_OU"), n->Unit);
+				}
+				if (UniIsEmptyStr(n->Country) == false)
+				{
+					CtInsert(ct, _UU("CMD_CrlGet_C"), n->Country);
+				}
+				if (UniIsEmptyStr(n->State) == false)
+				{
+					CtInsert(ct, _UU("CMD_CrlGet_ST"), n->State);
+				}
+				if (UniIsEmptyStr(n->Local) == false)
+				{
+					CtInsert(ct, _UU("CMD_CrlGet_L"), n->Local);
+				}
+			}
+
+			if (crl->Serial != NULL && crl->Serial->size >= 1)
+			{
+				wchar_t tmp[MAX_SIZE];
+				char str[MAX_SIZE];
+
+				BinToStrEx(str, sizeof(str), crl->Serial->data, crl->Serial->size);
+				StrToUni(tmp, sizeof(tmp), str);
+
+				CtInsert(ct, _UU("CMD_CrlGet_SERI"), tmp);
+			}
+
+			if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
+			{
+				wchar_t tmp[MAX_SIZE];
+				char str[MAX_SIZE];
+
+				BinToStrEx(str, sizeof(str), crl->DigestMD5, MD5_SIZE);
+				StrToUni(tmp, sizeof(tmp), str);
+
+				CtInsert(ct, _UU("CMD_CrlGet_MD5_HASH"), tmp);
+			}
+
+			if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
+			{
+				wchar_t tmp[MAX_SIZE];
+				char str[MAX_SIZE];
+
+				BinToStrEx(str, sizeof(str), crl->DigestSHA1, SHA1_SIZE);
+				StrToUni(tmp, sizeof(tmp), str);
+
+				CtInsert(ct, _UU("CMD_CrlGet_SHA1_HASH"), tmp);
+			}
+		}
+		CtFree(ct, c);
+	}
+
+	FreeRpcCrl(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// IP アクセス制御リストのルール一覧の取得
+UINT PsAcList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_AC_LIST t;
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetAcList(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		UINT i;
+		CT *ct;
+
+		ct = CtNew();
+		CtInsertColumn(ct, _UU("SM_AC_COLUMN_1"), true);
+		CtInsertColumn(ct, _UU("SM_AC_COLUMN_2"), true);
+		CtInsertColumn(ct, _UU("SM_AC_COLUMN_3"), false);
+		CtInsertColumn(ct, _UU("SM_AC_COLUMN_4"), false);
+
+		for (i = 0;i < LIST_NUM(t.o);i++)
+		{
+			wchar_t tmp1[32], *tmp2, tmp3[MAX_SIZE], tmp4[32];
+			char *tmp_str;
+			AC *ac = LIST_DATA(t.o, i);
+
+			UniToStru(tmp1, ac->Id);
+			tmp2 = ac->Deny ? _UU("SM_AC_DENY") : _UU("SM_AC_PASS");
+			tmp_str = GenerateAcStr(ac);
+			StrToUni(tmp3, sizeof(tmp3), tmp_str);
+
+			Free(tmp_str);
+
+			UniToStru(tmp4, ac->Priority);
+
+			CtInsert(ct, tmp1, tmp4, tmp2, tmp3);
+		}
+
+		CtFree(ct, c);
+	}
+
+	FreeRpcAcList(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// IP アクセス制御リストにルールを追加 (IPv4)
+UINT PsAcAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_AC_LIST t;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX mm =
+	{
+		"CMD_AcAdd_Eval_PRIORITY", 1, 4294967295UL,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[allow|deny]", CmdPrompt, _UU("CMD_AcAdd_Prompt_AD"), CmdEvalNotEmpty, NULL},
+		{"PRIORITY", CmdPrompt, _UU("CMD_AcAdd_Prompt_PRIORITY"), CmdEvalMinMax, &mm},
+		{"IP", CmdPrompt, _UU("CMD_AcAdd_Prompt_IP"), CmdEvalIpAndMask4, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetAcList(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// リストに新しい項目を追加する
+		AC *ac = ZeroMalloc(sizeof(AC));
+		char *test = GetParamStr(o, "[allow|deny]");
+		UINT u_ip, u_mask;
+
+		if (StartWith("deny", test))
+		{
+			ac->Deny = true;
+		}
+
+		ParseIpAndMask4(GetParamStr(o, "IP"), &u_ip, &u_mask);
+		UINTToIP(&ac->IpAddress, u_ip);
+
+		if (u_mask == 0xffffffff)
+		{
+			ac->Masked = false;
+		}
+		else
+		{
+			ac->Masked = true;
+			UINTToIP(&ac->SubnetMask, u_mask);
+		}
+
+		ac->Priority = GetParamInt(o, "PRIORITY");
+
+		Insert(t.o, ac);
+
+		ret = ScSetAcList(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeRpcAcList(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// IP アクセス制御リストにルールを追加 (IPv6)
+UINT PsAcAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_AC_LIST t;
+	// 指定できるパラメータ リスト
+	CMD_EVAL_MIN_MAX mm =
+	{
+		"CMD_AcAdd6_Eval_PRIORITY", 1, 4294967295UL,
+	};
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[allow|deny]", CmdPrompt, _UU("CMD_AcAdd6_Prompt_AD"), CmdEvalNotEmpty, NULL},
+		{"PRIORITY", CmdPrompt, _UU("CMD_AcAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &mm},
+		{"IP", CmdPrompt, _UU("CMD_AcAdd6_Prompt_IP"), CmdEvalIpAndMask6, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetAcList(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// リストに新しい項目を追加する
+		AC *ac = ZeroMalloc(sizeof(AC));
+		char *test = GetParamStr(o, "[allow|deny]");
+		IP u_ip, u_mask;
+
+		if (StartWith("deny", test))
+		{
+			ac->Deny = true;
+		}
+
+		ParseIpAndMask6(GetParamStr(o, "IP"), &u_ip, &u_mask);
+		Copy(&ac->IpAddress, &u_ip, sizeof(IP));
+
+		if (SubnetMaskToInt6(&u_mask) == 128)
+		{
+			ac->Masked = false;
+		}
+		else
+		{
+			ac->Masked = true;
+			Copy(&ac->SubnetMask, &u_mask, sizeof(IP));
+		}
+
+		ac->Priority = GetParamInt(o, "PRIORITY");
+
+		Insert(t.o, ac);
+
+		ret = ScSetAcList(ps->Rpc, &t);
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeRpcAcList(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// デバッグコマンドを実行する
+UINT PsDebug(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	UINT id;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", NULL, NULL, NULL, NULL},
+		{"ARG", NULL, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	id = GetParamInt(o, "[id]");
+
+	if (true)
+	{
+		RPC_TEST t;
+		UINT ret;
+
+		c->Write(c, _UU("CMD_Debug_Msg1"));
+
+		Zero(&t, sizeof(t));
+
+		t.IntValue = id;
+		StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "ARG"));
+
+		ret = ScDebug(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+		else
+		{
+			wchar_t tmp[sizeof(t.StrValue)];
+
+			UniFormat(tmp, sizeof(tmp), _UU("CMD_Debug_Msg2"), t.StrValue);
+			c->Write(c, tmp);
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// サーバーの設定ファイルをフラッシュする
+UINT PsFlush(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (true)
+	{
+		RPC_TEST t;
+		UINT ret;
+		wchar_t tmp[MAX_SIZE];
+		char sizestr[MAX_SIZE];
+
+		c->Write(c, _UU("CMD_Flush_Msg1"));
+
+		Zero(&t, sizeof(t));
+
+		ret = ScFlush(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+
+		ToStr3(sizestr, sizeof(sizestr), (UINT64)t.IntValue);
+		UniFormat(tmp, sizeof(tmp), _UU("CMD_Flush_Msg2"), sizestr);
+		c->Write(c, tmp);
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// クラッシュさせる
+UINT PsCrash(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	char *yes;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[yes]", CmdPrompt, _UU("CMD_Crash_Confirm"), NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	yes = GetParamStr(o, "[yes]");
+
+	if (StrCmpi(yes, "yes") != 0)
+	{
+		c->Write(c, _UU("CMD_Crash_Aborted"));
+	}
+	else
+	{
+		RPC_TEST t;
+		UINT ret;
+
+		c->Write(c, _UU("CMD_Crash_Msg"));
+
+		Zero(&t, sizeof(t));
+
+		ret = ScCrash(ps->Rpc, &t);
+
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// IP アクセス制御リスト内のルールの削除
+UINT PsAcDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_AC_LIST t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_AcDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+	};
+
+	// 仮想 HUB が選択されていない場合はエラー
+	if (ps->HubName == NULL)
+	{
+		c->Write(c, _UU("CMD_Hub_Not_Selected"));
+		return ERR_INVALID_PARAMETER;
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+	// RPC 呼び出し
+	ret = ScGetAcList(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+	else
+	{
+		// ID 一致を削除
+		UINT i;
+		bool b = false;
+
+		for (i = 0;i < LIST_NUM(t.o);i++)
+		{
+			AC *ac = LIST_DATA(t.o, i);
+
+			if (ac->Id == GetParamInt(o, "[id]"))
+			{
+				Delete(t.o, ac);
+				Free(ac);
+				b = true;
+				break;
+			}
+		}
+
+		if (b == false)
+		{
+			ret = ERR_OBJECT_NOT_FOUND;
+			FreeRpcAcList(&t);
+		}
+		else
+		{
+			ret = ScSetAcList(ps->Rpc, &t);
+		}
+		if (ret != ERR_NO_ERROR)
+		{
+			// エラー発生
+			CmdPrintError(c, ret);
+			FreeParamValueList(o);
+			return ret;
+		}
+	}
+
+	FreeRpcAcList(&t);
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 新しいライセンスキーの登録
+UINT PsLicenseAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_TEST t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[key]", CmdPrompt, _UU("CMD_LicenseAdd_Prompt_Key"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "[key]"));
+
+	// RPC 呼び出し
+	ret = ScAddLicenseKey(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 登録されているライセンスの削除
+UINT PsLicenseDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_TEST t;
+	// 指定できるパラメータ リスト
+	PARAM args[] =
+	{
+		// "name", prompt_proc, prompt_param, eval_proc, eval_param
+		{"[id]", CmdPrompt, _UU("CMD_LicenseDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.IntValue = GetParamInt(o, "[id]");
+
+	// RPC 呼び出し
+	ret = ScDelLicenseKey(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 登録されているライセンス一覧の取得
+UINT PsLicenseList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_ENUM_LICENSE_KEY t;
+	CT *ct;
+	UINT i;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	// RPC 呼び出し
+	ret = ScEnumLicenseKey(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNew();
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_2"), false);
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_3"), false);
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_4"), false);
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_5"), false);
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_6"), false);
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_7"), false);
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_8"), false);
+	CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_9"), false);
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		wchar_t tmp1[32], tmp2[LICENSE_KEYSTR_LEN + 1], tmp3[LICENSE_MAX_PRODUCT_NAME_LEN + 1],
+			*tmp4, tmp5[128], tmp6[LICENSE_LICENSEID_STR_LEN + 1], tmp7[64],
+			tmp8[64], tmp9[64];
+		RPC_ENUM_LICENSE_KEY_ITEM *e = &t.Items[i];
+
+		UniToStru(tmp1, e->Id);
+		StrToUni(tmp2, sizeof(tmp2), e->LicenseKey);
+		StrToUni(tmp3, sizeof(tmp3), e->LicenseName);
+		tmp4 = LiGetLicenseStatusStr(e->Status);
+		if (e->Expires == 0)
+		{
+			UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_LICENSE_NO_EXPIRES"));
+		}
+		else
+		{
+			GetDateStrEx64(tmp5, sizeof(tmp5), e->Expires, NULL);
+		}
+		StrToUni(tmp6, sizeof(tmp6), e->LicenseId);
+		UniToStru(tmp7, e->ProductId);
+		UniFormat(tmp8, sizeof(tmp8), L"%I64u", e->SystemId);
+		UniToStru(tmp9, e->SerialId);
+
+		CtInsert(ct,
+			tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+	}
+
+	CtFreeEx(ct, c, true);
+
+	FreeRpcEnumLicenseKey(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 現在の VPN Server のライセンス状態の取得
+UINT PsLicenseStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret = 0;
+	RPC_LICENSE_STATUS st;
+	CT *ct;
+	wchar_t tmp[MAX_SIZE];
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&st, sizeof(st));
+
+	// RPC 呼び出し
+	ret = ScGetLicenseStatus(ps->Rpc, &st);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		// エラー発生
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNewStandard();
+
+	if (st.EditionId == LICENSE_EDITION_VPN3_NO_LICENSE)
+	{
+		CtInsert(ct, _UU("SM_NO_LICENSE_COLUMN"), _UU("SM_NO_LICENSE"));
+	}
+	else
+	{
+		// 製品エディション名
+		StrToUni(tmp, sizeof(tmp), st.EditionStr);
+		CtInsert(ct, _UU("SM_LICENSE_STATUS_EDITION"), tmp);
+
+		// リリース日付
+		if (st.ReleaseDate != 0)
+		{
+			GetDateStrEx64(tmp, sizeof(tmp), st.ReleaseDate, NULL);
+			CtInsert(ct, _UU("SM_LICENSE_STATUS_RELEASE"), tmp);
+		}
+
+		// 現在のシステム ID
+		UniFormat(tmp, sizeof(tmp), L"%I64u", st.SystemId);
+		CtInsert(ct, _UU("SM_LICENSE_STATUS_SYSTEM_ID"), tmp);
+
+		// 現在の製品ライセンスの有効期限
+		if (st.SystemExpires == 0)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_NO_EXPIRES"));
+		}
+		else
+		{
+			GetDateStrEx64(tmp, sizeof(tmp), st.SystemExpires, NULL);
+		}
+		CtInsert(ct,  _UU("SM_LICENSE_STATUS_EXPIRES"), tmp);
+
+		// サブスクリプション (サポート) 契約
+		if (st.NeedSubscription == false)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONEED"));
+		}
+		else
+		{
+			if (st.SubscriptionExpires == 0)
+			{
+				UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONE"));
+			}
+			else
+			{
+				wchar_t dtstr[MAX_PATH];
+
+				GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+				UniFormat(tmp, sizeof(tmp),
+					st.IsSubscriptionExpired ? _UU("SM_LICENSE_STATUS_SUBSCRIPTION_EXPIRED") :  _UU("SM_LICENSE_STATUS_SUBSCRIPTION_VALID"),
+					dtstr);
+			}
+		}
+		CtInsert(ct, _UU("SM_LICENSE_STATUS_SUBSCRIPTION"), tmp);
+
+		if (st.NeedSubscription == false && st.SubscriptionExpires != 0)
+		{
+			wchar_t dtstr[MAX_PATH];
+
+			GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+			CtInsert(ct, _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD_STR"), tmp);
+		}
+
+		if (GetCapsBool(ps->CapsList, "b_vpn3"))
+		{
+			// ユーザー作成可能数
+			if (st.NumClientConnectLicense == INFINITE)
+			{
+				UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+			}
+			else
+			{
+				UniToStru(tmp, st.NumClientConnectLicense);
+			}
+			CtInsert(ct, _UU("SM_LICENSE_NUM_CLIENT"), tmp);
+		}
+
+		// クライアント同時接続可能数
+		if (st.NumBridgeConnectLicense == INFINITE)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+		}
+		else
+		{
+			UniToStru(tmp, st.NumBridgeConnectLicense);
+		}
+		CtInsert(ct, _UU("SM_LICENSE_NUM_BRIDGE"), tmp);
+
+		// エンタープライズ機能の利用可否
+		CtInsert(ct, _UU("SM_LICENSE_STATUS_ENTERPRISE"),
+			st.AllowEnterpriseFunction ? _UU("SM_LICENSE_STATUS_ENTERPRISE_YES") : _UU("SM_LICENSE_STATUS_ENTERPRISE_NO"));
+	}
+
+	CtFreeEx(ct, c, false);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+
+// クラスタ設定の取得
+UINT PsClusterSettingGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_FARM t;
+	CT *ct;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	ret = ScGetFarmSetting(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	if (t.Weight == 0)
+	{
+		t.Weight = FARM_DEFAULT_WEIGHT;
+	}
+
+	// クラスタ設定の表示
+	ct = CtNewStandard();
+
+	CtInsert(ct, _UU("CMD_ClusterSettingGet_Current"),
+		GetServerTypeStr(t.ServerType));
+
+	if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		CtInsert(ct, _UU("CMD_ClusterSettingGet_ControllerOnly"), t.ControllerOnly ? _UU("SEC_YES") : _UU("SEC_NO"));
+	}
+
+	if (t.ServerType != SERVER_TYPE_STANDALONE)
+	{
+		wchar_t tmp[MAX_SIZE];
+
+		UniToStru(tmp, t.Weight);
+
+		CtInsert(ct, _UU("CMD_ClusterSettingGet_Weight"), tmp);
+	}
+
+	if (t.ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		wchar_t tmp[MAX_SIZE];
+		UINT i;
+
+		// 公開 IP アドレス
+		if (t.PublicIp != 0)
+		{
+			IPToUniStr32(tmp, sizeof(tmp), t.PublicIp);
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("CMD_ClusterSettingGet_None"));
+		}
+
+		CtInsert(ct, _UU("CMD_ClusterSettingGet_PublicIp"), tmp);
+
+		// 公開ポート一覧
+		tmp[0] = 0;
+		for (i = 0;i < t.NumPort;i++)
+		{
+			wchar_t tmp2[64];
+
+			UniFormat(tmp2, sizeof(tmp2), L"%u, ", t.Ports[i]);
+
+			UniStrCat(tmp, sizeof(tmp), tmp2);
+		}
+
+		if (UniEndWith(tmp, L", "))
+		{
+			tmp[UniStrLen(tmp) - 2] = 0;
+		}
+
+		CtInsert(ct, _UU("CMD_ClusterSettingGet_PublicPorts"), tmp);
+
+		// 接続先コントローラ
+		UniFormat(tmp, sizeof(tmp), L"%S:%u", t.ControllerName, t.ControllerPort);
+		CtInsert(ct, _UU("CMD_ClusterSettingGet_Controller"), tmp);
+	}
+
+	CtFree(ct, c);
+
+	FreeRpcFarm(&t);
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// サーバーパスワードの設定
+UINT PsServerPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_SET_PASSWORD t;
+	char *pw;
+	PARAM args[] =
+	{
+		{"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	pw = GetParamStr(o, "[password]");
+
+	Zero(&t, sizeof(t));
+	Hash(t.HashedPassword, pw, StrLen(pw), true);
+
+	ret = ScSetServerPassword(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// パスワード決定プロンプト (プロンプト関数用)
+wchar_t *CmdPromptChoosePassword(CONSOLE *c, void *param)
+{
+	char *s;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	s = CmdPasswordPrompt(c);
+
+	if (s == NULL)
+	{
+		return NULL;
+	}
+	else
+	{
+		wchar_t *ret = CopyStrToUni(s);
+
+		Free(s);
+
+		return ret;
+	}
+}
+
+// パスワード入力用プロンプト (汎用)
+char *CmdPasswordPrompt(CONSOLE *c)
+{
+	char *pw1, *pw2;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	c->Write(c, _UU("CMD_UTVPNCMD_PWPROMPT_0"));
+
+RETRY:
+	c->Write(c, L"");
+
+
+	pw1 = c->ReadPassword(c, _UU("CMD_UTVPNCMD_PWPROMPT_1"));
+	if (pw1 == NULL)
+	{
+		return NULL;
+	}
+
+	pw2 = c->ReadPassword(c, _UU("CMD_UTVPNCMD_PWPROMPT_2"));
+	if (pw2 == NULL)
+	{
+		Free(pw1);
+		return NULL;
+	}
+
+	c->Write(c, L"");
+
+	if (StrCmp(pw1, pw2) != 0)
+	{
+		Free(pw1);
+		Free(pw2);
+		c->Write(c, _UU("CMD_UTVPNCMD_PWPROMPT_3"));
+		goto RETRY;
+	}
+
+	Free(pw1);
+
+	return pw2;
+}
+
+// リスナー無効化
+UINT PsListenerDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_LISTENER t;
+	PARAM args[] =
+	{
+		{"[port]", CmdPromptPort, _UU("CMD_ListenerDisable_PortPrompt"), CmdEvalPort, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Enable = false;
+	t.Port = ToInt(GetParamStr(o, "[port]"));
+
+	ret = ScEnableListener(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// リスナー有効化
+UINT PsListenerEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_LISTENER t;
+	PARAM args[] =
+	{
+		{"[port]", CmdPromptPort, _UU("CMD_ListenerEnable_PortPrompt"), CmdEvalPort, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Enable = true;
+	t.Port = ToInt(GetParamStr(o, "[port]"));
+
+	ret = ScEnableListener(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// コンソールテーブルの 1 行を描画
+void CtPrintRow(CONSOLE *c, UINT num, UINT *widths, wchar_t **strings, bool *rights, char separate_char)
+{
+	UINT i;
+	wchar_t *buf;
+	UINT buf_size;
+	bool is_sep_line = true;
+	// 引数チェック
+	if (c == NULL || num == 0 || widths == NULL || strings == NULL || rights == NULL)
+	{
+		return;
+	}
+
+	buf_size = 32;
+	for (i = 0;i < num;i++)
+	{
+		buf_size += sizeof(wchar_t) * widths[i] + 6;
+	}
+
+	buf = ZeroMalloc(buf_size);
+
+	for (i = 0;i < num;i++)
+	{
+		char *tmp;
+		wchar_t *space_string;
+		UINT w;
+		UINT space = 0;
+		wchar_t *string = strings[i];
+		wchar_t *tmp_line = NULL;
+
+		if (UniStrCmpi(string, L"---") == 0)
+		{
+			char *s = MakeCharArray('-', widths[i]);
+			tmp_line = string = CopyStrToUni(s);
+
+			Free(s);
+		}
+		else
+		{
+			is_sep_line = false;
+		}
+
+		w = UniStrWidth(string);
+
+		if (widths[i] >= w)
+		{
+			space = widths[i] - w;
+		}
+
+		tmp = MakeCharArray(' ', space);
+		space_string = CopyStrToUni(tmp);
+
+		if (rights[i] != false)
+		{
+			UniStrCat(buf, buf_size, space_string);
+		}
+
+		UniStrCat(buf, buf_size, string);
+
+		if (rights[i] == false)
+		{
+			UniStrCat(buf, buf_size, space_string);
+		}
+
+		Free(space_string);
+		Free(tmp);
+
+		if (i < (num - 1))
+		{
+			wchar_t tmp[4];
+			char str[2];
+
+			if (UniStrCmpi(strings[i], L"---") == 0)
+			{
+				str[0] = '+';
+			}
+			else
+			{
+				str[0] = separate_char;
+			}
+			str[1] = 0;
+
+			StrToUni(tmp, sizeof(tmp), str);
+
+			UniStrCat(buf, buf_size, tmp);
+		}
+
+		if (tmp_line != NULL)
+		{
+			Free(tmp_line);
+		}
+	}
+
+	UniTrimRight(buf);
+
+	if (is_sep_line)
+	{
+		if (UniStrLen(buf) > (c->GetWidth(c) - 1))
+		{
+			buf[c->GetWidth(c) - 1] = 0;
+		}
+	}
+
+	c->Write(c, buf);
+
+	Free(buf);
+}
+
+// コンソール テーブルを標準形式で描画
+void CtPrintStandard(CT *ct, CONSOLE *c)
+{
+	CT *t;
+	UINT i, j;
+	// 引数チェック
+	if (ct == NULL || c == NULL)
+	{
+		return;
+	}
+
+	t = CtNewStandard();
+	for (i = 0;i < LIST_NUM(ct->Rows);i++)
+	{
+		CTR *row = LIST_DATA(ct->Rows, i);
+
+		for (j = 0;j < LIST_NUM(ct->Columns);j++)
+		{
+			CTC *column = LIST_DATA(ct->Columns, j);
+
+			CtInsert(t, column->String, row->Strings[j]);
+		}
+
+		if (i != (LIST_NUM(ct->Rows) - 1))
+		{
+			CtInsert(t, L"---", L"---");
+		}
+	}
+
+	CtFree(t, c);
+}
+
+// コンソールテーブルの描画
+void CtPrint(CT *ct, CONSOLE *c)
+{
+	UINT *widths;
+	UINT num;
+	UINT i, j;
+	wchar_t **header_strings;
+	bool *rights;
+	// 引数チェック
+	if (ct == NULL || c == NULL)
+	{
+		return;
+	}
+
+	num = LIST_NUM(ct->Columns);
+	widths = ZeroMalloc(sizeof(UINT) * num);
+
+	// 各列の最大文字幅を計算する
+	for (i = 0;i < num;i++)
+	{
+		CTC *ctc = LIST_DATA(ct->Columns, i);
+		UINT w;
+
+		w = UniStrWidth(ctc->String);
+		widths[i] = MAX(widths[i], w);
+	}
+	for (j = 0;j < LIST_NUM(ct->Rows);j++)
+	{
+		CTR *ctr = LIST_DATA(ct->Rows, j);
+
+		for (i = 0;i < num;i++)
+		{
+			UINT w;
+
+			w = UniStrWidth(ctr->Strings[i]);
+			widths[i] = MAX(widths[i], w);
+		}
+	}
+
+	// ヘッダ部分を表示する
+	header_strings = ZeroMalloc(sizeof(wchar_t *) * num);
+	rights = ZeroMalloc(sizeof(bool) * num);
+
+	for (i = 0;i < num;i++)
+	{
+		CTC *ctc = LIST_DATA(ct->Columns, i);
+
+		header_strings[i] = ctc->String;
+		rights[i] = ctc->Right;
+	}
+
+	CtPrintRow(c, num, widths, header_strings, rights, '|');
+
+	for (i = 0;i < num;i++)
+	{
+		char *s;
+
+		s = MakeCharArray('-', widths[i]);
+		header_strings[i] = CopyStrToUni(s);
+		Free(s);
+	}
+
+	CtPrintRow(c, num, widths, header_strings, rights, '+');
+
+	for (i = 0;i < num;i++)
+	{
+		Free(header_strings[i]);
+	}
+
+	// データ部を表示する
+	for (j = 0;j < LIST_NUM(ct->Rows);j++)
+	{
+		CTR *ctr = LIST_DATA(ct->Rows, j);
+
+		CtPrintRow(c, num, widths, ctr->Strings, rights, '|');
+	}
+
+	Free(rights);
+	Free(header_strings);
+	Free(widths);
+}
+
+// CSV でのメタ文字をエスケープする
+void CtEscapeCsv(wchar_t *dst, UINT size, wchar_t *src){
+	UINT i;
+	UINT len = UniStrLen(src);
+	UINT idx;
+	BOOL need_to_escape = false;
+	wchar_t tmp[2]=L"*";
+
+	// 入力値のチェック
+	if (src==NULL || dst==NULL)
+	{
+		return;
+	}
+
+	// 入力文字中にエスケープする必要のある文字が無ければそのまま出力にコピー
+	len = UniStrLen(src);
+	for (i=0; i<len; i++)
+	{
+		tmp[0] = src[i];
+		if (tmp[0] == L","[0] || tmp[0] == L"\n"[0] || tmp[0] == L"\""[0])
+		{
+			need_to_escape = true;
+		}
+	}
+	if (need_to_escape == false)
+	{
+		UniStrCpy(dst,size,src);
+		return;
+	}
+
+	// メタ文字（改行、コンマ、ダブルクオート）を含んでいる場合は”で囲む
+	UniStrCpy(dst, size, L"\"");
+	idx = UniStrLen(dst);
+	if(idx<size-1)
+	{
+		for (i=0; i<len; i++)
+		{
+			tmp[0] = src[i];
+			// ”は””に変換する（MS-Excel方式）
+			if (tmp[0] == L"\""[0])
+			{
+				UniStrCat(dst, size, tmp);
+			}
+			UniStrCat(dst, size, tmp);
+		}
+	}
+	UniStrCat(dst, size, L"\"");
+	return;
+}
+
+// コンソールテーブルの CSV 形式の表示
+void CtPrintCsv(CT *ct, CONSOLE *c)
+{
+	UINT i, j;
+	UINT num_columns = LIST_NUM(ct->Columns);
+	wchar_t buf[MAX_SIZE];
+	wchar_t fmtbuf[MAX_SIZE];
+
+	// 見出しの行を表示
+	buf[0] = 0;
+	for(i=0; i<num_columns; i++)
+	{
+		CTC *ctc = LIST_DATA(ct->Columns, i);
+		CtEscapeCsv(fmtbuf, MAX_SIZE, ctc->String);
+		UniStrCat(buf, MAX_SIZE, fmtbuf);
+		if(i != num_columns-1)
+			UniStrCat(buf, MAX_SIZE, L",");
+	}
+	c->Write(c, buf);
+
+	// 表の本体を表示
+	for(j=0; j<LIST_NUM(ct->Rows); j++)
+	{
+		CTR *ctr = LIST_DATA(ct->Rows, j);
+		buf[0] = 0;
+		for(i=0; i<num_columns; i++)
+		{
+			CtEscapeCsv(fmtbuf, MAX_SIZE, ctr->Strings[i]);
+			UniStrCat(buf, MAX_SIZE, fmtbuf);
+			if(i != num_columns-1)
+				UniStrCat(buf, MAX_SIZE, L",");
+		}
+		c->Write(c, buf);
+	}
+}
+
+// コンソールテーブルの削除
+void CtFreeEx(CT *ct, CONSOLE *c, bool standard_view)
+{
+	UINT i, num;
+	// 引数チェック
+	if (ct == NULL)
+	{
+		return;
+	}
+
+	if (c != NULL)
+	{
+		if (c->ConsoleType == CONSOLE_CSV)
+		{
+			CtPrintCsv(ct, c);
+		}
+		else
+		{
+			if (standard_view == false)
+			{
+				CtPrint(ct, c);
+			}
+			else
+			{
+				CtPrintStandard(ct, c);
+			}
+		}
+	}
+
+	num = LIST_NUM(ct->Columns);
+
+	for (i = 0;i < LIST_NUM(ct->Rows);i++)
+	{
+		UINT j;
+		CTR *ctr = LIST_DATA(ct->Rows, i);
+
+		for (j = 0;j < num;j++)
+		{
+			Free(ctr->Strings[j]);
+		}
+
+		Free(ctr->Strings);
+		Free(ctr);
+	}
+
+	for (i = 0;i < LIST_NUM(ct->Columns);i++)
+	{
+		CTC *ctc = LIST_DATA(ct->Columns, i);
+
+		Free(ctc->String);
+		Free(ctc);
+	}
+
+	ReleaseList(ct->Columns);
+	ReleaseList(ct->Rows);
+
+	Free(ct);
+}
+void CtFree(CT *ct, CONSOLE *c)
+{
+	CtFreeEx(ct, c, false);
+}
+
+// テーブルに行を追加
+void CtInsert(CT *ct, ...)
+{
+	CTR *ctr;
+	UINT num, i;
+	va_list va;
+	// 引数チェック
+	if (ct == NULL)
+	{
+		return;
+	}
+
+	num = LIST_NUM(ct->Columns);
+
+	va_start(va, ct);
+
+	ctr = ZeroMalloc(sizeof(CTR));
+	ctr->Strings = ZeroMalloc(sizeof(wchar_t *) * num);
+
+	for (i = 0;i < num;i++)
+	{
+		wchar_t *s = va_arg(va, wchar_t *);
+
+		ctr->Strings[i] = CopyUniStr(s);
+	}
+
+	va_end(va);
+
+	Insert(ct->Rows, ctr);
+}
+
+// テーブルにカラムを追加
+void CtInsertColumn(CT *ct, wchar_t *str, bool right)
+{
+	CTC *ctc;
+	// 引数チェック
+	if (ct == NULL)
+	{
+		return;
+	}
+	if (str == NULL)
+	{
+		str = L"";
+	}
+
+	ctc = ZeroMalloc(sizeof(CTC));
+	ctc->String = CopyUniStr(str);
+	ctc->Right = right;
+
+	Insert(ct->Columns, ctc);
+}
+
+// 新規コンソールテーブルの作成
+CT *CtNew()
+{
+	CT *ct;
+
+	ct = ZeroMalloc(sizeof(CT));
+	ct->Columns = NewList(NULL);
+	ct->Rows = NewList(NULL);
+
+	return ct;
+}
+
+// テーブルのカラムに標準的なカラムを追加する
+CT *CtNewStandard()
+{
+	CT *ct = CtNew();
+
+	CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_2"), false);
+
+	return ct;
+}
+CT *CtNewStandardEx()
+{
+	CT *ct = CtNew();
+
+	CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_2"), false);
+	CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_3"), false);
+
+	return ct;
+}
+
+// TCP リスナー一覧の取得
+UINT PsListenerList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_LISTENER_LIST t;
+	UINT i;
+	CT *ct;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+
+	ret = ScEnumListener(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNew();
+
+	CtInsertColumn(ct, _UU("CM_LISTENER_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("CM_LISTENER_COLUMN_2"), false);
+
+	for (i = 0;i < t.NumPort;i++)
+	{
+		wchar_t *status = _UU("CM_LISTENER_OFFLINE");
+		wchar_t tmp[128];
+
+		if (t.Errors[i])
+		{
+			status = _UU("CM_LISTENER_ERROR");
+		}
+		else if (t.Enables[i])
+		{
+			status = _UU("CM_LISTENER_ONLINE");
+		}
+
+		UniFormat(tmp, sizeof(tmp), _UU("CM_LISTENER_TCP_PORT"), t.Ports[i]);
+
+		CtInsert(ct, tmp, status);
+	}
+
+	CtFree(ct, c);
+
+	FreeRpcListenerList(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// TCP リスナーの削除
+UINT PsListenerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_LISTENER t;
+	PARAM args[] =
+	{
+		{"[port]", CmdPromptPort, _UU("CMD_ListenerDelete_PortPrompt"), CmdEvalPort, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Enable = true;
+	t.Port = ToInt(GetParamStr(o, "[port]"));
+
+	ret = ScDeleteListener(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 行を描画
+void CmdPrintRow(CONSOLE *c, wchar_t *title, wchar_t *tag, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	wchar_t buf2[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (title == NULL || c == NULL || tag == NULL)
+	{
+		return;
+	}
+
+	va_start(args, tag);
+	UniFormatArgs(buf, sizeof(buf), tag, args);
+
+	UniFormat(buf2, sizeof(buf2), L"[%s] %s", title, buf);
+
+	va_end(args);
+
+	c->Write(c, buf2);
+}
+
+// ServerInfoGet コマンド
+UINT PsServerInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_SERVER_INFO t;
+	CT *ct;
+	wchar_t tmp[MAX_SIZE];
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	ret = ScGetServerInfo(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNew();
+
+	CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_2"), false);
+
+	// 製品名
+	StrToUni(tmp, sizeof(tmp), t.ServerProductName);
+	CtInsert(ct, _UU("SM_INFO_PRODUCT_NAME"), tmp);
+
+	// バージョン
+	StrToUni(tmp, sizeof(tmp), t.ServerVersionString);
+	CtInsert(ct, _UU("SM_INFO_VERSION"), tmp);
+
+	// ビルド
+	StrToUni(tmp, sizeof(tmp), t.ServerBuildInfoString);
+	CtInsert(ct, _UU("SM_INFO_BUILD"), tmp);
+
+	// ホスト名
+	StrToUni(tmp, sizeof(tmp), t.ServerHostName);
+	CtInsert(ct, _UU("SM_INFO_HOSTNAME"), tmp);
+
+	// 種類
+	CtInsert(ct, _UU("SM_ST_SERVER_TYPE"), GetServerTypeStr(t.ServerType));
+
+	// OS
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsSystemName);
+	CtInsert(ct, _UU("SM_OS_SYSTEM_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsProductName);
+	CtInsert(ct, _UU("SM_OS_PRODUCT_NAME"), tmp);
+
+	if (t.OsInfo.OsServicePack != 0)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("SM_OS_SP_TAG"), t.OsInfo.OsServicePack);
+		CtInsert(ct, _UU("SM_OS_SERVICE_PACK"), tmp);
+	}
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVendorName);
+	CtInsert(ct, _UU("SM_OS_VENDER_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVersion);
+	CtInsert(ct, _UU("SM_OS_VERSION"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelName);
+	CtInsert(ct, _UU("SM_OS_KERNEL_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelVersion);
+	CtInsert(ct, _UU("SM_OS_KERNEL_VERSION"), tmp);
+
+	CtFree(ct, c);
+
+	FreeRpcServerInfo(&t);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// HUB の種類の文字列を取得
+wchar_t *GetHubTypeStr(UINT type)
+{
+	if (type == HUB_TYPE_FARM_STATIC)
+	{
+		return _UU("SM_HUB_STATIC");
+	}
+	else if (type == HUB_TYPE_FARM_DYNAMIC)
+	{
+		return _UU("SM_HUB_DYNAMIC");
+	}
+	return _UU("SM_HUB_STANDALONE");
+}
+
+// サーバーの種類の文字列を取得
+wchar_t *GetServerTypeStr(UINT type)
+{
+	if (type == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		return _UU("SM_FARM_CONTROLLER");
+	}
+	else if (type == SERVER_TYPE_FARM_MEMBER)
+	{
+		return _UU("SM_FARM_MEMBER");
+	}
+	return _UU("SM_SERVER_STANDALONE");
+}
+
+// ServerStatusGet コマンド
+UINT PsServerStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_SERVER_STATUS t;
+	wchar_t tmp[MAX_PATH];
+	char tmp2[MAX_PATH];
+	CT *ct;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	ret = ScGetServerStatus(ps->Rpc, &t);
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	ct = CtNew();
+
+	CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_1"), false);
+	CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_2"), false);
+
+	// サーバーの種類
+	CtInsert(ct, _UU("SM_ST_SERVER_TYPE"),
+		t.ServerType == SERVER_TYPE_STANDALONE ? _UU("SM_SERVER_STANDALONE") :
+		t.ServerType == SERVER_TYPE_FARM_MEMBER ? _UU("SM_FARM_MEMBER") : _UU("SM_FARM_CONTROLLER"));
+
+	// TCP コネクション数
+	UniToStru(tmp, t.NumTcpConnections);
+	CtInsert(ct, _UU("SM_ST_NUM_TCP"), tmp);
+
+	if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// ローカル TCP コネクション数
+		UniToStru(tmp, t.NumTcpConnectionsLocal);
+		CtInsert(ct, _UU("SM_ST_NUM_TCP_LOCAL"), tmp);
+
+		// リモート TCP コネクション数
+		UniToStru(tmp, t.NumTcpConnectionsRemote);
+		CtInsert(ct, _UU("SM_ST_NUM_TCP_REMOTE"), tmp);
+	}
+
+	// 仮想 HUB 数
+	UniToStru(tmp, t.NumHubTotal);
+	CtInsert(ct, _UU("SM_ST_NUM_HUB_TOTAL"), tmp);
+
+	if (t.ServerType != SERVER_TYPE_STANDALONE)
+	{
+		// スタティック HUB 数
+		UniToStru(tmp, t.NumHubStatic);
+		CtInsert(ct, _UU("SM_ST_NUM_HUB_STATIC"), tmp);
+
+		// ダイナミック HUB 数
+		UniToStru(tmp, t.NumHubDynamic);
+		CtInsert(ct, _UU("SM_ST_NUM_HUB_DYNAMIC"), tmp);
+	}
+
+	// セッション数
+	UniToStru(tmp, t.NumSessionsTotal);
+	CtInsert(ct, _UU("SM_ST_NUM_SESSION_TOTAL"), tmp);
+
+	if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// ローカルセッション数
+		UniToStru(tmp, t.NumSessionsLocal);
+		CtInsert(ct, _UU("SM_ST_NUM_SESSION_LOCAL"), tmp);
+
+		// ローカルセッション数
+		UniToStru(tmp, t.NumSessionsRemote);
+		CtInsert(ct, _UU("SM_ST_NUM_SESSION_REMOTE"), tmp);
+	}
+
+	// MAC テーブル数
+	UniToStru(tmp, t.NumMacTables);
+	CtInsert(ct, _UU("SM_ST_NUM_MAC_TABLE"), tmp);
+
+	// IP テーブル数
+	UniToStru(tmp, t.NumIpTables);
+	CtInsert(ct, _UU("SM_ST_NUM_IP_TABLE"), tmp);
+
+	// ユーザー数
+	UniToStru(tmp, t.NumUsers);
+	CtInsert(ct, _UU("SM_ST_NUM_USERS"), tmp);
+
+	// グループ数
+	UniToStru(tmp, t.NumGroups);
+	CtInsert(ct, _UU("SM_ST_NUM_GROUPS"), tmp);
+
+	// 割り当て済みライセンス数
+	UniToStru(tmp, t.AssignedClientLicenses);
+	CtInsert(ct, _UU("SM_ST_CLIENT_LICENSE"), tmp);
+
+	UniToStru(tmp, t.AssignedBridgeLicenses);
+	CtInsert(ct, _UU("SM_ST_BRIDGE_LICENSE"), tmp);
+
+	if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		UniToStru(tmp, t.AssignedClientLicensesTotal);
+		CtInsert(ct, _UU("SM_ST_CLIENT_LICENSE_EX"), tmp);
+
+		UniToStru(tmp, t.AssignedBridgeLicensesTotal);
+		CtInsert(ct, _UU("SM_ST_BRIDGE_LICENSE_EX"), tmp);
+	}
+
+	// トラフィック
+	CmdInsertTrafficInfo(ct, &t.Traffic);
+
+	// サーバー起動時刻
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartTime), NULL);
+	CtInsert(ct, _UU("SM_ST_START_TIME"), tmp);
+
+	// 現在時刻
+	GetDateTimeStrMilli64(tmp2, sizeof(tmp2), SystemToLocal64(t.CurrentTime));
+	StrToUni(tmp, sizeof(tmp), tmp2);
+	CtInsert(ct, _UU("SM_ST_CURRENT_TIME"), tmp);
+
+	// Tick 値
+	UniFormat(tmp, sizeof(tmp), L"%I64u", t.CurrentTick);
+	CtInsert(ct, _UU("SM_ST_CURRENT_TICK"), tmp);
+
+	// メモリ情報
+	if (t.MemInfo.TotalMemory != 0)
+	{
+		char vv[128];
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.TotalMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		CtInsert(ct, _UU("SM_ST_TOTAL_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.UsedMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		CtInsert(ct, _UU("SM_ST_USED_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.FreeMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		CtInsert(ct, _UU("SM_ST_FREE_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.TotalPhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		CtInsert(ct, _UU("SM_ST_TOTAL_PHYS"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.UsedPhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		CtInsert(ct, _UU("SM_ST_USED_PHYS"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.FreePhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		CtInsert(ct, _UU("SM_ST_FREE_PHYS"), tmp);
+	}
+
+	CtFree(ct, c);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// トラフィック情報を LVB に追加
+void CmdInsertTrafficInfo(CT *ct, TRAFFIC *t)
+{
+	wchar_t tmp[MAX_SIZE];
+	char vv[128];
+	// 引数チェック
+	if (ct == NULL || t == NULL)
+	{
+		return;
+	}
+
+	// 送信情報
+	ToStr3(vv, sizeof(vv), t->Send.UnicastCount);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+	CtInsert(ct, _UU("SM_ST_SEND_UCAST_NUM"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Send.UnicastBytes);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+	CtInsert(ct, _UU("SM_ST_SEND_UCAST_SIZE"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Send.BroadcastCount);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+	CtInsert(ct, _UU("SM_ST_SEND_BCAST_NUM"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Send.BroadcastBytes);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+	CtInsert(ct, _UU("SM_ST_SEND_BCAST_SIZE"), tmp);
+
+	// 受信情報
+	ToStr3(vv, sizeof(vv), t->Recv.UnicastCount);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+	CtInsert(ct, _UU("SM_ST_RECV_UCAST_NUM"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Recv.UnicastBytes);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+	CtInsert(ct, _UU("SM_ST_RECV_UCAST_SIZE"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Recv.BroadcastCount);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+	CtInsert(ct, _UU("SM_ST_RECV_BCAST_NUM"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Recv.BroadcastBytes);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+	CtInsert(ct, _UU("SM_ST_RECV_BCAST_SIZE"), tmp);
+}
+
+// ポート番号の入力
+wchar_t *CmdPromptPort(CONSOLE *c, void *param)
+{
+	wchar_t *prompt_str;
+
+	if (param != NULL)
+	{
+		prompt_str = (wchar_t *)param;
+	}
+	else
+	{
+		prompt_str = _UU("CMD_PROPMT_PORT");
+	}
+
+	return c->ReadLine(c, prompt_str, true);
+}
+
+// ポート番号の検証
+bool CmdEvalPort(CONSOLE *c, wchar_t *str, void *param)
+{
+	UINT i;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	i = UniToInt(str);
+
+	if (i >= 1 && i <= 65535)
+	{
+		return true;
+	}
+
+	c->Write(c, _UU("CMD_EVAL_PORT"));
+
+	return false;
+}
+
+// ListenerCreate コマンド
+UINT PsListenerCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	PS *ps = (PS *)param;
+	UINT ret;
+	RPC_LISTENER t;
+	PARAM args[] =
+	{
+		{"[port]", CmdPromptPort, _UU("CMD_ListenerCreate_PortPrompt"), CmdEvalPort, NULL},
+	};
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Enable = true;
+	t.Port = ToInt(GetParamStr(o, "[port]"));
+
+	ret = ScCreateListener(ps->Rpc, &t);
+
+	if (ret != ERR_NO_ERROR)
+	{
+		CmdPrintError(c, ret);
+		FreeParamValueList(o);
+		return ret;
+	}
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// About コマンド
+UINT PsAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+
+	o = ParseCommandList(c, cmd_name, str, NULL, 0);
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// バージョン情報を表示する
+	CmdPrintAbout(c);
+
+	FreeParamValueList(o);
+
+	return 0;
+}
+
+// 新しいサーバー管理コンテキストの作成
+PS *NewPs(CONSOLE *c, RPC *rpc, char *servername, UINT serverport, char *hubname, char *adminhub, wchar_t *cmdline)
+{
+	PS *ps;
+	// 引数チェック
+	if (c == NULL || rpc == NULL || servername == NULL)
+	{
+		return NULL;
+	}
+
+	if (IsEmptyStr(hubname))
+	{
+		hubname = NULL;
+	}
+	if (IsEmptyStr(adminhub))
+	{
+		adminhub = NULL;
+	}
+	if (UniIsEmptyStr(cmdline))
+	{
+		cmdline = NULL;
+	}
+
+	ps = ZeroMalloc(sizeof(PS));
+	ps->ConsoleForServer = true;
+	ps->ServerPort = serverport;
+	ps->ServerName = CopyStr(servername);
+	ps->Console = c;
+	ps->Rpc = rpc;
+	ps->HubName = CopyStr(hubname);
+	ps->LastError = 0;
+	ps->AdminHub = CopyStr(adminhub);
+	ps->CmdLine = CopyUniStr(cmdline);
+
+	return ps;
+}
+
+// サーバー管理コンテキストの解放
+void FreePs(PS *ps)
+{
+	// 引数チェック
+	if (ps == NULL)
+	{
+		return;
+	}
+
+	Free(ps->HubName);
+	Free(ps->AdminHub);
+	Free(ps->CmdLine);
+	Free(ps->ServerName);
+
+	Free(ps);
+}
+
+// サーバー管理ツール
+UINT PsConnect(CONSOLE *c, char *host, UINT port, char *hub, char *adminhub, wchar_t *cmdline, char *password)
+{
+	UINT retcode = 0;
+	RPC *rpc = NULL;
+	CEDAR *cedar;
+	CLIENT_OPTION o;
+	UCHAR hashed_password[SHA1_SIZE];
+	bool b = false;
+	// 引数チェック
+	if (c == NULL || host == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+	if (port == 0)
+	{
+		port = 443;
+	}
+	if (hub != NULL)
+	{
+		adminhub = NULL;
+	}
+
+	cedar = NewCedar(NULL, NULL);
+
+	Zero(&o, sizeof(o));
+	UniStrCpy(o.AccountName, sizeof(o.AccountName), L"VPNCMD");
+	StrCpy(o.Hostname, sizeof(o.Hostname), host);
+	o.Port = port;
+	o.ProxyType = PROXY_DIRECT;
+
+	Hash(hashed_password, password, StrLen(password), true);
+
+	if (IsEmptyStr(password) == false)
+	{
+		b = true;
+	}
+
+	// 接続
+	while (true)
+	{
+		UINT err;
+
+		rpc = AdminConnectEx(cedar, &o, hub, hashed_password, &err, CEDAR_CUI_STR);
+		if (rpc == NULL)
+		{
+			// 失敗
+			retcode = err;
+
+			if (err == ERR_ACCESS_DENIED)
+			{
+				char *pass;
+				// パスワード違い
+				if (b)
+				{
+					// パスワードを入力させる
+					c->Write(c, _UU("CMD_UTVPNCMD_PASSWORD_1"));
+				}
+
+				b = true;
+
+				pass = c->ReadPassword(c, _UU("CMD_UTVPNCMD_PASSWORD_2"));
+				c->Write(c, L"");
+
+				if (pass != NULL)
+				{
+					Hash(hashed_password, pass, StrLen(pass), true);
+					Free(pass);
+				}
+				else
+				{
+					break;
+				}
+			}
+			else
+			{
+				// その他のエラー
+				CmdPrintError(c, err);
+				break;
+			}
+		}
+		else
+		{
+			PS *ps;
+
+			// 成功
+			ps = NewPs(c, rpc, host, port, hub, adminhub, cmdline);
+			PsMain(ps);
+			retcode = ps->LastError;
+			FreePs(ps);
+			AdminDisconnect(rpc);
+			break;
+		}
+	}
+
+	ReleaseCedar(cedar);
+
+	return retcode;
+}
+
+// エラーを表示する
+void CmdPrintError(CONSOLE *c, UINT err)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	UniFormat(tmp, sizeof(tmp), _UU("CMD_UTVPNCMD_ERROR"),
+		err, GetUniErrorStr(err));
+	c->Write(c, tmp);
+
+	if (err == ERR_DISCONNECTED)
+	{
+		c->Write(c, _UU("CMD_DISCONNECTED_MSG"));
+	}
+}
+
+// バージョン情報を表示する
+void CmdPrintAbout(CONSOLE *c)
+{
+	CEDAR *cedar;
+	wchar_t tmp[MAX_SIZE];
+	char exe[MAX_PATH];
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	cedar = NewCedar(NULL, NULL);
+
+	GetExeName(exe, sizeof(exe));
+
+	UniFormat(tmp, sizeof(tmp), _UU("CMD_UTVPNCMD_ABOUT"),
+		cedar->VerString, cedar->BuildInfo);
+
+	c->Write(c, tmp);
+
+	ReleaseCedar(cedar);
+}
+
+// ホスト名とポート番号をパースする (@ で区切る)
+bool ParseHostPortAtmark(char *src, char **host, UINT *port, UINT default_port)
+{
+	TOKEN_LIST *t;
+	bool ret = false;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return false;
+	}
+
+	t = ParseToken(src, "@");
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	if (port != NULL)
+	{
+		*port = 0;
+	}
+
+	if (default_port == 0)
+	{
+		if (t->NumTokens < 2)
+		{
+			FreeToken(t);
+			return false;
+		}
+
+		if (ToInt(t->Token[1]) == 0)
+		{
+			FreeToken(t);
+			return false;
+		}
+	}
+
+	if (t->NumTokens >= 2 && ToInt(t->Token[1]) == 0)
+	{
+		FreeToken(t);
+		return false;
+	}
+
+	if (t->NumTokens >= 1 && IsEmptyStr(t->Token[0]) == false)
+	{
+		ret = true;
+
+		if (host != NULL)
+		{
+			*host = CopyStr(t->Token[0]);
+			Trim(*host);
+		}
+
+		if (t->NumTokens >= 2)
+		{
+			if (port != NULL)
+			{
+				*port = ToInt(t->Token[1]);
+			}
+		}
+	}
+
+	if (port != NULL)
+	{
+		if (*port == 0)
+		{
+			*port = default_port;
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// ホスト名とポート番号をパースする
+bool ParseHostPort(char *src, char **host, UINT *port, UINT default_port)
+{
+	TOKEN_LIST *t;
+	bool ret = false;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return false;
+	}
+
+	if (StartWith(src, "["))
+	{
+		if (InStr(src, "]"))
+		{
+			// [target]:port の形式
+			UINT i, n;
+			char tmp[MAX_SIZE];
+
+			StrCpy(tmp, sizeof(tmp), src);
+
+			n = SearchStrEx(tmp, "]", 0, false);
+			if (n != INFINITE)
+			{
+				UINT len = StrLen(tmp);
+
+				for (i = n;i < len;i++)
+				{
+					if (tmp[i] == ':')
+					{
+						tmp[i] = '@';
+					}
+				}
+			}
+
+			return ParseHostPortAtmark(tmp, host, port, default_port);
+		}
+	}
+
+	if (InStr(src, "@"))
+	{
+		// @ で区切られている
+		return ParseHostPortAtmark(src, host, port, default_port);
+	}
+
+	t = ParseToken(src, ":");
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	if (port != NULL)
+	{
+		*port = 0;
+	}
+
+	if (default_port == 0)
+	{
+		if (t->NumTokens < 2)
+		{
+			FreeToken(t);
+			return false;
+		}
+
+		if (ToInt(t->Token[1]) == 0)
+		{
+			FreeToken(t);
+			return false;
+		}
+	}
+
+	if (t->NumTokens >= 2 && ToInt(t->Token[1]) == 0)
+	{
+		FreeToken(t);
+		return false;
+	}
+
+	if (t->NumTokens >= 1 && IsEmptyStr(t->Token[0]) == false)
+	{
+		ret = true;
+
+		if (host != NULL)
+		{
+			*host = CopyStr(t->Token[0]);
+			Trim(*host);
+		}
+
+		if (t->NumTokens >= 2)
+		{
+			if (port != NULL)
+			{
+				*port = ToInt(t->Token[1]);
+			}
+		}
+	}
+
+	if (port != NULL)
+	{
+		if (*port == 0)
+		{
+			*port = default_port;
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// vpncmd コマンドプロシージャ
+UINT VpnCmdProc(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+	LIST *o;
+	char *target;
+	bool server = false;
+	bool client = false;
+	bool tools = false;
+	char *hostname = NULL;
+	char *password;
+	wchar_t *cmdline;
+	bool host_inputted = false;
+	UINT port = 0;
+	UINT retcode = 0;
+	PARAM args[] =
+	{
+		{"[host:port]", NULL, NULL, NULL, NULL},
+		{"CLIENT", NULL, NULL, NULL, NULL},
+		{"SERVER", NULL, NULL, NULL, NULL},
+		{"TOOLS", NULL, NULL, NULL, NULL},
+		{"HUB", NULL, NULL, NULL, NULL},
+		{"ADMINHUB", NULL, NULL, NULL, NULL},
+		{"PASSWORD", NULL, NULL, NULL, NULL},
+		{"IN", NULL, NULL, NULL, NULL},
+		{"OUT", NULL, NULL, NULL, NULL},
+		{"CMD", NULL, NULL, NULL, NULL},
+		{"CSV", NULL, NULL, NULL, NULL},
+	};
+
+	if (c->ConsoleType == CONSOLE_LOCAL)
+	{
+		// 起動パス情報の初期化
+		VpnCmdInitBootPath();
+	}
+
+	if(c->ConsoleType != CONSOLE_CSV)
+	{
+		CmdPrintAbout(c);
+		c->Write(c, L"");
+	}
+
+	o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+
+	if (o == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// Client か Server か Tools かの指定
+	if ((GetParamStr(o, "CLIENT") == NULL && GetParamStr(o, "SERVER") == NULL && GetParamStr(o, "TOOLS") == NULL) ||
+		(GetParamStr(o, "CLIENT") != NULL && GetParamStr(o, "SERVER") != NULL && GetParamStr(o, "TOOLS") != NULL))
+	{
+		wchar_t *ret;
+		UINT code;
+		// Client か Server か Tools かが指定されていない
+		c->Write(c, _UU("CMD_UTVPNCMD_CS_1"));
+
+		ret = c->ReadLine(c, _UU("CMD_UTVPNCMD_CS_2"), true);
+
+		code = UniToInt(ret);
+		Free(ret);
+
+		switch (code)
+		{
+		case 1:
+			// Server
+			server = true;
+			break;
+
+		case 2:
+			// Client
+			client = true;
+			break;
+
+		case 3:
+			// Tools
+			tools = true;
+			break;
+
+		default:
+			// 指定無し
+			FreeParamValueList(o);
+			return ERR_USER_CANCEL;
+		}
+
+		c->Write(c, L"");
+	}
+	else
+	{
+		if (GetParamStr(o, "SERVER") != NULL)
+		{
+			server = true;
+		}
+		else if (GetParamStr(o, "CLIENT") != NULL)
+		{
+			client = true;
+		}
+		else
+		{
+			tools = true;
+		}
+	}
+
+	// 接続先ホスト名
+	target = CopyStr(GetParamStr(o, "[host:port]"));
+
+	if (target == NULL && tools == false)
+	{
+		wchar_t *str;
+		// ホスト名を入力させる
+		if (server)
+		{
+			c->Write(c, _UU("CMD_UTVPNCMD_HOST_1"));
+		}
+		else if (client)
+		{
+			c->Write(c, _UU("CMD_UTVPNCMD_HOST_2"));
+		}
+
+		str = c->ReadLine(c, _UU("CMD_UTVPNCMD_HOST_3"), true);
+		c->Write(c, L"");
+		target = CopyUniToStr(str);
+		Free(str);
+
+		if (target == NULL)
+		{
+			// キャンセル
+			FreeParamValueList(o);
+			return ERR_USER_CANCEL;
+		}
+
+		if (IsEmptyStr(target))
+		{
+			Free(target);
+			target = CopyStr("localhost");
+		}
+	}
+	else
+	{
+		// ユーザーがホスト名を指定した
+		host_inputted = true;
+	}
+
+	if (tools == false)
+	{
+		if (ParseHostPort(target, &hostname, &port, 443) == false)
+		{
+			c->Write(c, _UU("CMD_MSG_INVALID_HOSTNAME"));
+			Free(target);
+			FreeParamValueList(o);
+			return ERR_INVALID_PARAMETER;
+		}
+	}
+
+	// パスワード
+	password = GetParamStr(o, "PASSWORD");
+	if (password == NULL)
+	{
+		password = "";
+	}
+
+	// コマンドライン
+	cmdline = GetParamUniStr(o, "CMD");
+
+	if (server)
+	{
+		// サーバーとしての処理
+		char *hub;
+		char *adminhub = NULL;
+
+		hub = CopyStr(GetParamStr(o, "HUB"));
+		adminhub = GetParamStr(o, "ADMINHUB");
+
+		// 仮想 HUB 管理モードで指定する仮想 HUB を決定する
+		if (hub == NULL)
+		{
+			if (host_inputted == false)
+			{
+				wchar_t *s;
+				// ユーザーがホスト名をコマンドラインで指定していない場合は
+				// プロンプトを表示して仮想 HUB 名も取得する
+				c->Write(c, _UU("CMD_UTVPNCMD_HUB_1"));
+
+				s = c->ReadLine(c, _UU("CMD_UTVPNCMD_HUB_2"), true);
+
+				hub = CopyUniToStr(s);
+				Free(s);
+			}
+		}
+
+		if (IsEmptyStr(hub))
+		{
+			Free(hub);
+			hub = NULL;
+		}
+		if (IsEmptyStr(adminhub))
+		{
+			adminhub = NULL;
+		}
+
+		retcode = PsConnect(c, hostname, port, hub, adminhub, cmdline, password);
+
+		Free(hub);
+	}
+	else if (client)
+	{
+		// クライアントとしての処理
+		Trim(target);
+
+		retcode = PcConnect(c, target, cmdline, password);
+	}
+	else if (tools)
+	{
+		// VPN Tools として処理
+		retcode = PtConnect(c, cmdline);
+	}
+
+	Free(hostname);
+	Free(target);
+	FreeParamValueList(o);
+
+	return retcode;
+}
+
+// vpncmd のエントリポイント
+UINT CommandMain(wchar_t *command_line)
+{
+	UINT ret = 0;
+	wchar_t *infile, *outfile;
+	char *a_infile, *a_outfile;
+	wchar_t *csvmode;
+	CONSOLE *c;
+
+	// 引数チェック
+	if (command_line == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	// /in と /out の項目だけ先読みする
+	infile = ParseCommand(command_line, L"in");
+	outfile = ParseCommand(command_line, L"out");
+	if (UniIsEmptyStr(infile))
+	{
+		Free(infile);
+		infile = NULL;
+	}
+	if (UniIsEmptyStr(outfile))
+	{
+		Free(outfile);
+		outfile = NULL;
+	}
+
+	a_infile = CopyUniToStr(infile);
+	a_outfile = CopyUniToStr(outfile);
+
+	// ローカルコンソールの確保
+	c = NewLocalConsole(infile, outfile);
+	if (c != NULL)
+	{
+		// vpncmd コマンドの定義
+		CMD cmd[] =
+		{
+			{"utvpncmd", VpnCmdProc},
+		};
+
+		// CSV モードを先読みしてチェック
+		csvmode = ParseCommand(command_line, L"csv");
+		if(csvmode != NULL)
+		{
+			Free(csvmode);
+			c->ConsoleType = CONSOLE_CSV;
+		}
+
+		if (DispatchNextCmdEx(c, command_line, ">", cmd, sizeof(cmd) / sizeof(cmd[0]), NULL) == false)
+		{
+			ret = ERR_INVALID_PARAMETER;
+		}
+		else
+		{
+			ret = c->RetCode;
+		}
+
+		// ローカルコンソールの解放
+		c->Free(c);
+	}
+	else
+	{
+		Print("Error: Couldn't open local console.\n");
+	}
+
+	Free(a_infile);
+	Free(a_outfile);
+	Free(infile);
+	Free(outfile);
+
+	return ret;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Command.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Command.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Command.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,617 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Command.h
+// Command.c のヘッダ
+
+#ifndef	COMMAND_H
+#define	COMMAND_H
+
+// 定数
+#define	TRAFFIC_DEFAULT_PORT		9821
+#define	TRAFFIC_NUMTCP_MAX			32
+#define	TRAFFIC_NUMTCP_DEFAULT		32
+#define	TRAFFIC_SPAN_DEFAULT		15
+#define	TRAFFIC_TYPE_DOWNLOAD		1
+#define	TRAFFIC_TYPE_UPLOAD			2
+#define	TRAFFIC_TYPE_FULL			0
+#define	TRAFFIC_BUF_SIZE			65535
+#define	TRAFFIC_VER_STR_SIZE		16
+#define	TRAFFIC_VER_STR				"TrafficServer\r\n"
+
+// Win32 用定数
+#define	VPNCMD_BOOTSTRAP_REG_KEYNAME	"Software\\SoftEther Corporation\\UT-VPN Command Line Utility"
+#define	VPNCMD_BOOTSTRAP_REG_VALUENAME_VER	"InstalledVersion"
+#define	VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH	"InstalledPath"
+#define	VPNCMD_BOOTSTRAP_FILENAME		"|utvpncmdsys.exe"
+#define	VPNCMD_BOOTSTRAP_FILENAME_X64	"|utvpncmdsys_x64.exe"
+#define	VPNCMD_BOOTSTRAP_FILENAME_IA64	"|utvpncmdsys_ia64.exe"
+
+
+// トラフィックテスト結果
+struct TT_RESULT
+{
+	bool Raw;					// 生データかどうか
+	bool Double;				// 2 倍にしているかどうか
+	UINT64 NumBytesUpload;		// アップロードしたサイズ
+	UINT64 NumBytesDownload;	// ダウンロードしたサイズ
+	UINT64 NumBytesTotal;		// 合計サイズ
+	UINT64 Span;				// 期間 (ミリ秒)
+	UINT64 BpsUpload;			// アップロードスループット
+	UINT64 BpsDownload;			// ダウンロードスループット
+	UINT64 BpsTotal;			// 合計スループット
+};
+
+// 文字表示関数
+typedef void (TT_PRINT_PROC)(void *param, wchar_t *str);
+
+// クライアント側ソケット
+struct TTC_SOCK
+{
+	SOCK *Sock;				// ソケット
+	UINT State;				// ステート
+	UINT64 NumBytes;		// 伝送したバイト数
+	bool Download;			// ダウンロードソケット
+	bool ServerUploadReportReceived;	// サーバーからのアップロード量レポートの受信完了
+	UINT64 NextSendRequestReportTick;	// 次にレポートをリクエストする時刻
+	UINT Id;
+};
+
+// トラフィックテストクライアント
+struct TTC
+{
+	TT_PRINT_PROC *Print;	// 文字表示関数
+	void *Param;			// 任意のパラメータ
+	bool Double;			// 2 倍モード
+	bool Raw;				// 生データモード
+	UINT Port;				// ポート番号
+	char Host[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	UINT NumTcp;			// TCP コネクション数
+	UINT Type;				// 種類
+	UINT64 Span;			// 期間
+	UINT64 RealSpan;		// 実際の期間
+	THREAD *Thread;			// スレッド
+	volatile bool Halt;		// 停止フラグ
+	SOCK_EVENT *SockEvent;	// ソケットイベント
+	LIST *ItcSockList;		// クライアントソケットリスト
+	TT_RESULT Result;		// 結果
+	UINT ErrorCode;			// エラーコード
+	bool AbnormalTerminated;	// 異常終了
+	EVENT *StartEvent;		// 開始イベント
+	EVENT *InitedEvent;		// 初期化完了通知イベント
+};
+
+// サーバー側ソケット
+struct TTS_SOCK
+{
+	SOCK *Sock;				// ソケット
+	UINT State;				// ステート
+	UINT64 NumBytes;		// 伝送したバイト数
+	bool SockJoined;		// イベントに追加されたかどうか
+	UINT Id;				// ID
+	UINT64 LastWaitTick;	// クライアントにサイズ情報を通知するための再試行待機時間
+};
+
+// トラフィックテストサーバー
+struct TTS
+{
+	TT_PRINT_PROC *Print;	// 文字表示関数
+	void *Param;			// 任意のパラメータ
+	volatile bool Halt;		// 停止フラグ
+	UINT Port;				// ポート番号
+	THREAD *Thread;			// スレッド
+	THREAD *WorkThread;		// ワーカースレッド
+	THREAD *IPv6AcceptThread;	// IPv6 Accept スレッド
+	SOCK *ListenSocket;		// 待機するソケット
+	SOCK *ListenSocketV6;	// 待機するソケット (IPv6)
+	UINT ErrorCode;			// エラーコード
+	SOCK_EVENT *SockEvent;	// ソケットイベント
+	LIST *TtsSockList;		// サーバーソケットリスト
+	bool NewSocketArrived;	// 新しいソケットが到着している
+	UINT IdSeed;			// ID 値
+};
+
+// VPN Tools コンテキスト
+struct PT
+{
+	CONSOLE *Console;	// コンソール
+	UINT LastError;		// 最後のエラー
+	wchar_t *CmdLine;	// 実行するコマンドライン
+};
+
+// サーバー管理コンテキスト
+struct PS
+{
+	bool ConsoleForServer;	// サーバーのためのコンソール (常に true)
+	CONSOLE *Console;	// コンソール
+	RPC *Rpc;			// RPC
+	char *ServerName;	// サーバー名
+	UINT ServerPort;	// ポート番号
+	char *HubName;		// 現在管理対象にある仮想 HUB 名
+	UINT LastError;		// 最後のエラー
+	char *AdminHub;		// デフォルトで管理する仮想 HUB
+	wchar_t *CmdLine;	// 実行するコマンドライン
+	CAPSLIST *CapsList;	// Caps リスト
+};
+
+// クライアント管理コンテキスト
+struct PC
+{
+	bool ConsoleForServer;	// サーバーのためのコンソール (常に false)
+	CONSOLE *Console;	// コンソール
+	REMOTE_CLIENT *RemoteClient;	// リモートクライアント
+	char *ServerName;	// サーバー名
+	UINT LastError;		// 最後のエラー
+	wchar_t *CmdLine;	// コマンドライン
+};
+
+// テーブルのカラム
+struct CTC
+{
+	wchar_t *String;	// 文字列
+	bool Right;			// 右寄せ
+};
+
+// テーブルの行
+struct CTR
+{
+	wchar_t **Strings;	// 文字列リスト
+};
+
+// コンソール用テーブル
+struct CT
+{
+	LIST *Columns;		// カラム一覧
+	LIST *Rows;			// 行一覧
+};
+
+UINT CommandMain(wchar_t *command_line);
+UINT VpnCmdProc(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+bool ParseHostPort(char *src, char **host, UINT *port, UINT default_port);
+bool ParseHostPortAtmark(char *src, char **host, UINT *port, UINT default_port);
+CT *CtNew();
+void CtFree(CT *ct, CONSOLE *c);
+void CtFreeEx(CT *ct, CONSOLE *c, bool standard_view);
+void CtInsertColumn(CT *ct, wchar_t *str, bool right);
+CT *CtNewStandard();
+CT *CtNewStandardEx();
+void CtInsert(CT *ct, ...);
+void CtPrint(CT *ct, CONSOLE *c);
+void CtPrintStandard(CT *ct, CONSOLE *c);
+void CtPrintRow(CONSOLE *c, UINT num, UINT *widths, wchar_t **strings, bool *rights, char separate_char);
+void VpnCmdInitBootPath();
+void OutRpcTtResult(PACK *p, TT_RESULT *t);
+void InRpcTtResult(PACK *p, TT_RESULT *t);
+
+void CmdPrintError(CONSOLE *c, UINT err);
+void CmdPrintAbout(CONSOLE *c);
+void CmdPrintRow(CONSOLE *c, wchar_t *title, wchar_t *tag, ...);
+wchar_t *CmdPromptPort(CONSOLE *c, void *param);
+wchar_t *CmdPromptChoosePassword(CONSOLE *c, void *param);
+bool CmdEvalPort(CONSOLE *c, wchar_t *str, void *param);
+void CmdInsertTrafficInfo(CT *ct, TRAFFIC *t);
+wchar_t *GetHubTypeStr(UINT type);
+wchar_t *GetServerTypeStr(UINT type);
+char *CmdPasswordPrompt(CONSOLE *c);
+bool CmdEvalIp(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *PsClusterSettingMemberPromptIp(CONSOLE *c, void *param);
+bool CmdEvalHostAndPort(CONSOLE *c, wchar_t *str, void *param);
+LIST *StrToPortList(char *str);
+bool CmdEvalPortList(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param);
+K *CmdLoadKey(CONSOLE *c, char *filename);
+bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, char *cert_filename, char *key_filename);
+bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *GetConnectionTypeStr(UINT type);
+bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask6(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask46(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask6(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask46(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *GetLogSwitchStr(UINT i);
+wchar_t *GetPacketLogNameStr(UINT i);
+UINT StrToLogSwitchType(char *str);
+UINT StrToPacketLogType(char *str);
+UINT StrToPacketLogSaveInfoType(char *str);
+wchar_t *GetProxyTypeStr(UINT i);
+wchar_t *GetClientAuthTypeStr(UINT i);
+void PrintPolicyList(CONSOLE *c, char *name);
+void PrintPolicy(CONSOLE *c, POLICY *pol, bool cascade_mode);
+bool EditPolicy(CONSOLE *c, POLICY *pol, char *name, char *value, bool cascade_mode);
+void CmdPrintStatusToListView(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s);
+void CmdPrintStatusToListViewEx(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode);
+bool CmdEvalPassOrDiscard(CONSOLE *c, wchar_t *str, void *param);
+bool StrToPassOrDiscard(char *str);
+bool CmdEvalProtocol(CONSOLE *c, wchar_t *str, void *param);
+UINT StrToProtocol(char *str);
+bool CmdEvalPortRange(CONSOLE *c, wchar_t *str, void *param);
+bool ParsePortRange(char *str, UINT *start, UINT *end);
+wchar_t *GetAuthTypeStr(UINT id);
+UINT64 StrToDateTime64(char *str);
+bool CmdEvalDateTime(CONSOLE *c, wchar_t *str, void *param);
+void CmdPrintNodeInfo(CT *ct, NODE_INFO *info);
+wchar_t *GetProtocolName(UINT n);
+void CmdGenerateImportName(REMOTE_CLIENT *r, wchar_t *name, UINT size, wchar_t *old_name);
+bool CmdIsAccountName(REMOTE_CLIENT *r, wchar_t *name);
+wchar_t *GetSyslogSettingName(UINT n);
+
+
+void TtPrint(void *param, TT_PRINT_PROC *print_proc, wchar_t *str);
+void TtGenerateRandomData(UCHAR **buf, UINT *size);
+void TtsWorkerThread(THREAD *thread, void *param);
+void TtsListenThread(THREAD *thread, void *param);
+void TtsAcceptProc(TTS *tts, SOCK *listen_socket);
+void TtsIPv6AcceptThread(THREAD *thread, void *param);
+wchar_t *GetTtcTypeStr(UINT type);
+void TtcPrintSummary(TTC *ttc);
+void StopTtc(TTC *ttc);
+void TtcGenerateResult(TTC *ttc);
+void TtcThread(THREAD *thread, void *param);
+TTC *NewTtcEx(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param, EVENT *start_event);
+TTC *NewTtc(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param);
+UINT FreeTtc(TTC *ttc, TT_RESULT *result);
+TTS *NewTts(UINT port, void *param, TT_PRINT_PROC *print_proc);
+UINT FreeTts(TTS *tts);
+void PtTrafficPrintProc(void *param, wchar_t *str);
+void TtcPrintResult(CONSOLE *c, TT_RESULT *res);
+
+
+bool SystemCheck();
+bool CheckKernel();
+bool CheckMemory();
+bool CheckStrings();
+bool CheckFileSystem();
+bool CheckThread();
+bool CheckNetwork();
+void InputToNull(void *p);
+UINT RetZero();
+
+
+
+UINT PtConnect(CONSOLE *c, wchar_t *cmdline);
+PT *NewPt(CONSOLE *c, wchar_t *cmdline);
+void FreePt(PT *pt);
+void PtMain(PT *pt);
+UINT PtMakeCert(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtTrafficClient(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtTrafficServer(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtCheck(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+UINT PcConnect(CONSOLE *c, char *target, wchar_t *cmdline, char *password);
+PC *NewPc(CONSOLE *c, REMOTE_CLIENT *remote_client, char *servername, wchar_t *cmdline);
+void FreePc(PC *pc);
+void PcMain(PC *pc);
+UINT PcAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcVersionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcPasswordGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureSelect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicUpgrade(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicGetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicSetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountConnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountNicSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusShow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusHide(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountSecureCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountRetrySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStartupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStartupRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountExport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountImport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcRemoteEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcRemoteDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+PS *NewPs(CONSOLE *c, RPC *rpc, char *servername, UINT serverport, char *hubname, char *adminhub, wchar_t *cmdline);
+void FreePs(PS *ps);
+UINT PsConnect(CONSOLE *c, char *host, UINT port, char *hub, char *adminhub, wchar_t *cmdline, char *password);
+void PsMain(PS *ps);
+UINT PsAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingStandalone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingController(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingMember(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterConnectionStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrash(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsFlush(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDebug(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerKeyGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCipherGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCipherSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeDeviceList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCaps(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsReboot(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConfigGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConfigSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterStart(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterStop(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogFileList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogFileGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreateDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreateStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubSetStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubSetDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHub(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetMaxSession(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetHubPassword(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetEnumAllow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetEnumDeny(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOptionsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogSwitchSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogPacketSaveType(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCADelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsPolicyList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAddEx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAddEx6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserSignedSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserRadiusSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserNTLMSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserExpiresSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupJoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupUnjoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsMacTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsMacDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIpDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatHostGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatHostSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAdminOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAdminOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsExtOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsExtOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+#endif	// COMMAND_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Connection.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Connection.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Connection.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2926 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Connection.c
+// コネクションマネージャ
+
+#include "CedarPch.h"
+
+// 送信に使用するかどうかの判別
+#define	IS_SEND_TCP_SOCK(ts)		\
+	((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode == false)))
+
+// 受信に使用するかどうかの判別
+#define	IS_RECV_TCP_SOCK(ts)		\
+	((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode == false)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode)))
+
+// SECURE_SIGN の変換
+void InRpcSecureSign(SECURE_SIGN *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(SECURE_SIGN));
+	PackGetStr(p, "SecurePublicCertName", t->SecurePublicCertName, sizeof(t->SecurePublicCertName));
+	PackGetStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName, sizeof(t->SecurePrivateKeyName));
+	t->ClientCert = PackGetX(p, "ClientCert");
+	PackGetData2(p, "Random", t->Random, sizeof(t->Random));
+	PackGetData2(p, "Signature", t->Signature, sizeof(t->Signature));
+	t->UseSecureDeviceId = PackGetInt(p, "UseSecureDeviceId");
+	t->BitmapId = PackGetInt(p, "BitmapId");
+}
+void OutRpcSecureSign(PACK *p, SECURE_SIGN *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "SecurePublicCertName", t->SecurePublicCertName);
+	PackAddStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName);
+	PackAddX(p, "ClientCert", t->ClientCert);
+	PackAddData(p, "Random", t->Random, sizeof(t->Random));
+	PackAddData(p, "Signature", t->Signature, sizeof(t->Signature));
+	PackAddInt(p, "UseSecureDeviceId", t->UseSecureDeviceId);
+	PackAddInt(p, "BitmapId", t->BitmapId);
+}
+void FreeRpcSecureSign(SECURE_SIGN *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FreeX(t->ClientCert);
+}
+
+// 次のパケットを生成する
+BUF *NewKeepPacket(bool server_mode)
+{
+	BUF *b = NewBuf();
+	char *string = KEEP_ALIVE_STRING;
+
+	WriteBuf(b, string, StrLen(string));
+
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// KEEP スレッド
+void KeepThread(THREAD *thread, void *param)
+{
+	KEEP *k = (KEEP *)param;
+	SOCK *s;
+	char server_name[MAX_HOST_NAME_LEN + 1];
+	UINT server_port;
+	bool udp_mode;
+	bool enabled;
+	// 引数チェック
+	if (thread == NULL || k == NULL)
+	{
+		return;
+	}
+
+WAIT_FOR_ENABLE:
+	Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+
+	// 有効になるまで待機する
+	while (true)
+	{
+		enabled = false;
+		Lock(k->lock);
+		{
+			if (k->Enable)
+			{
+				if (StrLen(k->ServerName) != 0 && k->ServerPort != 0 && k->Interval != 0)
+				{
+					StrCpy(server_name, sizeof(server_name), k->ServerName);
+					server_port = k->ServerPort;
+					udp_mode = k->UdpMode;
+					enabled = true;
+				}
+			}
+		}
+		Unlock(k->lock);
+		if (enabled)
+		{
+			break;
+		}
+		if (k->Halt)
+		{
+			return;
+		}
+		Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+	}
+
+	if (udp_mode == false)
+	{
+		// TCP モード
+		// 接続に成功するまで試行する
+		while (true)
+		{
+			UINT64 connect_started_tick;
+			bool changed = false;
+			Lock(k->lock);
+			{
+				if (StrCmpi(k->ServerName, server_name) != 0 ||
+					k->ServerPort != server_port || k->Enable == false ||
+					k->UdpMode)
+				{
+					changed = true;
+				}
+			}
+			Unlock(k->lock);
+			if (changed)
+			{
+				// 設定が変更された
+				goto WAIT_FOR_ENABLE;
+			}
+
+			if (k->Halt)
+			{
+				// 停止
+				return;
+			}
+
+			// サーバーへ接続を試行
+			connect_started_tick = Tick64();
+			s = ConnectEx2(server_name, server_port, KEEP_TCP_TIMEOUT, (bool *)&k->Halt);
+			if (s != NULL)
+			{
+				// 接続成功
+				break;
+			}
+
+			// 接続失敗 設定が変更されるかタイムアウトするまで待機する
+			while (true)
+			{
+				changed = false;
+				if (k->Halt)
+				{
+					// 停止
+					return;
+				}
+				Lock(k->lock);
+				{
+					if (StrCmpi(k->ServerName, server_name) != 0 ||
+						k->ServerPort != server_port || k->Enable == false ||
+						k->UdpMode)
+					{
+						changed = true;
+					}
+				}
+				Unlock(k->lock);
+
+				if (changed)
+				{
+					// 設定が変更された
+					goto WAIT_FOR_ENABLE;
+				}
+
+				if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)
+				{
+					break;
+				}
+
+				Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+			}
+		}
+
+		// サーバーへの接続に成功した
+		// 一定時間ごとにパケットデータを送受信する
+		if (s != NULL)
+		{
+			UINT64 last_packet_sent_time = 0;
+			while (true)
+			{
+				SOCKSET set;
+				UINT ret;
+				UCHAR buf[MAX_SIZE];
+				bool changed;
+
+				InitSockSet(&set);
+				AddSockSet(&set, s);
+
+				Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);
+
+				ret = Recv(s, buf, sizeof(buf), false);
+				if (ret == 0)
+				{
+					// 切断された
+					Disconnect(s);
+					ReleaseSock(s);
+					s = NULL;
+				}
+
+				if (s != NULL)
+				{
+					if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)
+					{
+						BUF *b;
+
+						// 次のパケットを送出する
+						last_packet_sent_time = Tick64();
+
+						b = NewKeepPacket(k->Server);
+
+						ret = Send(s, b->Buf, b->Size, false);
+						FreeBuf(b);
+
+						if (ret == 0)
+						{
+							// 切断された
+							Disconnect(s);
+							ReleaseSock(s);
+							s = NULL;
+						}
+					}
+				}
+
+				changed = false;
+
+				Lock(k->lock);
+				{
+					if (StrCmpi(k->ServerName, server_name) != 0 ||
+						k->ServerPort != server_port || k->Enable == false ||
+						k->UdpMode)
+					{
+						changed = true;
+					}
+				}
+				Unlock(k->lock);
+
+				if (changed || s == NULL)
+				{
+					// 設定が変更された または 切断された
+					Disconnect(s);
+					ReleaseSock(s);
+					s = NULL;
+					goto WAIT_FOR_ENABLE;
+				}
+				else
+				{
+					if (k->Halt)
+					{
+						// 停止
+						Disconnect(s);
+						ReleaseSock(s);
+						return;
+					}
+				}
+			}
+		}
+	}
+	else
+	{
+		IP dest_ip;
+		// UDP モード
+		// ソケット作成が成功するまで試行する
+		while (true)
+		{
+			UINT64 connect_started_tick;
+			bool changed = false;
+			Lock(k->lock);
+			{
+				if (StrCmpi(k->ServerName, server_name) != 0 ||
+					k->ServerPort != server_port || k->Enable == false ||
+					k->UdpMode == false)
+				{
+					changed = true;
+				}
+			}
+			Unlock(k->lock);
+			if (changed)
+			{
+				// 設定が変更された
+				goto WAIT_FOR_ENABLE;
+			}
+
+			if (k->Halt)
+			{
+				// 停止
+				return;
+			}
+
+			// ソケット作成を試行
+			connect_started_tick = Tick64();
+
+			// まず名前解決を試行
+			if (GetIP(&dest_ip, server_name))
+			{
+				// 名前解決に成功したら、次にソケットを作成
+				s = NewUDP(0);
+				if (s != NULL)
+				{
+					// 作成成功
+					break;
+				}
+			}
+
+			// 作成失敗 設定が変更されるかタイムアウトするまで待機する
+			while (true)
+			{
+				changed = false;
+				if (k->Halt)
+				{
+					// 停止
+					return;
+				}
+				Lock(k->lock);
+				{
+					if (StrCmpi(k->ServerName, server_name) != 0 ||
+						k->ServerPort != server_port || k->Enable == false ||
+						k->UdpMode)
+					{
+						changed = true;
+					}
+				}
+				Unlock(k->lock);
+
+				if (changed)
+				{
+					// 設定が変更された
+					goto WAIT_FOR_ENABLE;
+				}
+
+				if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)
+				{
+					break;
+				}
+
+				Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+			}
+		}
+
+		// 一定時間ごとにパケットデータを送信する
+		if (s != NULL)
+		{
+			UINT64 last_packet_sent_time = 0;
+			while (true)
+			{
+				SOCKSET set;
+				UINT ret;
+				UCHAR buf[MAX_SIZE];
+				bool changed;
+				IP src_ip;
+				UINT src_port;
+
+				InitSockSet(&set);
+				AddSockSet(&set, s);
+
+				Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);
+
+				// 受信
+				ret = RecvFrom(s, &src_ip, &src_port, buf, sizeof(buf));
+				if (ret == 0 && s->IgnoreRecvErr == false)
+				{
+					// 切断された
+					Disconnect(s);
+					ReleaseSock(s);
+					s = NULL;
+				}
+
+				if (s != NULL)
+				{
+					if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)
+					{
+						BUF *b;
+
+						// 次のパケットを送出する
+						last_packet_sent_time = Tick64();
+
+						b = NewKeepPacket(k->Server);
+
+						ret = SendTo(s, &dest_ip, server_port, b->Buf, b->Size);
+						FreeBuf(b);
+
+						if (ret == 0 && s->IgnoreSendErr == false)
+						{
+							// 切断された
+							Disconnect(s);
+							ReleaseSock(s);
+							s = NULL;
+						}
+					}
+				}
+
+				changed = false;
+
+				Lock(k->lock);
+				{
+					if (StrCmpi(k->ServerName, server_name) != 0 ||
+						k->ServerPort != server_port || k->Enable == false ||
+						k->UdpMode == false)
+					{
+						changed = true;
+					}
+				}
+				Unlock(k->lock);
+
+				if (changed || s == NULL)
+				{
+					// 設定が変更された または 切断された
+					Disconnect(s);
+					ReleaseSock(s);
+					s = NULL;
+					goto WAIT_FOR_ENABLE;
+				}
+				else
+				{
+					if (k->Halt)
+					{
+						// 停止
+						Disconnect(s);
+						ReleaseSock(s);
+						return;
+					}
+				}
+			}
+		}
+	}
+}
+
+// KEEP 停止
+void StopKeep(KEEP *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	k->Halt = true;
+	Set(k->HaltEvent);
+	Cancel(k->Cancel);
+
+	WaitThread(k->Thread, INFINITE);
+	ReleaseThread(k->Thread);
+	DeleteLock(k->lock);
+
+	ReleaseCancel(k->Cancel);
+	ReleaseEvent(k->HaltEvent);
+
+	Free(k);
+}
+
+// KEEP 開始
+KEEP *StartKeep()
+{
+	KEEP *k = ZeroMalloc(sizeof(KEEP));
+
+	k->lock = NewLock();
+	k->HaltEvent = NewEvent();
+	k->Cancel = NewCancel();
+
+	// スレッド開始
+	k->Thread = NewThread(KeepThread, k);
+
+	return k;
+}
+
+// クライアント認証データのコピー
+CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a)
+{
+	CLIENT_AUTH *ret;
+	// 引数チェック
+	if (a == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMallocEx(sizeof(CLIENT_AUTH), true);
+
+	ret->AuthType = a->AuthType;
+	StrCpy(ret->Username, sizeof(ret->Username), a->Username);
+
+	switch (a->AuthType)
+	{
+	case CLIENT_AUTHTYPE_ANONYMOUS:
+		// 匿名認証
+		break;
+
+	case CLIENT_AUTHTYPE_PASSWORD:
+		// パスワード認証
+		Copy(ret->HashedPassword, a->HashedPassword, SHA1_SIZE);
+		break;
+
+	case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+		// 平文パスワード認証
+		StrCpy(ret->PlainPassword, sizeof(ret->PlainPassword), a->PlainPassword);
+		break;
+
+	case CLIENT_AUTHTYPE_CERT:
+		// 証明書認証
+		ret->ClientX = CloneX(a->ClientX);
+		ret->ClientK = CloneK(a->ClientK);
+		break;
+
+	case CLIENT_AUTHTYPE_SECURE:
+		// セキュアデバイス認証
+		StrCpy(ret->SecurePublicCertName, sizeof(ret->SecurePublicCertName), a->SecurePublicCertName);
+		StrCpy(ret->SecurePrivateKeyName, sizeof(ret->SecurePrivateKeyName), a->SecurePrivateKeyName);
+		break;
+	}
+
+	return ret;
+}
+
+// 送信 FIFO にデータを書き込む (自動暗号化)
+void WriteSendFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+	// 引数チェック
+	if (s == NULL || ts == NULL || data == NULL)
+	{
+		return;
+	}
+
+	if (s->UseFastRC4)
+	{
+		Encrypt(ts->SendKey, data, data, size);
+	}
+
+	WriteFifo(ts->SendFifo, data, size);
+}
+
+// 受信 FIFO にデータを書き込む (自動解読)
+void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+	// 引数チェック
+	if (s == NULL || ts == NULL || data == NULL)
+	{
+		return;
+	}
+
+	if (s->UseFastRC4)
+	{
+		Encrypt(ts->RecvKey, data, data, size);
+	}
+
+	WriteFifo(ts->RecvFifo, data, size);
+}
+
+// TCP ソケット受信
+UINT TcpSockRecv(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+	// 受信
+	return Recv(ts->Sock, data, size, s->UseSSLDataEncryption);
+}
+
+// TCP ソケット送信
+UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+	// 送信
+	return Send(ts->Sock, data, size, s->UseSSLDataEncryption);
+}
+
+// データを UDP パケットとして送信する
+void SendDataWithUDP(SOCK *s, CONNECTION *c)
+{
+	UCHAR *buf;
+	BUF *b;
+	UINT64 dummy_64 = 0;
+	UCHAR dummy_buf[16];
+	UINT64 now = Tick64();
+	UINT ret;
+	bool force_flag = false;
+	bool packet_sent = false;
+	// 引数チェック
+	if (s == NULL || c == NULL)
+	{
+		return;
+	}
+
+	// 一時バッファをヒープから確保しておく
+	if (c->RecvBuf == NULL)
+	{
+		c->RecvBuf = Malloc(RECV_BUF_SIZE);
+	}
+	buf = c->RecvBuf;
+
+	if (c->Udp->NextKeepAliveTime == 0 || c->Udp->NextKeepAliveTime <= now)
+	{
+		force_flag = true;
+	}
+
+	// バッファの作成
+	while ((c->SendBlocks->num_item > 0) || force_flag)
+	{
+		UINT *key32;
+		UINT64 *seq;
+		char *sign;
+
+		force_flag = false;
+
+		// 現在のキューからバッファを組み立てる
+		b = NewBuf();
+
+		// パケットヘッダ (16バイト) 分の領域を確保
+		WriteBuf(b, dummy_buf, sizeof(dummy_buf));
+
+		// 送信キューのパケットを詰め込む
+		LockQueue(c->SendBlocks);
+		{
+			while (true)
+			{
+				BLOCK *block;
+
+				if (b->Size > UDP_BUF_SIZE)
+				{
+					break;
+				}
+				block = GetNext(c->SendBlocks);
+				if (block == NULL)
+				{
+					break;
+				}
+
+				if (block->Size != 0)
+				{
+					WriteBufInt(b, block->Size);
+					WriteBuf(b, block->Buf, block->Size);
+
+					c->Session->TotalSendSize += (UINT64)block->SizeofData;
+					c->Session->TotalSendSizeReal += (UINT64)block->Size;
+				}
+
+				FreeBlock(block);
+				break;
+			}
+		}
+		UnlockQueue(c->SendBlocks);
+
+		// セッションキーとシーケンス番号の書き込み
+		sign = (char *)(((UCHAR *)b->Buf));
+		key32 = (UINT *)(((UCHAR *)b->Buf + 4));
+		seq = (UINT64 *)(((UCHAR *)b->Buf + 8));
+		Copy(sign, SE_UDP_SIGN, 4);
+		*key32 = Endian32(c->Session->SessionKey32);
+		*seq = Endian64(c->Udp->Seq++); // シーケンス番号をインクリメントする
+
+//		InsertQueue(c->Udp->BufferQueue, b);
+
+		packet_sent = true;
+/*	}
+
+	// バッファの送信
+	while (c->Udp->BufferQueue->num_item != 0)
+	{
+		FIFO *f = c->Udp->BufferQueue->fifo;
+		BUF **pb = (BUF**)(((UCHAR *)f->p) + f->pos);
+		BUF *b = *pb;
+
+*/		ret = SendTo(s, &c->Udp->ip, c->Udp->port, b->Buf, b->Size);
+		if (ret == SOCK_LATER)
+		{
+			// ブロッキング
+			Debug(".");
+//			break;
+		}
+		if (ret != b->Size)
+		{
+			if (s->IgnoreSendErr == false)
+			{
+				// エラー
+				Debug("******* SendTo Error !!!\n");
+			}
+		}
+
+		// メモリ解放
+		FreeBuf(b);
+//		GetNext(c->Udp->BufferQueue);
+	}
+
+	if (packet_sent)
+	{
+		// KeepAlive 時刻更新
+		c->Udp->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+	}
+}
+
+// UDP パケットのデータをコネクションに書き込む
+void PutUDPPacketData(CONNECTION *c, void *data, UINT size)
+{
+	BUF *b;
+	char sign[4];
+	// 引数チェック
+	if (c == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// プロトコルを調べる
+	if (c->Protocol != CONNECTION_UDP)
+	{
+		// UDP プロトコルは利用されていない
+		return;
+	}
+
+	// バッファ構成
+	b = NewBuf();
+	WriteBuf(b, data, size);
+
+	SeekBuf(b, 0, 0);
+	ReadBuf(b, sign, 4);
+
+	// サイン確認
+	if (Cmp(sign, SE_UDP_SIGN, 4) == 0)
+	{
+		UINT key32;
+
+		// セッションキー番号
+		key32 = ReadBufInt(b);
+
+		if (c->Session->SessionKey32 == key32)
+		{
+			UINT64 seq;
+
+			// シーケンス番号読み込み
+			ReadBuf(b, &seq, sizeof(seq));
+			seq = Endian64(seq);
+
+			if ((UINT)(seq - c->Udp->RecvSeq - (UINT64)1))
+			{
+				//Debug("** UDP Seq Lost %u\n", (UINT)(seq - c->Udp->RecvSeq - (UINT64)1));
+			}
+			c->Udp->RecvSeq = seq;
+
+			//Debug("SEQ: %I32u\n", seq);
+
+			while (true)
+			{
+				UINT size;
+
+				size = ReadBufInt(b);
+				if (size == 0)
+				{
+					break;
+				}
+				else if (size <= MAX_PACKET_SIZE)
+				{
+					void *tmp;
+					BLOCK *block;
+
+					tmp = Malloc(size);
+					if (ReadBuf(b, tmp, size) != size)
+					{
+						Free(tmp);
+						break;
+					}
+
+					// ブロック構成
+					block = NewBlock(tmp, size, 0);
+
+					// ブロック挿入
+					InsertReveicedBlockToQueue(c, block);
+				}
+			}
+
+			// 最終通信時刻を更新
+			c->Session->LastCommTime = Tick64();
+		}
+		else
+		{
+			Debug("Invalid SessionKey: 0x%X\n", key32);
+		}
+	}
+
+	FreeBuf(b);
+}
+
+// 受信キューにブロックを追加する
+void InsertReveicedBlockToQueue(CONNECTION *c, BLOCK *block)
+{
+	SESSION *s;
+	// 引数チェック
+	if (c == NULL || block == NULL)
+	{
+		return;
+	}
+
+	s = c->Session;
+	
+	if (c->Protocol == CONNECTION_TCP)
+	{
+		s->TotalRecvSizeReal += block->SizeofData;
+		s->TotalRecvSize += block->Size;
+	}
+
+	LockQueue(c->ReceivedBlocks);
+	{
+		InsertQueue(c->ReceivedBlocks, block);
+	}
+	UnlockQueue(c->ReceivedBlocks);
+}
+
+// 次の Keep-Alive パケットまでの間隔を生成 (ネットワーク負荷減少のため乱数にする)
+UINT GenNextKeepAliveSpan(CONNECTION *c)
+{
+	UINT a, b;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return INFINITE;
+	}
+
+	a = c->Session->Timeout;
+	b = rand() % (a / 2);
+	b = MAX(b, a / 5);
+
+	return b;
+}
+
+// Keep-Alive パケットを送信する
+void SendKeepAlive(CONNECTION *c, TCPSOCK *ts)
+{
+	UINT size, i, num;
+	UINT size_be;
+	UCHAR *buf;
+	// 引数チェック
+	if (c == NULL || ts == NULL)
+	{
+		return;
+	}
+
+	size = rand() % MAX_KEEPALIVE_SIZE;
+	num = KEEP_ALIVE_MAGIC;
+	buf = MallocFast(size);
+
+	for (i = 0;i < size;i++)
+	{
+		buf[i] = rand();
+	}
+
+	num = Endian32(num);
+	size_be = Endian32(size);
+	WriteSendFifo(c->Session, ts, &num, sizeof(UINT));
+	WriteSendFifo(c->Session, ts, &size_be, sizeof(UINT));
+	WriteSendFifo(c->Session, ts, buf, size);
+
+	c->Session->TotalSendSize += sizeof(UINT) * 2 + size;
+	c->Session->TotalSendSizeReal += sizeof(UINT) * 2 + size;
+
+	Free(buf);
+}
+
+// ブロックの送信
+void ConnectionSend(CONNECTION *c)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	UINT i, num;
+	UINT64 now;
+	UINT min_count;
+	TCPSOCK **tcpsocks;
+	UINT size;
+	SESSION *s;
+	bool use_qos;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	s = c->Session;
+	use_qos = s->QoS;
+
+	now = Tick64();
+
+	// プロトコル
+	if (c->Protocol == CONNECTION_TCP)
+	{
+		// TCP
+		TCP *tcp = c->Tcp;
+		TCPSOCK *ts;
+		TCPSOCK *ts_hp;
+		UINT num_available;
+		LockList(tcp->TcpSockList);
+		{
+			num = LIST_NUM(tcp->TcpSockList);
+			tcpsocks = ToArrayEx(tcp->TcpSockList, true);
+		}
+		UnlockList(tcp->TcpSockList);
+
+		// 送信に使用するソケットを選択する
+		// 遅延回数が最も少ないソケットを選出
+		min_count = INFINITE;
+		ts = NULL;
+		ts_hp = NULL;
+
+		num_available = 0;
+
+		for (i = 0;i < num;i++)
+		{
+			TCPSOCK *tcpsock = tcpsocks[i];
+			if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
+				IS_SEND_TCP_SOCK(tcpsock))
+			{
+				// KeepAlive の処理
+				if (now >= tcpsock->NextKeepAliveTime || tcpsock->NextKeepAliveTime == 0)
+				{
+					// KeepAlive を打つ
+					SendKeepAlive(c, tcpsock);
+					tcpsock->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+				}
+
+				// 送信に利用可能なソケット数を計測する
+				num_available++;
+
+				ts_hp = tcpsock;
+			}
+		}
+
+		for (i = 0;i < num;i++)
+		{
+			TCPSOCK *tcpsock = tcpsocks[i];
+			if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
+				IS_SEND_TCP_SOCK(tcpsock))
+			{
+				// ソケットの選出
+				bool b = false;
+
+				if (use_qos == false)
+				{
+					b = true;
+				}
+				else if (num_available < 2)
+				{
+					b = true;
+				}
+				else if (tcpsock != ts_hp)
+				{
+					b = true;
+				}
+
+				if (b)
+				{
+					if (tcpsock->LateCount <= min_count)
+					{
+						min_count = tcpsock->LateCount;
+						ts = tcpsock;
+					}
+				}
+			}
+		}
+
+		if (use_qos == false)
+		{
+			ts_hp = ts;
+		}
+
+		if (ts == NULL || ts_hp == NULL)
+		{
+			// 現在 送信可能なソケットが存在しない
+		}
+		else
+		{
+			TCPSOCK *tss;
+			UINT j;
+			QUEUE *q;
+
+			for (j = 0;j < 2;j++)
+			{
+				if (j == 0)
+				{
+					q = c->SendBlocks2;
+					tss = ts_hp;
+				}
+				else
+				{
+					q = c->SendBlocks;
+					tss = ts;
+				}
+				// 選択されたソケット ts に対して送信データを予約する
+				LockQueue(c->SendBlocks);
+				if (q->num_item != 0)
+				{
+					UINT num_data;
+					BLOCK *b;
+
+					if (tss->SendFifo->size >= MAX((MAX_SEND_SOCKET_QUEUE_SIZE / s->MaxConnection), MIN_SEND_SOCKET_QUEUE_SIZE))
+					{
+						// 送信ソケットキューのサイズが超過
+						// 送信できない
+						while (b = GetNext(q))
+						{
+							if (b != NULL)
+							{
+								c->CurrentSendQueueSize -= b->Size;
+								FreeBlock(b);
+							}
+						}
+					}
+					else
+					{
+						bool update_keepalive_timer = false;
+						// 個数データ
+						num_data = Endian32(q->num_item);
+						PROBE_DATA2("WriteSendFifo num", &num_data, sizeof(UINT));
+						WriteSendFifo(s, tss, &num_data, sizeof(UINT));
+
+						s->TotalSendSize += sizeof(UINT);
+						s->TotalSendSizeReal += sizeof(UINT);
+
+						while (b = GetNext(q))
+						{
+							// サイズデータ
+							UINT size_data;
+							size_data = Endian32(b->Size);
+							PROBE_DATA2("WriteSendFifo size", &size_data, sizeof(UINT));
+							WriteSendFifo(s, tss, &size_data, sizeof(UINT));
+
+							c->CurrentSendQueueSize -= b->Size;
+
+							s->TotalSendSize += sizeof(UINT);
+							s->TotalSendSizeReal += sizeof(UINT);
+
+							// データ本体
+							PROBE_DATA2("WriteSendFifo data", b->Buf, b->Size);
+							WriteSendFifo(s, tss, b->Buf, b->Size);
+
+							s->TotalSendSize += b->SizeofData;
+							s->TotalSendSizeReal += b->Size;
+
+							update_keepalive_timer = true;
+
+							// ブロック解放
+							FreeBlock(b);
+						}
+
+						if (update_keepalive_timer)
+						{
+							// KeepAlive タイマを増加させる
+							tss->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+						}
+					}
+				}
+				UnlockQueue(c->SendBlocks);
+			}
+		}
+
+		// 現在各ソケットに登録されている送信予約データを送信する
+		for (i = 0;i < num;i++)
+		{
+			ts = tcpsocks[i];
+
+SEND_START:
+			if (ts->Sock->Connected == false)
+			{
+				s->LastTryAddConnectTime = Tick64();
+				// 通信が切断された
+				LockList(tcp->TcpSockList);
+				{
+					// ソケットリストからこのソケットを削除する
+					Delete(tcp->TcpSockList, ts);
+					// TCPSOCK の解放
+					FreeTcpSock(ts);
+					// 個数のデクリメント
+					Dec(c->CurrentNumConnection);
+					Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);
+					Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));
+				}
+				UnlockList(tcp->TcpSockList);
+
+				continue;
+			}
+
+			// Fifo サイズを取得
+			if (ts->SendFifo->size != 0)
+			{
+				UCHAR *buf;
+				UINT want_send_size;
+				// 1 バイト以上送信予定データが存在する場合のみ送信する
+				// バッファへのポインタを取得
+				buf = (UCHAR *)ts->SendFifo->p + ts->SendFifo->pos;
+				want_send_size = ts->SendFifo->size;
+
+				PROBE_DATA2("TcpSockSend", buf, want_send_size);
+				size = TcpSockSend(s, ts, buf, want_send_size);
+				if (size == 0)
+				{
+					// 切断された
+					continue;
+				}
+				else if (size == SOCK_LATER)
+				{
+					// パケットが詰まっている
+					ts->LateCount++; // 遅延カウンタのインクリメント
+					PROBE_STR("ts->LateCount++;");
+				}
+				else
+				{
+					// パケットが size だけ送信された
+					// FIFO を進める
+					ReadFifo(ts->SendFifo, NULL, size);
+					if (size < want_send_size)
+					{
+						// 予定されたデータのすべてを送信することができなかった
+#ifdef	USE_PROBE
+						{
+							char tmp[MAX_SIZE];
+
+							snprintf(tmp, sizeof(tmp), "size < want_send_size: %u < %u",
+								size, want_send_size);
+
+							PROBE_STR(tmp);
+						}
+#endif	// USE_PROBE
+					}
+					else
+					{
+						// すべてのパケットの送信が完了した (キューが無くなった)
+						// ので、遅延カウンタをリセットする
+						ts->LateCount = 0;
+
+						PROBE_STR("TcpSockSend All Completed");
+					}
+					// 最終通信日時を更新
+					c->Session->LastCommTime = now;
+
+					goto SEND_START;
+				}
+			}
+		}
+
+		Free(tcpsocks);
+	}
+	else if (c->Protocol == CONNECTION_UDP)
+	{
+		// UDP
+		UDP *udp = c->Udp;
+		SOCK *sock = NULL;
+
+		Lock(c->lock);
+		{
+			sock = udp->s;
+			if (sock != NULL)
+			{
+				AddRef(sock->ref);
+			}
+		}
+		Unlock(c->lock);
+
+		if (sock != NULL)
+		{
+			// UDP で送信する
+
+			// KeepAlive 送信
+			if ((udp->NextKeepAliveTime == 0 || udp->NextKeepAliveTime <= now) ||
+				(c->SendBlocks->num_item != 0) || (udp->BufferQueue->num_item != 0))
+			{
+				// 現在のキューを UDP で送信
+				SendDataWithUDP(sock, c);
+			}
+		}
+
+		if (sock != NULL)
+		{
+			ReleaseSock(sock);
+		}
+	}
+	else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)
+	{
+		// SecureNAT セッション
+		SNAT *snat = s->SecureNAT;
+		VH *v = snat->Nat->Virtual;
+
+		LockQueue(c->SendBlocks);
+		{
+			BLOCK *block;
+			UINT num_packet = 0;
+
+			while (block = GetNext(c->SendBlocks))
+			{
+				num_packet++;
+				c->CurrentSendQueueSize -= block->Size;
+				VirtualPutPacket(v, block->Buf, block->Size);
+				Free(block);
+			}
+
+			if (num_packet != 0)
+			{
+				VirtualPutPacket(v, NULL, 0);
+			}
+		}
+		UnlockQueue(c->SendBlocks);
+	}
+	else if (c->Protocol == CONNECTION_HUB_LAYER3)
+	{
+		// Layer-3 セッション
+		L3IF *f = s->L3If;
+
+		LockQueue(c->SendBlocks);
+		{
+			BLOCK *block;
+			UINT num_packet = 0;
+
+			while (block = GetNext(c->SendBlocks))
+			{
+				num_packet++;
+				c->CurrentSendQueueSize -= block->Size;
+				L3PutPacket(f, block->Buf, block->Size);
+				Free(block);
+			}
+
+			if (num_packet != 0)
+			{
+				L3PutPacket(f, NULL, 0);
+			}
+		}
+		UnlockQueue(c->SendBlocks);
+	}
+	else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
+	{
+		// HUB リンク
+		LINK *k = (LINK *)s->Link;
+
+		if (k != NULL)
+		{
+			LockQueue(c->SendBlocks);
+			{
+				UINT num_blocks = 0;
+				LockQueue(k->SendPacketQueue);
+				{
+					BLOCK *block;
+
+					// パケットキューをクライアントスレッドに転送する
+					while (block = GetNext(c->SendBlocks))
+					{
+						num_blocks++;
+						c->CurrentSendQueueSize -= block->Size;
+						InsertQueue(k->SendPacketQueue, block);
+					}
+				}
+				UnlockQueue(k->SendPacketQueue);
+
+				if (num_blocks != 0)
+				{
+					// キャンセルの発行
+					Cancel(k->ClientSession->Cancel1);
+				}
+			}
+			UnlockQueue(c->SendBlocks);
+		}
+	}
+	else if (c->Protocol == CONNECTION_HUB_BRIDGE)
+	{
+		// ローカルブリッジ
+		BRIDGE *b = s->Bridge;
+
+		if (b != NULL)
+		{
+			if (b->Active)
+			{
+				LockQueue(c->SendBlocks);
+				{
+					BLOCK *block;
+					UINT num_packet = c->SendBlocks->num_item; // パケット数
+
+					if (num_packet != 0)
+					{
+						// パケットデータ配列
+						void **datas = MallocFast(sizeof(void *) * num_packet);
+						UINT *sizes = MallocFast(sizeof(UINT *) * num_packet);
+						UINT i;
+
+						i = 0;
+						while (block = GetNext(c->SendBlocks))
+						{
+							datas[i] = block->Buf;
+							sizes[i] = block->Size;
+
+							if (block->Size > 1514)
+							{
+								NormalizeEthMtu(b, c, block->Size);
+							}
+
+							c->CurrentSendQueueSize -= block->Size;
+							Free(block);
+							i++;
+						}
+
+						// パケットを書き込む
+						EthPutPackets(b->Eth, num_packet, datas, sizes);
+
+						Free(datas);
+						Free(sizes);
+					}
+				}
+				UnlockQueue(c->SendBlocks);
+			}
+		}
+	}
+}
+
+// ブロックの受信
+void ConnectionReceive(CONNECTION *c, CANCEL *c1, CANCEL *c2)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	UINT i, num;
+	SOCKSET set;
+	SESSION *s;
+	TCPSOCK **tcpsocks;
+	UCHAR *buf;
+	UINT size;
+	UINT64 now;
+	UINT time;
+	UINT num_delayed = 0;
+	bool no_spinlock_for_delay = false;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	PROBE_STR("ConnectionReceive");
+
+	s = c->Session;
+
+	if (s->Hub != NULL)
+	{
+		no_spinlock_for_delay = s->Hub->Option->NoSpinLockForPacketDelay;
+	}
+
+	now = Tick64();
+
+	if (c->RecvBuf == NULL)
+	{
+		c->RecvBuf = Malloc(RECV_BUF_SIZE);
+	}
+	buf = c->RecvBuf;
+
+	// プロトコル
+	if (c->Protocol == CONNECTION_TCP)
+	{
+		// TCP
+		TCP *tcp = c->Tcp;
+
+		// コネクション切断間隔が指定されている場合はコネクションの切断を行う
+		if (s->ServerMode == false)
+		{
+			if (s->ClientOption->ConnectionDisconnectSpan != 0)
+			{
+				LockList(tcp->TcpSockList);
+				{
+					UINT i;
+					for (i = 0;i < LIST_NUM(tcp->TcpSockList);i++)
+					{
+						TCPSOCK *ts = LIST_DATA(tcp->TcpSockList, i);
+						if (ts->DisconnectTick != 0 &&
+							ts->DisconnectTick <= now)
+						{
+							Debug("ts->DisconnectTick <= now\n");
+							Disconnect(ts->Sock);
+						}
+					}
+				}
+				UnlockList(tcp->TcpSockList);
+			}
+		}
+
+		if (s->HalfConnection && (s->ServerMode == false))
+		{
+			// 現在の TCP コネクションの方向を調べ、
+			// 一方向しか無く かつコネクション数が限界の場合は
+			// 1 つ切断する
+			LockList(tcp->TcpSockList);
+			{
+				UINT i, num;
+				UINT c2s, s2c;
+				c2s = s2c = 0;
+				num = LIST_NUM(tcp->TcpSockList);
+				if (num >= s->MaxConnection)
+				{
+					TCPSOCK *ts;
+					for (i = 0;i < num;i++)
+					{
+						ts = LIST_DATA(tcp->TcpSockList, i);
+						if (ts->Direction == TCP_SERVER_TO_CLIENT)
+						{
+							s2c++;
+						}
+						else
+						{
+							c2s++;
+						}
+					}
+					if (s2c == 0 || c2s == 0)
+					{
+						// 最後のソケットを切断する
+						Disconnect(ts->Sock);
+						Debug("Disconnect (s2c=%u, c2s=%u)\n", s2c, c2s);
+					}
+				}
+			}
+			UnlockList(tcp->TcpSockList);
+		}
+
+		// ソケットセットの初期化
+		InitSockSet(&set);
+		LockList(tcp->TcpSockList);
+		{
+			num = LIST_NUM(tcp->TcpSockList);
+			tcpsocks = ToArrayEx(tcp->TcpSockList, true);
+		}
+		UnlockList(tcp->TcpSockList);
+
+		for (i = 0;i < num;i++)
+		{
+			AddSockSet(&set, tcpsocks[i]->Sock);
+		}
+
+		// Select
+		time = SELECT_TIME;
+		if (s->VirtualHost)
+		{
+			time = MIN(time, SELECT_TIME_FOR_NAT);
+		}
+		time = MIN(time, GetNextDelayedPacketTickDiff(s));
+		num_delayed = LIST_NUM(s->DelayedPacketList);
+
+		PROBE_STR("ConnectionReceive: Select 0");
+
+		if (s->Flag1 != set.NumSocket)
+		{
+			Select(&set, (num_delayed == 0 ? time : 1), c1, c2);
+			s->Flag1 = set.NumSocket;
+		}
+		else
+		{
+			if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+			{
+				Select(&set, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+				s->Flag1 = set.NumSocket;
+			}
+			else
+			{
+				YieldCpu();
+			}
+		}
+
+		PROBE_STR("ConnectionReceive: Select 1");
+
+		// TCP ソケットに到着しているデータをすべて読み込む
+		for (i = 0;i < num;i++)
+		{
+			TCPSOCK *ts = tcpsocks[i];
+			if (ts->WantSize == 0)
+			{
+				// 最初に必ず sizeof(UINT) だけ読み込む
+				ts->WantSize = sizeof(UINT);
+			}
+
+RECV_START:
+			// 受信
+			size = TcpSockRecv(s, ts, buf, RECV_BUF_SIZE);
+			if (size == 0)
+			{
+DISCONNECT_THIS_TCP:
+				s->LastTryAddConnectTime = Tick64();
+				// 通信が切断された
+				LockList(tcp->TcpSockList);
+				{
+					// ソケットリストからこのソケットを削除する
+					Delete(tcp->TcpSockList, ts);
+					// TCPSOCK の解放
+					FreeTcpSock(ts);
+					// デクリメント
+					Dec(c->CurrentNumConnection);
+					Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);
+					Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));
+				}
+				UnlockList(tcp->TcpSockList);
+
+				continue;
+			}
+			else if (size == SOCK_LATER)
+			{
+				// 受信待ち状態: 何もしない
+				if (IS_RECV_TCP_SOCK(ts))
+				{
+					if ((now > ts->LastCommTime) && ((now - ts->LastCommTime) >= ((UINT64)s->Timeout)))
+					{
+						// このコネクションはタイムアウトした
+						Debug("Connection %u Timeouted.\n", i);
+						goto DISCONNECT_THIS_TCP;
+					}
+				}
+			}
+			else
+			{
+				// 最終通信時刻を更新
+				ts->LastCommTime = now;
+				c->Session->LastCommTime = now;
+
+				// データが受信できたので FIFO に書き込む
+				PROBE_DATA2("WriteRecvFifo", buf, size);
+				WriteRecvFifo(s, ts, buf, size);
+
+				// 受信バッファがいっぱいになったら受信をやめる
+				if (ts->RecvFifo->size < MAX_SEND_SOCKET_QUEUE_SIZE)
+				{
+					goto RECV_START;
+				}
+			}
+
+			// FIFO に書き込まれたデータを処理する
+			while (ts->RecvFifo->size >= ts->WantSize)
+			{
+				UCHAR *buf;
+				void *data;
+				BLOCK *block;
+				UINT sz;
+				// すでに十分な量のデータが格納されている
+				// データのポインタを取得
+				buf = (UCHAR *)ts->RecvFifo->p + ts->RecvFifo->pos;
+
+				switch (ts->Mode)
+				{
+				case 0:
+					// データブロック個数
+					ts->WantSize = sizeof(UINT);
+					Copy(&sz, buf, sizeof(UINT));
+					PROBE_DATA2("ReadFifo 0", buf, sizeof(UINT));
+					sz = Endian32(sz);
+					ts->NextBlockNum = sz;
+					ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+					s->TotalRecvSize += sizeof(UINT);
+					s->TotalRecvSizeReal += sizeof(UINT);
+
+					ts->CurrentPacketNum = 0;
+					if (ts->NextBlockNum != 0)
+					{
+						if (ts->NextBlockNum == KEEP_ALIVE_MAGIC)
+						{
+							ts->Mode = 3;
+						}
+						else
+						{
+							ts->Mode = 1;
+						}
+					}
+					break;
+
+				case 1:
+					// データブロックサイズ
+					Copy(&sz, buf, sizeof(UINT));
+					sz = Endian32(sz);
+					PROBE_DATA2("ReadFifo 1", buf, sizeof(UINT));
+					if (sz > (MAX_PACKET_SIZE * 2))
+					{
+						// おかしなデータサイズを受信した
+						// TCP/IP 通信エラー?
+						Debug("%s %u sz > (MAX_PACKET_SIZE * 2)\n", __FILE__, __LINE__);
+						Disconnect(ts->Sock);
+					}
+					ts->NextBlockSize = MIN(sz, MAX_PACKET_SIZE * 2);
+					ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+					s->TotalRecvSize += sizeof(UINT);
+					s->TotalRecvSizeReal += sizeof(UINT);
+
+					ts->WantSize = ts->NextBlockSize;
+					if (ts->WantSize != 0)
+					{
+						ts->Mode = 2;
+					}
+					else
+					{
+						ts->Mode = 1;
+						ts->WantSize = sizeof(UINT);
+						ts->CurrentPacketNum++;
+						if (ts->CurrentPacketNum >= ts->NextBlockNum)
+						{
+							ts->Mode = 0;
+						}
+					}
+					break;
+
+				case 2:
+					// データブロック本体
+					ts->WantSize = sizeof(UINT);
+					ts->CurrentPacketNum++;
+					data = MallocFast(ts->NextBlockSize);
+					Copy(data, buf, ts->NextBlockSize);
+					PROBE_DATA2("ReadFifo 2", buf, ts->NextBlockSize);
+					ReadFifo(ts->RecvFifo, NULL, ts->NextBlockSize);
+					block = NewBlock(data, ts->NextBlockSize, s->UseCompress ? -1 : 0);
+
+					if (block->Size > MAX_PACKET_SIZE)
+					{
+						// パケットサイズ超過
+						FreeBlock(block);
+					}
+					else
+					{
+						// データブロックをキューに追加
+						InsertReveicedBlockToQueue(c, block);
+					}
+
+					if (ts->CurrentPacketNum >= ts->NextBlockNum)
+					{
+						// すべてのデータブロックの受信が完了
+						ts->Mode = 0;
+					}
+					else
+					{
+						// 次のデータブロックサイズを受信
+						ts->Mode = 1;
+					}
+					break;
+
+				case 3:
+					// Keep-Alive パケットサイズ
+					ts->Mode = 4;
+					Copy(&sz, buf, sizeof(UINT));
+					PROBE_DATA2("ReadFifo 3", buf, sizeof(UINT));
+					sz = Endian32(sz);
+					if (sz > MAX_KEEPALIVE_SIZE)
+					{
+						// おかしなデータサイズを受信した
+						// TCP/IP 通信エラー?
+						Debug("%s %u sz > MAX_KEEPALIVE_SIZE\n", __FILE__, __LINE__);
+						Disconnect(ts->Sock);
+					}
+					ts->NextBlockSize = MIN(sz, MAX_KEEPALIVE_SIZE);
+					ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+					s->TotalRecvSize += sizeof(UINT);
+					s->TotalRecvSizeReal += sizeof(UINT);
+
+					ts->WantSize = sz;
+					break;
+
+				case 4:
+					// Keep-Alive パケット本体
+					//Debug("KeepAlive Recved.\n");
+					ts->Mode = 0;
+					sz = ts->NextBlockSize;
+					PROBE_DATA2("ReadFifo 4", NULL, 0);
+					ReadFifo(ts->RecvFifo, NULL, sz);
+
+					s->TotalRecvSize += sz;
+					s->TotalRecvSizeReal += sz;
+
+					ts->WantSize = sizeof(UINT);
+					break;
+				}
+			}
+		}
+
+		Free(tcpsocks);
+	}
+	else if (c->Protocol == CONNECTION_UDP)
+	{
+		// UDP
+		UDP *udp = c->Udp;
+		SOCK *sock = NULL;
+
+		if (s->ServerMode == false)
+		{
+			Lock(c->lock);
+			{
+				if (c->Udp->s != NULL)
+				{
+					sock = c->Udp->s;
+					if (sock != NULL)
+					{
+						AddRef(sock->ref);
+					}
+				}
+			}
+			Unlock(c->lock);
+
+			InitSockSet(&set);
+
+			if (sock != NULL)
+			{
+				AddSockSet(&set, sock);
+			}
+
+			Select(&set, SELECT_TIME, c1, c2);
+
+			if (sock != NULL)
+			{
+				IP ip;
+				UINT port;
+				UCHAR *buf;
+				UINT size;
+
+				while (true)
+				{
+					buf = c->RecvBuf;
+					size = RecvFrom(sock, &ip, &port, buf, RECV_BUF_SIZE);
+					if (size == 0 && sock->IgnoreRecvErr == false)
+					{
+						Debug("UDP Socket Disconnected.\n");
+						Lock(c->lock);
+						{
+							ReleaseSock(udp->s);
+							udp->s = NULL;
+						}
+						Unlock(c->lock);
+						break;
+					}
+					else if (size == SOCK_LATER)
+					{
+						break;
+					}
+					else
+					{
+						if (size)
+						{
+							PutUDPPacketData(c, buf, size);
+						}
+					}
+				}
+			}
+
+			if (sock != NULL)
+			{
+				Release(sock->ref);
+			}
+		}
+		else
+		{
+			Select(NULL, SELECT_TIME, c1, c2);
+		}
+	}
+	else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)
+	{
+		SNAT *snat = c->Session->SecureNAT;
+		VH *v = snat->Nat->Virtual;
+		UINT size;
+		void *data;
+		UINT num;
+		UINT select_wait_time = SELECT_TIME_FOR_NAT;
+
+		if (snat->Nat != NULL && snat->Nat->Option.UseNat == false)
+		{
+			select_wait_time = SELECT_TIME;
+		}
+		else
+		{
+			if (snat->Nat != NULL)
+			{
+				LockList(v->NatTable);
+				{
+					if (LIST_NUM(v->NatTable) == 0 && LIST_NUM(v->ArpWaitTable) == 0)
+					{
+						select_wait_time = SELECT_TIME;
+					}
+				}
+				UnlockList(v->NatTable);
+			}
+		}
+
+		select_wait_time = MIN(select_wait_time, GetNextDelayedPacketTickDiff(s));
+		num_delayed = LIST_NUM(s->DelayedPacketList);
+
+		if (no_spinlock_for_delay || select_wait_time >= 50 || num_delayed == false)
+		{
+			Select(NULL, (num_delayed == 0 ? select_wait_time :
+				(select_wait_time > 100 ? (select_wait_time - 100) : 1)), c1, c2);
+		}
+		else
+		{
+			YieldCpu();
+		}
+
+		num = 0;
+
+		// 仮想マシンからパケットを受信する
+		while (size = VirtualGetNextPacket(v, &data))
+		{
+			BLOCK *block;
+
+			// パケットブロックを生成
+			block = NewBlock(data, size, 0);
+			if (block->Size > MAX_PACKET_SIZE)
+			{
+				// パケットサイズ超過
+				FreeBlock(block);
+			}
+			else
+			{
+				// データブロックをキューに追加
+				InsertReveicedBlockToQueue(c, block);
+			}
+			num++;
+			if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+			{
+//				WHERE;
+				break;
+			}
+		}
+	}
+	else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
+	{
+		// HUB リンク
+		// 単純に Cancel を待つだけ
+		if (c->SendBlocks->num_item == 0)
+		{
+			UINT time = SELECT_TIME;
+
+			time = MIN(time, GetNextDelayedPacketTickDiff(s));
+			num_delayed = LIST_NUM(s->DelayedPacketList);
+
+			if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+			{
+				Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+			}
+			else
+			{
+				YieldCpu();
+			}
+		}
+	}
+	else if (c->Protocol == CONNECTION_HUB_LAYER3)
+	{
+		// Layer-3 スイッチ セッション
+		L3IF *f = s->L3If;
+		UINT size, num = 0;
+		void *data;
+
+		if (f->SendQueue->num_item == 0)
+		{
+			UINT time = SELECT_TIME_FOR_NAT;
+
+			if (f->ArpWaitTable != NULL)
+			{
+				LockList(f->ArpWaitTable);
+				{
+					if (LIST_NUM(f->ArpWaitTable) == 0)
+					{
+						time = SELECT_TIME;
+					}
+				}
+				UnlockList(f->ArpWaitTable);
+			}
+
+			time = MIN(time, GetNextDelayedPacketTickDiff(s));
+			num_delayed = LIST_NUM(s->DelayedPacketList);
+
+			if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+			{
+				Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+			}
+			else
+			{
+				YieldCpu();
+			}
+		}
+
+		// 次のパケットを取得する
+		while (size = L3GetNextPacket(f, &data))
+		{
+			BLOCK *block = NewBlock(data, size, 0);
+			if (block->Size > MAX_PACKET_SIZE)
+			{
+				FreeBlock(block);
+			}
+			else
+			{
+				InsertReveicedBlockToQueue(c, block);
+			}
+
+			num++;
+			if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+			{
+				break;
+			}
+		}
+	}
+	else if (c->Protocol == CONNECTION_HUB_BRIDGE)
+	{
+		BRIDGE *b = c->Session->Bridge;
+
+		// Bridge セッション
+		if (b->Active)
+		{
+			void *data;
+			UINT ret;
+			UINT num = 0;
+			bool check_device_num = false;
+			UINT time = SELECT_TIME;
+
+			time = MIN(time, GetNextDelayedPacketTickDiff(s));
+			num_delayed = LIST_NUM(s->DelayedPacketList);
+
+			// ブリッジ動作中
+			if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+			{
+				Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+			}
+			else
+			{
+				YieldCpu();
+			}
+
+			if ((b->LastNumDeviceCheck + BRIDGE_NUM_DEVICE_CHECK_SPAN) <= Tick64())
+			{
+				check_device_num = true;
+				b->LastNumDeviceCheck = Tick64();
+			}
+
+			// ブリッジから次のパケットを取得する
+			while (true)
+			{
+				if (check_device_num && b->LastNumDevice != GetEthDeviceHash())
+				{
+					ret = INFINITE;
+				}
+				else
+				{
+					ret = EthGetPacket(b->Eth, &data);
+				}
+
+#ifdef	OS_WIN32
+				if (b->Eth != NULL && b->Eth->LoopbackBlock)
+				{
+					// ブリッジにおける eth デバイスがループバックパケットを遮断
+					// する能力がある場合は CheckMac ポリシーを無効にする
+					if (c->Session != NULL && c->Session->Policy != NULL)
+					{
+						c->Session->Policy->CheckMac = false;
+					}
+				}
+#endif	// OS_WIN32
+
+				if (ret == INFINITE)
+				{
+					// エラー発生 ブリッジを停止させる
+					CloseEth(b->Eth);
+					b->Eth = NULL;
+					b->Active = false;
+					ReleaseCancel(s->Cancel2);
+					s->Cancel2 = NULL;
+
+					HLog(s->Hub, "LH_BRIDGE_2", s->Name, b->Name);
+					Debug("Bridge Device Error.\n");
+
+					break;
+				}
+				else if (ret == 0)
+				{
+					// これ以上パケットが無い
+					break;
+				}
+				else
+				{
+					// パケットをキューに追加
+					BLOCK *block = NewBlock(data, ret, 0);
+
+					PROBE_DATA2("ConnectionReceive: NewBlock", data, ret);
+
+					if (ret > 1514)
+					{
+						NormalizeEthMtu(b, c, ret);
+					}
+
+					if (block->Size > MAX_PACKET_SIZE)
+					{
+						// パケットサイズ超過
+						FreeBlock(block);
+					}
+					else
+					{
+						InsertReveicedBlockToQueue(c, block);
+					}
+					num++;
+					if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+					{
+//						WHERE;
+						break;
+					}
+				}
+			}
+		}
+		else
+		{
+			ETH *e;
+			// 現在ブリッジは停止している
+			Select(NULL, SELECT_TIME, c1, NULL);
+
+			if (b->LastBridgeTry == 0 || (b->LastBridgeTry + BRIDGE_TRY_SPAN) <= Tick64())
+			{
+				b->LastBridgeTry = Tick64();
+
+				// Ethernet デバイスを開こうとしてみる
+				e = OpenEth(b->Name, b->Local, b->TapMode, b->TapMacAddress);
+				if (e != NULL)
+				{
+					// 成功
+					b->Eth = e;
+					b->Active = true;
+					b->LastNumDeviceCheck = Tick64();
+					b->LastNumDevice = GetEthDeviceHash();
+
+					Debug("Bridge Open Succeed.\n");
+
+					HLog(c->Session->Hub, "LH_BRIDGE_1", c->Session->Name, b->Name);
+
+					s->Cancel2 = EthGetCancel(b->Eth);
+				}
+			}
+		}
+	}
+}
+
+// Ethernet デバイスの MTU を正規化する
+void NormalizeEthMtu(BRIDGE *b, CONNECTION *c, UINT packet_size)
+{
+	// 引数チェック
+	if (packet_size == 0 || b == NULL || c == NULL)
+	{
+		return;
+	}
+
+	// 現在の MTU を超えるパケットの場合は MTU を引き上げる
+	if (EthIsChangeMtuSupported(b->Eth))
+	{
+		UINT currentMtu = EthGetMtu(b->Eth);
+		if (currentMtu != 0)
+		{
+			if (packet_size > currentMtu)
+			{
+				bool ok = EthSetMtu(b->Eth, packet_size);
+
+				if (ok)
+				{
+					HLog(c->Session->Hub, "LH_SET_MTU", c->Session->Name,
+						b->Name, currentMtu, packet_size, packet_size);
+				}
+				else
+				{
+					UINT64 now = Tick64();
+
+					if (b->LastChangeMtuError == 0 ||
+						now >= (b->LastChangeMtuError + 60000ULL))
+					{
+						HLog(c->Session->Hub, "LH_SET_MTU_ERROR", c->Session->Name,
+							b->Name, currentMtu, packet_size, packet_size);
+
+						b->LastChangeMtuError = now;
+					}
+				}
+			}
+		}
+	}
+}
+
+// ブロックの解放
+void FreeBlock(BLOCK *b)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	Free(b->Buf);
+	Free(b);
+}
+
+// 新しいブロック作成
+BLOCK *NewBlock(void *data, UINT size, int compress)
+{
+	BLOCK *b;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return NULL;
+	}
+
+	b = ZeroMallocFast(sizeof(BLOCK));
+
+	if (compress == 0)
+	{
+		// 非圧縮
+		b->Compressed = FALSE;
+		b->Buf = data;
+		b->Size = size;
+		b->SizeofData = size;
+	}
+	else if (compress == 1)
+	{
+		UINT max_size;
+
+		// 圧縮
+		b->Compressed = TRUE;
+		max_size = CalcCompress(size);
+		b->Buf = MallocFast(max_size);
+		b->Size = Compress(b->Buf, max_size, data, size);
+		b->SizeofData = size;
+
+		// 古いデータブロックを破棄
+		Free(data);
+	}
+	else
+	{
+		// 展開
+		UINT max_size;
+
+		max_size = MAX_PACKET_SIZE;
+		b->Buf = MallocFast(max_size);
+		b->Size = Uncompress(b->Buf, max_size, data, size);
+		b->SizeofData = size;
+
+		// 古いデータを破棄
+		Free(data);
+	}
+
+	return b;
+}
+
+// TCP ソケットの作成
+TCPSOCK *NewTcpSock(SOCK *s)
+{
+	TCPSOCK *ts;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	ts = ZeroMalloc(sizeof(TCPSOCK));
+
+	ts->Sock = s;
+	AddRef(s->ref);
+
+	ts->RecvFifo = NewFifo();
+	ts->SendFifo = NewFifo();
+	ts->LastCommTime = Tick64();
+
+	// タイムアウト値の解消
+	SetTimeout(s, TIMEOUT_INFINITE);
+
+	return ts;
+}
+
+// TCP ソケット用暗号化鍵の設定
+void InitTcpSockRc4Key(TCPSOCK *ts, bool server_mode)
+{
+	RC4_KEY_PAIR *pair;
+	CRYPT *c1, *c2;
+	// 引数チェック
+	if (ts == NULL)
+	{
+		return;
+	}
+
+	pair = &ts->Rc4KeyPair;
+
+	c1 = NewCrypt(pair->ClientToServerKey, sizeof(pair->ClientToServerKey));
+	c2 = NewCrypt(pair->ServerToClientKey, sizeof(pair->ServerToClientKey));
+
+	if (server_mode)
+	{
+		ts->RecvKey = c1;
+		ts->SendKey = c2;
+	}
+	else
+	{
+		ts->SendKey = c1;
+		ts->RecvKey = c2;
+	}
+}
+
+// TCP ソケットの解放
+void FreeTcpSock(TCPSOCK *ts)
+{
+	// 引数チェック
+	if (ts == NULL)
+	{
+		return;
+	}
+
+	Disconnect(ts->Sock);
+	ReleaseSock(ts->Sock);
+	ReleaseFifo(ts->RecvFifo);
+	ReleaseFifo(ts->SendFifo);
+
+	if (ts->SendKey)
+	{
+		FreeCrypt(ts->SendKey);
+	}
+	if (ts->RecvKey)
+	{
+		FreeCrypt(ts->RecvKey);
+	}
+
+	Free(ts);
+}
+
+// コネクションのトンネリングモードを終了する
+void EndTunnelingMode(CONNECTION *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	// プロトコル
+	if (c->Protocol == CONNECTION_TCP)
+	{
+		// TCP
+		DisconnectTcpSockets(c);
+	}
+	else
+	{
+		// UDP
+		DisconnectUDPSockets(c);
+	}
+}
+
+// コネクションをトンネリングモードに移行させる
+void StartTunnelingMode(CONNECTION *c)
+{
+	SOCK *s;
+	TCP *tcp;
+	TCPSOCK *ts;
+	IP ip;
+	UINT port;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	tcp = c->Tcp;
+
+	// プロトコル
+	if (c->Protocol == CONNECTION_TCP)
+	{
+		// TCP
+		s = c->FirstSock;
+
+		ts = NewTcpSock(s);
+
+		if (c->ServerMode == false)
+		{
+			if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)
+			{
+				ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;
+			}
+		}
+
+		LockList(tcp->TcpSockList);
+		{
+			Add(tcp->TcpSockList, ts);
+		}
+		UnlockList(tcp->TcpSockList);
+		ReleaseSock(s);
+		c->FirstSock = NULL;
+	}
+	else
+	{
+		// UDP
+		s = c->FirstSock;
+		Copy(&ip, &s->RemoteIP, sizeof(IP));
+		// この時点で TCP コネクションは切断してよい
+		c->FirstSock = NULL;
+		Disconnect(s);
+		ReleaseSock(s);
+
+		// UDP 構造体の初期化
+		c->Udp = ZeroMalloc(sizeof(UDP));
+
+		if (c->ServerMode)
+		{
+			// サーバーモード
+			// エントリの追加
+			AddUDPEntry(c->Cedar, c->Session);
+			c->Udp->s = NULL;
+		}
+		else
+		{
+			port = c->Session->ClientOption->PortUDP;
+			// クライアントモード
+			c->Udp->s = NewUDP(0);
+			// IP アドレスとポート番号を書く
+			Copy(&c->Udp->ip, &ip, sizeof(IP));
+			c->Udp->port = port;
+		}
+
+		// キュー
+		c->Udp->BufferQueue = NewQueue();
+	}
+}
+
+// 新しいコネクションを受け付ける関数
+void ConnectionAccept(CONNECTION *c)
+{
+	SOCK *s;
+	X *x;
+	K *k;
+	char tmp[128];
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	Debug("ConnectionAccept()\n");
+
+	// ソケットを取得する
+	s = c->FirstSock;
+	AddRef(s->ref);
+
+	Dec(c->Cedar->AcceptingSockets);
+
+	IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+	SLog(c->Cedar, "LS_CONNECTION_START_1", tmp, s->RemoteHostname, s->RemotePort, c->Name);
+
+	// タイムアウト設定
+	SetTimeout(s, CONNECTING_TIMEOUT);
+
+	// 暗号化アルゴリズムを指定する
+	Lock(c->lock);
+	{
+		if (c->Cedar->CipherList != NULL)
+		{
+			SetWantToUseCipher(s, c->Cedar->CipherList);
+		}
+
+		x = CloneX(c->Cedar->ServerX);
+		k = CloneK(c->Cedar->ServerK);
+	}
+	Unlock(c->lock);
+
+	// SSL 通信を開始する
+	Debug("StartSSL()\n");
+	if (StartSSL(s, x, k) == false)
+	{
+		// 失敗
+		Debug("Failed to StartSSL.\n");
+		FreeX(x);
+		FreeK(k);
+		goto ERROR;
+	}
+
+	FreeX(x);
+	FreeK(k);
+
+	SLog(c->Cedar, "LS_SSL_START", c->Name, s->CipherName);
+
+	// 接続を受諾する
+	if (ServerAccept(c) == false)
+	{
+		// 失敗
+		Debug("ServerAccept Failed. Err = %u\n", c->Err);
+		goto ERROR;
+	}
+
+	if (c->flag1 == false)
+	{
+		Debug("%s %u c->flag1 == false\n", __FILE__, __LINE__);
+		Disconnect(s);
+	}
+	DelConnection(c->Cedar, c);
+	ReleaseSock(s);
+	return;
+
+ERROR:
+	Debug("ConnectionAccept() Error.\n");
+	Disconnect(s);
+	DelConnection(c->Cedar, c);
+	ReleaseSock(s);
+}
+
+// 現在動作しているすべての追加コネクションを張るスレッドを中断する
+void StopAllAdditionalConnectThread(CONNECTION *c)
+{
+	UINT i, num;
+	SOCK **socks;
+	THREAD **threads;
+	// 引数チェック
+	if (c == NULL || c->ServerMode != false)
+	{
+		return;
+	}
+
+	// まずソケットを切断する
+	LockList(c->ConnectingSocks);
+	{
+		num = LIST_NUM(c->ConnectingSocks);
+		socks = ToArray(c->ConnectingSocks);
+		DeleteAll(c->ConnectingSocks);
+	}
+	UnlockList(c->ConnectingSocks);
+	for (i = 0;i < num;i++)
+	{
+		Disconnect(socks[i]);
+		ReleaseSock(socks[i]);
+	}
+	Free(socks);
+
+	// 次にスレッドの停止を待つ
+	LockList(c->ConnectingThreads);
+	{
+		num = LIST_NUM(c->ConnectingThreads);
+		Debug("c->ConnectingThreads: %u\n", num);
+		threads = ToArray(c->ConnectingThreads);
+		DeleteAll(c->ConnectingThreads);
+	}
+	UnlockList(c->ConnectingThreads);
+	for (i = 0;i < num;i++)
+	{
+		WaitThread(threads[i], INFINITE);
+		ReleaseThread(threads[i]);
+	}
+	Free(threads);
+}
+
+// コネクションの停止
+void StopConnection(CONNECTION *c, bool no_wait)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	Debug("Stop Connection: %s\n", c->Name);
+
+	// 停止フラグ
+	c->Halt = true;
+	Disconnect(c->FirstSock);
+
+	if (no_wait == false)
+	{
+		// スレッド停止まで待機
+		WaitThread(c->Thread, INFINITE);
+	}
+}
+
+// UDP ソケットをすべて閉じる
+void DisconnectUDPSockets(CONNECTION *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+	if (c->Protocol != CONNECTION_UDP)
+	{
+		return;
+	}
+
+	// エントリの削除
+	if (c->ServerMode)
+	{
+		DelUDPEntry(c->Cedar, c->Session);
+	}
+
+	// UDP 構造体の削除
+	if (c->Udp != NULL)
+	{
+		if (c->Udp->s != NULL)
+		{
+			ReleaseSock(c->Udp->s);
+		}
+		if (c->Udp->BufferQueue != NULL)
+		{
+			// キューの解放
+			BUF *b;
+			while (b = GetNext(c->Udp->BufferQueue))
+			{
+				FreeBuf(b);
+			}
+			ReleaseQueue(c->Udp->BufferQueue);
+		}
+		Free(c->Udp);
+		c->Udp = NULL;
+	}
+
+	if (c->FirstSock != NULL)
+	{
+		Disconnect(c->FirstSock);
+		ReleaseSock(c->FirstSock);
+		c->FirstSock = NULL;
+	}
+}
+
+// TCP コネクションをすべて閉じる
+void DisconnectTcpSockets(CONNECTION *c)
+{
+	UINT i, num;
+	TCP *tcp;
+	TCPSOCK **tcpsocks;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+	if (c->Protocol != CONNECTION_TCP)
+	{
+		return;
+	}
+
+	tcp = c->Tcp;
+	LockList(tcp->TcpSockList);
+	{
+		tcpsocks = ToArray(tcp->TcpSockList);
+		num = LIST_NUM(tcp->TcpSockList);
+		DeleteAll(tcp->TcpSockList);
+	}
+	UnlockList(tcp->TcpSockList);
+
+	if (num != 0)
+	{
+		Debug("--- SOCKET STATUS ---\n");
+		for (i = 0;i < num;i++)
+		{
+			TCPSOCK *ts = tcpsocks[i];
+			Debug(" SOCK %2u: %u\n", i, ts->Sock->SendSize);
+			FreeTcpSock(ts);
+		}
+	}
+
+	Free(tcpsocks);
+}
+
+// コネクションのクリーンアップ
+void CleanupConnection(CONNECTION *c)
+{
+	UINT i, num;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	DeleteLock(c->lock);
+	ReleaseCedar(c->Cedar);
+
+	switch (c->Protocol)
+	{
+	case CONNECTION_TCP:
+		// TCP コネクションリストの解放
+		DisconnectTcpSockets(c);
+		break;
+
+	case CONNECTION_UDP:
+		break;
+	}
+
+	ReleaseList(c->Tcp->TcpSockList);
+	Free(c->Tcp);
+
+	ReleaseSock(c->FirstSock);
+	c->FirstSock = NULL;
+
+	ReleaseThread(c->Thread);
+	Free(c->Name);
+
+	// すべての送信ブロックと受信ブロックを解放
+	if (c->SendBlocks)
+	{
+		LockQueue(c->SendBlocks);
+		{
+			BLOCK *b;
+			while (b = GetNext(c->SendBlocks))
+			{
+				FreeBlock(b);
+			}
+		}
+		UnlockQueue(c->SendBlocks);
+	}
+	if (c->SendBlocks2)
+	{
+		LockQueue(c->SendBlocks2);
+		{
+			BLOCK *b;
+			while (b = GetNext(c->SendBlocks2))
+			{
+				FreeBlock(b);
+			}
+		}
+		UnlockQueue(c->SendBlocks2);
+	}
+	if (c->ReceivedBlocks)
+	{
+		LockQueue(c->ReceivedBlocks);
+		{
+			BLOCK *b;
+			while (b = GetNext(c->ReceivedBlocks))
+			{
+				FreeBlock(b);
+			}
+		}
+		UnlockQueue(c->ReceivedBlocks);
+	}
+
+	if (c->ConnectingThreads)
+	{
+		THREAD **threads;
+		LockList(c->ConnectingThreads);
+		{
+			num = LIST_NUM(c->ConnectingThreads);
+			threads = ToArray(c->ConnectingThreads);
+			for (i = 0;i < num;i++)
+			{
+				ReleaseThread(threads[i]);
+			}
+			Free(threads);
+		}
+		UnlockList(c->ConnectingThreads);
+		ReleaseList(c->ConnectingThreads);
+	}
+
+	if (c->ConnectingSocks)
+	{
+		SOCK **socks;
+		LockList(c->ConnectingSocks);
+		{
+			num = LIST_NUM(c->ConnectingSocks);
+			socks = ToArray(c->ConnectingSocks);
+			for (i = 0;i < num;i++)
+			{
+				Disconnect(socks[i]);
+				ReleaseSock(socks[i]);
+			}
+			Free(socks);
+		}
+		UnlockList(c->ConnectingSocks);
+		ReleaseList(c->ConnectingSocks);
+	}
+
+	if (c->RecvBuf)
+	{
+		Free(c->RecvBuf);
+	}
+
+	if (c->ServerX != NULL)
+	{
+		FreeX(c->ServerX);
+	}
+
+	if (c->ClientX != NULL)
+	{
+		FreeX(c->ClientX);
+	}
+
+	ReleaseQueue(c->ReceivedBlocks);
+	ReleaseQueue(c->SendBlocks);
+	ReleaseQueue(c->SendBlocks2);
+
+	DeleteCounter(c->CurrentNumConnection);
+
+	if (c->CipherName != NULL)
+	{
+		Free(c->CipherName);
+	}
+
+	Free(c);
+}
+
+// コネクションの解放
+void ReleaseConnection(CONNECTION *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	if (Release(c->ref) == 0)
+	{
+		CleanupConnection(c);
+	}
+}
+
+// コネクションの比較
+int CompareConnection(void *p1, void *p2)
+{
+	CONNECTION *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(CONNECTION **)p1;
+	c2 = *(CONNECTION **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(c1->Name, c2->Name);
+}
+
+// サーバーコネクションの作成
+CONNECTION *NewServerConnection(CEDAR *cedar, SOCK *s, THREAD *t)
+{
+	CONNECTION *c;
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return NULL;
+	}
+
+	c = ZeroMalloc(sizeof(CONNECTION));
+	c->ConnectedTick = Tick64();
+	c->lock = NewLock();
+	c->ref = NewRef();
+	c->Cedar = cedar;
+	AddRef(c->Cedar->ref);
+	c->Protocol = CONNECTION_TCP;
+	c->Type = CONNECTION_TYPE_INIT;
+	c->FirstSock = s;
+	if (s != NULL)
+	{
+		AddRef(c->FirstSock->ref);
+		Copy(&c->ClientIp, &s->RemoteIP, sizeof(IP));
+		StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname);
+	}
+	c->Tcp = ZeroMalloc(sizeof(TCP));
+	c->Tcp->TcpSockList = NewList(NULL);
+	c->ServerMode = true;
+	c->Status = CONNECTION_STATUS_ACCEPTED;
+	c->Name = CopyStr("INITING");
+	c->Thread = t;
+	AddRef(t->ref);
+	c->CurrentNumConnection = NewCounter();
+	Inc(c->CurrentNumConnection);
+
+	c->ServerVer = cedar->Version;
+	c->ServerBuild = cedar->Build;
+	StrCpy(c->ServerStr, sizeof(c->ServerStr), cedar->ServerStr);
+	GetServerProductName(cedar->Server, c->ServerStr, sizeof(c->ServerStr));
+
+	if (s != NULL && s->RemoteX != NULL)
+	{
+		c->ServerX = CloneX(s->RemoteX);
+	}
+
+	// キューの作成
+	c->ReceivedBlocks = NewQueue();
+	c->SendBlocks = NewQueue();
+	c->SendBlocks2 = NewQueue();
+
+	return c;
+}
+
+// クライアントコネクションの作成
+CONNECTION *NewClientConnection(SESSION *s)
+{
+	return NewClientConnectionEx(s, NULL, 0, 0);
+}
+CONNECTION *NewClientConnectionEx(SESSION *s, char *client_str, UINT client_ver, UINT client_build)
+{
+	CONNECTION *c;
+
+	// CONNECTION オブジェクトの初期化
+	c = ZeroMalloc(sizeof(CONNECTION));
+	c->ConnectedTick = Tick64();
+	c->lock = NewLock();
+	c->ref = NewRef();
+	c->Cedar = s->Cedar;
+	AddRef(c->Cedar->ref);
+	if (s->ClientOption->PortUDP == 0)
+	{
+		// TCP
+		c->Protocol = CONNECTION_TCP;
+		c->Tcp = ZeroMalloc(sizeof(TCP));
+		c->Tcp->TcpSockList = NewList(NULL);
+	}
+	else
+	{
+		// UDP
+		c->Protocol = CONNECTION_UDP;
+	}
+	c->ServerMode = false;
+	c->Status = CONNECTION_STATUS_CONNECTING;
+	c->Name = CopyStr("CLIENT_CONNECTION");
+	c->Session = s;
+	c->CurrentNumConnection = NewCounter();
+	Inc(c->CurrentNumConnection);
+
+	c->ConnectingThreads = NewList(NULL);
+	c->ConnectingSocks = NewList(NULL);
+
+	if (client_str == NULL)
+	{
+		c->ClientVer = s->Cedar->Version;
+		c->ClientBuild = s->Cedar->Build;
+
+		if (c->Session->VirtualHost == false)
+		{
+			if (c->Session->LinkModeClient == false)
+			{
+				StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_CLIENT_STR);
+			}
+			else
+			{
+				StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_SERVER_LINK_STR);
+			}
+		}
+		else
+		{
+			StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_ROUTER_STR);
+		}
+	}
+	else
+	{
+		c->ClientVer = client_ver;
+		c->ClientBuild = client_build;
+		StrCpy(c->ClientStr, sizeof(c->ClientStr), client_str);
+	}
+
+	// サーバー名とポート番号
+	StrCpy(c->ServerName, sizeof(c->ServerName), s->ClientOption->Hostname);
+	c->ServerPort = s->ClientOption->Port;
+
+	// TLS 1.0 使用フラグ
+	c->DontUseTls1 = s->ClientOption->NoTls1;
+
+	// キューの作成
+	c->ReceivedBlocks = NewQueue();
+	c->SendBlocks = NewQueue();
+	c->SendBlocks2 = NewQueue();
+
+	return c;
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Connection.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Connection.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Connection.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,317 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Connection.h
+// Connection.c のヘッダ
+
+#ifndef	CONNECTION_H
+#define	CONNECTION_H
+
+#define	KEEP_ALIVE_STRING				"Internet Connection Keep Alive Packet"
+
+// KEEP CONNECT 構造体
+struct KEEP
+{
+	LOCK *lock;										// ロック
+	bool Server;									// サーバーモード
+	volatile bool Halt;								// 停止フラグ
+	bool Enable;									// 有効フラグ
+	char ServerName[MAX_HOST_NAME_LEN + 1];			// サーバー名
+	UINT ServerPort;								// サーバーポート番号
+	bool UdpMode;									// UDP モード
+	UINT Interval;									// パケット送出間隔
+	THREAD *Thread;									// 接続スレッド
+	EVENT *HaltEvent;								// 停止イベント
+	CANCEL *Cancel;									// キャンセル
+};
+
+// 構造体
+struct SECURE_SIGN
+{
+	char SecurePublicCertName[MAX_SECURE_DEVICE_FILE_LEN + 1];	// セキュアデバイス証明書名
+	char SecurePrivateKeyName[MAX_SECURE_DEVICE_FILE_LEN + 1];	// セキュアデバイス秘密鍵名
+	X *ClientCert;					// クライアント証明書
+	UCHAR Random[SHA1_SIZE];		// 署名元乱数値
+	UCHAR Signature[128];			// 署名済データ
+	UINT UseSecureDeviceId;
+	UINT BitmapId;					// ビットマップ ID
+};
+
+// 関数型宣言
+typedef bool (CHECK_CERT_PROC)(SESSION *s, CONNECTION *c, X *server_x, bool *expired);
+typedef bool (SECURE_SIGN_PROC)(SESSION *s, CONNECTION *c, SECURE_SIGN *sign);
+
+// RC4 鍵ペア
+struct RC4_KEY_PAIR
+{
+	UCHAR ServerToClientKey[16];
+	UCHAR ClientToServerKey[16];
+};
+
+// クライアントオプション
+struct CLIENT_OPTION
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// 接続設定名
+	char Hostname[MAX_HOST_NAME_LEN + 1];			// ホスト名
+	UINT Port;										// ポート番号
+	UINT PortUDP;									// UDP ポート番号 (0…TCPのみ使用)
+	UINT ProxyType;									// プロキシの種類
+	char ProxyName[MAX_HOST_NAME_LEN + 1];			// プロキシサーバー名
+	UINT ProxyPort;									// プロキシサーバーのポート番号
+	char ProxyUsername[MAX_PROXY_USERNAME_LEN + 1];	// 最大ユーザー名長
+	char ProxyPassword[MAX_PROXY_PASSWORD_LEN + 1];	// 最大パスワード長
+	UINT NumRetry;									// 自動リトライ回数
+	UINT RetryInterval;								// リトライ間隔
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT MaxConnection;								// 最大同時接続 TCP コネクション数
+	bool UseEncrypt;								// 暗号化通信を使用
+	bool UseCompress;								// データ圧縮を使用
+	bool HalfConnection;							// TCP でハーフコネクションを利用する
+	bool NoRoutingTracking;							// ルーティング追跡を無効にする
+	char DeviceName[MAX_DEVICE_NAME_LEN + 1];		// VLAN デバイス名
+	UINT AdditionalConnectionInterval;				// 追加コネクション確立時の接続試行間隔
+	UINT ConnectionDisconnectSpan;					// コネクション切断間隔
+	bool HideStatusWindow;							// 状況ウインドウを非表示にする
+	bool HideNicInfoWindow;							// NIC 状態ウインドウを非表示にする
+	bool RequireMonitorMode;						// モニタポートモード
+	bool RequireBridgeRoutingMode;					// ブリッジまたはルーティングモード
+	bool DisableQoS;								// VoIP / QoS 機能を無効化する
+	bool FromAdminPack;								// Administration Pack 用
+	bool NoTls1;									// TLS 1.0 を使用しない
+};
+
+// クライアント認証データ
+struct CLIENT_AUTH
+{
+	UINT AuthType;									// 認証の種類
+	char Username[MAX_USERNAME_LEN + 1];			// ユーザー名
+	UCHAR HashedPassword[SHA1_SIZE];				// ハッシュされたパスワード
+	char PlainPassword[MAX_PASSWORD_LEN + 1];		// パスワード
+	X *ClientX;										// クライアント証明書
+	K *ClientK;										// クライアント秘密鍵
+	char SecurePublicCertName[MAX_SECURE_DEVICE_FILE_LEN + 1];	// セキュアデバイス証明書名
+	char SecurePrivateKeyName[MAX_SECURE_DEVICE_FILE_LEN + 1];	// セキュアデバイス秘密鍵名
+	CHECK_CERT_PROC *CheckCertProc;					// サーバー証明書確認用プロシージャ
+	SECURE_SIGN_PROC *SecureSignProc;				// セキュリティ署名用プロシージャ
+};
+
+// TCP ソケットデータ構造体
+struct TCPSOCK
+{
+	SOCK *Sock;						// ソケット
+	FIFO *RecvFifo;					// 受信バッファ
+	FIFO *SendFifo;					// 送信バッファ
+	UINT Mode;						// 読み取りモード
+	UINT WantSize;					// 要求しているデータサイズ
+	UINT NextBlockNum;				// 次に読み取れるブロック数の合計
+	UINT NextBlockSize;				// 次に読み取る予定のブロックサイズ
+	UINT CurrentPacketNum;			// 現在のパケット番号
+	UINT64 LastCommTime;			// 最後に通信を行った時刻
+	UINT LateCount;					// 遅延回数
+	UINT Direction;					// 方向
+	UINT64 NextKeepAliveTime;		// 次に KeepAlive パケットを送信する時刻
+	RC4_KEY_PAIR Rc4KeyPair;		// RC4 キーペア
+	CRYPT *SendKey;					// 送信鍵
+	CRYPT *RecvKey;					// 受信鍵
+	UINT64 DisconnectTick;			// このコネクションを切断する予定の時刻
+};
+
+// TCP 通信データ構造体
+struct TCP
+{
+	LIST *TcpSockList;				// TCP ソケットリスト
+};
+
+// UDP 通信データ構造体
+struct UDP
+{
+	SOCK *s;						// UDP ソケット (送信用)
+	IP ip;							// 送信先 IP アドレス
+	UINT port;						// 送信先ポート番号
+	UINT64 NextKeepAliveTime;		// 次に KeepAlive パケットを送信する時刻
+	UINT64 Seq;						// パケットシーケンス番号
+	UINT64 RecvSeq;
+	QUEUE *BufferQueue;				// 送信予定バッファのキュー
+};
+
+// データブロック
+struct BLOCK
+{
+	BOOL Compressed;				// 圧縮フラグ
+	UINT Size;						// ブロックサイズ
+	UINT SizeofData;				// データサイズ
+	UCHAR *Buf;						// バッファ
+	bool PriorityQoS;				// VoIP / QoS 機能用優先パケット
+};
+
+// コネクション構造体
+struct CONNECTION
+{
+	LOCK *lock;						// ロック
+	REF *ref;						// 参照カウンタ
+	CEDAR *Cedar;					// Cedar
+	struct SESSION *Session;		// セッション
+	UINT Protocol;					// プロトコル
+	SOCK *FirstSock;				// ネゴシエーション用のソケット
+	TCP *Tcp;						// TCP 通信データ構造体
+	UDP *Udp;						// UDP 通信データ構造体
+	bool ServerMode;				// サーバーモード
+	UINT Status;					// 状態
+	char *Name;						// コネクション名
+	THREAD *Thread;					// スレッド
+	volatile bool Halt;				// 停止フラグ
+	UCHAR Random[SHA1_SIZE];		// 認証用乱数
+	UINT ServerVer;					// サーバーバージョン
+	UINT ServerBuild;				// サーバービルド番号
+	UINT ClientVer;					// クライアントバージョン
+	UINT ClientBuild;				// クライアントビルド番号
+	char ServerStr[MAX_SERVER_STR_LEN + 1];	// サーバー文字列
+	char ClientStr[MAX_CLIENT_STR_LEN + 1];	// クライアント文字列
+	UINT Err;						// エラー値
+	bool ClientConnectError_NoSavePassword;	// 指定されたユーザー名に関してパスワードを保存しない
+	QUEUE *ReceivedBlocks;			// 受信したブロック キュー
+	QUEUE *SendBlocks;				// 送信する予定のブロック キュー
+	QUEUE *SendBlocks2;				// 送信キュー (優先度高)
+	COUNTER *CurrentNumConnection;	// 現在のコネクション数のカウンタ
+	LIST *ConnectingThreads;		// 接続中のスレッドのリスト
+	LIST *ConnectingSocks;			// 接続中のソケットのリスト
+	bool flag1;						// フラグ 1
+	UCHAR *RecvBuf;					// 受信バッファ
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	UINT ServerPort;				// ポート番号
+	bool RestoreServerNameAndPort;	// サーバー名とポート番号を元に戻すフラグ
+	bool UseTicket;					// チケット使用フラグ
+	UCHAR Ticket[SHA1_SIZE];		// チケット
+	UINT CurrentSendQueueSize;		// 送信キューの合計サイズ
+	X *ServerX;						// サーバー証明書
+	X *ClientX;						// クライアント証明書
+	char *CipherName;				// 暗号化アルゴリズム名
+	UINT64 ConnectedTick;			// 接続された時刻
+	IP ClientIp;					// クライアント IP アドレス
+	char ClientHostname[MAX_HOST_NAME_LEN + 1];	// クライアントホスト名
+	UINT Type;						// 種類
+	bool DontUseTls1;				// TLS 1.0 を使用しない
+	void *hWndForUI;				// 親ウインドウ
+};
+
+
+
+// 関数プロトタイプ
+
+CONNECTION *NewClientConnection(SESSION *s);
+CONNECTION *NewClientConnectionEx(SESSION *s, char *client_str, UINT client_ver, UINT client_build);
+CONNECTION *NewServerConnection(CEDAR *cedar, SOCK *s, THREAD *t);
+void ReleaseConnection(CONNECTION *c);
+void CleanupConnection(CONNECTION *c);
+int CompareConnection(void *p1, void *p2);
+void StopConnection(CONNECTION *c, bool no_wait);
+void ConnectionAccept(CONNECTION *c);
+void StartTunnelingMode(CONNECTION *c);
+void EndTunnelingMode(CONNECTION *c);
+void DisconnectTcpSockets(CONNECTION *c);
+void ConnectionReceive(CONNECTION *c, CANCEL *c1, CANCEL *c2);
+void ConnectionSend(CONNECTION *c);
+TCPSOCK *NewTcpSock(SOCK *s);
+void FreeTcpSock(TCPSOCK *ts);
+BLOCK *NewBlock(void *data, UINT size, int compress);
+void FreeBlock(BLOCK *b);
+void StopAllAdditionalConnectThread(CONNECTION *c);
+UINT GenNextKeepAliveSpan(CONNECTION *c);
+void SendKeepAlive(CONNECTION *c, TCPSOCK *ts);
+void DisconnectUDPSockets(CONNECTION *c);
+void PutUDPPacketData(CONNECTION *c, void *data, UINT size);
+void SendDataWithUDP(SOCK *s, CONNECTION *c);
+void InsertReveicedBlockToQueue(CONNECTION *c, BLOCK *block);
+void InitTcpSockRc4Key(TCPSOCK *ts, bool server_mode);
+UINT TcpSockRecv(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+void WriteSendFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a);
+BUF *NewKeepPacket(bool server_mode);
+void KeepThread(THREAD *thread, void *param);
+KEEP *StartKeep();
+void StopKeep(KEEP *k);
+void InRpcSecureSign(SECURE_SIGN *t, PACK *p);
+void OutRpcSecureSign(PACK *p, SECURE_SIGN *t);
+void FreeRpcSecureSign(SECURE_SIGN *t);
+void NormalizeEthMtu(BRIDGE *b, CONNECTION *c, UINT packet_size);
+
+
+
+#endif	// CONNECTION_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Console.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Console.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Console.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2411 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Console.c
+// コンソール サービス
+
+#include "CedarPch.h"
+
+
+// コマンドのヘルプを表示する
+void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list)
+{
+	wchar_t tmp[MAX_SIZE];
+	wchar_t *buf;
+	UINT buf_size;
+	wchar_t *description, *args, *help;
+	UNI_TOKEN_LIST *t;
+	UINT width;
+	UINT i;
+	char *space;
+	// 引数チェック
+	if (c == NULL || cmd_name == NULL || param_list == NULL)
+	{
+		return;
+	}
+
+	width = GetConsoleWidth(c) - 2;
+
+	buf_size = sizeof(wchar_t) * (width + 32);
+	buf = Malloc(buf_size);
+
+	GetCommandHelpStr(cmd_name, &description, &args, &help);
+
+	space = MakeCharArray(' ', 2);
+
+	// タイトル
+	UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_TITLE"), cmd_name);
+	c->Write(c, tmp);
+	c->Write(c, L"");
+
+	// 目的
+	c->Write(c, _UU("CMD_HELP_DESCRIPTION"));
+	t = SeparateStringByWidth(description, width - 2);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+		c->Write(c, buf);
+	}
+	UniFreeToken(t);
+	c->Write(c, L"");
+
+	// 説明
+	c->Write(c, _UU("CMD_HELP_HELP"));
+	t = SeparateStringByWidth(help, width - 2);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+		c->Write(c, buf);
+	}
+	UniFreeToken(t);
+	c->Write(c, L"");
+
+	// 使用方法
+	c->Write(c, _UU("CMD_HELP_USAGE"));
+	t = SeparateStringByWidth(args, width - 2);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+		c->Write(c, buf);
+	}
+	UniFreeToken(t);
+
+	// 引数
+	if (param_list->NumTokens >= 1)
+	{
+		c->Write(c, L"");
+		c->Write(c, _UU("CMD_HELP_ARGS"));
+		PrintCandidateHelp(c, cmd_name, param_list, 2);
+	}
+
+	Free(space);
+
+	Free(buf);
+}
+
+// SafeStr であるかどうかの評価
+bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param)
+{
+	wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_SAFE") : (wchar_t *)param;
+
+	if (IsSafeUniStr(str))
+	{
+		return true;
+	}
+
+	c->Write(c, p);
+
+	return false;
+}
+
+// 文字列入力プロンプト
+wchar_t *CmdPrompt(CONSOLE *c, void *param)
+{
+	wchar_t *p = (param == NULL) ? _UU("CMD_PROMPT") : (wchar_t *)param;
+
+	return c->ReadLine(c, p, true);
+}
+
+// 指定されたファイルが存在するかどうか評価
+bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param)
+{
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	if (IsEmptyStr(tmp))
+	{
+		c->Write(c, _UU("CMD_FILE_NAME_EMPTY"));
+		return false;
+	}
+
+	if (IsFileExists(tmp) == false)
+	{
+		wchar_t tmp2[MAX_SIZE];
+
+		UniFormat(tmp2, sizeof(tmp2), _UU("CMD_FILE_NOT_FOUND"), tmp);
+		c->Write(c, tmp2);
+
+		return false;
+	}
+
+	return true;
+}
+
+// 整数の評価
+bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param)
+{
+	wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_INT") : (wchar_t *)param;
+
+	if (UniToInt(str) == 0)
+	{
+		c->Write(c, p);
+
+		return false;
+	}
+
+	return true;
+}
+
+// 空白を指定できないパラメータの評価
+bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param)
+{
+	wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_NOT_EMPTY") : (wchar_t *)param;
+
+	if (UniIsEmptyStr(str) == false)
+	{
+		return true;
+	}
+
+	c->Write(c, p);
+
+	return false;
+}
+
+// パラメータの最小 / 最大値評価関数
+bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param)
+{
+	CMD_EVAL_MIN_MAX *e;
+	wchar_t *tag;
+	UINT v;
+	// 引数チェック
+	if (param == NULL)
+	{
+		return false;
+	}
+
+	e = (CMD_EVAL_MIN_MAX *)param;
+
+	if (e->StrName == NULL)
+	{
+		tag = _UU("CMD_EVAL_MIN_MAX");
+	}
+	else
+	{
+		tag = _UU(e->StrName);
+	}
+
+	v = UniToInt(str);
+
+	if (v >= e->MinValue && v <= e->MaxValue)
+	{
+		return true;
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+
+		UniFormat(tmp, sizeof(tmp), tag, e->MinValue, e->MaxValue);
+		c->Write(c, tmp);
+
+		return false;
+	}
+}
+
+// コマンドのヘルプ文字列を取得する
+void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help)
+{
+	char tmp1[128], tmp2[128], tmp3[128];
+
+	Format(tmp1, sizeof(tmp1), "CMD_%s", command_name);
+	Format(tmp2, sizeof(tmp2), "CMD_%s_ARGS", command_name);
+	Format(tmp3, sizeof(tmp3), "CMD_%s_HELP", command_name);
+
+	if (description != NULL)
+	{
+		*description = _UU(tmp1);
+		if (UniIsEmptyStr(*description))
+		{
+			*description = _UU("CMD_UNKNOWM");
+		}
+	}
+
+	if (args != NULL)
+	{
+		*args = _UU(tmp2);
+		if (UniIsEmptyStr(*args))
+		{
+			*args = _UU("CMD_UNKNOWN_ARGS");
+		}
+	}
+
+	if (help != NULL)
+	{
+		*help = _UU(tmp3);
+		if (UniIsEmptyStr(*help))
+		{
+			*help = _UU("CMD_UNKNOWN_HELP");
+		}
+	}
+}
+
+// パラメータのヘルプ文字列を取得する
+void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description)
+{
+	char tmp[160];
+	if (description == NULL)
+	{
+		return;
+	}
+
+	Format(tmp, sizeof(tmp), "CMD_%s_%s", command_name, param_name);
+
+	*description = _UU(tmp);
+
+	if (UniIsEmptyStr(*description))
+	{
+		*description = _UU("CMD_UNKNOWN_PARAM");
+	}
+}
+
+// 文字列比較関数
+int CompareCandidateStr(void *p1, void *p2)
+{
+	char *s1, *s2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(char **)p1;
+	s2 = *(char **)p2;
+	if (s1 == NULL || s2 == NULL)
+	{
+		return 0;
+	}
+
+	if (s1[0] == '[' && s2[0] != '[')
+	{
+		return -1;
+	}
+	else if (s2[0] == '[' && s1[0] != '[')
+	{
+		return 1;
+	}
+
+	return StrCmp(s1, s2);
+}
+
+// 候補一覧のヘルプを表示する
+void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space)
+{
+	UINT console_width;
+	UINT max_keyword_width;
+	LIST *o;
+	UINT i;
+	wchar_t *tmpbuf;
+	UINT tmpbuf_size;
+	char *left_space_array;
+	char *max_space_array;
+	// 引数チェック
+	if (c == NULL || candidate_list == NULL)
+	{
+		return;
+	}
+
+	// 画面の横幅の取得
+	console_width = GetConsoleWidth(c) - 1;
+
+	tmpbuf_size = sizeof(wchar_t) * (console_width + 32);
+	tmpbuf = Malloc(tmpbuf_size);
+
+	left_space_array = MakeCharArray(' ', left_space);
+
+	// コマンド名はソートしてリスト化する
+	// パラメータ名はソートしない
+	o = NewListFast(cmd_name == NULL ? CompareCandidateStr : NULL);
+
+	max_keyword_width = 0;
+
+	for (i = 0;i < candidate_list->NumTokens;i++)
+	{
+		UINT keyword_width;
+
+		// 各キーワードの横幅を取得する
+		Insert(o, candidate_list->Token[i]);
+
+		keyword_width = StrWidth(candidate_list->Token[i]);
+		if (cmd_name != NULL)
+		{
+			if (candidate_list->Token[i][0] != '[')
+			{
+				keyword_width += 1;
+			}
+			else
+			{
+				keyword_width -= 2;
+			}
+		}
+
+		max_keyword_width = MAX(max_keyword_width, keyword_width);
+	}
+
+	max_space_array = MakeCharArray(' ', max_keyword_width);
+
+	// 候補を表示する
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		char tmp[128];
+		char *name = LIST_DATA(o, i);
+		UNI_TOKEN_LIST *t;
+		wchar_t *help;
+		UINT j;
+		UINT keyword_start_width = left_space;
+		UINT descript_start_width = left_space + max_keyword_width + 1;
+		UINT descript_width;
+		char *space;
+
+		if (console_width >= (descript_start_width + 5))
+		{
+			descript_width = console_width - descript_start_width - 3;
+		}
+		else
+		{
+			descript_width = 2;
+		}
+
+		// 名前を生成する
+		if (cmd_name != NULL && name[0] != '[')
+		{
+			// パラメータの場合は先頭に "/" を付ける
+			Format(tmp, sizeof(tmp), "/%s", name);
+		}
+		else
+		{
+			// コマンド名の場合はそのままの文字を使用する
+			if (cmd_name == NULL)
+			{
+				StrCpy(tmp, sizeof(tmp), name);
+			}
+			else
+			{
+				StrCpy(tmp, sizeof(tmp), name + 1);
+				if (StrLen(tmp) >= 1)
+				{
+					tmp[StrLen(tmp) - 1] = 0;
+				}
+			}
+		}
+
+		// ヘルプ文字を取得する
+		if (cmd_name == NULL)
+		{
+			GetCommandHelpStr(name, &help, NULL, NULL);
+		}
+		else
+		{
+			GetCommandParamHelpStr(cmd_name, name, &help);
+		}
+
+		space = MakeCharArray(' ', max_keyword_width - StrWidth(name) - (cmd_name == NULL ? 0 : (name[0] != '[' ? 1 : -2)));
+
+		t = SeparateStringByWidth(help, descript_width);
+
+		for (j = 0;j < t->NumTokens;j++)
+		{
+			if (j == 0)
+			{
+				UniFormat(tmpbuf, tmpbuf_size, L"%S%S%S - %s",
+					left_space_array, tmp, space, t->Token[j]);
+			}
+			else
+			{
+				UniFormat(tmpbuf, tmpbuf_size, L"%S%S   %s",
+					left_space_array, max_space_array, t->Token[j]);
+			}
+
+			c->Write(c, tmpbuf);
+		}
+
+		Free(space);
+
+		UniFreeToken(t);
+	}
+
+	ReleaseList(o);
+
+	Free(max_space_array);
+	Free(tmpbuf);
+	Free(left_space_array);
+}
+
+// 文字列を指定された横幅で分割する
+UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width)
+{
+	UINT wp;
+	wchar_t *tmp;
+	UINT len, i;
+	LIST *o;
+	UNI_TOKEN_LIST *ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return UniNullToken();
+	}
+	if (width == 0)
+	{
+		width = 1;
+	}
+
+	o = NewListFast(NULL);
+
+	len = UniStrLen(str);
+	tmp = ZeroMalloc(sizeof(wchar_t) * (len + 32));
+	wp = 0;
+
+	for (i = 0;i < (len + 1);i++)
+	{
+		wchar_t c = str[i];
+
+		switch (c)
+		{
+		case 0:
+		case L'\r':
+		case L'\n':
+			if (c == L'\r')
+			{
+				if (str[i + 1] == L'\n')
+				{
+					i++;
+				}
+			}
+
+			tmp[wp++] = 0;
+			wp = 0;
+
+			Insert(o, UniCopyStr(tmp));
+			break;
+
+		default:
+			tmp[wp++] = c;
+			tmp[wp] = 0;
+			if (UniStrWidth(tmp) >= width)
+			{
+				tmp[wp++] = 0;
+				wp = 0;
+
+				Insert(o, UniCopyStr(tmp));
+			}
+			break;
+		}
+	}
+
+	if (LIST_NUM(o) == 0)
+	{
+		Insert(o, CopyUniStr(L""));
+	}
+
+	ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+	ret->NumTokens = LIST_NUM(o);
+	ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t *s = LIST_DATA(o, i);
+
+		ret->Token[i] = s;
+	}
+
+	ReleaseList(o);
+	Free(tmp);
+
+	return ret;
+}
+
+// 指定した文字列が help を示すかどうかをチェック
+bool IsHelpStr(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	if (StrCmpi(str, "help") == 0 || StrCmpi(str, "?") == 0 ||
+		StrCmpi(str, "man") == 0 || StrCmpi(str, "/man") == 0 ||
+		StrCmpi(str, "-man") == 0 || StrCmpi(str, "--man") == 0 ||
+		StrCmpi(str, "/help") == 0 || StrCmpi(str, "/?") == 0 ||
+		StrCmpi(str, "-help") == 0 || StrCmpi(str, "-?") == 0 ||
+		StrCmpi(str, "/h") == 0 || StrCmpi(str, "--help") == 0 ||
+		StrCmpi(str, "--?") == 0)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// コマンドの実行
+bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param)
+{
+	return DispatchNextCmdEx(c, NULL, prompt, cmd, num_cmd, param);
+}
+bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param)
+{
+	wchar_t *str;
+	wchar_t *tmp;
+	char *cmd_name;
+	bool b_exit = false;
+	wchar_t *cmd_param;
+	UINT ret = ERR_NO_ERROR;
+	TOKEN_LIST *t;
+	TOKEN_LIST *candidate;
+	bool no_end_crlf = false;
+	UINT i;
+	// 引数チェック
+	if (c == NULL || (num_cmd >= 1 && cmd == NULL))
+	{
+		return false;
+	}
+
+	if (exec_command == NULL)
+	{
+		// プロンプトを表示
+RETRY:
+		tmp = CopyStrToUni(prompt);
+		str = c->ReadLine(c, tmp, false);
+		Free(tmp);
+
+		if (str != NULL && IsEmptyUniStr(str))
+		{
+			Free(str);
+			goto RETRY;
+		}
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		// exec_command を使用
+		if (UniStartWith(exec_command, L"utvpncmd") == false)
+		{
+			if (prompt != NULL)
+			{
+				if (c->ConsoleType != CONSOLE_CSV)
+				{
+					UniFormat(tmp, sizeof(tmp), L"%S%s", prompt, exec_command);
+					c->Write(c, tmp);
+				}
+			}
+		}
+		str = CopyUniStr(exec_command);
+	}
+
+	if (str == NULL)
+	{
+		// ユーザーキャンセル
+		return false;
+	}
+
+	UniTrimCrlf(str);
+	UniTrim(str);
+
+	if (UniIsEmptyStr(str))
+	{
+		// 何もしない
+		Free(str);
+		return true;
+	}
+
+	// コマンド名とパラメータに分ける
+	if (SeparateCommandAndParam(str, &cmd_name, &cmd_param) == false)
+	{
+		// 何もしない
+		Free(str);
+		return true;
+	}
+
+	if (StrLen(cmd_name) >= 2 && cmd_name[0] == '?' && cmd_name[1] != '?')
+	{
+		char tmp[MAX_SIZE];
+		wchar_t *s;
+
+		StrCpy(tmp, sizeof(tmp), cmd_name + 1);
+		StrCpy(cmd_name, 0, tmp);
+
+		s = UniCopyStr(L"/?");
+		Free(cmd_param);
+
+		cmd_param = s;
+	}
+
+	if (StrLen(cmd_name) >= 2 && EndWith(cmd_name, "?") && cmd_name[StrLen(cmd_name) - 2] != '?')
+	{
+		wchar_t *s;
+
+		cmd_name[StrLen(cmd_name) - 1] = 0;
+
+		s = UniCopyStr(L"/?");
+		Free(cmd_param);
+
+		cmd_param = s;
+	}
+
+	// コマンドの候補を取得する
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = num_cmd;
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		t->Token[i] = CopyStr(cmd[i].Name);
+	}
+
+	if (IsHelpStr(cmd_name))
+	{
+		if (UniIsEmptyStr(cmd_param))
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			// 使用できるコマンド一覧を表示する
+			UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_1"), t->NumTokens);
+			c->Write(c, tmp);
+
+			PrintCandidateHelp(c, NULL, t, 1);
+
+			c->Write(c, L"");
+			c->Write(c, _UU("CMD_HELP_2"));
+		}
+		else
+		{
+			char *cmd_name;
+
+			// 指定したコマンドのヘルプを表示する
+			if (SeparateCommandAndParam(cmd_param, &cmd_name, NULL))
+			{
+				bool b = true;
+
+				if (IsHelpStr(cmd_name))
+				{
+					b = false;
+				}
+
+				if (b)
+				{
+					wchar_t str[MAX_SIZE];
+
+					UniFormat(str, sizeof(str), L"%S /help", cmd_name);
+					DispatchNextCmdEx(c, str, NULL, cmd, num_cmd, param);
+					no_end_crlf = true;
+				}
+
+				Free(cmd_name);
+			}
+		}
+	}
+	else if (StrCmpi(cmd_name, "exit") == 0 || StrCmpi(cmd_name, "quit") == 0)
+	{
+		// 終了
+		b_exit = true;
+	}
+	else
+	{
+		candidate = GetRealnameCandidate(cmd_name, t);
+
+		if (candidate == NULL || candidate->NumTokens == 0)
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			// 候補無し
+			UniFormat(tmp, sizeof(tmp), _UU("CON_UNKNOWN_CMD"), cmd_name);
+			c->Write(c, tmp);
+
+			c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
+		}
+		else if (candidate->NumTokens >= 2)
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			// 候補が複数ある
+			UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_CMD"), cmd_name);
+			c->Write(c, tmp);
+			c->Write(c, _UU("CON_AMBIGIOUS_CMD_1"));
+			PrintCandidateHelp(c, NULL, candidate, 1);
+			c->Write(c, _UU("CON_AMBIGIOUS_CMD_2"));
+
+			c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
+		}
+		else
+		{
+			char *real_cmd_name;
+			UINT i;
+
+			// 1 つに定まった
+			real_cmd_name = candidate->Token[0];
+
+			for (i = 0;i < num_cmd;i++)
+			{
+				if (StrCmpi(cmd[i].Name, real_cmd_name) == 0)
+				{
+					if (cmd[i].Proc != NULL)
+					{
+						// CSV モードでなければコマンドの説明を表示する
+						if(c->ConsoleType != CONSOLE_CSV)
+						{
+							wchar_t tmp[256];
+							wchar_t *note;
+
+							GetCommandHelpStr(cmd[i].Name, &note, NULL, NULL);
+							UniFormat(tmp, sizeof(tmp), _UU("CMD_EXEC_MSG_NAME"), cmd[i].Name, note);
+							c->Write(c, tmp);
+						}
+
+						// コマンドのプロシージャを呼び出す
+						ret = cmd[i].Proc(c, cmd[i].Name, cmd_param, param);
+
+						if (ret == INFINITE)
+						{
+							// 終了コマンド
+							b_exit = true;
+						}
+						else
+						{
+							c->RetCode = ret;
+						}
+					}
+				}
+			}
+		}
+
+		FreeToken(candidate);
+	}
+
+	FreeToken(t);
+	Free(str);
+	Free(cmd_name);
+	Free(cmd_param);
+
+	if (no_end_crlf == false)
+	{
+		//c->Write(c, L"");
+	}
+
+	if (b_exit)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 現在のコンソールの横幅を取得する
+UINT GetConsoleWidth(CONSOLE *c)
+{
+	UINT size;
+
+	size = c->GetWidth(c);
+
+	if (size == 0)
+	{
+		size = 80;
+	}
+
+	if (size < 32)
+	{
+		size = 32;
+	}
+
+	if (size > 65536)
+	{
+		size = 65535;
+	}
+
+	return size;
+}
+
+// コマンドラインをコマンドとパラメータの 2 つに分離する
+bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param)
+{
+	UINT i, len, wp;
+	wchar_t *tmp;
+	wchar_t *src_tmp;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return false;
+	}
+	if (cmd != NULL)
+	{
+		*cmd = NULL;
+	}
+	if (param != NULL)
+	{
+		*param = NULL;
+	}
+
+	src_tmp = UniCopyStr(src);
+	UniTrimCrlf(src_tmp);
+	UniTrim(src_tmp);
+
+	len = UniStrLen(src_tmp);
+	tmp = Malloc(sizeof(wchar_t) * (len + 32));
+	wp = 0;
+
+	for (i = 0;i < (len + 1);i++)
+	{
+		wchar_t c = src_tmp[i];
+
+		switch (c)
+		{
+		case 0:
+		case L' ':
+		case L'\t':
+			tmp[wp] = 0;
+			if (UniIsEmptyStr(tmp))
+			{
+				Free(tmp);
+				Free(src_tmp);
+				return false;
+			}
+			if (cmd != NULL)
+			{
+				*cmd = CopyUniToStr(tmp);
+				Trim(*cmd);
+			}
+			goto ESCAPE;
+
+		default:
+			tmp[wp++] = c;
+			break;
+		}
+	}
+
+ESCAPE:
+	if (param != NULL)
+	{
+		*param = CopyUniStr(&src_tmp[wp]);
+		UniTrim(*param);
+	}
+
+	Free(tmp);
+	Free(src_tmp);
+
+	return true;
+}
+
+// ユーザーが指定したコマンド名の省略形に一致する実在するコマンドの一覧の候補を取得する
+TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list)
+{
+	TOKEN_LIST *ret;
+	LIST *o;
+	UINT i;
+	bool ok = false;
+	// 引数チェック
+	if (input_name == NULL || real_name_list == NULL)
+	{
+		return NullToken();
+	}
+
+	o = NewListFast(NULL);
+
+	for (i = 0;i < real_name_list->NumTokens;i++)
+	{
+		char *name = real_name_list->Token[i];
+
+		// まず最優先で完全一致するものを検索する
+		if (StrCmpi(name, input_name) == 0)
+		{
+			Insert(o, name);
+			ok = true;
+			break;
+		}
+	}
+
+	if (ok == false)
+	{
+		// 完全一致するコマンドが無い場合、省略形コマンドとして一致するかどうかチェックする
+		for (i = 0;i < real_name_list->NumTokens;i++)
+		{
+			char *name = real_name_list->Token[i];
+
+			if (IsOmissionName(input_name, name) || IsNameInRealName(input_name, name))
+			{
+				// 省略形を発見した
+				Insert(o, name);
+				ok = true;
+			}
+		}
+	}
+
+	if (ok)
+	{
+		// 1 つ以上の候補が見つかった
+		ret = ListToTokenList(o);
+	}
+	else
+	{
+		ret = NullToken();
+	}
+
+	ReleaseList(o);
+
+	return ret;
+}
+
+// ユーザーが指定したコマンドが既存のコマンドの省略形かどうかチェックする
+bool IsOmissionName(char *input_name, char *real_name)
+{
+	char oname[128];
+	// 引数チェック
+	if (input_name == NULL || real_name == NULL)
+	{
+		return false;
+	}
+
+	if (IsAllUpperStr(real_name))
+	{
+		// すべて大文字のコマンドは省略形をとらない
+		return false;
+	}
+
+	GetOmissionName(oname, sizeof(oname), real_name);
+
+	if (IsEmptyStr(oname))
+	{
+		return false;
+	}
+
+	if (StartWith(oname, input_name))
+	{
+		// 例: AccountSecureCertSet の oname は ascs だが
+		//     ユーザーが asc と入力した場合は true を返す
+		return true;
+	}
+
+	if (StartWith(input_name, oname))
+	{
+		// 例: AccountConnect と
+		//     AccountCreate の 2 つのコマンドが実在する際、
+		//     ユーザーが "aconnect" と入力すると、
+		//     AccountConnect のみ true になるようにする
+
+		if (EndWith(real_name, &input_name[StrLen(oname)]))
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// 指定したコマンド名の省略名を取得する
+void GetOmissionName(char *dst, UINT size, char *src)
+{
+	UINT i, len;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	StrCpy(dst, size, "");
+	len = StrLen(src);
+
+	for (i = 0;i < len;i++)
+	{
+		char c = src[i];
+
+		if ((c >= '0' && c <= '9') ||
+			(c >= 'A' && c <= 'Z'))
+		{
+			char tmp[2];
+			tmp[0] = c;
+			tmp[1] = 0;
+
+			StrCat(dst, size, tmp);
+		}
+	}
+}
+
+// ユーザーが指定したコマンドが既存のコマンドに一致するかどうかチェックする
+bool IsNameInRealName(char *input_name, char *real_name)
+{
+	// 引数チェック
+	if (input_name == NULL || real_name == NULL)
+	{
+		return false;
+	}
+
+	if (StartWith(real_name, input_name))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// コマンドリストをパースする
+LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param)
+{
+	UINT i;
+	LIST *o;
+	bool ok = true;
+	TOKEN_LIST *param_list;
+	TOKEN_LIST *real_name_list;
+	bool help_mode = false;
+	wchar_t *tmp;
+	// 引数チェック
+	if (c == NULL || command == NULL || (num_param >= 1 && param == NULL) || cmd_name == NULL)
+	{
+		return NULL;
+	}
+
+	// 初期化
+	for (i = 0;i < num_param;i++)
+	{
+		if (IsEmptyStr(param[i].Name) == false)
+		{
+			if (param[i].Name[0] == '[')
+			{
+				param[i].Tmp = "";
+			}
+			else
+			{
+				param[i].Tmp = NULL;
+			}
+		}
+		else
+		{
+			param[i].Tmp = "";
+		}
+	}
+
+	real_name_list = ZeroMalloc(sizeof(TOKEN_LIST));
+	real_name_list->NumTokens = num_param;
+	real_name_list->Token = ZeroMalloc(sizeof(char *) * real_name_list->NumTokens);
+
+	for (i = 0;i < real_name_list->NumTokens;i++)
+	{
+		real_name_list->Token[i] = CopyStr(param[i].Name);
+	}
+
+	// ユーザーが指定したパラメータ名のリストを生成する
+	param_list = GetCommandNameList(command);
+
+	for (i = 0;i < param_list->NumTokens;i++)
+	{
+		char *s = param_list->Token[i];
+
+		if (StrCmpi(s, "help") == 0 || StrCmpi(s, "?") == 0)
+		{
+			help_mode = true;
+			break;
+		}
+	}
+
+	tmp = ParseCommand(command, L"");
+	if (tmp != NULL)
+	{
+		if (UniStrCmpi(tmp, L"?") == 0)
+		{
+			help_mode = true;
+		}
+		Free(tmp);
+	}
+
+	if (help_mode)
+	{
+		// ヘルプを表示
+		PrintCmdHelp(c, cmd_name, real_name_list);
+		FreeToken(param_list);
+		FreeToken(real_name_list);
+		return NULL;
+	}
+
+	for (i = 0;i < param_list->NumTokens;i++)
+	{
+		// ユーザーが指定したすべてのパラメータ名について対応するコマンドを取得する
+		TOKEN_LIST *candidate = GetRealnameCandidate(param_list->Token[i], real_name_list);
+
+		if (candidate != NULL && candidate->NumTokens >= 1)
+		{
+			if (candidate->NumTokens >= 2)
+			{
+				wchar_t tmp[MAX_SIZE];
+
+				// 2 つ以上の候補がある
+				UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM"), param_list->Token[i]);
+				c->Write(c, tmp);
+				UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM_1"), cmd_name);
+				c->Write(c, tmp);
+
+				PrintCandidateHelp(c, cmd_name, candidate, 1);
+
+				c->Write(c, _UU("CON_AMBIGIOUS_PARAM_2"));
+
+				ok = false;
+			}
+			else
+			{
+				UINT j;
+				char *real_name = candidate->Token[0];
+
+				// 候補が 1 つだけしか無い
+				for (j = 0;j < num_param;j++)
+				{
+					if (StrCmpi(param[j].Name, real_name) == 0)
+					{
+						param[j].Tmp = param_list->Token[i];
+					}
+				}
+			}
+		}
+		else
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			// 候補無し
+			UniFormat(tmp, sizeof(tmp), _UU("CON_INVALID_PARAM"), param_list->Token[i], cmd_name, cmd_name);
+			c->Write(c, tmp);
+
+			ok = false;
+		}
+
+		FreeToken(candidate);
+	}
+
+	if (ok == false)
+	{
+		FreeToken(param_list);
+		FreeToken(real_name_list);
+
+		return NULL;
+	}
+
+	// リストの作成
+	o = NewParamValueList();
+
+	// パラメータ一覧に指定された名前のすべてのパラメータを読み込む
+	for (i = 0;i < num_param;i++)
+	{
+		bool prompt_input_value = false;
+		PARAM *p = &param[i];
+
+		if (p->Tmp != NULL || p->PromptProc != NULL)
+		{
+			wchar_t *name = CopyStrToUni(p->Name);
+			wchar_t *tmp;
+			wchar_t *str;
+
+			if (p->Tmp != NULL)
+			{
+				tmp = CopyStrToUni(p->Tmp);
+			}
+			else
+			{
+				tmp = CopyStrToUni(p->Name);
+			}
+
+			str = ParseCommand(command, tmp);
+			Free(tmp);
+			if (str != NULL)
+			{
+				wchar_t *unistr;
+				bool ret;
+EVAL_VALUE:
+				// 読み込みに成功した
+				unistr = str;
+
+				if (p->EvalProc != NULL)
+				{
+					// EvalProc が指定されている場合は値を評価する
+					ret = p->EvalProc(c, unistr, p->EvalProcParam);
+				}
+				else
+				{
+					// EvalProc が指定されていない場合はどのような値でも受け付ける
+					ret = true;
+				}
+
+				if (ret == false)
+				{
+					// 指定した値は不正である
+					if (p->PromptProc == NULL)
+					{
+						// キャンセル
+						ok = false;
+						Free(name);
+						Free(str);
+						break;
+					}
+					else
+					{
+						// もう一度入力させる
+						Free(str);
+						str = NULL;
+						goto SHOW_PROMPT;
+					}
+				}
+				else
+				{
+					PARAM_VALUE *v;
+					// 読み込み完了したのでリストに追加する
+					v = ZeroMalloc(sizeof(PARAM_VALUE));
+					v->Name = CopyStr(p->Name);
+					v->StrValue = CopyUniToStr(str);
+					v->UniStrValue = CopyUniStr(str);
+					v->IntValue = ToInt(v->StrValue);
+					Insert(o, v);
+				}
+			}
+			else
+			{
+				// 読み込みに失敗した。指定されたパラメータが指定されていない
+				if (p->PromptProc != NULL)
+				{
+					wchar_t *tmp;
+SHOW_PROMPT:
+					// 必須パラメータであるのでプロンプトを表示する
+					tmp = p->PromptProc(c, p->PromptProcParam);
+					if (tmp == NULL)
+					{
+						// ユーザーがキャンセルした
+						ok = false;
+						Free(str);
+						Free(name);
+						break;
+					}
+					else
+					{
+						// ユーザーが入力した
+						c->Write(c, L"");
+						str = tmp;
+						prompt_input_value = true;
+						goto EVAL_VALUE;
+					}
+				}
+			}
+
+			Free(str);
+			Free(name);
+		}
+	}
+
+	FreeToken(param_list);
+	FreeToken(real_name_list);
+
+	if (ok)
+	{
+		return o;
+	}
+	else
+	{
+		FreeParamValueList(o);
+		return NULL;
+	}
+}
+
+// [はい] か [いいえ] の取得
+bool GetParamYes(LIST *o, char *name)
+{
+	char *s;
+	char tmp[64];
+	// 引数チェック
+	if (o == NULL)
+	{
+		return false;
+	}
+
+	s = GetParamStr(o, name);
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(tmp, sizeof(tmp), s);
+	Trim(tmp);
+
+	if (StartWith(tmp, "y"))
+	{
+		return true;
+	}
+
+	if (StartWith(tmp, "t"))
+	{
+		return true;
+	}
+
+	if (ToInt(tmp) != 0)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// パラメータ値 Int の取得
+UINT GetParamInt(LIST *o, char *name)
+{
+	PARAM_VALUE *v;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return 0;
+	}
+
+	v = FindParamValue(o, name);
+	if (v == NULL)
+	{
+		return 0;
+	}
+	else
+	{
+		return v->IntValue;
+	}
+}
+
+// パラメータ値 Unicode 文字列の取得
+wchar_t *GetParamUniStr(LIST *o, char *name)
+{
+	PARAM_VALUE *v;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	v = FindParamValue(o, name);
+	if (v == NULL)
+	{
+		return NULL;
+	}
+	else
+	{
+		return v->UniStrValue;
+	}
+}
+
+// パラメータ値文字列の所得
+char *GetParamStr(LIST *o, char *name)
+{
+	PARAM_VALUE *v;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	v = FindParamValue(o, name);
+	if (v == NULL)
+	{
+		return NULL;
+	}
+	else
+	{
+		return v->StrValue;
+	}
+}
+
+// パラメータ値の取得
+PARAM_VALUE *FindParamValue(LIST *o, char *name)
+{
+	PARAM_VALUE t, *ret;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+	if (name == NULL)
+	{
+		name = "";
+	}
+
+	Zero(&t, sizeof(t));
+	t.Name = name;
+
+	ret = Search(o, &t);
+
+	return ret;
+}
+
+// パラメータ値リストの解放
+void FreeParamValueList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		PARAM_VALUE *v = LIST_DATA(o, i);
+
+		Free(v->StrValue);
+		Free(v->UniStrValue);
+		Free(v->Name);
+		Free(v);
+	}
+
+	ReleaseList(o);
+}
+
+// パラメータ値リストソート関数
+int CmpParamValue(void *p1, void *p2)
+{
+	PARAM_VALUE *v1, *v2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	v1 = *(PARAM_VALUE **)p1;
+	v2 = *(PARAM_VALUE **)p2;
+	if (v1 == NULL || v2 == NULL)
+	{
+		return 0;
+	}
+
+	if (IsEmptyStr(v1->Name) && IsEmptyStr(v2->Name))
+	{
+		return 0;
+	}
+	return StrCmpi(v1->Name, v2->Name);
+}
+
+// パラメータ値リストの生成
+LIST *NewParamValueList()
+{
+	return NewListFast(CmpParamValue);
+}
+
+// 入力されたコマンドに含まれていたパラメータ名のリストを取得する
+TOKEN_LIST *GetCommandNameList(wchar_t *str)
+{
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NullToken();
+	}
+
+	Free(ParseCommandEx(str, L"dummy_str", &t));
+
+	return t;
+}
+
+// 指定した名前で始まるコマンドを取得する
+wchar_t *ParseCommand(wchar_t *str, wchar_t *name)
+{
+	return ParseCommandEx(str, name, NULL);
+}
+wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list)
+{
+	UNI_TOKEN_LIST *t;
+	UINT i;
+	wchar_t *tmp;
+	wchar_t *ret = NULL;
+	LIST *o;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+	if (name != NULL && UniIsEmptyStr(name))
+	{
+		name = NULL;
+	}
+
+	o = NULL;
+	if (param_list != NULL)
+	{
+		o = NewListFast(CompareStr);
+	}
+
+	tmp = CopyUniStr(str);
+	UniTrim(tmp);
+
+	i = UniSearchStrEx(tmp, L"/CMD ", 0, false);
+
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+	{
+		i = INFINITE;
+	}
+	if (i == INFINITE)
+	{
+		i = UniSearchStrEx(tmp, L"/CMD\t", 0, false);
+		if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+		{
+			i = INFINITE;
+		}
+	}
+	if (i == INFINITE)
+	{
+		i = UniSearchStrEx(tmp, L"/CMD:", 0, false);
+		if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+		{
+			i = INFINITE;
+		}
+	}
+	if (i == INFINITE)
+	{
+		i = UniSearchStrEx(tmp, L"/CMD=", 0, false);
+		if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+		{
+			i = INFINITE;
+		}
+	}
+	if (i == INFINITE)
+	{
+		i = UniSearchStrEx(tmp, L"-CMD ", 0, false);
+		if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+		{
+			i = INFINITE;
+		}
+	}
+	if (i == INFINITE)
+	{
+		i = UniSearchStrEx(tmp, L"-CMD\t", 0, false);
+		if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+		{
+			i = INFINITE;
+		}
+	}
+	if (i == INFINITE)
+	{
+		i = UniSearchStrEx(tmp, L"-CMD:", 0, false);
+		if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+		{
+			i = INFINITE;
+		}
+	}
+	if (i == INFINITE)
+	{
+		i = UniSearchStrEx(tmp, L"-CMD=", 0, false);
+		if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+		{
+			i = INFINITE;
+		}
+	}
+
+	if (i != INFINITE)
+	{
+		char *s = CopyStr("CMD");
+		if (InsertStr(o, s) == false)
+		{
+			Free(s);
+		}
+		if (UniStrCmpi(name, L"CMD") == 0)
+		{
+			ret = CopyUniStr(&str[i + 5]);
+			UniTrim(ret);
+		}
+		else
+		{
+			tmp[i] = 0;
+		}
+	}
+
+	if (ret == NULL)
+	{
+		t = UniParseCmdLine(tmp);
+
+		if (t != NULL)
+		{
+			for (i = 0;i < t->NumTokens;i++)
+			{
+				wchar_t *token = t->Token[i];
+
+				if ((token[0] == L'-' && token[1] != L'-') ||
+					(UniStrCmpi(token, L"--help") == 0) ||
+					(token[0] == L'/' && token[1] != L'/'))
+				{
+					UINT i;
+
+					// 名前付き引数
+					// コロン文字があるかどうか調べる
+
+					if (UniStrCmpi(token, L"--help") == 0)
+					{
+						token++;
+					}
+
+					i = UniSearchStrEx(token, L":", 0, false);
+					if (i == INFINITE)
+					{
+						i = UniSearchStrEx(token, L"=", 0, false);
+					}
+					if (i != INFINITE)
+					{
+						wchar_t *tmp;
+						char *a;
+
+						// コロン文字がある
+						tmp = CopyUniStr(token);
+						tmp[i] = 0;
+
+						a = CopyUniToStr(&tmp[1]);
+						if (InsertStr(o, a) == false)
+						{
+							Free(a);
+						}
+
+						if (UniStrCmpi(name, &tmp[1]) == 0)
+						{
+							if (ret == NULL)
+							{
+								// 内容
+								ret = UniCopyStr(&token[i + 1]);
+							}
+						}
+
+						Free(tmp);
+					}
+					else
+					{
+						// コロン文字が無い
+						char *a;
+
+						a = CopyUniToStr(&token[1]);
+						if (InsertStr(o, a) == false)
+						{
+							Free(a);
+						}
+
+						if (UniStrCmpi(name, &token[1]) == 0)
+						{
+							if (ret == NULL)
+							{
+								// 空文字
+								ret = UniCopyStr(L"");
+							}
+						}
+					}
+				}
+				else
+				{
+					// 名前無し引数
+					if (name == NULL)
+					{
+						if (ret == NULL)
+						{
+							if (token[0] == L'-' && token[1] == L'-')
+							{
+								ret = UniCopyStr(&token[1]);
+							}
+							else if (token[0] == L'/' && token[1] == L'/')
+							{
+								ret = UniCopyStr(&token[1]);
+							}
+							else
+							{
+								ret = UniCopyStr(token);
+							}
+						}
+					}
+				}
+			}
+
+			UniFreeToken(t);
+		}
+	}
+
+	Free(tmp);
+
+	if (o != NULL)
+	{
+		TOKEN_LIST *t = ZeroMalloc(sizeof(TOKEN_LIST));
+		UINT i;
+
+		t->NumTokens = LIST_NUM(o);
+		t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			t->Token[i] = LIST_DATA(o, i);
+		}
+
+		ReleaseList(o);
+
+		*param_list = t;
+	}
+
+	if (UniStrCmpi(ret, L"none") == 0 || UniStrCmpi(ret, L"null") == 0)
+	{
+		// none と null は予約語である
+		ret[0] = 0;
+	}
+
+	return ret;
+}
+char *ParseCommandA(wchar_t *str, char *name)
+{
+	wchar_t *tmp1, *tmp2;
+	char *ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	if (name != NULL)
+	{
+		tmp1 = CopyStrToUni(name);
+	}
+	else
+	{
+		tmp1 = NULL;
+	}
+
+	tmp2 = ParseCommand(str, tmp1);
+
+	if (tmp2 == NULL)
+	{
+		ret = NULL;
+	}
+	else
+	{
+		ret = CopyUniToStr(tmp2);
+		Free(tmp2);
+	}
+
+	Free(tmp1);
+
+	return ret;
+}
+
+// パスワードプロンプト
+bool PasswordPrompt(char *password, UINT size)
+{
+	UINT wp;
+	bool escape = false;
+	void *console;
+	// 引数チェック
+	if (password == NULL || size <= 1)
+	{
+		if (size >= 1)
+		{
+			password[0] = 0;
+		}
+		return false;
+	}
+
+	wp = 0;
+
+	Zero(password, size);
+
+	console = SetConsoleRaw();
+
+	while (true)
+	{
+		int c;
+
+#ifdef	OS_WIN32
+		c = getch();
+#else	// OS_WIN32
+		c = getc(stdin);
+#endif	// OS_WIN32
+
+		if (c >= 0x20 && c <= 0x7E)
+		{
+			// 文字
+			if ((wp + 1) < size)
+			{
+				password[wp++] = (char)c;
+				putc('*', stdout);
+			}
+		}
+		else if (c == 0x03)
+		{
+			// 強制終了
+			exit(0);
+		}
+		else if (c == 0x04 || c == 0x1a || c == 0x0D || c==0x0A)
+		{
+			// 終了
+			if (c == 0x04 || c == 0x1a)
+			{
+				escape = true;
+			}
+			break;
+		}
+		else if (c == 0xE0)
+		{
+			// もう 1 文字読む
+			c = getch();
+			if (c == 0x4B || c == 0x53)
+			{
+				// バックスペース
+				goto BACKSPACE;
+			}
+		}
+		else if (c == 0x08)
+		{
+BACKSPACE:
+			// バックスペース
+			if (wp >= 1)
+			{
+				password[--wp] = 0;
+				putc(0x08, stdout);
+				putc(' ', stdout);
+				putc(0x08, stdout);
+			}
+		}
+	}
+	Print("\n");
+
+	RestoreConsole(console);
+
+	return (escape ? false : true);
+}
+
+// プロンプトを表示
+wchar_t *Prompt(wchar_t *prompt_str)
+{
+	wchar_t *ret = NULL;
+	wchar_t *tmp = NULL;
+	// 引数チェック
+	if (prompt_str == NULL)
+	{
+		prompt_str = L"";
+	}
+
+#ifdef	OS_WIN32
+	UniPrint(L"%s", prompt_str);
+	tmp = Malloc(MAX_PROMPT_STRSIZE);
+	if (fgetws(tmp, MAX_PROMPT_STRSIZE - 1, stdin) != NULL)
+	{
+		bool escape = false;
+		UINT i, len;
+
+		len = UniStrLen(tmp);
+		for (i = 0;i < len;i++)
+		{
+			if (tmp[i] == 0x04 || tmp[i] == 0x1A)
+			{
+				escape = true;
+				break;
+			}
+		}
+
+		if (escape == false)
+		{
+			UniTrimCrlf(tmp);
+
+			ret = UniCopyStr(tmp);
+		}
+	}
+	Free(tmp);
+#else	// OS_WIN32
+	{
+		char *prompt = CopyUniToStr(prompt_str);
+		char *s = readline(prompt);
+		Free(prompt);
+
+		if (s != NULL)
+		{
+			TrimCrlf(s);
+			Trim(s);
+
+			if (IsEmptyStr(s) == false)
+			{
+				add_history(s);
+			}
+
+			ret = CopyStrToUni(s);
+
+			free(s);
+		}
+	}
+#endif	// OS_WIN32
+
+	if (ret == NULL)
+	{
+		Print("\n");
+	}
+
+	return ret;
+}
+char *PromptA(wchar_t *prompt_str)
+{
+	wchar_t *str = Prompt(prompt_str);
+
+	if (str == NULL)
+	{
+		return NULL;
+	}
+	else
+	{
+		char *ret = CopyUniToStr(str);
+
+		Free(str);
+		return ret;
+	}
+}
+
+// コンソールを Raw モードにする
+void *SetConsoleRaw()
+{
+#ifdef	OS_UNIX
+	struct termios t, *ret;
+
+	Zero(&t, sizeof(t));
+	if (tcgetattr(0, &t) != 0)
+	{
+		// 失敗
+		return NULL;
+	}
+
+	// 現在の設定をコピー
+	ret = Clone(&t, sizeof(t));
+
+	// 設定を変更
+	t.c_lflag &= (~ICANON);
+	t.c_lflag &= (~ECHO);
+	t.c_cc[VTIME] = 0;
+	t.c_cc[VMIN] = 1;
+	tcsetattr(0, TCSANOW, &t);
+
+	return ret;
+#else	// OS_UNIX
+	return Malloc(0);
+#endif	// OS_UNIX
+}
+
+// コンソールのモードを復帰する
+void RestoreConsole(void *p)
+{
+#ifdef	OS_UNIX
+	struct termios *t;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	t = (struct termios *)p;
+
+	// 設定を復帰する
+	tcsetattr(0, TCSANOW, t);
+
+	Free(t);
+#else	// OS_UNIX
+	if (p != NULL)
+	{
+		Free(p);
+	}
+#endif	// OS_UNIX
+}
+
+////////////////////////////
+// ローカルコンソール関数
+
+// 新しいローカルコンソールの作成
+CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile)
+{
+	IO *in_io = NULL, *out_io = NULL;
+	CONSOLE *c = ZeroMalloc(sizeof(CONSOLE));
+	LOCAL_CONSOLE_PARAM *p;
+	UINT old_size = 0;
+
+#ifdef	OS_WIN32
+	if (MsGetConsoleWidth() == 80)
+	{
+		//old_size = MsSetConsoleWidth(WIN32_DEFAULT_CONSOLE_WIDTH);
+	}
+#endif	// OS_WIN32
+
+	c->ConsoleType = CONSOLE_LOCAL;
+	c->Free = ConsoleLocalFree;
+	c->ReadLine = ConsoleLocalReadLine;
+	c->ReadPassword = ConsoleLocalReadPassword;
+	c->Write = ConsoleLocalWrite;
+	c->GetWidth = ConsoleLocalGetWidth;
+
+	if (UniIsEmptyStr(infile) == false)
+	{
+		// 入力ファイルが指定されている
+		in_io = FileOpenW(infile, false);
+		if (in_io == NULL)
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_ERROR"), infile);
+			c->Write(c, tmp);
+			Free(c);
+			return NULL;
+		}
+		else
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_START"), infile);
+			c->Write(c, tmp);
+		}
+	}
+
+	if (UniIsEmptyStr(outfile) == false)
+	{
+		// 出力ファイルが指定されている
+		out_io = FileCreateW(outfile);
+		if (out_io == NULL)
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_ERROR"), outfile);
+			c->Write(c, tmp);
+			Free(c);
+
+			if (in_io != NULL)
+			{
+				FileClose(in_io);
+			}
+			return NULL;
+		}
+		else
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_START"), outfile);
+			c->Write(c, tmp);
+		}
+	}
+
+	p = ZeroMalloc(sizeof(LOCAL_CONSOLE_PARAM));
+	c->Param = p;
+
+	p->InFile = in_io;
+	p->OutFile = out_io;
+	p->Win32_OldConsoleWidth = old_size;
+
+	if (in_io != NULL)
+	{
+		UINT size;
+		void *buf;
+
+		size = FileSize(in_io);
+		buf = ZeroMalloc(size + 1);
+		FileRead(in_io, buf, size);
+
+		p->InBuf = NewBuf();
+		WriteBuf(p->InBuf, buf, size);
+		Free(buf);
+
+		p->InBuf->Current = 0;
+	}
+
+	return c;
+}
+
+// コンソール解放
+void ConsoleLocalFree(CONSOLE *c)
+{
+	LOCAL_CONSOLE_PARAM *p;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+#ifdef	OS_WIN32
+	if (p->Win32_OldConsoleWidth != 0)
+	{
+		MsSetConsoleWidth(p->Win32_OldConsoleWidth);
+	}
+#endif	// OS_WIN32
+
+	if (p != NULL)
+	{
+		if (p->InFile != NULL)
+		{
+			FileClose(p->InFile);
+			FreeBuf(p->InBuf);
+		}
+
+		if (p->OutFile != NULL)
+		{
+			FileClose(p->OutFile);
+		}
+
+		Free(p);
+	}
+
+	// メモリ解放
+	Free(c);
+}
+
+// 画面の横幅を取得
+UINT ConsoleLocalGetWidth(CONSOLE *c)
+{
+	UINT ret = 0;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return 0;
+	}
+
+#ifdef	OS_WIN32
+	ret = MsGetConsoleWidth();
+#else	// OS_WIN32
+	{
+		struct winsize t;
+
+		Zero(&t, sizeof(t));
+
+		if (ioctl(1, TIOCGWINSZ, &t) == 0)
+		{
+			ret = t.ws_col;
+		}
+	}
+#endif	// OS_WIN32
+
+	return ret;
+}
+
+// コンソールから 1 行読み込む
+wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile)
+{
+	wchar_t *ret;
+	LOCAL_CONSOLE_PARAM *p;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+	p = (LOCAL_CONSOLE_PARAM *)c->Param;
+	if (prompt == NULL)
+	{
+		prompt = L">";
+	}
+
+	ConsoleWriteOutFile(c, prompt, false);
+
+	if (nofile == false && p->InBuf != NULL)
+	{
+		// ファイルから次の行を読み込む
+		ret = ConsoleReadNextFromInFile(c);
+
+		if (ret != NULL)
+		{
+			// 擬似プロンプトを表示する
+			UniPrint(L"%s", prompt);
+
+			// 画面に描画する
+			UniPrint(L"%s\n", ret);
+		}
+	}
+	else
+	{
+		// 画面から次の行を読み込む
+		ret = Prompt(prompt);
+	}
+
+	if (ret != NULL)
+	{
+		ConsoleWriteOutFile(c, ret, true);
+	}
+	else
+	{
+		ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
+	}
+
+	return ret;
+}
+
+// コンソールからパスワードを読み込む
+char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt)
+{
+	char tmp[64];
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+	if (prompt == NULL)
+	{
+		prompt = L"Password>";
+	}
+
+	UniPrint(L"%s", prompt);
+	ConsoleWriteOutFile(c, prompt, false);
+
+	if (PasswordPrompt(tmp, sizeof(tmp)))
+	{
+		ConsoleWriteOutFile(c, L"********", true);
+		return CopyStr(tmp);
+	}
+	else
+	{
+		ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
+		return NULL;
+	}
+}
+
+// コンソールに文字列を表示する
+bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str)
+{
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	UniPrint(L"%s%s", str, (UniEndWith(str, L"\n") ? L"" : L"\n"));
+
+	ConsoleWriteOutFile(c, str, true);
+
+	return true;
+}
+
+// 入力ファイルから次の 1 行を読み込む
+wchar_t *ConsoleReadNextFromInFile(CONSOLE *c)
+{
+	LOCAL_CONSOLE_PARAM *p;
+	char *str;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+	if (p->InBuf == NULL)
+	{
+		return NULL;
+	}
+
+	while (true)
+	{
+		str = CfgReadNextLine(p->InBuf);
+
+		if (str == NULL)
+		{
+			return NULL;
+		}
+
+		Trim(str);
+
+		if (IsEmptyStr(str) == false)
+		{
+			UINT size;
+			wchar_t *ret;
+
+			size = CalcUtf8ToUni((BYTE *)str, StrLen(str));
+			ret = ZeroMalloc(size + 32);
+			Utf8ToUni(ret, size, (BYTE *)str, StrLen(str));
+
+			Free(str);
+
+			return ret;
+		}
+
+		Free(str);
+	}
+}
+
+// 出力ファイルが指定されている場合は書き出す
+void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf)
+{
+	LOCAL_CONSOLE_PARAM *p;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return;
+	}
+
+	p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+	if (p != NULL && p->OutFile != NULL)
+	{
+		wchar_t *tmp = UniNormalizeCrlf(str);
+		UINT utf8_size;
+		UCHAR *utf8;
+
+		utf8_size = CalcUniToUtf8(tmp);
+		utf8 = ZeroMalloc(utf8_size + 1);
+		UniToUtf8(utf8, utf8_size + 1, tmp);
+
+		FileWrite(p->OutFile, utf8, utf8_size);
+
+		if (UniEndWith(str, L"\n") == false && add_last_crlf)
+		{
+			char *crlf = "\r\n";
+			FileWrite(p->OutFile, "\r\n", StrLen(crlf));
+		}
+
+		Free(utf8);
+		Free(tmp);
+	}
+
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Console.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Console.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Console.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,213 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Console.h
+// Console.c のヘッダ
+
+#ifndef	CONSOLE_H
+#define	CONSOLE_H
+
+// 定数
+#define	MAX_PROMPT_STRSIZE			65536
+#define	WIN32_DEFAULT_CONSOLE_WIDTH	100
+
+// コンソールの種類
+#define	CONSOLE_LOCAL				0	// ローカルコンソール
+#define	CONSOLE_CSV					1	// CSV 出力モード
+
+// パラメータ補完プロンプト関数
+typedef wchar_t *(PROMPT_PROC)(CONSOLE *c, void *param);
+
+// パラメータ検証プロンプト関数
+typedef bool (EVAL_PROC)(CONSOLE *c, wchar_t *str, void *param);
+
+// パラメータ項目の定義
+struct PARAM
+{
+	char *Name;					// パラメータ名
+	PROMPT_PROC *PromptProc;	// パラメータが指定されていない場合に自動的に呼び出す
+								// プロンプト関数 (NULL の場合は呼ばない)
+	void *PromptProcParam;		// プロンプト関数に渡す任意のポインタ
+	EVAL_PROC *EvalProc;		// パラメータ文字列検証関数
+	void *EvalProcParam;		// 検証関数に渡す任意のポインタ
+	char *Tmp;					// 一時変数
+};
+
+// パラメータ値内部データ
+struct PARAM_VALUE
+{
+	char *Name;					// 名前
+	char *StrValue;				// 文字列値
+	wchar_t *UniStrValue;		// Unicode 文字列値
+	UINT IntValue;				// 整数値
+};
+
+// コンソールサービス構造体
+struct CONSOLE
+{
+	UINT ConsoleType;										// コンソールの種類
+	UINT RetCode;											// 最後の終了コード
+	void *Param;											// 任意のデータ
+	void (*Free)(CONSOLE *c);								// 解放関数
+	wchar_t *(*ReadLine)(CONSOLE *c, wchar_t *prompt, bool nofile);		// 1 行読み込む関数
+	char *(*ReadPassword)(CONSOLE *c, wchar_t *prompt);		// パスワードを読み込む関数
+	bool (*Write)(CONSOLE *c, wchar_t *str);				// 文字列を書き出す関数
+	UINT (*GetWidth)(CONSOLE *c);							// 画面の横幅の取得
+};
+
+// ローカルコンソールパラメータ
+struct LOCAL_CONSOLE_PARAM
+{
+	IO *InFile;		// 入力ファイル
+	BUF *InBuf;		// 入力バッファ
+	IO *OutFile;	// 出力ファイル
+	UINT Win32_OldConsoleWidth;	// 以前のコンソールサイズ
+};
+
+// コマンドプロシージャ
+typedef UINT (COMMAND_PROC)(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+// コマンドの定義
+struct CMD
+{
+	char *Name;				// コマンド名
+	COMMAND_PROC *Proc;		// プロシージャ関数
+};
+
+// パラメータの最小 / 最大値評価
+struct CMD_EVAL_MIN_MAX
+{
+	char *StrName;
+	UINT MinValue, MaxValue;
+};
+
+
+// 関数プロトタイプ
+wchar_t *Prompt(wchar_t *prompt_str);
+char *PromptA(wchar_t *prompt_str);
+bool PasswordPrompt(char *password, UINT size);
+void *SetConsoleRaw();
+void RestoreConsole(void *p);
+wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list);
+wchar_t *ParseCommand(wchar_t *str, wchar_t *name);
+TOKEN_LIST *GetCommandNameList(wchar_t *str);
+char *ParseCommandA(wchar_t *str, char *name);
+LIST *NewParamValueList();
+int CmpParamValue(void *p1, void *p2);
+void FreeParamValueList(LIST *o);
+PARAM_VALUE *FindParamValue(LIST *o, char *name);
+char *GetParamStr(LIST *o, char *name);
+wchar_t *GetParamUniStr(LIST *o, char *name);
+UINT GetParamInt(LIST *o, char *name);
+bool GetParamYes(LIST *o, char *name);
+LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param);
+bool IsNameInRealName(char *input_name, char *real_name);
+void GetOmissionName(char *dst, UINT size, char *src);
+bool IsOmissionName(char *input_name, char *real_name);
+TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list);
+bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param);
+UINT GetConsoleWidth(CONSOLE *c);
+bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param);
+bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param);
+void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space);
+UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width);
+void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help);
+void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description);
+bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *CmdPrompt(CONSOLE *c, void *param);
+bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param);
+void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list);
+int CompareCandidateStr(void *p1, void *p2);
+bool IsHelpStr(char *str);
+
+CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile);
+void ConsoleLocalFree(CONSOLE *c);
+wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile);
+char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt);
+bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str);
+void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf);
+wchar_t *ConsoleReadNextFromInFile(CONSOLE *c);
+UINT ConsoleLocalGetWidth(CONSOLE *c);
+
+
+#endif	// CONSOLE_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Database.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Database.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Database.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,217 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Database.c
+// ライセンスデータベース
+
+// 注意: このコードは製品版 PacketiX VPN と互換性を保つために存在しており、
+//       UT-VPN ではほとんど必要がないプログラムが含まれている。
+
+#include "CedarPch.h"
+
+// ライセンス状態文字列の取得
+wchar_t *LiGetLicenseStatusStr(UINT i)
+{
+	wchar_t *ret = _UU("LICENSE_STATUS_OTHERERROR");
+
+	switch (i)
+	{
+	case LICENSE_STATUS_OK:
+		ret = _UU("LICENSE_STATUS_OK");
+		break;
+
+	case LICENSE_STATUS_EXPIRED:
+		ret = _UU("LICENSE_STATUS_EXPIRED");
+		break;
+
+	case LICENSE_STATUS_ID_DIFF:
+		ret = _UU("LICENSE_STATUS_ID_DIFF");
+		break;
+
+	case LICENSE_STATUS_DUP:
+		ret = _UU("LICENSE_STATUS_DUP");
+		break;
+
+	case LICENSE_STATUS_INSUFFICIENT:
+		ret = _UU("LICENSE_STATUS_INSUFFICIENT");
+		break;
+
+	case LICENSE_STATUS_COMPETITION:
+		ret = _UU("LICENSE_STATUS_COMPETITION");
+		break;
+
+	case LICENSE_STATUS_NONSENSE:
+		ret = _UU("LICENSE_STATUS_NONSENSE");
+		break;
+
+	case LICENSE_STATUS_CPU:
+		ret = _UU("LICENSE_STATUS_CPU");
+		break;
+	}
+
+	return ret;
+}
+
+// 現在のライセンスのステータスを解析して保存する
+void LiParseCurrentLicenseStatus(LICENSE_SYSTEM *s, LICENSE_STATUS *status)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		if (status != NULL)
+		{
+			Zero(status, sizeof(LICENSE_STATUS));
+		}
+		return;
+	}
+
+	if (true)
+	{
+		LICENSE_STATUS *st = ZeroMalloc(sizeof(LICENSE_STATUS));
+
+		st->MaxHubs = MAX_HUBS;
+
+		if (Is64())
+		{
+			st->MaxHubs = MAX_HUBS_FOR_64BIT;
+		}
+
+		st->MaxSessions = SERVER_MAX_SESSIONS;
+
+		if (Is64())
+		{
+			st->MaxSessions = SERVER_MAX_SESSIONS_FOR_64BIT;
+		}
+
+		// エディション名
+		StrCpy(st->EditionStr, sizeof(st->EditionStr),
+			"SoftEther UT-VPN Server (GPL)");
+		st->Edition = LICENSE_EDITION_UTVPN_GPL;
+
+		st->AllowAcceptFromClient = true;
+		st->NeedSubscription = false;
+		st->NumUserLicense = INFINITE;
+		st->NumBridgeLicense = INFINITE;
+		st->NumClientLicense = INFINITE;
+		st->AllowEnterpriseFunction = true;
+		st->CarrierEdition = false;
+		st->Expires = 0;
+		st->IsSubscriptionExpired = false;
+		st->SystemId = 0;
+
+		if (status != NULL)
+		{
+			Copy(status, st, sizeof(LICENSE_STATUS));
+		}
+
+		Copy(s->Status, st, sizeof(LICENSE_STATUS));
+
+		Free(st);
+	}
+	UnlockList(s->LicenseList);
+}
+
+// ライセンスシステムの解放
+void LiFreeLicenseSystem(LICENSE_SYSTEM *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	ReleaseList(s->LicenseList);
+
+	if (s->Status != NULL)
+	{
+		Free(s->Status);
+	}
+
+	Free(s);
+}
+
+// ライセンスシステムをデバッグモードで作成
+LICENSE_SYSTEM *LiNewLicenseSystem()
+{
+	LICENSE_SYSTEM *s;
+
+	s = ZeroMalloc(sizeof(LICENSE_SYSTEM));
+
+	s->Status = ZeroMalloc(sizeof(LICENSE_STATUS));
+
+	return s;
+}
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Database.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Database.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Database.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,145 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Database.h
+// Database.c のヘッダ
+
+#ifndef	DATABASE_H
+#define	DATABASE_H
+
+// ライセンスシステム
+struct LICENSE_SYSTEM
+{
+	LIST *LicenseList;									// ライセンスリスト
+	LICENSE_STATUS *Status;								// ライセンス状況
+};
+
+// ライセンスデータ
+struct LICENSE_DATA
+{
+	UINT ProductId;			// 製品 ID
+	UINT SerialId;			// シリアル ID (16 bit)
+	UINT64 SystemId;		// システム ID (40 bit)
+	UINT ExpiresInt;		// 有効期限 (数値)
+	UINT64 Expires;			// 有効期限
+};
+
+// 登録されているライセンス
+struct LICENSE
+{
+	UINT Id;											// 番号
+	char Name[LICENSE_MAX_PRODUCT_NAME_LEN + 1];		// 製品名
+	char LicenseKeyStr[LICENSE_KEYSTR_LEN + 1];			// ライセンスキー文字列
+	char LicenseIdStr[LICENSE_LICENSEID_STR_LEN + 1];	// ライセンス ID 文字列 
+	UINT ProductId;										// 製品 ID
+	UINT64 SystemId;									// システム ID
+	UINT SerialId;										// シリアル ID
+	UINT64 Expires;										// 有効期限
+	UINT Status;										// 状況
+};
+
+// ライセンス状況
+struct LICENSE_STATUS
+{
+	UINT Edition;			// エディション
+	char EditionStr[LICENSE_MAX_PRODUCT_NAME_LEN + 1];	// エディション名
+	UINT64 SystemId;		// システム ID
+	UINT MaxSessions;		// システムでサポートされている最大同時接続可能セッション数
+	UINT MaxHubs;			// システムでサポートされている最大同時接続可能仮想 HUB 数
+	UINT NumUserLicense;	// ユーザー作成ライセンス数
+	UINT NumClientLicense;	// クライアント接続ライセンス数
+	UINT NumBridgeLicense;	// ブリッジ接続ライセンス数
+	UINT64 Expires;			// ライセンスの有効期限
+	UINT64 SubscriptionExpires;	// サブスクリプションの有効期限
+	bool NeedSubscription;	// サブスクリプションが必要かどうか
+	bool AllowAcceptFromClient;	// クライアントからの接続を受け付ける
+	bool AllowEnterpriseFunction;	// エンタープライズ向け機能が動作する
+	bool CarrierEdition;	// Carrier Edition である
+	bool IsSubscriptionExpired;	// サブスクリプションの期限が切れているかどうか
+};
+
+
+// 関数プロトタイプ
+LICENSE_SYSTEM *LiNewLicenseSystem();
+void LiFreeLicenseSystem(LICENSE_SYSTEM *s);
+void LiParseCurrentLicenseStatus(LICENSE_SYSTEM *s, LICENSE_STATUS *status);
+wchar_t *LiGetLicenseStatusStr(UINT i);
+
+
+#endif	// DATABASE_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Hub.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Hub.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Hub.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,5840 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Hub.c
+// 仮想 HUB モジュール
+
+#include "CedarPch.h"
+
+static UCHAR broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+// 現在サポートされている管理オプションの一覧とデフォルト値
+// 名前は 63 文字以内にすること
+ADMIN_OPTION admin_options[] =
+{
+	{"allow_hub_admin_change_option", 0},
+	{"max_users", 0},
+	{"max_multilogins_per_user", 0},
+	{"max_groups", 0},
+	{"max_accesslists", 0},
+	{"max_sessions_client_bridge_apply", 0},
+	{"max_sessions", 0},
+	{"max_sessions_client", 0},
+	{"max_sessions_bridge", 0},
+	{"max_bitrates_download", 0},
+	{"max_bitrates_upload", 0},
+	{"deny_empty_password", 0},
+	{"deny_bridge", 0},
+	{"deny_routing", 0},
+	{"deny_qos", 0},
+	{"deny_change_user_password", 0},
+	{"no_change_users", 0},
+	{"no_change_groups", 0},
+	{"no_securenat", 0},
+	{"no_securenat_enablenat", 0},
+	{"no_securenat_enabledhcp", 0},
+	{"no_cascade", 0},
+	{"no_online", 0},
+	{"no_offline", 0},
+	{"no_change_log_config", 0},
+	{"no_disconnect_session", 0},
+	{"no_delete_iptable", 0},
+	{"no_delete_mactable", 0},
+	{"no_enum_session", 0},
+	{"no_query_session", 0},
+	{"no_change_admin_password", 0},
+	{"no_change_log_switch_type", 0},
+	{"no_change_access_list", 0},
+	{"no_change_access_control_list", 0},
+	{"no_change_cert_list", 0},
+	{"no_change_crl_list", 0},
+	{"no_read_log_file", 0},
+	{"deny_hub_admin_change_ext_option", 0},
+	{"no_delay_jitter_packet_loss", 0},
+	{"no_change_msg", 0},
+};
+
+UINT num_admin_options = sizeof(admin_options) / sizeof(ADMIN_OPTION);
+
+// 指定されたメッセージが URL 文字列かどうか取得
+bool IsURLMsg(wchar_t *str, char *url, UINT url_size)
+{
+	UNI_TOKEN_LIST *t;
+	bool ret = false;
+	UINT i;
+	UINT n = 0;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	t = UniParseToken(str, L"\r\n");
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		wchar_t *str = t->Token[i];
+
+		if (IsEmptyUniStr(str) == false)
+		{
+			n++;
+
+			UniTrim(str);
+
+			if (n == 1)
+			{
+				if (UniStartWith(str, L"http://") ||
+					UniStartWith(str, L"https://") ||
+					UniStartWith(str, L"ftp://"))
+				{
+					ret = true;
+
+					UniToStr(url, url_size, str);
+				}
+			}
+		}
+	}
+
+	if (n != 1)
+	{
+		ret = false;
+	}
+
+	UniFreeToken(t);
+
+	return ret;
+}
+
+// RPC_ADMIN_OPTION からデータを取得
+UINT GetHubAdminOptionData(RPC_ADMIN_OPTION *ao, char *name)
+{
+	UINT i;
+	// 引数チェック
+	if (ao == NULL || name == NULL)
+	{
+		return INFINITE;
+	}
+
+	for (i = 0;i < ao->NumItem;i++)
+	{
+		ADMIN_OPTION *a = &ao->Items[i];
+
+		if (StrCmpi(a->Name, name) == 0)
+		{
+			return a->Value;
+		}
+	}
+
+	return INFINITE;
+}
+void GetHubAdminOptionDataAndSet(RPC_ADMIN_OPTION *ao, char *name, UINT *dest)
+{
+	UINT value;
+	// 引数チェック
+	if (ao == NULL || name == NULL || dest == NULL)
+	{
+		return;
+	}
+
+	value = GetHubAdminOptionData(ao, name);
+	if (value == INFINITE)
+	{
+		return;
+	}
+
+	*dest = value;
+}
+
+// データをもとに HUB_OPTION の内容を設定
+void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao)
+{
+	// 引数チェック
+	if (o == NULL || ao == NULL)
+	{
+		return;
+	}
+
+	GetHubAdminOptionDataAndSet(ao, "NoAddressPollingIPv4", &o->NoArpPolling);
+	GetHubAdminOptionDataAndSet(ao, "NoAddressPollingIPv6", &o->NoIPv6AddrPolling);
+	GetHubAdminOptionDataAndSet(ao, "NoIpTable", &o->NoIpTable);
+	GetHubAdminOptionDataAndSet(ao, "NoMacAddressLog", &o->NoMacAddressLog);
+	GetHubAdminOptionDataAndSet(ao, "ManageOnlyPrivateIP", &o->ManageOnlyPrivateIP);
+	GetHubAdminOptionDataAndSet(ao, "ManageOnlyLocalUnicastIPv6", &o->ManageOnlyLocalUnicastIPv6);
+	GetHubAdminOptionDataAndSet(ao, "DisableIPParsing", &o->DisableIPParsing);
+	GetHubAdminOptionDataAndSet(ao, "YieldAfterStorePacket", &o->YieldAfterStorePacket);
+	GetHubAdminOptionDataAndSet(ao, "NoSpinLockForPacketDelay", &o->NoSpinLockForPacketDelay);
+	GetHubAdminOptionDataAndSet(ao, "BroadcastStormDetectionThreshold", &o->BroadcastStormDetectionThreshold);
+	GetHubAdminOptionDataAndSet(ao, "ClientMinimumRequiredBuild", &o->ClientMinimumRequiredBuild);
+	GetHubAdminOptionDataAndSet(ao, "FilterPPPoE", &o->FilterPPPoE);
+	GetHubAdminOptionDataAndSet(ao, "FilterOSPF", &o->FilterOSPF);
+	GetHubAdminOptionDataAndSet(ao, "FilterIPv4", &o->FilterIPv4);
+	GetHubAdminOptionDataAndSet(ao, "FilterIPv6", &o->FilterIPv6);
+	GetHubAdminOptionDataAndSet(ao, "FilterNonIP", &o->FilterNonIP);
+	GetHubAdminOptionDataAndSet(ao, "NoIPv4PacketLog", &o->NoIPv4PacketLog);
+	GetHubAdminOptionDataAndSet(ao, "NoIPv6PacketLog", &o->NoIPv6PacketLog);
+	GetHubAdminOptionDataAndSet(ao, "FilterBPDU", &o->FilterBPDU);
+	GetHubAdminOptionDataAndSet(ao, "NoIPv6DefaultRouterInRAWhenIPv6", &o->NoIPv6DefaultRouterInRAWhenIPv6);
+	GetHubAdminOptionDataAndSet(ao, "NoLookBPDUBridgeId", &o->NoLookBPDUBridgeId);
+	GetHubAdminOptionDataAndSet(ao, "NoManageVlanId", &o->NoManageVlanId);
+	GetHubAdminOptionDataAndSet(ao, "VlanTypeId", &o->VlanTypeId);
+	GetHubAdminOptionDataAndSet(ao, "FixForDLinkBPDU", &o->FixForDLinkBPDU);
+	GetHubAdminOptionDataAndSet(ao, "RequiredClientId", &o->RequiredClientId);
+}
+
+// HUB_OPTION の内容をデータに変換
+void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name)
+{
+	LIST *aol;
+	UINT i;
+	// 引数チェック
+	if (ao == NULL || o == NULL || hub_name == NULL)
+	{
+		return;
+	}
+
+	aol = NewListFast(NULL);
+
+	Add(aol, NewAdminOption("NoAddressPollingIPv4", o->NoArpPolling));
+	Add(aol, NewAdminOption("NoAddressPollingIPv6", o->NoIPv6AddrPolling));
+	Add(aol, NewAdminOption("NoIpTable", o->NoIpTable));
+	Add(aol, NewAdminOption("NoMacAddressLog", o->NoMacAddressLog));
+	Add(aol, NewAdminOption("ManageOnlyPrivateIP", o->ManageOnlyPrivateIP));
+	Add(aol, NewAdminOption("ManageOnlyLocalUnicastIPv6", o->ManageOnlyLocalUnicastIPv6));
+	Add(aol, NewAdminOption("DisableIPParsing", o->DisableIPParsing));
+	Add(aol, NewAdminOption("YieldAfterStorePacket", o->YieldAfterStorePacket));
+	Add(aol, NewAdminOption("NoSpinLockForPacketDelay", o->NoSpinLockForPacketDelay));
+	Add(aol, NewAdminOption("BroadcastStormDetectionThreshold", o->BroadcastStormDetectionThreshold));
+	Add(aol, NewAdminOption("ClientMinimumRequiredBuild", o->ClientMinimumRequiredBuild));
+	Add(aol, NewAdminOption("FilterPPPoE", o->FilterPPPoE));
+	Add(aol, NewAdminOption("FilterOSPF", o->FilterOSPF));
+	Add(aol, NewAdminOption("FilterIPv4", o->FilterIPv4));
+	Add(aol, NewAdminOption("FilterIPv6", o->FilterIPv6));
+	Add(aol, NewAdminOption("FilterNonIP", o->FilterNonIP));
+	Add(aol, NewAdminOption("NoIPv4PacketLog", o->NoIPv4PacketLog));
+	Add(aol, NewAdminOption("NoIPv6PacketLog", o->NoIPv6PacketLog));
+	Add(aol, NewAdminOption("FilterBPDU", o->FilterBPDU));
+	Add(aol, NewAdminOption("NoIPv6DefaultRouterInRAWhenIPv6", o->NoIPv6DefaultRouterInRAWhenIPv6));
+	Add(aol, NewAdminOption("NoLookBPDUBridgeId", o->NoLookBPDUBridgeId));
+	Add(aol, NewAdminOption("NoManageVlanId", o->NoManageVlanId));
+	Add(aol, NewAdminOption("VlanTypeId", o->VlanTypeId));
+	Add(aol, NewAdminOption("FixForDLinkBPDU", o->FixForDLinkBPDU));
+	Add(aol, NewAdminOption("RequiredClientId", o->RequiredClientId));
+
+	Zero(ao, sizeof(RPC_ADMIN_OPTION));
+
+	StrCpy(ao->HubName, sizeof(ao->HubName), hub_name);
+
+	ao->NumItem = LIST_NUM(aol);
+	ao->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * ao->NumItem);
+
+	for (i = 0;i < LIST_NUM(aol);i++)
+	{
+		ADMIN_OPTION *a = LIST_DATA(aol, i);
+
+		Copy(&ao->Items[i], a, sizeof(ADMIN_OPTION));
+
+		Free(a);
+	}
+
+	ReleaseList(aol);
+}
+
+// 新しい ADMIN OPTION の作成
+ADMIN_OPTION *NewAdminOption(char *name, UINT value)
+{
+	ADMIN_OPTION *a;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	a = ZeroMalloc(sizeof(ADMIN_OPTION));
+	StrCpy(a->Name, sizeof(a->Name), name);
+	a->Value = value;
+
+	return a;
+}
+
+// AC リストのクローン
+LIST *CloneAcList(LIST *o)
+{
+	LIST *ret;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	ret = NewAcList();
+	SetAcList(ret, o);
+
+	return ret;
+}
+
+// AC リストをすべてセットする
+void SetAcList(LIST *o, LIST *src)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || src == NULL)
+	{
+		return;
+	}
+
+	DelAllAc(o);
+
+	for (i = 0;i < LIST_NUM(src);i++)
+	{
+		AC *ac = LIST_DATA(src, i);
+
+		AddAc(o, ac);
+	}
+}
+
+// AC リストからすべての AC を削除する
+void DelAllAc(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		AC *ac = LIST_DATA(o, i);
+
+		Free(ac);
+	}
+
+	DeleteAll(o);
+}
+
+// AC リストを解放する
+void FreeAcList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		AC *ac = LIST_DATA(o, i);
+
+		Free(ac);
+	}
+
+	ReleaseList(o);
+}
+
+// AC の内容を示す文字列を生成する
+char *GenerateAcStr(AC *ac)
+{
+	char tmp[MAX_SIZE];
+	char ip[64], mask[64];
+
+	if (ac == NULL)
+	{
+		return NULL;
+	}
+
+	IPToStr(ip, sizeof(ip), &ac->IpAddress);
+	MaskToStr(mask, sizeof(mask), &ac->SubnetMask);
+
+	if (ac->Masked == false)
+	{
+		Format(tmp, sizeof(tmp), "%s", ip);
+	}
+	else
+	{
+		Format(tmp, sizeof(tmp), "%s/%s", ip, mask);
+	}
+
+	return CopyStr(tmp);
+}
+
+// AC の設定
+void SetAc(LIST *o, UINT id, AC *ac)
+{
+	// 引数チェック
+	if (o == NULL || id == 0 || ac == NULL)
+	{
+		return;
+	}
+
+	if (DelAc(o, id))
+	{
+		AddAc(o, ac);
+	}
+}
+
+// AC の取得
+AC *GetAc(LIST *o, UINT id)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || id == 0)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		AC *ac = LIST_DATA(o, i);
+
+		if (ac->Id == id)
+		{
+			return Clone(ac, sizeof(AC));
+		}
+	}
+
+	return NULL;
+}
+
+// AC の削除
+bool DelAc(LIST *o, UINT id)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || id == 0)
+	{
+		return false;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		AC *ac = LIST_DATA(o, i);
+
+		if (ac->Id == id)
+		{
+			if (Delete(o, ac))
+			{
+				Free(ac);
+
+				NormalizeAcList(o);
+
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+// AC の追加
+void AddAc(LIST *o, AC *ac)
+{
+	// 引数チェック
+	if (o == NULL || ac == NULL)
+	{
+		return;
+	}
+
+	if (LIST_NUM(o) < MAX_HUB_ACS)
+	{
+		Insert(o, Clone(ac, sizeof(AC)));
+
+		NormalizeAcList(o);
+	}
+}
+
+// AC リストを正規化する
+void NormalizeAcList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		AC *ac = LIST_DATA(o, i);
+
+		if (IsIP6(&ac->IpAddress))
+		{
+			ac->IpAddress.ipv6_scope_id = 0;
+		}
+
+		ac->Id = (i + 1);
+	}
+}
+
+// 新しい AC リストの作成
+LIST *NewAcList()
+{
+	return NewList(CmpAc);
+}
+
+// AC 比較
+int CmpAc(void *p1, void *p2)
+{
+	AC *a1, *a2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	a1 = *(AC **)p1;
+	a2 = *(AC **)p2;
+	if (a1 == NULL || a2 == NULL)
+	{
+		return 0;
+	}
+	if (a1->Priority > a2->Priority)
+	{
+		return 1;
+	}
+	else if (a1->Priority < a2->Priority)
+	{
+		return -1;
+	}
+	else if (a1->Deny > a2->Deny)
+	{
+		return 1;
+	}
+	else if (a1->Deny < a2->Deny)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// CRL のコピー
+CRL *CopyCrl(CRL *crl)
+{
+	CRL *ret;
+	// 引数チェック
+	if (crl == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(CRL));
+
+	if (crl->Serial != NULL)
+	{
+		ret->Serial = NewXSerial(crl->Serial->data, crl->Serial->size);
+	}
+
+	ret->Name = CopyName(crl->Name);
+
+	Copy(ret->DigestMD5, crl->DigestMD5, MD5_SIZE);
+	Copy(ret->DigestSHA1, crl->DigestSHA1, SHA1_SIZE);
+
+	return ret;
+}
+
+// CRL の解放
+void FreeCrl(CRL *crl)
+{
+	// 引数チェック
+	if (crl == NULL)
+	{
+		return;
+	}
+
+	if (crl->Serial != NULL)
+	{
+		FreeXSerial(crl->Serial);
+	}
+
+	if (crl->Name != NULL)
+	{
+		FreeName(crl->Name);
+	}
+
+	Free(crl);
+}
+
+// 仮想 HUB の CRL リストを検索して証明書が無効化されていないかどうか調べる
+bool IsValidCertInHub(HUB *h, X *x)
+{
+	bool ret;
+	// 引数チェック
+	if (h == NULL || x == NULL)
+	{
+		return false;
+	}
+
+	if (h->HubDb == NULL)
+	{
+		return false;
+	}
+
+	if (IsXRevoked(x))
+	{
+		// ファイルに保存されている CRL によって無効化されている
+		return false;
+	}
+
+	LockList(h->HubDb->CrlList);
+	{
+		ret = IsCertMatchCrlList(x, h->HubDb->CrlList);
+	}
+	UnlockList(h->HubDb->CrlList);
+
+	if (ret)
+	{
+		// 一致するので無効である
+		return false;
+	}
+
+	// 一致しなかったので有効である
+	return true;
+}
+
+// CRL リストに証明書が一致するかどうか検索
+bool IsCertMatchCrlList(X *x, LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (x == NULL || o == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		CRL *crl = LIST_DATA(o, i);
+
+		if (IsCertMatchCrl(x, crl))
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// CRL を示す文字列に変換する
+wchar_t *GenerateCrlStr(CRL *crl)
+{
+	wchar_t tmp[2048];
+	// 引数チェック
+	if (crl == NULL)
+	{
+		return NULL;
+	}
+
+	UniStrCpy(tmp, sizeof(tmp), L"");
+
+	if (crl->Name != NULL)
+	{
+		// 名前情報
+		wchar_t name[MAX_SIZE];
+
+		UniStrCat(tmp, sizeof(tmp), L"Subject=\"");
+
+		GetAllNameFromName(name, sizeof(name), crl->Name);
+		UniStrCat(tmp, sizeof(tmp), name);
+		UniStrCat(tmp, sizeof(tmp), L"\", ");
+	}
+
+	if (crl->Serial != NULL)
+	{
+		// シリアル情報
+		char str[128];
+		wchar_t uni[128];
+
+		BinToStrEx(str, sizeof(str), crl->Serial->data, crl->Serial->size);
+		StrToUni(uni, sizeof(uni), str);
+		UniStrCat(tmp, sizeof(tmp), L"Serial=\"");
+		UniStrCat(tmp, sizeof(tmp), uni);
+		UniStrCat(tmp, sizeof(tmp), L"\", ");
+	}
+
+	if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
+	{
+		// MD5
+		char str[128];
+		wchar_t uni[128];
+
+		BinToStrEx(str, sizeof(str), crl->DigestMD5, MD5_SIZE);
+		StrToUni(uni, sizeof(uni), str);
+		UniStrCat(tmp, sizeof(tmp), L"MD5=\"");
+		UniStrCat(tmp, sizeof(tmp), uni);
+		UniStrCat(tmp, sizeof(tmp), L"\", ");
+	}
+
+	if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
+	{
+		// MD5
+		char str[128];
+		wchar_t uni[128];
+
+		BinToStrEx(str, sizeof(str), crl->DigestSHA1, SHA1_SIZE);
+		StrToUni(uni, sizeof(uni), str);
+		UniStrCat(tmp, sizeof(tmp), L"SHA1=\"");
+		UniStrCat(tmp, sizeof(tmp), uni);
+		UniStrCat(tmp, sizeof(tmp), L"\", ");
+	}
+
+	if (UniEndWith(tmp, L", "))
+	{
+		tmp[UniStrLen(tmp) - 2] = 0;
+	}
+
+	return CopyUniStr(tmp);
+}
+
+// 証明書無効リストエントリに一致するかどうか検査する
+bool IsCertMatchCrl(X *x, CRL *crl)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	bool b = true;
+	// 引数チェック
+	if (x == NULL || crl == NULL)
+	{
+		return false;
+	}
+
+	if (crl->Serial != NULL)
+	{
+		// CRL にシリアル番号が定義されている場合
+		if (x->serial == NULL || CompareXSerial(x->serial, crl->Serial) == false)
+		{
+			// シリアル番号不一致
+			b = false;
+		}
+	}
+
+	if (IsZero(crl->DigestMD5, sizeof(crl->DigestMD5)) == false)
+	{
+		UCHAR test[MD5_SIZE];
+		// CRL に DigestMD5 が定義されている場合
+		GetXDigest(x, test, false);
+
+		if (Cmp(test, crl->DigestMD5, MD5_SIZE) != 0)
+		{
+			b = false;
+		}
+	}
+
+	if (IsZero(crl->DigestSHA1, sizeof(crl->DigestSHA1)) == false)
+	{
+		UCHAR test[SHA1_SIZE];
+		// CRL に DigestSHA1 が定義されている場合
+		GetXDigest(x, test, true);
+
+		if (Cmp(test, crl->DigestSHA1, SHA1_SIZE) != 0)
+		{
+			b = false;
+		}
+	}
+
+	if (crl->Name != NULL)
+	{
+		// CRL に名前が定義されている場合
+		NAME *xn, *cn;
+		xn = x->subject_name;
+		cn = crl->Name;
+
+		if (cn->CommonName != NULL && (UniIsEmptyStr(cn->CommonName) == false))
+		{
+			if (xn->CommonName == NULL || UniSoftStrCmp(xn->CommonName, cn->CommonName) != 0)
+			{
+				// CommonName 不一致
+				b = false;
+			}
+		}
+
+		if (cn->Organization != NULL && (UniIsEmptyStr(cn->Organization) == false))
+		{
+			if (xn->Organization == NULL || UniSoftStrCmp(xn->Organization, cn->Organization) != 0)
+			{
+				// Organization 不一致
+				b = false;
+			}
+		}
+
+		if (cn->Unit != NULL && (UniIsEmptyStr(cn->Unit) == false))
+		{
+			if (xn->Unit == NULL || UniSoftStrCmp(xn->Unit, cn->Unit) != 0)
+			{
+				// Unit不一致
+				b = false;
+			}
+		}
+
+		if (cn->Country != NULL && (UniIsEmptyStr(cn->Country) == false))
+		{
+			if (xn->Country == NULL || UniSoftStrCmp(xn->Country, cn->Country) != 0)
+			{
+				// Country 不一致
+				b = false;
+			}
+		}
+
+		if (cn->State != NULL && (UniIsEmptyStr(cn->State) == false))
+		{
+			if (xn->State == NULL || UniSoftStrCmp(xn->State, cn->State) != 0)
+			{
+				// State 不一致
+				b = false;
+			}
+		}
+
+		if (cn->Local != NULL && (UniIsEmptyStr(cn->Local) == false))
+		{
+			if (xn->Local == NULL || UniSoftStrCmp(xn->Local, cn->Local) != 0)
+			{
+				// Local 不一致
+				b = false;
+			}
+		}
+	}
+
+	return b;
+}
+
+// 管理オプションのヘルプ文字列を取得する
+wchar_t *GetHubAdminOptionHelpString(char *name)
+{
+	char tmp[MAX_SIZE];
+	wchar_t *ret;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return L"";
+	}
+
+	Format(tmp, sizeof(tmp), "HUB_AO_%s", name);
+
+	ret = _UU(tmp);
+	if (UniIsEmptyStr(ret))
+	{
+		ret = _UU("HUB_AO_UNKNOWN");
+	}
+
+	return ret;
+}
+
+// 仮想 HUB にデフォルトの管理オプションを追加する
+void AddHubAdminOptionsDefaults(HUB *h, bool lock)
+{
+	UINT i;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	if (lock)
+	{
+		LockList(h->AdminOptionList);
+	}
+
+	for (i = 0;i < num_admin_options;i++)
+	{
+		ADMIN_OPTION *e = &admin_options[i];
+		ADMIN_OPTION t, *r;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), e->Name);
+
+		r = Search(h->AdminOptionList, &t);
+		if (r == NULL)
+		{
+			ADMIN_OPTION *a = ZeroMalloc(sizeof(ADMIN_OPTION));
+
+			StrCpy(a->Name, sizeof(a->Name), e->Name);
+			a->Value = e->Value;
+
+			Insert(h->AdminOptionList, a);
+		}
+	}
+
+	if (lock)
+	{
+		UnlockList(h->AdminOptionList);
+	}
+}
+
+// 仮想 HUB のすべての管理オプションの削除
+void DeleteAllHubAdminOption(HUB *h, bool lock)
+{
+	UINT i;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	if (lock)
+	{
+		LockList(h->AdminOptionList);
+	}
+
+	for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
+	{
+		Free(LIST_DATA(h->AdminOptionList, i));
+	}
+
+	DeleteAll(h->AdminOptionList);
+
+	if (lock)
+	{
+		UnlockList(h->AdminOptionList);
+	}
+}
+
+// 仮想 HUB の管理オプションの取得
+UINT GetHubAdminOptionEx(HUB *h, char *name, UINT default_value)
+{
+	UINT ret = default_value;
+	// 引数チェック
+	if (h == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	LockList(h->AdminOptionList);
+	{
+		ADMIN_OPTION *a, t;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), name);
+		Trim(t.Name);
+
+		a = Search(h->AdminOptionList, &t);
+
+		if (a != NULL)
+		{
+			ret = a->Value;
+		}
+	}
+	UnlockList(h->AdminOptionList);
+
+	return ret;
+}
+UINT GetHubAdminOption(HUB *h, char *name)
+{
+	return GetHubAdminOptionEx(h, name, 0);
+}
+
+// 管理オプション
+int CompareAdminOption(void *p1, void *p2)
+{
+	ADMIN_OPTION *a1, *a2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	a1 = *(ADMIN_OPTION **)p1;
+	a2 = *(ADMIN_OPTION **)p2;
+	if (a1 == NULL || a2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(a1->Name, a2->Name);
+}
+
+// 番犬開始
+void StartHubWatchDog(HUB *h)
+{
+	THREAD *t;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	h->HaltWatchDog = false;
+	h->WatchDogEvent = NewEvent();
+
+	t = NewThread(HubWatchDogThread, h);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+}
+
+// 番犬停止
+void StopHubWatchDog(HUB *h)
+{
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	h->HaltWatchDog = true;
+	Set(h->WatchDogEvent);
+
+	WaitThread(h->WatchDogThread, INFINITE);
+	ReleaseThread(h->WatchDogThread);
+	h->WatchDogThread = NULL;
+	h->HaltWatchDog = false;
+
+	ReleaseEvent(h->WatchDogEvent);
+	h->WatchDogEvent = NULL;
+}
+
+// 番犬スレッド
+void HubWatchDogThread(THREAD *t, void *param)
+{
+	UINT num_packets_v4 = 0;
+	UINT num_packets_v6 = 0;
+	HUB *hub;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	hub = (HUB *)param;
+
+	hub->WatchDogThread = t;
+	AddRef(t->ref);
+
+	NoticeThreadInit(t);
+
+	while (true)
+	{
+		LIST *o;
+		LIST *o2;
+		UINT i, num;
+		UINT interval;
+		UINT wait_time = 100;
+		if (hub->HaltWatchDog)
+		{
+			break;
+		}
+
+		o = NewListFast(NULL);
+		o2 = NewListFast(NULL);
+
+		// ARP パケットの送信
+		LockList(hub->IpTable);
+		{
+			num = LIST_NUM(hub->IpTable);
+			for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+			{
+				IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+				if ((e->UpdatedTime + (UINT64)(IP_TABLE_EXPIRE_TIME)) > Tick64())
+				{
+					if (e->MacAddress[0] != 0xff || e->MacAddress[1] != 0xff || e->MacAddress[2] != 0xff ||
+						e->MacAddress[3] != 0xff || e->MacAddress[4] != 0xff || e->MacAddress[5] != 0xff)
+					{
+						if (hub->Option != NULL && hub->Option->NoArpPolling == false)
+						{
+							if (IsIP4(&e->Ip))
+							{
+								// IPv4
+								MAC_HEADER *mac = ZeroMalloc(sizeof(MAC_HEADER) + sizeof(ARPV4_HEADER));
+								ARPV4_HEADER *p = (ARPV4_HEADER *)(((UCHAR *)mac) + sizeof(MAC_HEADER));
+
+								Copy(mac->DestAddress, e->MacAddress, 6);
+								Copy(mac->SrcAddress, hub->HubMacAddr, 6);
+								mac->Protocol = Endian16(MAC_PROTO_ARPV4);
+
+								p->HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+								p->ProtocolType = Endian16(MAC_PROTO_IPV4);
+								p->HardwareSize = 6;
+								p->ProtocolSize = 4;
+								p->Operation = Endian16(ARP_OPERATION_REQUEST);
+								Copy(p->SrcAddress, hub->HubMacAddr, 6);
+								p->SrcIP = IPToUINT(&hub->HubIp);
+								p->TargetAddress[0] =
+									p->TargetAddress[1] =
+									p->TargetAddress[2] =
+									p->TargetAddress[3] =
+									p->TargetAddress[4] =
+									p->TargetAddress[5] = 0x00;
+								p->TargetIP = IPToUINT(&e->Ip);
+								Insert(o, mac);
+							}
+						}
+
+						if (hub->Option != NULL && hub->Option->NoIPv6AddrPolling == false)
+						{
+							if (IsIP6(&e->Ip))
+							{
+								// IPv6
+								BUF *buf;
+								IPV6_ADDR ip6addr;
+
+								if (IPToIPv6Addr(&ip6addr, &e->Ip))
+								{
+									buf = BuildICMPv6NeighborSoliciation(&hub->HubIpV6,
+										&ip6addr,
+										hub->HubMacAddr, ++hub->HubIP6Id);
+
+									if (buf != NULL)
+									{
+										BUF *buf2 = NewBuf();
+										MAC_HEADER mac;
+
+										Zero(&mac, sizeof(mac));
+
+										Copy(mac.DestAddress, e->MacAddress, 6);
+										Copy(mac.SrcAddress, hub->HubMacAddr, 6);
+										mac.Protocol = Endian16(MAC_PROTO_IPV6);
+
+										WriteBuf(buf2, &mac, sizeof(MAC_HEADER));
+
+										WriteBuf(buf2, buf->Buf, buf->Size);
+
+										FreeBuf(buf);
+
+										Insert(o2, buf2);
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		UnlockList(hub->IpTable);
+
+		if ((LIST_NUM(o) + LIST_NUM(o2)) != 0)
+		{
+			interval = HUB_ARP_SEND_INTERVAL / (LIST_NUM(o) + LIST_NUM(o2));
+		}
+		else
+		{
+			interval = HUB_ARP_SEND_INTERVAL;
+		}
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			PKT *packet;
+			void *p = LIST_DATA(o, i);
+
+			Wait(hub->WatchDogEvent, interval);
+			if (hub->HaltWatchDog)
+			{
+				for (;i < LIST_NUM(o);i++)
+				{
+					Free(LIST_DATA(o, i));
+				}
+				ReleaseList(o);
+
+				for (i = 0;i < LIST_NUM(o2);i++)
+				{
+					FreeBuf(LIST_DATA(o2, i));
+				}
+				ReleaseList(o2);
+				goto ESCAPE;
+			}
+
+			packet = ParsePacket((UCHAR *)p, sizeof(MAC_HEADER) + sizeof(ARPV4_HEADER));
+			if (packet != NULL)
+			{
+				StorePacket(hub, NULL, packet);
+				num_packets_v4++;
+			}
+			else
+			{
+				Free(p);
+			}
+		}
+
+		for (i = 0;i < LIST_NUM(o2);i++)
+		{
+			PKT *packet;
+			BUF *buf = LIST_DATA(o2, i);
+
+			Wait(hub->WatchDogEvent, interval);
+			if (hub->HaltWatchDog)
+			{
+				ReleaseList(o);
+
+				for (;i < LIST_NUM(o2);i++)
+				{
+					FreeBuf(LIST_DATA(o2, i));
+				}
+				ReleaseList(o2);
+				goto ESCAPE;
+			}
+
+			packet = ParsePacket(buf->Buf, buf->Size);
+			if (packet != NULL)
+			{
+				StorePacket(hub, NULL, packet);
+				num_packets_v6++;
+			}
+			else
+			{
+				Free(buf->Buf);
+			}
+
+			Free(buf);
+		}
+
+		ReleaseList(o);
+		ReleaseList(o2);
+
+		if (num == 0)
+		{
+			wait_time = HUB_ARP_SEND_INTERVAL;
+		}
+
+		Wait(hub->WatchDogEvent, wait_time);
+	}
+ESCAPE:
+	return;
+}
+
+// SecureNAT を有効/無効に設定する
+void EnableSecureNAT(HUB *h, bool enable)
+{
+	EnableSecureNATEx(h, enable, false);
+}
+void EnableSecureNATEx(HUB *h, bool enable, bool no_change)
+{
+	bool for_cluster = false;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+		{
+			for_cluster = true;
+		}
+	}
+
+	Lock(h->lock_online);
+	{
+		if (no_change == false)
+		{
+			h->EnableSecureNAT = enable;
+		}
+
+		if (h->EnableSecureNAT == false)
+		{
+STOP:
+			// すでに開始している場合は停止する
+			if (h->SecureNAT != NULL)
+			{
+				SnFreeSecureNAT(h->SecureNAT);
+				h->SecureNAT = NULL;
+			}
+		}
+		else
+		{
+			if (for_cluster)
+			{
+				if ((h->SecureNAT != NULL && LIST_NUM(h->SessionList) <= 1) ||
+					(h->SecureNAT == NULL && LIST_NUM(h->SessionList) == 0))
+				{
+					// 開始モードだが、ダイナミック仮想 HUB で他にセッションが無い場合
+					// は停止する
+					goto STOP;
+				}
+			}
+
+			// まだ開始していない場合で HUB がオンラインの場合は開始する
+			if (h->SecureNAT == NULL && h->Offline == false)
+			{
+				h->SecureNAT = SnNewSecureNAT(h, h->SecureNATOption);
+			}
+		}
+	}
+	Unlock(h->lock_online);
+}
+
+// アクセスリストを文字列に変換する
+void GetAccessListStr(char *str, UINT size, ACCESS *a)
+{
+	char tmp[MAX_SIZE];
+	char tmp1[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	bool l3 = false;
+	bool asterisk = false;
+	// 引数チェック
+	if (str == NULL || a == NULL)
+	{
+		return;
+	}
+
+	StrCpy(str, size, "");
+
+	if (a->IsIPv6 == false)
+	{
+		if (a->SrcIpAddress != 0 || a->SrcSubnetMask != 0)
+		{
+			IPToStr32(tmp1, sizeof(tmp1), a->SrcIpAddress);
+			MaskToStr32(tmp2, sizeof(tmp2), a->SrcSubnetMask);
+			Format(tmp, sizeof(tmp), "SrcIPv4=%s/%s, ", tmp1, tmp2);
+			StrCat(str, size, tmp);
+
+			l3 = true;
+		}
+
+		if (a->DestIpAddress != 0 || a->DestSubnetMask != 0)
+		{
+			IPToStr32(tmp1, sizeof(tmp1), a->DestIpAddress);
+			MaskToStr32(tmp2, sizeof(tmp2), a->DestSubnetMask);
+			Format(tmp, sizeof(tmp), "DstIPv4=%s/%s, ", tmp1, tmp2);
+			StrCat(str, size, tmp);
+
+			l3 = true;
+		}
+	}
+	else
+	{
+		if (IsZeroIP6Addr(&a->SrcIpAddress6) == false || IsZeroIP6Addr(&a->SrcSubnetMask6) == false)
+		{
+			IP6AddrToStr(tmp1, sizeof(tmp1), &a->SrcIpAddress6);
+			Mask6AddrToStr(tmp2, sizeof(tmp2), &a->SrcSubnetMask6);
+			Format(tmp, sizeof(tmp), "SrcIPv6=%s/%s, ", tmp1, tmp2);
+			StrCat(str, size, tmp);
+
+			l3 = true;
+		}
+
+		if (IsZeroIP6Addr(&a->DestIpAddress6) == false || IsZeroIP6Addr(&a->DestSubnetMask6) == false)
+		{
+			IP6AddrToStr(tmp1, sizeof(tmp1), &a->DestIpAddress6);
+			Mask6AddrToStr(tmp2, sizeof(tmp2), &a->DestSubnetMask6);
+			Format(tmp, sizeof(tmp), "DstIPv6=%s/%s, ", tmp1, tmp2);
+			StrCat(str, size, tmp);
+
+			l3 = true;
+		}
+	}
+
+	if (a->Protocol != 0)
+	{
+		StrCpy(tmp1, sizeof(tmp1), "");
+		switch (a->Protocol)
+		{
+		case 1:
+			StrCpy(tmp1, sizeof(tmp1), "ICMPv4");
+			break;
+		case 3:
+			StrCpy(tmp1, sizeof(tmp1), "GGP");
+			break;
+		case 6:
+			StrCpy(tmp1, sizeof(tmp1), "TCP");
+			break;
+		case 8:
+			StrCpy(tmp1, sizeof(tmp1), "EGP");
+			break;
+		case 12:
+			StrCpy(tmp1, sizeof(tmp1), "PUP");
+			break;
+		case 17:
+			StrCpy(tmp1, sizeof(tmp1), "UDP");
+			break;
+		case 20:
+			StrCpy(tmp1, sizeof(tmp1), "HMP");
+			break;
+		case 22:
+			StrCpy(tmp1, sizeof(tmp1), "XNS-IDP");
+			break;
+		case 27:
+			StrCpy(tmp1, sizeof(tmp1), "RDP");
+			break;
+		case 58:
+			StrCpy(tmp1, sizeof(tmp1), "ICMPv6");
+			break;
+		case 66:
+			StrCpy(tmp1, sizeof(tmp1), "RVD");
+			break;
+		}
+		Format(tmp, sizeof(tmp), "Protocol=%s(%u), ", tmp1, a->Protocol);
+		StrCat(str, size, tmp);
+
+		l3 = true;
+	}
+
+	if (a->SrcPortStart != 0)
+	{
+		if (a->SrcPortEnd == a->SrcPortStart)
+		{
+			Format(tmp, sizeof(tmp), "SrcPort=%u, ", a->SrcPortStart);
+			StrCat(str, size, tmp);
+		}
+		else
+		{
+			Format(tmp, sizeof(tmp), "SrcPort=%u-%u, ", a->SrcPortStart, a->SrcPortEnd);
+			StrCat(str, size, tmp);
+		}
+
+		l3 = true;
+	}
+
+	if (a->DestPortStart != 0)
+	{
+		if (a->DestPortEnd == a->DestPortStart)
+		{
+			Format(tmp, sizeof(tmp), "DstPort=%u, ", a->DestPortStart);
+			StrCat(str, size, tmp);
+		}
+		else
+		{
+			Format(tmp, sizeof(tmp), "DstPort=%u-%u, ", a->DestPortStart, a->DestPortEnd);
+			StrCat(str, size, tmp);
+		}
+
+		l3 = true;
+	}
+
+	if (StrLen(a->SrcUsername) != 0)
+	{
+		Format(tmp, sizeof(tmp), "SrcUser=%s, ", a->SrcUsername);
+		StrCat(str, size, tmp);
+	}
+
+	if (StrLen(a->DestUsername) != 0)
+	{
+		Format(tmp, sizeof(tmp), "DstUser=%s, ", a->DestUsername);
+		StrCat(str, size, tmp);
+	}
+
+	if (a->CheckSrcMac != false)
+	{
+		char mac[MAX_SIZE], mask[MAX_SIZE];
+		MacToStr(mac, sizeof(mac), a->SrcMacAddress);
+		MacToStr(mask, sizeof(mask), a->SrcMacMask);
+		Format(tmp, sizeof(tmp), "SrcMac=%s/%s, ", mac, mask);
+		StrCat(str, size, tmp);
+	}
+	if (a->CheckDstMac != false)
+	{
+		char mac[MAX_SIZE], mask[MAX_SIZE];
+		MacToStr(mac, sizeof(mac), a->DstMacAddress);
+		MacToStr(mask, sizeof(mask), a->DstMacMask);
+		Format(tmp, sizeof(tmp), "DstMac=%s/%s, ", mac, mask);
+		StrCat(str, size, tmp);
+	}
+
+	if (a->CheckTcpState)
+	{
+		if(a->Established)
+		{
+			StrCat(str, size, "Established, ");
+		}
+		else
+		{
+			StrCat(str, size, "Unestablished, ");
+		}
+
+		l3 = true;
+	}
+
+	if (a->Discard == false)
+	{
+		if (a->Delay >= 1)
+		{
+			Format(tmp, sizeof(tmp), "Delay=%u, ", a->Delay);
+			StrCat(str, size, tmp);
+		}
+
+		if (a->Jitter >= 1)
+		{
+			Format(tmp, sizeof(tmp), "Jitter=%u, ", a->Jitter);
+			StrCat(str, size, tmp);
+		}
+
+		if (a->Loss >= 1)
+		{
+			Format(tmp, sizeof(tmp), "Loss=%u, " , a->Loss);
+			StrCat(str, size, tmp);
+		}
+	}
+
+	if (StrLen(str) == 0)
+	{
+		asterisk = true;
+	}
+
+	if (l3)
+	{
+		if (a->IsIPv6)
+		{
+			StrCatLeft(str, size, "(ipv6) ");
+		}
+		else
+		{
+			StrCatLeft(str, size, "(ipv4) ");
+		}
+	}
+	else
+	{
+		StrCatLeft(str, size, "(ether) ");
+	}
+
+	if (EndWith(str, ", "))
+	{
+		str[StrLen(str) - 2] = 0;
+	}
+
+	if (asterisk)
+	{
+		StrCat(str, size, "*");
+	}
+}
+
+// パケットをアクセスリストによってマスクすることができるかどうか判定する
+bool IsPacketMaskedByAccessList(SESSION *s, PKT *p, ACCESS *a, UINT dest_username, UINT dest_groupname)
+{
+	UINT src_username;
+	UINT src_groupname;
+	HUB_PA *pa;
+	IPV4_HEADER *ip = NULL;
+	IPV6_HEADER *ip6 = NULL;
+	bool is_ipv4_packet = false;
+	bool is_ipv6_packet = false;
+	// 引数チェック
+	if (s == NULL || p == NULL || a == NULL)
+	{
+		return false;
+	}
+	if (a->Active == false)
+	{
+		// アクセスリストは無効
+		return false;
+	}
+
+	pa = (HUB_PA *)s->PacketAdapter->Param;
+
+	// 送信元のユーザー名ハッシュ
+	src_username = pa->UsernameHash;
+	src_groupname = pa->GroupnameHash;
+
+	// 送信元・宛先 MAC アドレスの判定
+	if (a->CheckSrcMac != false)
+	{
+		UINT i;
+		for (i = 0; i < 6; i++)
+		{
+			if((a->SrcMacAddress[i] & a->SrcMacMask[i]) != (a->SrcMacMask[i] & p->MacAddressSrc[i]))
+			{
+				return false;
+			}
+		}
+	}
+
+	if (a->CheckDstMac != false)
+	{
+		UINT i;
+		for (i = 0; i < 6; i++)
+		{
+			if ((a->DstMacAddress[i] & a->DstMacMask[i]) != (a->DstMacMask[i] & p->MacAddressDest[i]))
+			{
+				return false;
+			}
+		}
+	}
+
+	// 送信元ユーザー名 / グループ名のチェック
+	if (a->SrcUsernameHash != 0)
+	{
+		if ((a->SrcUsernameHash != src_username) && (a->SrcUsernameHash != src_groupname))
+		{
+			return false;
+		}
+	}
+
+	// 宛先ユーザー名 / グループ名のチェック
+	if (a->DestUsernameHash != 0)
+	{
+		if ((a->DestUsernameHash != dest_username) && (a->DestUsernameHash != dest_groupname))
+		{
+			return false;
+		}
+	}
+
+	// IP パケットの判定
+	if (p->TypeL3 != L3_IPV4)
+	{
+		is_ipv4_packet = false;
+	}
+	else
+	{
+		is_ipv4_packet = true;
+	}
+
+	if (p->TypeL3 != L3_IPV6)
+	{
+		is_ipv6_packet = false;
+	}
+	else
+	{
+		is_ipv6_packet = true;
+	}
+
+	if (is_ipv4_packet)
+	{
+		ip = p->L3.IPv4Header;
+	}
+
+	if (is_ipv6_packet)
+	{
+		ip6 = p->L3.IPv6Header;
+	}
+
+	if (a->IsIPv6 == false)
+	{
+		// IPv4
+
+		// 送信元 IP アドレスのチェック
+		if (a->SrcIpAddress != 0 || a->SrcSubnetMask != 0)
+		{
+			if (is_ipv4_packet == false)
+			{
+				if (p->TypeL3 == L3_ARPV4)
+				{
+					bool arp_match = false;
+					if (p->L3.ARPv4Header->HardwareSize == 6 &&
+						Endian16(p->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+						p->L3.ARPv4Header->ProtocolSize == 4 &&
+						Endian16(p->L3.ARPv4Header->ProtocolType) == 0x0800)
+					{
+						UINT uint_ip = p->L3.ARPv4Header->SrcIP;
+
+						if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(p->MacAddressSrc)))
+						{
+							if ((uint_ip & a->SrcSubnetMask) != (a->SrcIpAddress & a->SrcSubnetMask))
+							{
+							}
+							else
+							{
+								arp_match = true;
+							}
+						}
+					}
+
+					if (arp_match == false)
+					{
+						return false;
+					}
+				}
+				else
+				{
+					return false;
+				}
+			}
+			else
+			{
+				if ((ip->SrcIP & a->SrcSubnetMask) != (a->SrcIpAddress & a->SrcSubnetMask))
+				{
+					return false;
+				}
+			}
+		}
+
+		// 宛先 IP アドレスのチェック
+		if (a->DestIpAddress != 0 || a->DestSubnetMask != 0)
+		{
+			if (is_ipv4_packet == false)
+			{
+				if (p->TypeL3 == L3_ARPV4)
+				{
+					bool arp_match = false;
+					if (p->L3.ARPv4Header->HardwareSize == 6 &&
+						Endian16(p->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+						p->L3.ARPv4Header->ProtocolSize == 4 &&
+						Endian16(p->L3.ARPv4Header->ProtocolType) == 0x0800)
+					{
+						UINT uint_ip = p->L3.ARPv4Header->TargetIP;
+
+						if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(p->MacAddressSrc)))
+						{
+							if ((uint_ip & a->DestSubnetMask) != (a->DestIpAddress & a->DestSubnetMask))
+							{
+							}
+							else
+							{
+								arp_match = true;
+							}
+						}
+					}
+
+					if (arp_match == false)
+					{
+						return false;
+					}
+				}
+				else
+				{
+					return false;
+				}
+			}
+			else
+			{
+				if ((ip->DstIP & a->DestSubnetMask) != (a->DestIpAddress & a->DestSubnetMask))
+				{
+					return false;
+				}
+			}
+		}
+	}
+	else
+	{
+		// IPv6
+
+		// 送信元 IP アドレスのチェック
+		if (IsZeroIP6Addr(&a->SrcIpAddress6) == false ||
+			IsZeroIP6Addr(&a->SrcSubnetMask6) == false)
+		{
+			if (is_ipv6_packet == false)
+			{
+				return false;
+			}
+			else
+			{
+				IP a_ip, a_subnet, p_ip;
+				IP and1, and2;
+
+				IPv6AddrToIP(&a_ip, &a->SrcIpAddress6);
+				IPv6AddrToIP(&a_subnet, &a->SrcSubnetMask6);
+				IPv6AddrToIP(&p_ip, &ip6->SrcAddress);
+
+				IPAnd6(&and1, &a_ip, &a_subnet);
+				IPAnd6(&and2, &p_ip, &a_subnet);
+
+				if (CmpIpAddr(&and1, &and2) != 0)
+				{
+					return false;
+				}
+			}
+		}
+
+		// 宛先 IP アドレスのチェック
+		if (IsZeroIP6Addr(&a->DestIpAddress6) == false ||
+			IsZeroIP6Addr(&a->DestSubnetMask6) == false)
+		{
+			if (is_ipv6_packet == false)
+			{
+				return false;
+			}
+			else
+			{
+				IP a_ip, a_subnet, p_ip;
+				IP and1, and2;
+
+				IPv6AddrToIP(&a_ip, &a->DestIpAddress6);
+				IPv6AddrToIP(&a_subnet, &a->DestSubnetMask6);
+				IPv6AddrToIP(&p_ip, &ip6->DestAddress);
+
+				IPAnd6(&and1, &a_ip, &a_subnet);
+				IPAnd6(&and2, &p_ip, &a_subnet);
+
+				if (CmpIpAddr(&and1, &and2) != 0)
+				{
+					return false;
+				}
+			}
+		}
+	}
+
+	// IPv4 でも IPv6 でもないパケットはマッチさせない。
+	if(is_ipv4_packet == false && is_ipv6_packet==false){
+		return false;
+	}
+
+	// プロトコル番号のチェック
+	if (a->Protocol != 0)
+	{
+		if (a->IsIPv6 == false)
+		{
+			if (is_ipv4_packet == false)
+			{
+				return false;
+			}
+			else
+			{
+				if (ip->Protocol != a->Protocol)
+				{
+					return false;
+				}
+			}
+		}
+		else
+		{
+			if (is_ipv6_packet == false)
+			{
+				return false;
+			}
+			else
+			{
+				if (p->IPv6HeaderPacketInfo.Protocol != a->Protocol)
+				{
+					return false;
+				}
+			}
+		}
+	}
+
+	// ポート番号のチェック
+	if (a->SrcPortStart != 0 || a->DestPortStart != 0 ||
+		a->SrcPortEnd != 0 || a->DestPortEnd != 0)
+	{
+		if ((a->IsIPv6 == false && is_ipv4_packet == false) ||
+			(a->IsIPv6 && is_ipv6_packet == false))
+		{
+			return false;
+		}
+		else
+		{
+			if (p->TypeL4 == L4_TCP)
+			{
+				TCP_HEADER *tcp = p->L4.TCPHeader;
+				// 送信元ポートのチェック
+				if (a->SrcPortStart != 0 || a->SrcPortEnd != 0)
+				{
+					UINT src_port = Endian16(tcp->SrcPort);
+					if (src_port < a->SrcPortStart || src_port > a->SrcPortEnd)
+					{
+						return false;
+					}
+				}
+
+				// 宛先ポート番号のチェック
+				if (a->DestPortStart != 0 || a->DestPortEnd != 0)
+				{
+					UINT dest_port = Endian16(tcp->DstPort);
+					if (dest_port < a->DestPortStart || dest_port > a->DestPortEnd)
+					{
+						return false;
+					}
+				}
+			}
+			else if (p->TypeL4 == L4_UDP)
+			{
+				UDP_HEADER *udp = p->L4.UDPHeader;
+				// 送信元ポートのチェック
+				if (a->SrcPortStart != 0 || a->SrcPortEnd != 0)
+				{
+					UINT src_port = Endian16(udp->SrcPort);
+					if (src_port < a->SrcPortStart || src_port > a->SrcPortEnd)
+					{
+						return false;
+					}
+				}
+
+				// 宛先ポート番号のチェック
+				if (a->DestPortStart != 0 || a->DestPortEnd != 0)
+				{
+					UINT dest_port = Endian16(udp->DstPort);
+					if (dest_port < a->DestPortStart || dest_port > a->DestPortEnd)
+					{
+						return false;
+					}
+				}
+			}
+			else
+			{
+				// アクセスリストにポート番号が指定されているときは
+				// TCP か UDP 以外のパケットは適用されない
+				return false;
+			}
+		}
+	}
+
+	// TCP コネクションの状態チェック
+	if (a->CheckTcpState != false)
+	{
+		if ((a->IsIPv6 == false && is_ipv4_packet == false) ||
+			(a->IsIPv6 && is_ipv6_packet == false))
+		{
+			return false;
+		}
+		else
+		{
+			if(p->TypeL4 == L4_TCP)
+			{
+				// by shimizu
+				TCP_HEADER *tcp = p->L4.TCPHeader;
+				bool est = true;
+
+				if (tcp->Flag & TCP_SYN)
+				{
+					est = false;
+				}
+
+				if((MAKEBOOL(a->Established) ^ MAKEBOOL(est)))
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+// フォワードするパケットに対してアクセスリストを適用する
+bool ApplyAccessListToForwardPacket(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *p)
+{
+	UINT i;
+	bool pass = true;	// デフォルトでは通過させる
+	bool skip = true;
+	// 引数チェック
+	if (hub == NULL || src_session == NULL || p == NULL || dest_session == NULL)
+	{
+		return false;
+	}
+
+	// 既にチェックされたパケットはアクセスリストを再適用しない。
+	if (p->AccessChecked)
+	{
+		return true;
+	}
+
+	LockList(hub->AccessList);
+	{
+		for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+		{
+			ACCESS *a = LIST_DATA(hub->AccessList, i);
+
+			// あて先ユーザー名が指定されているエントリ以降のみを走査する。
+			if (a->DestUsernameHash != 0)
+			{
+				skip = false;
+			}
+
+			if (skip == false)
+			{
+				if (IsPacketMaskedByAccessList(src_session, p, a,
+					((HUB_PA *)dest_session->PacketAdapter->Param)->UsernameHash,
+					((HUB_PA *)dest_session->PacketAdapter->Param)->GroupnameHash))
+				{
+					// パケットの通過または破棄を決定する
+					pass = a->Discard ? false : true;
+
+					// リストの走査をここで完了する
+					break;
+				}
+			}
+		}
+	}
+	UnlockList(hub->AccessList);
+
+	return pass;
+}
+
+// ストアされたパケットに対してアクセスリストを適用する
+bool ApplyAccessListToStoredPacket(HUB *hub, SESSION *s, PKT *p)
+{
+	UINT i;
+	bool pass = true;	// デフォルトでは通過させる
+	// 引数チェック
+	if (hub == NULL || s == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	if (hub->Option != NULL && hub->Option->FilterPPPoE)
+	{
+		if (p->MacHeader != NULL)
+		{
+			USHORT proto = Endian16(p->MacHeader->Protocol);
+			if (proto == 0x8863 || proto == 0x8864)
+			{
+				// PPPoE Filter
+				return false;
+			}
+		}
+	}
+
+	if (hub->Option != NULL && hub->Option->FilterOSPF)
+	{
+		if (p->TypeL3 == L3_IPV4)
+		{
+			if (p->L3.IPv4Header != NULL)
+			{
+				if (p->L3.IPv4Header->Protocol == 89)
+				{
+					// OSPF Filter
+					return false;
+				}
+			}
+		}
+	}
+
+	if (hub->Option != NULL && hub->Option->FilterIPv4)
+	{
+		if (p->MacHeader != NULL)
+		{
+			USHORT proto = Endian16(p->MacHeader->Protocol);
+			if (proto == 0x0800 || proto == 0x0806)
+			{
+				// IPv4 Filter
+				return false;
+			}
+		}
+	}
+
+	if (hub->Option != NULL && hub->Option->FilterIPv6)
+	{
+		if (p->MacHeader != NULL)
+		{
+			USHORT proto = Endian16(p->MacHeader->Protocol);
+			if (proto == 0x86dd)
+			{
+				// IPv6 Filter
+				return false;
+			}
+		}
+	}
+
+	if (hub->Option != NULL && hub->Option->FilterNonIP)
+	{
+		if (p->MacHeader != NULL)
+		{
+			USHORT proto = Endian16(p->MacHeader->Protocol);
+			if (!(proto == 0x86dd || proto == 0x0800 || proto == 0x0806))
+			{
+				// Non-IP Filter
+				return false;
+			}
+		}
+	}
+
+	if (hub->Option != NULL && hub->Option->FilterBPDU)
+	{
+		if (p->MacHeader != NULL)
+		{
+			if (p->TypeL3 == L3_BPDU)
+			{
+				// BPDU Filter
+				return false;
+			}
+		}
+	}
+
+	LockList(hub->AccessList);
+	{
+		for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+		{
+			ACCESS *a = LIST_DATA(hub->AccessList, i);
+
+			if (a->DestUsernameHash != 0)
+			{
+				// あて先ユーザー名が指定されていたら、そこでリストの走査を中断する。
+				break;
+			}
+
+			if (IsPacketMaskedByAccessList(s, p, a, 0, 0))
+			{
+				// パケットの通過または破棄を決定する
+				pass = a->Discard ? false : true;
+
+				// ここで処理が決定したパケットはHUBを出るときに走査しない。
+				p->AccessChecked = true;
+
+				// 遅延・ジッタ・パケットロスのパラメータのコピー
+				p->Delay = a->Delay;
+				p->Jitter = a->Jitter;
+				p->Loss = a->Loss;
+
+				// リストの走査をここで完了する
+				break;
+			}
+		}
+	}
+	UnlockList(hub->AccessList);
+
+	return pass;
+}
+
+// アクセスリストの追加
+void AddAccessList(HUB *hub, ACCESS *a)
+{
+	// 引数チェック
+	if (hub == NULL || a == NULL)
+	{
+		return;
+	}
+
+	LockList(hub->AccessList);
+	{
+		ACCESS *access;
+		UINT i;
+
+		// 個数のチェック
+		if (LIST_NUM(hub->AccessList) >= MAX_ACCESSLISTS)
+		{
+			UnlockList(hub->AccessList);
+			return;
+		}
+
+		access = Malloc(sizeof(ACCESS));
+		Copy(access, a, sizeof(ACCESS));
+		access->SrcUsernameHash = UsernameToInt(access->SrcUsername);
+		access->DestUsernameHash = UsernameToInt(access->DestUsername);
+
+		// ポート番号補正
+		if (access->SrcPortStart != 0)
+		{
+			access->SrcPortEnd = MAX(access->SrcPortEnd, access->SrcPortStart);
+		}
+		if (access->DestPortStart != 0)
+		{
+			access->DestPortEnd = MAX(access->DestPortEnd, access->DestPortStart);
+		}
+
+		// 遅延、ジッタ、パケットロスの補正
+		access->Delay = MAKESURE(access->Delay, 0, HUB_ACCESSLIST_DELAY_MAX);
+		access->Jitter = MAKESURE(access->Jitter, 0, HUB_ACCESSLIST_JITTER_MAX);
+		access->Loss = MAKESURE(access->Loss, 0, HUB_ACCESSLIST_LOSS_MAX);
+
+		Insert(hub->AccessList, access);
+
+		// ID を振り直す
+		for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+		{
+			ACCESS *a = LIST_DATA(hub->AccessList, i);
+			a->Id = (i + 1);
+		}
+	}
+	UnlockList(hub->AccessList);
+}
+
+// アクセスリストの初期化
+void InitAccessList(HUB *hub)
+{
+	// 引数チェック
+	if (hub == NULL)
+	{
+		return;
+	}
+
+	hub->AccessList = NewList(CmpAccessList);
+}
+
+// アクセスリストの解放
+void FreeAccessList(HUB *hub)
+{
+	UINT i;
+	// 引数チェック
+	if (hub == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+	{
+		ACCESS *a = LIST_DATA(hub->AccessList, i);
+		Free(a);
+	}
+
+	ReleaseList(hub->AccessList);
+	hub->AccessList = NULL;
+}
+
+// アクセスリストの比較
+int CmpAccessList(void *p1, void *p2)
+{
+	ACCESS *a1, *a2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	a1 = *(ACCESS **)p1;
+	a2 = *(ACCESS **)p2;
+	if (a1 == NULL || a2 == NULL)
+	{
+		return 0;
+	}
+	// 優先順位別にソートする
+	if (a1->Priority > a2->Priority)
+	{
+		return 1;
+	}
+	else if (a1->Priority < a2->Priority)
+	{
+		return -1;
+	}
+	else if (a1->Discard > a2->Discard)
+	{
+		return 1;
+	}
+	else if (a1->Discard < a2->Discard)
+	{
+		return -1;
+	}
+	else
+	{
+		return Cmp(&a1->Active, &a2->Active, sizeof(ACCESS) - 4);
+	}
+}
+
+// ユーザー名を UINT に変換
+UINT UsernameToInt(char *name)
+{
+	UCHAR hash[SHA1_SIZE];
+	UINT ret;
+	char tmp[MAX_USERNAME_LEN + 1];
+	// 引数チェック
+	if (name == 0 || StrLen(name) == 0)
+	{
+		return 0;
+	}
+
+	StrCpy(tmp, sizeof(tmp), name);
+	Trim(tmp);
+	StrUpper(tmp);
+
+	if (StrLen(tmp) == 0)
+	{
+		return 0;
+	}
+
+	Hash(hash, tmp, StrLen(tmp), true);
+	Copy(&ret, hash, sizeof(ret));
+
+	return ret;
+}
+
+// セッションポインタからセッションを検索
+SESSION *GetSessionByPtr(HUB *hub, void *ptr)
+{
+	// 引数チェック
+	if (hub == NULL || ptr == NULL)
+	{
+		return NULL;
+	}
+
+	LockList(hub->SessionList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(hub->SessionList);i++)
+		{
+			SESSION *s = LIST_DATA(hub->SessionList, i);
+			if (s == (SESSION *)ptr)
+			{
+				// 発見
+				AddRef(s->ref);
+				UnlockList(hub->SessionList);
+				return s;
+			}
+		}
+	}
+	UnlockList(hub->SessionList);
+
+	return NULL;
+}
+
+// セッション名からセッションを検索
+SESSION *GetSessionByName(HUB *hub, char *name)
+{
+	// 引数チェック
+	if (hub == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	LockList(hub->SessionList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(hub->SessionList);i++)
+		{
+			SESSION *s = LIST_DATA(hub->SessionList, i);
+			if (StrCmpi(s->Name, name) == 0)
+			{
+				// 発見
+				AddRef(s->ref);
+				UnlockList(hub->SessionList);
+				return s;
+			}
+		}
+	}
+	UnlockList(hub->SessionList);
+
+	return NULL;
+}
+
+// STORM リストのソート
+int CompareStormList(void *p1, void *p2)
+{
+	STORM *s1, *s2;
+	UINT r;
+	// 引数チェック
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(STORM **)p1;
+	s2 = *(STORM **)p2;
+	if (s1 == NULL || s2 == NULL)
+	{
+		return 0;
+	}
+	r = CmpIpAddr(&s1->DestIp, &s2->DestIp);
+	if (r != 0)
+	{
+		return r;
+	}
+	r = CmpIpAddr(&s1->SrcIp, &s2->SrcIp);
+	if (r != 0)
+	{
+		return r;
+	}
+	r = Cmp(s1->MacAddress, s2->MacAddress, 6);
+	return r;
+}
+
+// パケットアダプタ初期化
+bool HubPaInit(SESSION *s)
+{
+	// パケットアダプタ情報の初期化
+	HUB_PA *pa = ZeroMalloc(sizeof(HUB_PA));
+	pa->Cancel = NewCancel();
+	pa->PacketQueue = NewQueue();
+	pa->Now = Tick64();
+	pa->Session = s;
+	pa->StormList = NewList(CompareStormList);
+	pa->UsernameHash = UsernameToInt(s->Username);
+	pa->GroupnameHash = UsernameToInt(s->GroupName);
+
+	s->PacketAdapter->Param = pa;
+
+	if (s->Policy->MonitorPort)
+	{
+		// このポートをモニタリングポートとしてマークする
+		pa->MonitorPort = true;
+
+		// HUB のモニタリングポート一覧にこのセッションを追加する
+		LockList(s->Hub->MonitorList);
+		{
+			Insert(s->Hub->MonitorList, s);
+		}
+		UnlockList(s->Hub->MonitorList);
+	}
+
+	return true;
+}
+
+// パケットアダプタ解放
+void HubPaFree(SESSION *s)
+{
+	HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+	HUB *hub = s->Hub;
+
+	if (pa->MonitorPort)
+	{
+		// HUB のモニタポート一覧からこのセッションを削除する
+		LockList(s->Hub->MonitorList);
+		{
+			Delete(s->Hub->MonitorList, s);
+		}
+		UnlockList(s->Hub->MonitorList);
+	}
+
+	// このセッションに関連付けられている MAC アドレステーブルを消去
+	LockList(hub->MacTable);
+	{
+		UINT i, num = LIST_NUM(hub->MacTable);
+		LIST *o = NewListFast(NULL);
+		for (i = 0;i < num;i++)
+		{
+			MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)LIST_DATA(hub->MacTable, i);
+			if (e->Session == s)
+			{
+				Add(o, e);
+			}
+		}
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)LIST_DATA(o, i);
+			Delete(hub->MacTable, e);
+			Free(e);
+		}
+		ReleaseList(o);
+	}
+	{
+		UINT i, num = LIST_NUM(hub->IpTable);
+		LIST *o = NewListFast(NULL);
+		for (i = 0;i < num;i++)
+		{
+			IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+			if (e->Session == s)
+			{
+				Add(o, e);
+			}
+		}
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+			Delete(hub->IpTable, e);
+			Free(e);
+		}
+		ReleaseList(o);
+	}
+	UnlockList(hub->MacTable);
+
+	// STORM リストを解放
+	LockList(pa->StormList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(pa->StormList);i++)
+		{
+			STORM *s = (STORM *)LIST_DATA(pa->StormList, i);
+			Free(s);
+		}
+		DeleteAll(pa->StormList);
+	}
+	UnlockList(pa->StormList);
+
+	ReleaseList(pa->StormList);
+
+	// キューに残っているパケットを解放
+	LockQueue(pa->PacketQueue);
+	{
+		BLOCK *b;
+
+		while (b = GetNext(pa->PacketQueue))
+		{
+			// ブロックの解放
+			FreeBlock(b);
+		}
+	}
+	UnlockQueue(pa->PacketQueue);
+
+	// キューを解放
+	ReleaseQueue(pa->PacketQueue);
+
+	// キャンセルオブジェクトの解放
+	ReleaseCancel(pa->Cancel);
+
+	// パケットアダプタ情報の解放
+	Free(pa);
+	s->PacketAdapter->Param = NULL;
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *HubPaGetCancel(SESSION *s)
+{
+	HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+
+	AddRef(pa->Cancel->ref);
+	return pa->Cancel;
+}
+
+// 次の送信予定パケットの取得
+UINT HubPaGetNextPacket(SESSION *s, void **data)
+{
+	UINT ret = 0;
+	HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+
+	// キューの先頭から 1 つ取得する
+	LockQueue(pa->PacketQueue);
+	{
+		BLOCK *block = GetNext(pa->PacketQueue);
+		if (block == NULL)
+		{
+			// キュー無し
+			ret = 0;
+		}
+		else
+		{
+			// あった
+			*data = block->Buf;
+			ret = block->Size;
+			// ブロックの構造体のメモリは解放する
+			Free(block);
+		}
+	}
+	UnlockQueue(pa->PacketQueue);
+
+	return ret;
+}
+
+// パケットの受信
+bool HubPaPutPacket(SESSION *s, void *data, UINT size)
+{
+	PKT *packet;
+	HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+	bool b = false;
+	HUB *hub;
+	bool no_l3 = false;
+	LIST *o = NULL;
+	UINT i;
+	UINT vlan_type_id = 0;
+	bool no_look_bpdu_bridge_id = false;
+
+	hub = s->Hub;
+
+	pa->Now = Tick64();
+
+	if (data == NULL)
+	{
+		// 遅延パケットのチェック
+		o = NULL;
+		LockList(s->DelayedPacketList);
+		{
+			UINT i;
+			if (LIST_NUM(s->DelayedPacketList) >= 1)
+			{
+				UINT64 now = TickHighres64();
+				for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
+				{
+					PKT *p = LIST_DATA(s->DelayedPacketList, i);
+
+					if (now >= p->DelayedForwardTick)
+					{
+						if (o == NULL)
+						{
+							o = NewListFast(NULL);
+						}
+
+						Add(o, p);
+					}
+				}
+			}
+
+			if (o != NULL)
+			{
+				for (i = 0;i < LIST_NUM(o);i++)
+				{
+					PKT *p = LIST_DATA(o, i);
+
+					Delete(s->DelayedPacketList, p);
+				}
+			}
+		}
+		UnlockList(s->DelayedPacketList);
+
+		// 遅延パケットがある場合はストアする
+		if (o != NULL)
+		{
+			for (i = 0;i < LIST_NUM(o);i++)
+			{
+				PKT *p = LIST_DATA(o, i);
+
+				StorePacket(s->Hub, s, p);
+			}
+
+			ReleaseList(o);
+		}
+
+		// このセッションからのすべてのパケットの受信が完了した
+		CancelList(s->CancelList);
+
+		// イールドする
+		if (hub->Option != NULL && hub->Option->YieldAfterStorePacket)
+		{
+			YieldCpu();
+		}
+
+		return true;
+	}
+
+	if (hub != NULL && hub->Option != NULL && hub->Option->DisableIPParsing)
+	{
+		no_l3 = true;
+	}
+
+	if (hub != NULL && hub->Option != NULL)
+	{
+		vlan_type_id = hub->Option->VlanTypeId;
+		no_look_bpdu_bridge_id = hub->Option->NoLookBPDUBridgeId;
+	}
+
+	// VLAN タグを挿入する
+	if (s->VLanId != 0)
+	{
+		VLanInsertTag(&data, &size, s->VLanId);
+	}
+
+	// パケットをパースする
+	packet = ParsePacketEx3(data, size, no_l3, vlan_type_id, !no_look_bpdu_bridge_id);
+
+	if (packet != NULL)
+	{
+		if (packet->InvalidSourcePacket)
+		{
+			// 不正な送信元のパケット
+			FreePacket(packet);
+			packet = NULL;
+		}
+	}
+
+	if (packet != NULL)
+	{
+		// パケットのストア
+		StorePacket(s->Hub, s, packet);
+	}
+	else
+	{
+		// 不良パケット (正しい MAC フレームではない)
+		// であるのでパケットデータを解放する
+		Free(data);
+	}
+
+	return true;
+}
+
+// ブロードキャストストームが発生しないようにチェックするアルゴリズム
+// 特定のエンドポイントからのブロードキャストが頻繁に来た場合はフィルタリングする
+bool CheckBroadcastStorm(SESSION *s, PKT *p)
+{
+	IP src_ip, dest_ip;
+	HUB_PA *pa;
+	UINT64 now = Tick64();
+	UINT limit_start_count;
+	SESSION *sess = s;
+	bool ret = true;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	if (s->Policy->NoBroadcastLimiter)
+	{
+		// ブロードキャスト数の制限無し
+		return true;
+	}
+
+	pa = (HUB_PA *)s->PacketAdapter->Param;
+
+	if (p->TypeL3 == L3_IPV4)
+	{
+		UINTToIP(&src_ip, p->L3.IPv4Header->SrcIP);
+		UINTToIP(&dest_ip, p->L3.IPv4Header->DstIP);
+	}
+	else if (p->TypeL3 == L3_ARPV4)
+	{
+		UINTToIP(&src_ip, p->L3.ARPv4Header->SrcIP);
+		Zero(&dest_ip, sizeof(IP));
+	}
+	else if (p->TypeL3 == L3_IPV6)
+	{
+		IPv6AddrToIP(&src_ip, &p->L3.IPv6Header->SrcAddress);
+		IPv6AddrToIP(&dest_ip, &p->L3.IPv6Header->DestAddress);
+	}
+	else
+	{
+		Zero(&src_ip, sizeof(IP));
+		Zero(&dest_ip, sizeof(IP));
+	}
+
+	// 1 間隔ごとに制限を開始する個数
+	limit_start_count = 32;
+
+	if (s->Hub != NULL && s->Hub->Option->BroadcastStormDetectionThreshold != 0)
+	{
+		limit_start_count = s->Hub->Option->BroadcastStormDetectionThreshold;
+	}
+
+	LockList(pa->StormList);
+	{
+		STORM *s;
+		UINT num;
+		s = SearchStormList(pa, p->MacAddressSrc, &src_ip, &dest_ip);
+		if (s == NULL)
+		{
+			s = AddStormList(pa, p->MacAddressSrc, &src_ip, &dest_ip);
+		}
+
+		s->CurrentBroadcastNum++;
+
+		if ((s->CheckStartTick + STORM_CHECK_SPAN) < now ||
+			s->CheckStartTick == 0 || s->CheckStartTick > now)
+		{
+			// 一定期間ごとにブロードキャスト数を計測する
+			UINT64 diff_time;
+			if (s->CheckStartTick < now)
+			{
+				diff_time = now - s->CheckStartTick;
+			}
+			else
+			{
+				diff_time = 0;
+			}
+			s->CheckStartTick = now;
+			num = (UINT)((UINT64)s->CurrentBroadcastNum * (UINT64)1000 / (UINT64)STORM_CHECK_SPAN);
+			s->CurrentBroadcastNum = 0;
+			if (num >= limit_start_count)
+			{
+				char ip1[64];
+				char ip2[64];
+				char mac[MAX_SIZE];
+				IPToStr(ip1, sizeof(ip1), &src_ip);
+				IPToStr(ip2, sizeof(ip2), &dest_ip);
+				ret = false;
+				if (s->DiscardValue < STORM_DISCARD_VALUE_END)
+				{
+					s->DiscardValue = MAX(s->DiscardValue, 1) * 2;
+				}
+				Debug("s->DiscardValue: %u  (%u)\n", s->DiscardValue, num);
+
+				MacToStr(mac, sizeof(mac), p->MacAddressSrc);
+
+				HLog(sess->Hub, "LH_BCAST_STORM", sess->Name, mac, ip1, ip2, num);
+			}
+			else
+			{
+				if (s->DiscardValue >= 1)
+				{
+					s->DiscardValue = (UINT)((UINT64)s->DiscardValue / MAX((UINT64)2, (UINT64)diff_time / (UINT64)STORM_CHECK_SPAN));
+				}
+			}
+		}
+
+		if (s->DiscardValue >= STORM_DISCARD_VALUE_START)
+		{
+			if (s->DiscardValue >= 128)
+			{
+				ret = false;
+			}
+			else if ((rand() % s->DiscardValue) != 0)
+			{
+				ret = false;
+			}
+		}
+
+	}
+	UnlockList(pa->StormList);
+
+	return ret;
+}
+
+// パケットのストア
+void StorePacket(HUB *hub, SESSION *s, PKT *packet)
+{
+	MAC_TABLE_ENTRY *entry = NULL;
+	MAC_TABLE_ENTRY t;
+	void *data;
+	UINT size;
+	bool broadcast_mode;
+	HUB_PA *dest_pa;
+	SESSION *dest_session;
+	TRAFFIC traffic;
+	UINT64 now = Tick64();
+	// 引数チェック
+	if (hub == NULL || packet == NULL)
+	{
+		return;
+	}
+
+	if (s != NULL)
+	{
+		if (((HUB_PA *)s->PacketAdapter->Param)->MonitorPort)
+		{
+			// モニタポートからもらったパケットはフォワードしてはならない
+			Free(packet->PacketData);
+			FreePacket(packet);
+			return;
+		}
+	}
+
+	// MAC アドレステーブル全体をロック
+	LockList(hub->MacTable);
+	{
+		// フィルタリング
+		if (s != NULL && (packet->DelayedForwardTick == 0 && StorePacketFilter(s, packet) == false))
+		{
+DISCARD_PACKET:
+			// 通過が不許可となったのでパケットを解放する
+			Free(packet->PacketData);
+			FreePacket(packet);
+		}
+		else // 通過が許可された
+		{
+			bool forward_now = true;
+
+			if (packet->Loss >= 1)
+			{
+				// パケットロスを発生させる
+				UINT r = rand() % 100;
+				if ((packet->Loss >= 100) || (r < packet->Loss))
+				{
+					// パケットロス
+					goto DISCARD_PACKET;
+				}
+			}
+
+			if (packet->Delay >= 1)
+			{
+				float delay = (float)packet->Delay;
+				float jitter;
+				UINT delay_uint;
+				bool f = Rand1();
+				if (packet->Jitter == 0)
+				{
+					jitter = 0;
+				}
+				else
+				{
+					jitter = (float)(Rand32() % (int)((float)packet->Jitter * delay / 100.0f));
+				}
+
+				delay += jitter * (f ? 1 : -1);
+				delay_uint = (UINT)delay;
+
+				if (delay_uint >= 1)
+				{
+					// 遅延を発生させる
+					forward_now = false;
+					packet->Loss = packet->Jitter = packet->Delay = 0;
+					packet->DelayedForwardTick = TickHighres64() + (UINT64)delay_uint;
+					packet->DelayedSrcSession = s;
+
+					LockList(s->DelayedPacketList);
+					{
+						Add(s->DelayedPacketList, packet);
+					}
+					UnlockList(s->DelayedPacketList);
+				}
+			}
+
+			if (forward_now)
+			{
+				if (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) == 0)
+				{
+					if (s != NULL)
+					{
+						// この HUB 自身が発信しようとしたパケットが外部から入力された
+						goto DISCARD_PACKET;
+					}
+				}
+				if (s != NULL && (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) != 0))
+				{
+					// 送信元 MAC アドレスがテーブルに登録されているかどうか調べる
+					Copy(t.MacAddress, packet->MacAddressSrc, 6);
+					if (hub->Option->NoManageVlanId == false)
+					{
+						t.VlanId = packet->VlanId;
+					}
+					else
+					{
+						t.VlanId = 0;
+					}
+					entry = Search(hub->MacTable, &t);
+
+					if (entry == NULL)
+					{
+						// 古いエントリを削除する
+						DeleteExpiredMacTableEntry(hub->MacTable);
+
+						// 登録されていないので登録する
+						if (s->Policy->MaxMac != 0 || s->Policy->NoBridge)
+						{
+							UINT i, num_mac_for_me = 0;
+							UINT limited_count;
+
+							// 現在このセッションで登録されている MAC アドレス数を調べる
+							for (i = 0;i < LIST_NUM(hub->MacTable);i++)
+							{
+								MAC_TABLE_ENTRY *e = LIST_DATA(hub->MacTable, i);
+								if (e->Session == s)
+								{
+									num_mac_for_me++;
+								}
+							}
+
+							limited_count = 0xffffffff;
+							if (s->Policy->NoBridge)
+							{
+								limited_count = MIN(limited_count, MAC_MIN_LIMIT_COUNT);
+							}
+							if (s->Policy->MaxMac != 0)
+							{
+								limited_count = MIN(limited_count, s->Policy->MaxMac);
+							}
+							limited_count = MAX(limited_count, MAC_MIN_LIMIT_COUNT);
+
+							if (num_mac_for_me >= limited_count)
+							{
+								// すでに登録されている MAC アドレス数が上限を超えている
+								char mac_str[64];
+
+								if (s != NULL)
+								{
+									MacToStr(mac_str, sizeof(mac_str), packet->MacAddressSrc);
+									if (s->Policy->NoBridge)
+									{
+										HLog(hub, "LH_BRIDGE_LIMIT", s->Name, mac_str, num_mac_for_me, limited_count);
+									}
+									else
+									{
+										HLog(hub, "LH_MAC_LIMIT", s->Name, mac_str, num_mac_for_me, limited_count);
+									}
+								}
+
+								goto DISCARD_PACKET;	// パケット破棄
+							}
+						}
+
+						if (LIST_NUM(hub->MacTable) >= MAX_MAC_TABLES)
+						{
+							// MAC テーブルデータベースが最大件数を超えたので
+							// 最も古いテーブルを削除する
+							UINT i;
+							UINT64 old_time = 0xffffffffffffffffULL;
+							MAC_TABLE_ENTRY *old_entry = NULL;
+							for (i = 0;i < LIST_NUM(hub->MacTable);i++)
+							{
+								MAC_TABLE_ENTRY *e = LIST_DATA(hub->MacTable, i);
+								if (e->UpdatedTime <= old_time)
+								{
+									old_time = e->CreatedTime;
+									old_entry = e;
+								}
+							}
+							if (old_entry != NULL)
+							{
+								Delete(hub->MacTable, old_entry);
+								Free(old_entry);
+							}
+						}
+
+						entry = ZeroMalloc(sizeof(MAC_TABLE_ENTRY));
+						entry->HubPa = (HUB_PA *)s->PacketAdapter->Param;
+						Copy(entry->MacAddress, packet->MacAddressSrc, 6);
+						if (hub->Option->NoManageVlanId == false)
+						{
+							entry->VlanId = packet->VlanId;
+						}
+						else
+						{
+							entry->VlanId = 0;
+						}
+						entry->Session = s;
+						entry->UpdatedTime = entry->CreatedTime = now;
+
+						Insert(hub->MacTable, entry);
+
+						if (hub->Option->NoMacAddressLog == false)
+						{
+							// デバッグ表示
+							char mac_address[32];
+
+							if (s != NULL)
+							{
+								MacToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc);
+//								Debug("Register MAC Address %s to Session %X.\n", mac_address, s);
+
+								if (packet->VlanId == 0)
+								{
+									HLog(hub, "LH_MAC_REGIST", s->Name, mac_address);
+								}
+								else
+								{
+									HLog(hub, "LH_MAC_REGIST_VLAN", s->Name, mac_address, packet->VlanId);
+								}
+							}
+						}
+					}
+					else
+					{
+						if (entry->Session == s)
+						{
+							// 既に登録されているので何もしない
+							entry->UpdatedTime = now;
+						}
+						else
+						{
+							// 既に登録されていて自分のセッション以外である
+							if (s->Policy->CheckMac && (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) != 0) &&
+								((entry->UpdatedTime + MAC_TABLE_EXCLUSIVE_TIME) >= now))
+							{
+								UCHAR *mac = packet->MacAddressSrc;
+								if (hub->Option != NULL && hub->Option->FixForDLinkBPDU &&
+									(mac[0] == 0x00 && mac[1] == 0x80 && mac[2] == 0xc8 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00) ||
+									(mac[0] == 0x00 && mac[1] == 0x0d && mac[2] == 0x88 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00))
+								{
+									// D-Link 用バグ対策。D-Link のスパニングツリーパケットは上記アドレスから送出される。
+									// ローカルブリッジ時の CheckMac オプションが悪影響を与えることがある。
+									// そこで例外的に処理。
+									UCHAR hash[MD5_SIZE];
+									UINT64 tick_diff = Tick64() - s->LastDLinkSTPPacketSendTick;
+
+									Hash(hash, packet->PacketData, packet->PacketSize, false);
+
+									if ((s->LastDLinkSTPPacketSendTick != 0) &&
+										(tick_diff < 750ULL) &&
+										(Cmp(hash, s->LastDLinkSTPPacketDataHash, MD5_SIZE) == 0))
+									{
+										// 750ms より前に同一パケットを送信した場合は破棄
+										Debug("D-Link Discard %u\n", (UINT)tick_diff);
+										goto DISCARD_PACKET;	// パケット破棄
+									}
+									else
+									{
+										goto UPDATE_FDB;
+									}
+								}
+								else
+								{
+									if (0)
+									{
+										// CheckMac ポリシーが有効な場合
+										// 別のセッションが同じ MAC アドレスを持っていることは禁止されている
+										// (2 バイト目が 0xAE の場合はこのチェックを行わない)
+										char mac_address[32];
+										BinToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc, 6);
+									}
+								}
+
+								goto DISCARD_PACKET;	// パケット破棄
+							}
+							else
+							{
+								// MAC アドレステーブルのセッションと HUB_PA を書き換える
+								char mac_address[32];
+UPDATE_FDB:
+								BinToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc, 6);
+
+								entry->Session = s;
+								entry->HubPa = (HUB_PA *)s->PacketAdapter->Param;
+								entry->UpdatedTime = entry->CreatedTime = now;
+
+								if (1)
+								{
+									// デバッグ表示
+									char mac_address[32];
+
+									if (s != NULL)
+									{
+										MacToStr(mac_address, sizeof(mac_address), packet->MacHeader->SrcAddress);
+										Debug("Register MAC Address %s to Session %X.\n", mac_address, s);
+										if (packet->VlanId == 0)
+										{
+											HLog(hub, "LH_MAC_REGIST", s->Name, mac_address);
+										}
+										else
+										{
+											HLog(hub, "LH_MAC_REGIST_VLAN", s->Name, mac_address, packet->VlanId);
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+
+				broadcast_mode = false;
+				dest_pa = NULL;
+				dest_session = NULL;
+
+				if (packet->BroadcastPacket)
+				{
+					// ブロードキャストパケット
+					broadcast_mode = true;
+				}
+				else
+				{
+					// 宛先 MAC アドレスがテーブルに登録されているかどうか調べる
+					Copy(t.MacAddress, packet->MacAddressDest, 6);
+					if (hub->Option->NoManageVlanId == false)
+					{
+						t.VlanId = packet->VlanId;
+					}
+					else
+					{
+						t.VlanId = 0;
+					}
+					entry = Search(hub->MacTable, &t);
+
+					if (entry == NULL)
+					{
+						// 宛先が見つからないのでブロードキャストする
+						broadcast_mode = true;
+					}
+					else
+					{
+						if (entry->Session != s)
+						{
+							// 宛先が見つかった
+							dest_pa = entry->HubPa;
+							dest_session = entry->Session;
+						}
+						else
+						{
+							// 宛先が自分自身である不正なパケット
+							goto DISCARD_PACKET;
+						}
+					}
+				}
+
+				if (s != NULL && hub->Option->NoIpTable == false)
+				{
+					if (packet->TypeL3 == L3_IPV6)
+					{
+						// IPv6 パケット
+						IP ip;
+						bool b = true;
+						UINT ip_type;
+						bool dhcp_or_ra = false;
+
+						IPv6AddrToIP(&ip, &packet->L3.IPv6Header->SrcAddress);
+						ip_type = GetIPv6AddrType(&packet->L3.IPv6Header->SrcAddress);
+
+						if (!(ip_type & IPV6_ADDR_UNICAST))
+						{
+							// マルチキャストアドレス
+							b = false;
+						}
+						else if ((ip_type & IPV6_ADDR_LOOPBACK) || (ip_type & IPV6_ADDR_ZERO))
+						{
+							// ループバックアドレスまたは All-Zero アドレス
+							b = false;
+						}
+
+						if (packet->TypeL4 == L4_ICMPV6)
+						{
+							if (packet->ICMPv6HeaderPacketInfo.Type == 133 ||
+								packet->ICMPv6HeaderPacketInfo.Type == 134)
+							{
+								// ICMPv6 RS/RA
+								dhcp_or_ra = true;
+							}
+						}
+						else if (packet->TypeL4 == L4_UDP)
+						{
+							if (Endian16(packet->L4.UDPHeader->DstPort) == 546 ||
+								Endian16(packet->L4.UDPHeader->DstPort) == 547)
+							{
+								// DHCPv6
+								dhcp_or_ra = true;
+							}
+						}
+
+						if (IsHubMacAddress(packet->MacAddressSrc) &&
+							IsHubIpAddress64(&packet->L3.IPv6Header->SrcAddress))
+						{
+							// 仮想 HUB のポーリング用送信元アドレス
+							b = false;
+						}
+
+						if (b)
+						{
+							// ICMPv6 RS/RA および DHCPv6 以外のパケット
+							IP_TABLE_ENTRY t, *e;
+
+							Copy(&t.Ip, &ip, sizeof(IP));
+
+							// 既存のテーブルに登録されているかどうかチェック
+							e = Search(hub->IpTable, &t);
+
+							if (e == NULL)
+							{
+								// 登録されていないので登録する
+								if (s->Policy->NoRoutingV6 || s->Policy->MaxIPv6 != 0)
+								{
+									UINT i, num_ip_for_me = 0;
+									UINT limited_count = 0xffffffff;
+
+									for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+									{
+										IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+										if (e->Session == s)
+										{
+											if (IsIP6(&e->Ip))
+											{
+												num_ip_for_me++;
+											}
+										}
+									}
+
+									if (s->Policy->NoRoutingV6)
+									{
+										limited_count = MIN(limited_count, IP_LIMIT_WHEN_NO_ROUTING_V6);
+									}
+									if (s->Policy->MaxIPv6 != 0)
+									{
+										limited_count = MIN(limited_count, s->Policy->MaxIPv6);
+									}
+									limited_count = MAX(limited_count, IP_MIN_LIMIT_COUNT_V6);
+
+									if (dhcp_or_ra)
+									{
+										limited_count = 0xffffffff;
+									}
+
+									if (num_ip_for_me >= limited_count)
+									{
+										// 使用できる IP アドレスの上限を超えているので
+										// このパケットを破棄する
+										char tmp[64];
+										IPToStr(tmp, sizeof(tmp), &ip);
+										if (s->Policy->NoRoutingV6 == false)
+										{
+											HLog(hub, "LH_IP_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+										}
+										else
+										{
+											HLog(hub, "LH_ROUTING_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+										}
+										goto DISCARD_PACKET;
+									}
+								}
+
+								if (IsIPManagementTargetForHUB(&ip, hub))
+								{
+									// エントリ作成
+									e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+									e->CreatedTime = e->UpdatedTime = now;
+									e->DhcpAllocated = false;
+									Copy(&e->Ip, &ip, sizeof(IP));
+									Copy(e->MacAddress, packet->MacAddressSrc, 6);
+									e->Session = s;
+
+									DeleteExpiredIpTableEntry(hub->IpTable);
+
+									if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+									{
+										// 古い IP テーブルエントリを削除する
+										DeleteOldIpTableEntry(hub->IpTable);
+									}
+
+									Insert(hub->IpTable, e);
+
+									if (0)
+									{
+										char ip_address[64];
+										IPToStr(ip_address, sizeof(ip_address), &ip);
+										Debug("Registered IP Address %s to Session %X.\n",
+											ip_address, s);
+									}
+								}
+							}
+							else
+							{
+								if (e->Session == s)
+								{
+									// 自分のセッションであるので何もしない
+									// 更新日時を上書きする
+									e->UpdatedTime = now;
+									Copy(e->MacAddress, packet->MacAddressSrc, 6);
+								}
+								else
+								{
+									// 別のセッションが以前この IP アドレスを使っていた
+									if ((s->Policy->CheckIPv6) &&
+										((e->UpdatedTime + IP_TABLE_EXCLUSIVE_TIME) >= now))
+									{
+										// 他のセッションがこの IP アドレスを使っているので
+										// パケットを破棄する
+										char ip_address[32];
+										IPToStr(ip_address, sizeof(ip_address), &ip);
+
+										Debug("IP Address %s is Already used by Session %X.\n",
+											ip_address, s);
+
+										HLog(hub, "LH_IP_CONFLICT", s->Name, ip_address, e->Session->Name);
+
+										goto DISCARD_PACKET;
+									}
+								}
+							}
+						}
+					}
+				}
+
+				if (
+					(s != NULL) &&
+					(hub->Option->NoIpTable == false) &&
+					(
+						(packet->TypeL3 == L3_IPV4 ||
+							(packet->TypeL3 == L3_ARPV4 && packet->L3.ARPv4Header->HardwareSize == 6 &&
+							Endian16(packet->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+							packet->L3.ARPv4Header->ProtocolSize == 4 &&
+							Endian16(packet->L3.ARPv4Header->ProtocolType) == 0x0800)
+						) &&
+						(packet->TypeL7 != L7_DHCPV4)
+					)
+					) // DHCP パケット以外
+				{
+					// IP パケットまたは ARP 応答パケットの場合は IP アドレステーブルを検索する
+					IP_TABLE_ENTRY t, *e;
+					IP ip;
+					UINT uint_ip = 0;
+
+					if (packet->TypeL3 == L3_IPV4)
+					{
+						uint_ip = packet->L3.IPv4Header->SrcIP;
+					}
+					else if (packet->TypeL3 == L3_ARPV4)
+					{
+						uint_ip = packet->L3.ARPv4Header->SrcIP;
+					}
+
+					if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(packet->MacAddressSrc)))
+					{
+						UINTToIP(&ip, uint_ip);
+						Copy(&t.Ip, &ip, sizeof(IP));
+
+						// 既存のテーブルに登録されているかどうかチェック
+						e = Search(hub->IpTable, &t);
+
+						if (e == NULL)
+						{
+							// 登録されていないので登録する
+							if (s->Policy->DHCPForce)
+							{
+								char ipstr[MAX_SIZE];
+
+								// DHCP サーバーによって割り当てられた IP アドレスではない
+								// のでこのパケットを破棄する
+								IPToStr32(ipstr, sizeof(ipstr), uint_ip);
+								HLog(hub, "LH_DHCP_FORCE", s->Name, ipstr);
+								goto DISCARD_PACKET;
+							}
+
+	//						if (packet->TypeL3 == L3_ARPV4)
+							{
+								// すでにこのセッションで登録されている個数を調べる
+								if (s->Policy->NoRouting || s->Policy->MaxIP != 0)
+								{
+									UINT i, num_ip_for_me = 0;
+									UINT limited_count = 0xffffffff;
+
+									for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+									{
+										IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+										if (e->Session == s)
+										{
+											if (IsIP4(&e->Ip))
+											{
+												num_ip_for_me++;
+											}
+										}
+									}
+
+									if (s->Policy->NoRouting)
+									{
+										limited_count = MIN(limited_count, IP_MIN_LIMIT_COUNT);
+									}
+									if (s->Policy->MaxIP != 0)
+									{
+										limited_count = MIN(limited_count, s->Policy->MaxIP);
+									}
+									limited_count = MAX(limited_count, IP_MIN_LIMIT_COUNT);
+
+									if (num_ip_for_me >= limited_count)
+									{
+										// 使用できる IP アドレスの上限を超えているので
+										// このパケットを破棄する
+										char tmp[64];
+										IPToStr32(tmp, sizeof(tmp), uint_ip);
+										if (s->Policy->NoRouting == false)
+										{
+											HLog(hub, "LH_IP_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+										}
+										else
+										{
+											HLog(hub, "LH_ROUTING_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+										}
+										goto DISCARD_PACKET;
+									}
+								}
+
+								if (IsIPManagementTargetForHUB(&ip, hub))
+								{
+									// エントリ作成
+									e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+									e->CreatedTime = e->UpdatedTime = now;
+									e->DhcpAllocated = false;
+									Copy(&e->Ip, &ip, sizeof(IP));
+									Copy(e->MacAddress, packet->MacAddressSrc, 6);
+									e->Session = s;
+
+									DeleteExpiredIpTableEntry(hub->IpTable);
+
+									if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+									{
+										// 古い IP テーブルエントリを削除する
+										DeleteOldIpTableEntry(hub->IpTable);
+									}
+
+									Insert(hub->IpTable, e);
+
+									if (0)
+									{
+										char ip_address[64];
+										IPToStr(ip_address, sizeof(ip_address), &ip);
+										Debug("Registered IP Address %s to Session %X.\n",
+											ip_address, s);
+									}
+								}
+							}
+						}
+						else
+						{
+							if (e->Session == s)
+							{
+								// 自分のセッションであるので何もしない
+								// 更新日時を上書きする
+								e->UpdatedTime = now;
+								Copy(e->MacAddress, packet->MacAddressSrc, 6);
+							}
+							else
+							{
+								// 別のセッションが以前この IP アドレスを使っていた
+								if ((s->Policy->CheckIP || s->Policy->DHCPForce) &&
+									((e->UpdatedTime + IP_TABLE_EXCLUSIVE_TIME) >= now))
+								{
+									// 他のセッションがこの IP アドレスを使っているので
+									// パケットを破棄する
+									char ip_address[32];
+									IPToStr(ip_address, sizeof(ip_address), &ip);
+
+									Debug("IP Address %s is Already used by Session %X.\n",
+										ip_address, s);
+
+									HLog(hub, "LH_IP_CONFLICT", s->Name, ip_address, e->Session->Name);
+
+									goto DISCARD_PACKET;
+								}
+
+								if (s->Policy->DHCPForce)
+								{
+									if (e->DhcpAllocated == false)
+									{
+										char ipstr[MAX_SIZE];
+
+										// DHCP サーバーによって割り当てられた IP アドレスではない
+										// のでこのパケットを破棄する
+										IPToStr32(ipstr, sizeof(ipstr), uint_ip);
+										HLog(hub, "LH_DHCP_FORCE", s->Name, ipstr);
+										goto DISCARD_PACKET;
+									}
+								}
+
+								// エントリを上書きする
+								e->Session = s;
+								e->UpdatedTime = now;
+								Copy(e->MacAddress, packet->MacAddressSrc, 6);
+							}
+						}
+					}
+				}
+
+				if (s != NULL && broadcast_mode)
+				{
+					// ブロードキャストパケットのループや
+					// 大量のブロードキャストの発生を防止するため
+					// Broadcast Storm 回避アルゴリズムを呼び出す
+					if (CheckBroadcastStorm(s, packet) == false)
+					{
+						goto DISCARD_PACKET;
+					}
+				}
+
+				// トラフィック加算
+				Zero(&traffic, sizeof(traffic));
+				if (packet->BroadcastPacket)
+				{
+					// ブロードキャスト
+					traffic.Send.BroadcastBytes = packet->PacketSize;
+					traffic.Send.BroadcastCount = 1;
+				}
+				else
+				{
+					// ユニキャスト
+					traffic.Send.UnicastBytes = packet->PacketSize;
+					traffic.Send.UnicastCount = 1;
+				}
+
+				if (s != NULL)
+				{
+					AddTrafficForSession(s, &traffic);
+				}
+
+				// トラフィック情報の Send と Recv を反転
+				Copy(&traffic.Recv, &traffic.Send, sizeof(TRAFFIC_ENTRY));
+				Zero(&traffic.Send, sizeof(TRAFFIC_ENTRY));
+
+				// HUB のモニタポートにこのパケットをブロードキャストする
+				if (hub->MonitorList->num_item != 0)
+				{
+					LockList(hub->MonitorList);
+					{
+						UINT i;
+						void *data;
+						UINT size = packet->PacketSize;
+						for (i = 0;i < LIST_NUM(hub->MonitorList);i++)
+						{
+							SESSION *monitor_session = (SESSION *)LIST_DATA(hub->MonitorList, i);
+
+							// パケットをフラッディング
+							if (monitor_session->PacketAdapter->Param != NULL)
+							{
+								data = MallocFast(size);
+								Copy(data, packet->PacketData, size);
+								StorePacketToHubPa((HUB_PA *)monitor_session->PacketAdapter->Param,
+									s, data, size, packet);
+							}
+						}
+					}
+					UnlockList(hub->MonitorList);
+				}
+
+				if (broadcast_mode == false)
+				{
+					if (dest_pa != NULL)
+					{
+						if (dest_session->Policy->NoIPv6DefaultRouterInRA ||
+							(dest_session->Policy->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session) ||
+							(hub->Option->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session))
+						{
+							DeleteIPv6DefaultRouterInRA(packet);
+						}
+						if (dest_session->Policy->RSandRAFilter)
+						{
+							if (packet->TypeL3 == L3_IPV6 &&
+								packet->TypeL4 == L4_ICMPV6 &&
+								(packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+								 packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+							{
+								goto DISCARD_UNICAST_PACKET;
+							}
+						}
+						if (dest_session->Policy->DHCPFilter)
+						{
+							if (packet->TypeL3 == L3_IPV4 &&
+								packet->TypeL4 == L4_UDP &&
+								packet->TypeL7 == L7_DHCPV4)
+							{
+								goto DISCARD_UNICAST_PACKET;
+							}
+						}
+						if (dest_session->Policy->DHCPv6Filter)
+						{
+							if (packet->TypeL3 == L3_IPV6 &&
+								packet->TypeL4 == L4_UDP &&
+								(Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+							{
+								goto DISCARD_UNICAST_PACKET;
+							}
+						}
+						if (dest_session->Policy->ArpDhcpOnly)
+						{
+							if (packet->BroadcastPacket)
+							{
+								bool b = true;
+
+								if (packet->TypeL3 == L3_IPV4 &&
+									packet->TypeL4 == L4_UDP &&
+									packet->TypeL7 == L7_DHCPV4)
+								{
+									b = false;
+								}
+								else if (packet->TypeL3 == L3_ARPV4)
+								{
+									b = false;
+								}
+								else if (packet->TypeL3 == L3_IPV6 &&
+									packet->TypeL4 == L4_UDP &&
+									(Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+								{
+									b = false;
+								}
+								else if (packet->TypeL3 == L3_IPV6 &&
+									packet->TypeL4 == L4_ICMPV6)
+								{
+									b = false;
+								}
+
+								if (b)
+								{
+									goto DISCARD_UNICAST_PACKET;
+								}
+							}
+						}
+						if (dest_session->Policy->FilterIPv4)
+						{
+							if (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4)
+							{
+								goto DISCARD_UNICAST_PACKET;
+							}
+						}
+						if (dest_session->Policy->FilterIPv6)
+						{
+							if (packet->TypeL3 == L3_IPV6)
+							{
+								goto DISCARD_UNICAST_PACKET;
+							}
+						}
+						if (dest_session->Policy->FilterNonIP)
+						{
+							if (packet->TypeL3 != L3_IPV4 && packet->TypeL3 != L3_ARPV4 && packet->TypeL3 != L3_IPV6)
+							{
+								goto DISCARD_UNICAST_PACKET;
+							}
+						}
+
+						if (s != NULL &&
+							(packet->BroadcastPacket == false &&
+							s->Policy->PrivacyFilter &&
+							dest_session->Policy->PrivacyFilter)
+							)
+						{
+							// プライバシーフィルタ
+							if (packet->TypeL3 != L3_ARPV4)
+							{
+								goto DISCARD_UNICAST_PACKET;
+							}
+						}
+
+						if (s != NULL)
+						{
+							if (Cmp(packet->MacAddressSrc, s->Hub->HubMacAddr, 6) == 0 ||
+								Cmp(packet->MacAddressDest, s->Hub->HubMacAddr, 6) == 0)
+							{
+								goto DISCARD_UNICAST_PACKET;
+							}
+						}
+
+						// パケットログをとる
+						if (s != NULL)
+						{
+							PacketLog(s->Hub, s, dest_session, packet);
+						}
+
+						// 宛先 HUB_PA にストアする
+						StorePacketToHubPa(dest_pa, s, packet->PacketData, packet->PacketSize, packet);
+
+						// トラフィック加算
+						AddTrafficForSession(dest_session, &traffic);
+					}
+					else
+					{
+DISCARD_UNICAST_PACKET:
+						Free(packet->PacketData);
+					}
+				}
+				else
+				{
+					// すべてのセッションにストアする
+					LockList(hub->SessionList);
+					{
+						UINT i, num = LIST_NUM(hub->SessionList);
+						for (i = 0;i < num;i++)
+						{
+							SESSION *dest_session = LIST_DATA(hub->SessionList, i);
+							HUB_PA *dest_pa = (HUB_PA *)dest_session->PacketAdapter->Param;
+							bool discard = false;
+
+							if (dest_session != s)
+							{
+								bool delete_default_router_in_ra = false;
+
+								if (dest_session->VLanId != 0 && packet->TypeL3 == L3_TAGVLAN &&
+									packet->VlanId != dest_session->VLanId)
+								{
+									discard = true;
+								}
+
+								if (dest_session->Policy->NoIPv6DefaultRouterInRA ||
+									(dest_session->Policy->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session) ||
+									(hub->Option->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session))
+								{
+									if (packet->TypeL3 == L3_IPV6 && packet->TypeL4 == L4_ICMPV6 &&
+										(packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+									{
+										if (packet->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime != 0)
+										{
+											delete_default_router_in_ra = true;
+										}
+									}
+								}
+								if (dest_session->Policy->RSandRAFilter)
+								{
+									if (packet->TypeL3 == L3_IPV6 &&
+										packet->TypeL4 == L4_ICMPV6 &&
+										(packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+										 packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+									{
+										discard = true;
+									}
+								}
+
+								if (dest_session->Policy->DHCPFilter)
+								{
+									if (packet->TypeL3 == L3_IPV4 &&
+										packet->TypeL4 == L4_UDP &&
+										packet->TypeL7 == L7_DHCPV4)
+									{
+										discard = true;
+									}
+								}
+
+								if (dest_session->Policy->DHCPv6Filter)
+								{
+									if (packet->TypeL3 == L3_IPV6 &&
+										packet->TypeL4 == L4_UDP &&
+										(Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+									{
+										discard = true;
+									}
+								}
+
+								if (dest_session->Policy->ArpDhcpOnly)
+								{
+									if (packet->BroadcastPacket)
+									{
+										bool b = true;
+
+										if (packet->TypeL3 == L3_IPV4 &&
+											packet->TypeL4 == L4_UDP &&
+											packet->TypeL7 == L7_DHCPV4)
+										{
+											b = false;
+										}
+										else if (packet->TypeL3 == L3_ARPV4)
+										{
+											b = false;
+										}
+										else if (packet->TypeL3 == L3_IPV6 &&
+											packet->TypeL4 == L4_UDP &&
+											(Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+										{
+											b = false;
+										}
+										else if (packet->TypeL3 == L3_IPV6 &&
+											packet->TypeL4 == L4_ICMPV6)
+										{
+											b = false;
+										}
+
+										if (discard == false)
+										{
+											discard = b;
+										}
+									}
+								}
+
+								if (dest_session->Policy->FilterIPv4)
+								{
+									if (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4)
+									{
+										discard = true;
+									}
+								}
+								if (dest_session->Policy->FilterIPv6)
+								{
+									if (packet->TypeL3 == L3_IPV6)
+									{
+										discard = true;
+									}
+								}
+								if (dest_session->Policy->FilterNonIP)
+								{
+									if (packet->TypeL3 != L3_IPV4 && packet->TypeL3 != L3_ARPV4 && packet->TypeL3 != L3_IPV6)
+									{
+										discard = true;
+									}
+								}
+
+								if (s != NULL &&
+									(packet->BroadcastPacket == false &&
+									s->Policy->PrivacyFilter &&
+									dest_session->Policy->PrivacyFilter)
+									)
+								{
+									// プライバシーフィルタ
+									if (packet->TypeL3 != L3_ARPV4)
+									{
+										discard = true;
+									}
+								}
+
+								if (s != NULL)
+								{
+									if (Cmp(packet->MacAddressSrc, s->Hub->HubMacAddr, 6) == 0 ||
+										Cmp(packet->MacAddressDest, s->Hub->HubMacAddr, 6) == 0)
+									{
+										discard = true;
+									}
+								}
+
+								if (discard == false && dest_pa != NULL)
+								{
+									// 自分以外のセッションにストア
+									data = MallocFast(packet->PacketSize);
+									Copy(data, packet->PacketData, packet->PacketSize);
+									size = packet->PacketSize;
+
+									if (delete_default_router_in_ra)
+									{
+										PKT *pkt2 = ParsePacket(data, size);
+
+										DeleteIPv6DefaultRouterInRA(pkt2);
+
+										FreePacket(pkt2);
+									}
+
+									StorePacketToHubPa(dest_pa, s, data, size, packet);
+
+									// トラフィック加算
+									AddTrafficForSession(dest_session, &traffic);
+								}
+							}
+						}
+					}
+					UnlockList(hub->SessionList);
+
+					// パケットログをとる
+					if (s != NULL)
+					{
+						PacketLog(s->Hub, s, NULL, packet);
+					}
+
+					Free(packet->PacketData);
+				}
+				FreePacket(packet);
+			}
+		}
+	}
+	UnlockList(hub->MacTable);
+}
+
+// 指定された IP アドレスがプライベート IP アドレスかどうかチェックする
+bool IsIPPrivate(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	if (ip->addr[0] == 10)
+	{
+		return true;
+	}
+
+	if (ip->addr[0] == 172)
+	{
+		if (ip->addr[1] >= 16 && ip->addr[1] <= 31)
+		{
+			return true;
+		}
+	}
+
+	if (ip->addr[0] == 192 && ip->addr[1] == 168)
+	{
+		return true;
+	}
+
+	if (ip->addr[0] == 2)
+	{
+		// Special !!
+		return true;
+	}
+
+	if (ip->addr[0] == 169 && ip->addr[1] == 254)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// 指定された IP アドレスが仮想 HUB による管理対象かどうか確認する
+bool IsIPManagementTargetForHUB(IP *ip, HUB *hub)
+{
+	// 引数チェック
+	if (ip == NULL || hub == NULL)
+	{
+		return false;
+	}
+
+	if (hub->Option == NULL)
+	{
+		return true;
+	}
+
+	if (IsIP4(ip))
+	{
+		if (hub->Option->ManageOnlyPrivateIP)
+		{
+			if (IsIPPrivate(ip) == false)
+			{
+				return false;
+			}
+		}
+	}
+	else
+	{
+		if (hub->Option->ManageOnlyLocalUnicastIPv6)
+		{
+			UINT ip_type = GetIPAddrType6(ip);
+
+			if (!(ip_type & IPV6_ADDR_LOCAL_UNICAST))
+			{
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+// 古い IP テーブルエントリを削除する
+void DeleteOldIpTableEntry(LIST *o)
+{
+	UINT i;
+	UINT64 oldest_time = 0xffffffffffffffffULL;
+	IP_TABLE_ENTRY *old = NULL;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+
+		if (e->UpdatedTime <= oldest_time)
+		{
+			old = e;
+		}
+	}
+
+	if (old != NULL)
+	{
+		Delete(o, old);
+		Free(old);
+	}
+}
+
+// ストームリストの追加
+STORM *AddStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip)
+{
+	STORM *s;
+	// 引数チェック
+	if (pa == NULL || mac_address == NULL)
+	{
+		return NULL;
+	}
+
+	s = ZeroMalloc(sizeof(STORM));
+	if (src_ip != NULL)
+	{
+		Copy(&s->SrcIp, src_ip, sizeof(IP));
+	}
+	if (dest_ip != NULL)
+	{
+		Copy(&s->DestIp, dest_ip, sizeof(IP));
+	}
+	Copy(s->MacAddress, mac_address, 6);
+
+	Insert(pa->StormList, s);
+
+	return s;
+}
+
+// ストームリストのサーチ
+STORM *SearchStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip)
+{
+	STORM t, *s;
+	// 引数チェック
+	if (pa == NULL || mac_address == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	if (src_ip != NULL)
+	{
+		Copy(&t.SrcIp, src_ip, sizeof(IP));
+	}
+	if (dest_ip != NULL)
+	{
+		Copy(&t.DestIp, dest_ip, sizeof(IP));
+	}
+	Copy(t.MacAddress, mac_address, 6);
+
+	s = Search(pa->StormList, &t);
+
+	return s;
+}
+
+// パケットを宛先の HUB_PA にストアする
+void StorePacketToHubPa(HUB_PA *dest, SESSION *src, void *data, UINT size, PKT *packet)
+{
+	BLOCK *b;
+	// 引数チェック
+	if (dest == NULL || data == NULL)
+	{
+		return;
+	}
+
+	if (size < 14)
+	{
+		Free(data);
+		return;
+	}
+
+	if (src != NULL)
+	{
+		// フォワード用のアクセスリスト適用
+		if (ApplyAccessListToForwardPacket(src->Hub, src, dest->Session, packet) == false)
+		{
+			Free(data);
+			return;
+		}
+	}
+
+	if (src != NULL)
+	{
+		if (dest->Session->Policy->MaxDownload != 0)
+		{
+			// トラフィック制限
+			if (packet != NULL && IsMostHighestPriorityPacket(dest->Session, packet) == false)
+			{
+				TRAFFIC_LIMITER *tr = &dest->DownloadLimiter;
+				IntoTrafficLimiter(tr, packet);
+
+				if ((tr->Value * (UINT64)1000 / (UINT64)LIMITER_SAMPLING_SPAN) > dest->Session->Policy->MaxDownload)
+				{
+					// 制限する
+					Free(data);
+					return;
+				}
+			}
+		}
+	}
+
+	if (src != NULL && src->Hub != NULL && src->Hub->Option != NULL && src->Hub->Option->FixForDLinkBPDU)
+	{
+		// D-Link バグ対策
+		UCHAR *mac = packet->MacAddressSrc;
+		if ((mac[0] == 0x00 && mac[1] == 0x80 && mac[2] == 0xc8 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00) ||
+			(mac[0] == 0x00 && mac[1] == 0x0d && mac[2] == 0x88 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00))
+		{
+			SESSION *session = dest->Session;
+
+			if (session != NULL)
+			{
+				if (session->Policy != NULL && session->Policy->CheckMac)
+				{
+					UCHAR hash[MD5_SIZE];
+					Hash(hash, packet->PacketData, packet->PacketSize, false);
+
+					Copy(session->LastDLinkSTPPacketDataHash, hash, MD5_SIZE);
+					session->LastDLinkSTPPacketSendTick = Tick64();
+				}
+			}
+		}
+	}
+
+	// VLAN タグを除去
+	if (dest->Session != NULL && dest->Session->VLanId != 0)
+	{
+		if (VLanRemoveTag(&data, &size, dest->Session->VLanId) == false)
+		{
+			Free(data);
+			return;
+		}
+	}
+
+	// ブロック作成
+	b = NewBlock(data, size, 0);
+
+	LockQueue(dest->PacketQueue);
+	{
+		// キューの数を測定
+		if ((dest->PacketQueue->num_item < MAX_STORED_QUEUE_NUM) ||
+			(((UCHAR *)data)[12] == 'S' && ((UCHAR *)data)[13] == 'E'))
+		{
+			// ストア
+			InsertQueue(dest->PacketQueue, b);
+		}
+		else
+		{
+			// パケット破棄
+			FreeBlock(b);
+		}
+	}
+	UnlockQueue(dest->PacketQueue);
+
+	// キャンセルの発行
+	if (src != NULL)
+	{
+		AddCancelList(src->CancelList, dest->Cancel);
+	}
+	else
+	{
+		Cancel(dest->Cancel);
+	}
+}
+
+// IPv6 ルータ広告からデフォルトルータ指定を削除
+bool DeleteIPv6DefaultRouterInRA(PKT *p)
+{
+	if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+		(p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+	{
+		if (p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime != 0)
+		{
+			p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime = 0;
+
+			p->L4.ICMPHeader->Checksum = 0;
+			p->L4.ICMPHeader->Checksum =
+				CalcChecksumForIPv6(&p->L3.IPv6Header->SrcAddress,
+					&p->L3.IPv6Header->DestAddress, IP_PROTO_ICMPV6,
+					p->L4.ICMPHeader, p->IPv6HeaderPacketInfo.PayloadSize);
+		}
+	}
+
+	return false;
+}
+
+// ポリシーによるパケットフィルタ
+bool StorePacketFilterByPolicy(SESSION *s, PKT *p)
+{
+	POLICY *pol;
+	HUB *hub;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	hub = s->Hub;
+
+	// ポリシー
+	pol = s->Policy;
+
+	// サーバーとしての動作を禁止する
+	if (pol->NoServer)
+	{
+		if (p->TypeL3 == L3_IPV4)
+		{
+			if (p->TypeL4 == L4_TCP)
+			{
+				UCHAR flag = p->L4.TCPHeader->Flag;
+				if ((flag & TCP_SYN) && (flag & TCP_ACK))
+				{
+					char ip1[64], ip2[64];
+					// SYN + ACK パケットを送信させない
+					Debug("pol->NoServer: Discard SYN+ACK Packet.\n");
+
+					IPToStr32(ip1, sizeof(ip1), p->L3.IPv4Header->SrcIP);
+					IPToStr32(ip2, sizeof(ip2), p->L3.IPv4Header->DstIP);
+
+					HLog(s->Hub, "LH_NO_SERVER", s->Name, ip2, p->L4.TCPHeader->DstPort,
+						ip1, p->L4.TCPHeader->SrcPort);
+
+					return false;
+				}
+			}
+		}
+	}
+
+	// サーバーとしての動作を禁止する (IPv6)
+	if (pol->NoServerV6)
+	{
+		if (p->TypeL3 == L3_IPV6)
+		{
+			if (p->TypeL4 == L4_TCP)
+			{
+				UCHAR flag = p->L4.TCPHeader->Flag;
+				if ((flag & TCP_SYN) && (flag & TCP_ACK))
+				{
+					char ip1[128], ip2[128];
+					// SYN + ACK パケットを送信させない
+					Debug("pol->NoServerV6: Discard SYN+ACK Packet.\n");
+
+					IP6AddrToStr(ip1, sizeof(ip1), &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress);
+					IP6AddrToStr(ip2, sizeof(ip2), &p->IPv6HeaderPacketInfo.IPv6Header->DestAddress);
+
+					HLog(s->Hub, "LH_NO_SERVER", s->Name, ip2, p->L4.TCPHeader->DstPort,
+						ip1, p->L4.TCPHeader->SrcPort);
+
+					return false;
+				}
+			}
+		}
+	}
+
+	// ブロードキャストは ARP と DHCP のみ許可
+	if (pol->ArpDhcpOnly && p->BroadcastPacket)
+	{
+		bool ok = false;
+
+		if (p->TypeL3 == L3_ARPV4)
+		{
+			ok = true;
+		}
+		if (p->TypeL3 == L3_IPV4)
+		{
+			if (p->TypeL4 == L4_UDP)
+			{
+				if (p->TypeL7 == L7_DHCPV4)
+				{
+					ok = true;
+				}
+			}
+		}
+		if (p->TypeL3 == L3_IPV6)
+		{
+			if (p->TypeL4 == L4_ICMPV6)
+			{
+				ok = true;
+			}
+		}
+
+		if (p->TypeL3 == L3_IPV6 &&
+			p->TypeL4 == L4_UDP &&
+			(Endian16(p->L4.UDPHeader->DstPort) == 546 || Endian16(p->L4.UDPHeader->DstPort) == 547))
+		{
+			ok = true;
+		}
+
+		if (ok == false)
+		{
+			return false;
+		}
+	}
+
+	// IPv4 パケットのフィルタリング
+	if (pol->FilterIPv4)
+	{
+		if (p->MacHeader != NULL)
+		{
+			USHORT proto = Endian16(p->MacHeader->Protocol);
+			if (proto == 0x0800 || proto == 0x0806)
+			{
+				return false;
+			}
+		}
+	}
+
+	// IPv6 パケットのフィルタリング
+	if (pol->FilterIPv6)
+	{
+		if (p->MacHeader != NULL)
+		{
+			USHORT proto = Endian16(p->MacHeader->Protocol);
+			if (proto == 0x86dd)
+			{
+				return false;
+			}
+		}
+	}
+
+	// 非 IP パケットのフィルタリング
+	if (pol->FilterNonIP)
+	{
+		if (p->MacHeader != NULL)
+		{
+			USHORT proto = Endian16(p->MacHeader->Protocol);
+			if (!(proto == 0x86dd || proto == 0x0800 || proto == 0x0806))
+			{
+				return false;
+			}
+		}
+	}
+
+	// DHCP パケットのフィルタリング
+	if (pol->DHCPFilter)
+	{
+		if (p->TypeL3 == L3_IPV4 &&
+			p->TypeL4 == L4_UDP &&
+			p->TypeL7 == L7_DHCPV4)
+		{
+			// DHCP パケットを破棄する
+			Debug("pol->DHCPFilter: Discard DHCP Packet.\n");
+
+			return false;
+		}
+	}
+
+	// DHCPv6 パケットのフィルタリング
+	if (pol->DHCPv6Filter)
+	{
+		if (p->TypeL3 == L3_IPV6 &&
+			p->TypeL4 == L4_UDP)
+		{
+			if (Endian16(p->L4.UDPHeader->DstPort) == 546 ||
+				Endian16(p->L4.UDPHeader->DstPort) == 547)
+			{
+				// DHCPv6 パケットを破棄する
+				Debug("pol->DHCPv6Filter: Discard DHCPv6 Packet.\n");
+
+				return false;
+			}
+		}
+	}
+
+	// DHCP サーバーとしての動作を禁止
+	if (pol->DHCPNoServer)
+	{
+		if (p->TypeL3 == L3_IPV4 &&
+			p->TypeL4 == L4_UDP &&
+			p->TypeL7 == L7_DHCPV4)
+		{
+			DHCPV4_HEADER *h = p->L7.DHCPv4Header;
+			if (h->OpCode == 2)
+			{
+				char ip1[64], ip2[64];
+
+				// DHCP パケットを破棄する
+				IPToStr32(ip1, sizeof(ip1), p->L3.IPv4Header->SrcIP);
+				IPToStr32(ip2, sizeof(ip2), p->L3.IPv4Header->DstIP);
+
+				HLog(s->Hub, "LH_NO_DHCP", s->Name, ip1, ip2);
+
+				// DHCP 応答パケットを破棄する
+				Debug("pol->DHCPNoServer: Discard DHCP Response Packet.\n");
+				return false;
+			}
+		}
+	}
+
+	// DHCPv6 サーバーとしての動作を禁止
+	if (pol->DHCPv6NoServer)
+	{
+		if (p->TypeL3 == L3_IPV6 &&
+			p->TypeL4 == L4_UDP &&
+			(Endian16(p->L4.UDPHeader->DstPort) == 546 || Endian16(p->L4.UDPHeader->SrcPort) == 547))
+		{
+			char ip1[128], ip2[128];
+
+			// DHCP パケットを破棄する
+			IP6AddrToStr(ip1, sizeof(ip1), &p->L3.IPv6Header->SrcAddress);
+			IP6AddrToStr(ip2, sizeof(ip2), &p->L3.IPv6Header->DestAddress);
+
+			HLog(s->Hub, "LH_NO_DHCP", s->Name, ip1, ip2);
+
+			// DHCP 応答パケットを破棄する
+			Debug("pol->DHCPv6NoServer: Discard DHCPv6 Response Packet.\n");
+			return false;
+		}
+	}
+
+	// ルータ要請/広告パケットをフィルタリング (IPv6)
+	if (pol->RSandRAFilter)
+	{
+		if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+			(p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+			 p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+		{
+			return false;
+		}
+	}
+
+	// ルータ広告パケットをフィルタリング (IPv6)
+	if (pol->RAFilter)
+	{
+		if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+			p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT)
+		{
+			return false;
+		}
+	}
+
+	// DHCP 応答パケットを記録して IP テーブルに登録
+	if (p->TypeL3 == L3_IPV4 &&
+		p->TypeL4 == L4_UDP &&
+		p->TypeL7 == L7_DHCPV4 &&
+		(s->Hub != NULL && s->Hub->Option->NoIpTable == false))
+	{
+		DHCPV4_HEADER *h = p->L7.DHCPv4Header;
+		if (h->OpCode == 2)
+		{
+			// DHCP 応答パケットの中身を見て IP テーブルに登録する
+			if (h->HardwareType == ARP_HARDWARE_TYPE_ETHERNET)
+			{
+				if (h->HardwareAddressSize == 6)
+				{
+					if (h->YourIP != 0 && h->YourIP != 0xffffffff)
+					{
+						UINT ip_uint = h->YourIP;
+						IP ip;
+						IP_TABLE_ENTRY *e, t;
+						MAC_TABLE_ENTRY *mac_table, mt;
+						mt.VlanId = 0;
+						Copy(&mt.MacAddress, &h->ClientMacAddress, 6);
+						mac_table = Search(hub->MacTable, &mt);
+
+						if (mac_table != NULL)
+						{
+							bool new_entry = true;
+							UINTToIP(&ip, ip_uint);
+							Copy(&t.Ip, &ip, sizeof(IP));
+
+							e = Search(hub->IpTable, &t);
+							if (e == NULL)
+							{
+								// 新しく登録
+								e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+UPDATE_DHCP_ALLOC_ENTRY:
+								e->CreatedTime = e->UpdatedTime = Tick64();
+								e->DhcpAllocated = true;
+								Copy(&e->Ip, &ip, sizeof(IP));
+								e->Session = mac_table->Session;
+								Copy(e->MacAddress, p->MacAddressDest, 6);
+
+								if (new_entry)
+								{
+									// 有効期限の切れた IP テーブルエントリを削除する
+									DeleteExpiredIpTableEntry(hub->IpTable);
+									if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+									{
+										// 古いエントリを削除する
+										DeleteOldIpTableEntry(hub->IpTable);
+									}
+									Insert(hub->IpTable, e);
+								}
+
+								if (new_entry)
+								{
+									char dhcp_mac_addr[64];
+									char dest_mac_addr[64];
+									char dest_ip_addr[64];
+									char server_ip_addr[64];
+									MacToStr(dhcp_mac_addr, sizeof(dhcp_mac_addr), p->MacAddressSrc);
+									MacToStr(dest_mac_addr, sizeof(dest_mac_addr), h->ClientMacAddress);
+									IPToStr(dest_ip_addr, sizeof(dest_ip_addr), &ip);
+									IPToStr32(server_ip_addr, sizeof(server_ip_addr), p->L3.IPv4Header->SrcIP);
+									Debug("DHCP Allocated; dhcp server: %s, client: %s, new_ip: %s\n",
+										dhcp_mac_addr, dest_mac_addr, dest_ip_addr);
+
+									HLog(s->Hub, "LH_REGIST_DHCP", s->Name, dhcp_mac_addr, server_ip_addr,
+										mac_table->Session->Name, dest_mac_addr, dest_ip_addr);
+								}
+							}
+							else
+							{
+								// 更新
+								new_entry = false;
+								goto UPDATE_DHCP_ALLOC_ENTRY;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return true;
+}
+
+// 有効期限の切れた MAC テーブルエントリを削除する
+void DeleteExpiredMacTableEntry(LIST *o)
+{
+	LIST *o2;
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	o2 = NewListFast(NULL);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		MAC_TABLE_ENTRY *e = LIST_DATA(o, i);
+		if ((e->UpdatedTime + (UINT64)MAC_TABLE_EXPIRE_TIME) <= Tick64())
+		{
+			Add(o2, e);
+		}
+	}
+
+	for (i = 0;i < LIST_NUM(o2);i++)
+	{
+		MAC_TABLE_ENTRY *e = LIST_DATA(o2, i);
+		Delete(o, e);
+		Free(e);
+	}
+
+	ReleaseList(o2);
+}
+
+// 有効期限の切れた IP テーブルエントリを削除する
+void DeleteExpiredIpTableEntry(LIST *o)
+{
+	LIST *o2;
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	o2 = NewListFast(NULL);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+		if ((e->UpdatedTime + (UINT64)(e->DhcpAllocated ? IP_TABLE_EXPIRE_TIME_DHCP : IP_TABLE_EXPIRE_TIME)) <= Tick64())
+		{
+			Add(o2, e);
+		}
+	}
+
+	for (i = 0;i < LIST_NUM(o2);i++)
+	{
+		IP_TABLE_ENTRY *e = LIST_DATA(o2, i);
+		Delete(o, e);
+		Free(e);
+	}
+
+	ReleaseList(o2);
+}
+
+// 優先して取り扱うべきパケットかどうかを判断
+bool IsMostHighestPriorityPacket(SESSION *s, PKT *p)
+{
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	if (p->TypeL3 == L3_ARPV4)
+	{
+		// ARP パケット
+		return true;
+	}
+
+	if (p->TypeL3 == L3_IPV4)
+	{
+		if (p->TypeL4 == L4_ICMPV4)
+		{
+			// ICMP パケット
+			return true;
+		}
+
+		if (p->TypeL4 == L4_TCP)
+		{
+			if ((p->L4.TCPHeader->Flag & TCP_SYN) || (p->L4.TCPHeader->Flag & TCP_FIN)
+				|| (p->L4.TCPHeader->Flag & TCP_RST))
+			{
+				// SYN, FIN, RST パケット
+				return true;
+			}
+		}
+
+		if (p->TypeL4 == L4_UDP)
+		{
+			if (p->TypeL7 == L7_DHCPV4)
+			{
+				// DHCP パケット
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+// トラフィック リミッターへのパケット追加
+void IntoTrafficLimiter(TRAFFIC_LIMITER *tr, PKT *p)
+{
+	UINT64 now = Tick64();
+	// 引数チェック
+	if (tr == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (tr->LastTime == 0 || tr->LastTime > now ||
+		(tr->LastTime + LIMITER_SAMPLING_SPAN) < now)
+	{
+		// サンプリング初期化
+		tr->Value = 0;
+		tr->LastTime = now;
+	}
+
+	// 値増加
+	tr->Value += (UINT64)(p->PacketSize * 8);
+}
+
+// トラフィック リミッターによる帯域幅削減
+bool StorePacketFilterByTrafficLimiter(SESSION *s, PKT *p)
+{
+	HUB_PA *pa;
+	TRAFFIC_LIMITER *tr;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	if (s->Policy->MaxUpload == 0)
+	{
+		// 制限無し
+		return true;
+	}
+
+	pa = (HUB_PA *)s->PacketAdapter->Param;
+	tr = &pa->UploadLimiter;
+
+	// 優先パケットは制限を適用しない
+	if (IsMostHighestPriorityPacket(s, p))
+	{
+		return true;
+	}
+
+	// リミッターへパケットを投入
+	IntoTrafficLimiter(tr, p);
+
+	// 現在の帯域幅と制限値を比較
+	if ((tr->Value * (UINT64)1000 / (UINT64)LIMITER_SAMPLING_SPAN) > s->Policy->MaxUpload)
+	{
+		// パケットを破棄
+		return false;
+	}
+
+	return true;
+}
+
+// ストアするパケットのフィルタリング
+bool StorePacketFilter(SESSION *s, PKT *packet)
+{
+	// 引数チェック
+	if (s == NULL || packet == NULL)
+	{
+		return false;
+	}
+
+	// トラフィック リミッターによる帯域幅削減
+	if (StorePacketFilterByTrafficLimiter(s, packet) == false)
+	{
+		return false;
+	}
+
+	// ポリシーによるパケットフィルタ
+	if (StorePacketFilterByPolicy(s, packet) == false)
+	{
+		return false;
+	}
+
+	// アクセスリストによるパケットフィルタ
+	if (ApplyAccessListToStoredPacket(s->Hub, s, packet) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// HUB 用のパケットアダプタの取得
+PACKET_ADAPTER *GetHubPacketAdapter()
+{
+	// 関数リストを生成して引き渡す
+	PACKET_ADAPTER *pa = NewPacketAdapter(HubPaInit,
+		HubPaGetCancel, HubPaGetNextPacket, HubPaPutPacket, HubPaFree);
+
+	return pa;
+}
+
+// HUB のすべての SESSION を停止させる
+void StopAllSession(HUB *h)
+{
+	SESSION **s;
+	UINT i, num;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->SessionList);
+	{
+		num = LIST_NUM(h->SessionList);
+		s = ToArray(h->SessionList);
+		DeleteAll(h->SessionList);
+	}
+	UnlockList(h->SessionList);
+
+	for (i = 0;i < num;i++)
+	{
+		StopSession(s[i]);
+		ReleaseSession(s[i]);
+	}
+
+	Free(s);
+}
+
+// HUB から SESSION を削除
+void DelSession(HUB *h, SESSION *s)
+{
+	// 引数チェック
+	if (h == NULL || s == NULL)
+	{
+		return;
+	}
+
+	LockList(h->SessionList);
+	{
+		if (Delete(h->SessionList, s))
+		{
+			Debug("Session %s was Deleted from %s.\n", s->Name, h->Name);
+			ReleaseSession(s);
+		}
+	}
+	UnlockList(h->SessionList);
+}
+
+// HUB に SESSION を追加
+void AddSession(HUB *h, SESSION *s)
+{
+	// 引数チェック
+	if (h == NULL || s == NULL)
+	{
+		return;
+	}
+
+	LockList(h->SessionList);
+	{
+		Insert(h->SessionList, s);
+		AddRef(s->ref);
+		Debug("Session %s Inserted to %s.\n", s->Name, h->Name);
+	}
+	UnlockList(h->SessionList);
+}
+
+// HUB の動作を停止する
+void StopHub(HUB *h)
+{
+	bool old_status = false;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	old_status = h->Offline;
+	h->HubIsOnlineButHalting = true;
+
+	SetHubOffline(h);
+
+	if (h->Halt == false)
+	{
+		SLog(h->Cedar, "LS_HUB_STOP", h->Name);
+		h->Halt = true;
+	}
+
+	h->Offline = old_status;
+	h->HubIsOnlineButHalting = false;
+}
+
+// HUB をオンラインにする
+void SetHubOnline(HUB *h)
+{
+	bool for_cluster = false;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+		{
+			for_cluster = true;
+		}
+	}
+
+	Lock(h->lock_online);
+	{
+		if (h->Offline == false)
+		{
+			Unlock(h->lock_online);
+			return;
+		}
+		HLog(h, "LH_ONLINE");
+
+		// すべてのリンクを開始
+		StartAllLink(h);
+
+		// SecureNAT を開始
+		if (h->EnableSecureNAT)
+		{
+			if (h->SecureNAT == NULL)
+			{
+				if (for_cluster == false)
+				{
+					h->SecureNAT = SnNewSecureNAT(h, h->SecureNATOption);
+				}
+			}
+		}
+
+		// この HUB に関連付けられているローカルブリッジをすべて開始する
+		if (h->Type != HUB_TYPE_FARM_DYNAMIC)
+		{
+			LockList(h->Cedar->LocalBridgeList);
+			{
+				UINT i;
+				for (i = 0;i < LIST_NUM(h->Cedar->LocalBridgeList);i++)
+				{
+					LOCALBRIDGE *br = LIST_DATA(h->Cedar->LocalBridgeList, i);
+
+					if (StrCmpi(br->HubName, h->Name) == 0)
+					{
+						if (br->Bridge == NULL)
+						{
+							br->Bridge = BrNewBridge(h, br->DeviceName, NULL, br->Local, br->Monitor,
+								br->TapMode, br->TapMacAddress, br->FullBroadcast);
+						}
+					}
+				}
+			}
+			UnlockList(h->Cedar->LocalBridgeList);
+		}
+
+		h->Offline = false;
+	}
+	Unlock(h->lock_online);
+
+	if (h->Cedar->Server != NULL)
+	{
+		SiHubOnlineProc(h);
+	}
+}
+
+// HUB をオフラインにする
+void SetHubOffline(HUB *h)
+{
+	UINT i;
+	bool for_cluster = false;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+		{
+			for_cluster = true;
+		}
+	}
+
+	h->BeingOffline = true;
+
+	Lock(h->lock_online);
+	{
+		if (h->Offline || h->Halt)
+		{
+			Unlock(h->lock_online);
+			h->BeingOffline = false;
+			return;
+		}
+
+		HLog(h, "LH_OFFLINE");
+
+		// すべてのリンクを停止
+		StopAllLink(h);
+
+		// SecureNAT を停止
+		SnFreeSecureNAT(h->SecureNAT);
+		h->SecureNAT = NULL;
+
+		// この HUB に関連付けられているローカルブリッジをすべて停止する
+		LockList(h->Cedar->LocalBridgeList);
+		{
+			for (i = 0;i < LIST_NUM(h->Cedar->LocalBridgeList);i++)
+			{
+				LOCALBRIDGE *br = LIST_DATA(h->Cedar->LocalBridgeList, i);
+
+				if (StrCmpi(br->HubName, h->Name) == 0)
+				{
+					BrFreeBridge(br->Bridge);
+					br->Bridge = NULL;
+				}
+			}
+		}
+		UnlockList(h->Cedar->LocalBridgeList);
+
+		// オフラインにする
+		h->Offline = true;
+
+		// すべてのセッションを切断する
+		StopAllSession(h);
+	}
+	Unlock(h->lock_online);
+
+	h->BeingOffline = false;
+
+	if (h->Cedar->Server != NULL)
+	{
+		SiHubOfflineProc(h);
+	}
+}
+
+// 指定された名前の HUB が存在するかどうか取得
+bool IsHub(CEDAR *cedar, char *name)
+{
+	HUB *h;
+	// 引数チェック
+	if (cedar == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	h = GetHub(cedar, name);
+	if (h == NULL)
+	{
+		return false;
+	}
+
+	ReleaseHub(h);
+
+	return true;
+}
+
+// HUB の取得
+HUB *GetHub(CEDAR *cedar, char *name)
+{
+	HUB *h, t;
+	// 引数チェック
+	if (cedar == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	LockHubList(cedar);
+
+	t.Name = name;
+	h = Search(cedar->HubList, &t);
+	if (h == NULL)
+	{
+		UnlockHubList(cedar);
+		return NULL;
+	}
+
+	AddRef(h->ref);
+
+	UnlockHubList(cedar);
+
+	return h;
+}
+
+// HUB リストのロック
+void LockHubList(CEDAR *cedar)
+{
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return;
+	}
+
+	LockList(cedar->HubList);
+}
+
+// HUB リストのロック解除
+void UnlockHubList(CEDAR *cedar)
+{
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return;
+	}
+
+	UnlockList(cedar->HubList);
+}
+
+// HUB の解放
+void ReleaseHub(HUB *h)
+{
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	if (Release(h->ref) == 0)
+	{
+		CleanupHub(h);
+	}
+}
+
+// Radius サーバー情報を取得
+bool GetRadiusServer(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size)
+{
+	UINT interval;
+	return GetRadiusServerEx(hub, name, size, port, secret, secret_size, &interval);
+}
+bool GetRadiusServerEx(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval)
+{
+	bool ret = false;
+	// 引数チェック
+	if (hub == NULL || name == NULL || port == NULL || secret == NULL || interval == NULL)
+	{
+		return false;
+	}
+
+	Lock(hub->RadiusOptionLock);
+	{
+		if (hub->RadiusServerName != NULL)
+		{
+			char *tmp;
+			UINT tmp_size;
+			StrCpy(name, size, hub->RadiusServerName);
+			*port = hub->RadiusServerPort;
+			*interval = hub->RadiusRetryInterval;
+
+			tmp_size = hub->RadiusSecret->Size + 1;
+			tmp = ZeroMalloc(tmp_size);
+			Copy(tmp, hub->RadiusSecret->Buf, hub->RadiusSecret->Size);
+			StrCpy(secret, secret_size, tmp);
+			Free(tmp);
+
+			ret = true;
+		}
+	}
+	Unlock(hub->RadiusOptionLock);
+
+	return ret;
+}
+
+// Radius サーバー情報を設定
+void SetRadiusServer(HUB *hub, char *name, UINT port, char *secret)
+{
+	SetRadiusServerEx(hub, name, port, secret, RADIUS_RETRY_INTERVAL);
+}
+void SetRadiusServerEx(HUB *hub, char *name, UINT port, char *secret, UINT interval)
+{
+	// 引数チェック
+	if (hub == NULL)
+	{
+		return;
+	}
+
+	Lock(hub->RadiusOptionLock);
+	{
+		if (hub->RadiusServerName != NULL)
+		{
+			Free(hub->RadiusServerName);
+		}
+
+		if (name == NULL)
+		{
+			hub->RadiusServerName = NULL;
+			hub->RadiusServerPort = 0;
+			hub->RadiusRetryInterval = RADIUS_RETRY_INTERVAL;
+			FreeBuf(hub->RadiusSecret);
+		}
+		else
+		{
+			hub->RadiusServerName = CopyStr(name);
+			hub->RadiusServerPort = port;
+			if (interval == 0)
+			{
+				hub->RadiusRetryInterval = RADIUS_RETRY_INTERVAL;
+			}
+			else if (interval > RADIUS_RETRY_TIMEOUT)
+			{
+				hub->RadiusRetryInterval = RADIUS_RETRY_TIMEOUT;
+			}
+			else
+			{
+				hub->RadiusRetryInterval = interval;
+			}
+			FreeBuf(hub->RadiusSecret);
+
+			if (secret == NULL)
+			{
+				hub->RadiusSecret = NewBuf();
+			}
+			else
+			{
+				hub->RadiusSecret = NewBuf();
+				WriteBuf(hub->RadiusSecret, secret, StrLen(secret));
+				SeekBuf(hub->RadiusSecret, 0, 0);
+			}
+		}
+	}
+	Unlock(hub->RadiusOptionLock);
+}
+
+// 仮想 HUB のトラフィック情報の追加
+void IncrementHubTraffic(HUB *h)
+{
+	TRAFFIC t;
+	// 引数チェック
+	if (h == NULL || h->FarmMember == false)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+
+	Lock(h->TrafficLock);
+	{
+		t.Send.BroadcastBytes =
+			h->Traffic->Send.BroadcastBytes - h->OldTraffic->Send.BroadcastBytes;
+		t.Send.BroadcastCount =
+			h->Traffic->Send.BroadcastCount - h->OldTraffic->Send.BroadcastCount;
+		t.Send.UnicastBytes =
+			h->Traffic->Send.UnicastBytes - h->OldTraffic->Send.UnicastBytes;
+		t.Send.UnicastCount =
+			h->Traffic->Send.UnicastCount - h->OldTraffic->Send.UnicastCount;
+		t.Recv.BroadcastBytes =
+			h->Traffic->Recv.BroadcastBytes - h->OldTraffic->Recv.BroadcastBytes;
+		t.Recv.BroadcastCount =
+			h->Traffic->Recv.BroadcastCount - h->OldTraffic->Recv.BroadcastCount;
+		t.Recv.UnicastBytes =
+			h->Traffic->Recv.UnicastBytes - h->OldTraffic->Recv.UnicastBytes;
+		t.Recv.UnicastCount =
+			h->Traffic->Recv.UnicastCount - h->OldTraffic->Recv.UnicastCount;
+		Copy(h->OldTraffic, h->Traffic, sizeof(TRAFFIC));
+	}
+	Unlock(h->TrafficLock);
+
+	if (IsZero(&t, sizeof(TRAFFIC)))
+	{
+		return;
+	}
+
+	AddTrafficDiff(h, h->Name, TRAFFIC_DIFF_HUB, &t);
+}
+
+// トラフィック情報の追加
+void AddTrafficDiff(HUB *h, char *name, UINT type, TRAFFIC *traffic)
+{
+	TRAFFIC_DIFF *d;
+	// 引数チェック
+	if (h == NULL || h->FarmMember == false || name == NULL || traffic == NULL)
+	{
+		return;
+	}
+
+	if (LIST_NUM(h->Cedar->TrafficDiffList) > MAX_TRAFFIC_DIFF)
+	{
+		return;
+	}
+
+	d = ZeroMallocFast(sizeof(TRAFFIC_DIFF));
+	d->HubName = CopyStr(h->Name);
+	d->Name = CopyStr(name);
+	d->Type = type;
+	Copy(&d->Traffic, traffic, sizeof(TRAFFIC));
+
+	LockList(h->Cedar->TrafficDiffList);
+	{
+		Insert(h->Cedar->TrafficDiffList, d);
+	}
+	UnlockList(h->Cedar->TrafficDiffList);
+}
+
+// HUB のクリーンアップ
+void CleanupHub(HUB *h)
+{
+	UINT i;
+	char name[MAX_SIZE];
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	StrCpy(name, sizeof(name), h->Name);
+
+	if (h->WatchDogStarted)
+	{
+		StopHubWatchDog(h);
+	}
+
+	FreeAccessList(h);
+
+	if (h->RadiusServerName != NULL)
+	{
+		Free(h->RadiusServerName);
+		FreeBuf(h->RadiusSecret);
+	}
+	ReleaseAllLink(h);
+	DeleteHubDb(h->HubDb);
+	ReleaseCedar(h->Cedar);
+	DeleteLock(h->lock);
+	DeleteLock(h->lock_online);
+	Free(h->Name);
+	ReleaseList(h->SessionList);
+	ReleaseList(h->MacTable);
+	ReleaseList(h->IpTable);
+	ReleaseList(h->MonitorList);
+	ReleaseList(h->LinkList);
+	DeleteCounter(h->NumSessions);
+	DeleteCounter(h->NumSessionsClient);
+	DeleteCounter(h->NumSessionsBridge);
+	DeleteCounter(h->SessionCounter);
+	FreeTraffic(h->Traffic);
+	FreeTraffic(h->OldTraffic);
+	Free(h->Option);
+
+	Free(h->SecureNATOption);
+
+	DeleteLock(h->TrafficLock);
+
+	for (i = 0;i < LIST_NUM(h->TicketList);i++)
+	{
+		Free(LIST_DATA(h->TicketList, i));
+	}
+
+	ReleaseList(h->TicketList);
+
+	DeleteLock(h->RadiusOptionLock);
+
+	FreeLog(h->PacketLogger);
+	FreeLog(h->SecurityLogger);
+
+	for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
+	{
+		Free(LIST_DATA(h->AdminOptionList, i));
+	}
+	ReleaseList(h->AdminOptionList);
+
+	if (h->Msg != NULL)
+	{
+		Free(h->Msg);
+	}
+
+	Free(h);
+}
+
+// IP テーブルの比較関数
+int CompareIpTable(void *p1, void *p2)
+{
+	IP_TABLE_ENTRY *e1, *e2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	e1 = *(IP_TABLE_ENTRY **)p1;
+	e2 = *(IP_TABLE_ENTRY **)p2;
+	if (e1 == NULL || e2 == NULL)
+	{
+		return 0;
+	}
+	return CmpIpAddr(&e1->Ip, &e2->Ip);
+}
+
+// MAC テーブルの比較関数
+int CompareMacTable(void *p1, void *p2)
+{
+	int r;
+	MAC_TABLE_ENTRY *e1, *e2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	e1 = *(MAC_TABLE_ENTRY **)p1;
+	e2 = *(MAC_TABLE_ENTRY **)p2;
+	if (e1 == NULL || e2 == NULL)
+	{
+		return 0;
+	}
+	r = Cmp(e1->MacAddress, e2->MacAddress, 6);
+	if (r != 0)
+	{
+		return r;
+	}
+	if (e1->VlanId > e2->VlanId)
+	{
+		return 1;
+	}
+	else if (e1->VlanId < e2->VlanId)
+	{
+		return -1;
+	}
+	return 0;
+}
+
+// HUB の比較関数
+int CompareHub(void *p1, void *p2)
+{
+	HUB *h1, *h2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	h1 = *(HUB **)p1;
+	h2 = *(HUB **)p2;
+	if (h1 == NULL || h2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(h1->Name, h2->Name);
+}
+
+// MAC アドレスが仮想 HUB の ARP ポーリング用の MAC アドレスかどうか調べる
+bool IsHubMacAddress(UCHAR *mac)
+{
+	// 引数チェック
+	if (mac == NULL)
+	{
+		return false;
+	}
+
+	if (mac[0] == 0x00 && mac[1] == SE_HUB_MAC_ADDR_SIGN)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// IP アドレスが仮想 HUB の ARP ポーリング用の IP アドレスかどうか調べる
+bool IsHubIpAddress32(UINT ip32)
+{
+	IP ip;
+
+	UINTToIP(&ip, ip32);
+
+	return IsHubIpAddress(&ip);
+}
+bool IsHubIpAddress(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	if (ip->addr[0] == 172 && ip->addr[1] == 31)
+	{
+		if (ip->addr[2] >= 1 && ip->addr[2] <= 254)
+		{
+			if (ip->addr[3] >= 1 && ip->addr[3] <= 254)
+			{
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+bool IsHubIpAddress64(IPV6_ADDR *addr)
+{
+	// 引数チェック
+	if (addr == NULL)
+	{
+		return false;
+	}
+
+	if (addr->Value[0] == 0xfe && addr->Value[1] == 0x80 &&
+		addr->Value[2] == 0 &&
+		addr->Value[3] == 0 &&
+		addr->Value[4] == 0 &&
+		addr->Value[5] == 0 &&
+		addr->Value[6] == 0 &&
+		addr->Value[7] == 0 &&
+		addr->Value[8] == 0x02 && addr->Value[9] == 0xae && 
+		addr->Value[11] == 0xff && addr->Value[12] == 0xfe)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// 仮想 HUB 用 IP アドレスの生成
+void GenHubIpAddress(IP *ip, char *name)
+{
+	char tmp1[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (ip == NULL || name == NULL)
+	{
+		return;
+	}
+
+	StrCpy(tmp1, sizeof(tmp1), name);
+	Trim(tmp1);
+	GenerateMachineUniqueHash(hash);
+	BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
+	StrCat(tmp2, sizeof(tmp2), tmp1);
+	StrUpper(tmp2);
+
+	Hash(hash, tmp2, StrLen(tmp2), true);
+
+	Zero(ip, sizeof(IP));
+	ip->addr[0] = 172;
+	ip->addr[1] = 31;
+	ip->addr[2] = hash[0] % 254 + 1;
+	ip->addr[3] = hash[1] % 254 + 1;
+}
+
+// 仮想 HUB 用 MAC アドレスの生成
+void GenHubMacAddress(UCHAR *mac, char *name)
+{
+	char tmp1[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (mac == NULL || name == NULL)
+	{
+		return;
+	}
+
+	StrCpy(tmp1, sizeof(tmp1), name);
+	Trim(tmp1);
+	GenerateMachineUniqueHash(hash);
+	BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
+	StrCat(tmp2, sizeof(tmp2), tmp1);
+	StrUpper(tmp2);
+
+	Hash(hash, tmp2, StrLen(tmp2), true);
+
+	mac[0] = 0x00;
+	mac[1] = SE_HUB_MAC_ADDR_SIGN;
+	mac[2] = hash[0];
+	mac[3] = hash[1];
+	mac[4] = hash[2];
+	mac[5] = hash[3];
+}
+
+// HUB からメッセージを取得
+wchar_t *GetHubMsg(HUB *h)
+{
+	wchar_t *ret = NULL;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	Lock(h->lock);
+	{
+		if (h->Msg != NULL)
+		{
+			ret = CopyUniStr(h->Msg);
+		}
+	}
+	Unlock(h->lock);
+
+	return ret;
+}
+
+// HUB にメッセージを設定
+void SetHubMsg(HUB *h, wchar_t *msg)
+{
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	Lock(h->lock);
+	{
+		if (h->Msg != NULL)
+		{
+			Free(h->Msg);
+			h->Msg = NULL;
+		}
+
+		if (UniIsEmptyStr(msg) == false)
+		{
+			h->Msg = UniCopyStr(msg);
+		}
+	}
+	Unlock(h->lock);
+}
+
+// 新しい HUB の作成
+HUB *NewHub(CEDAR *cedar, char *HubName, HUB_OPTION *option)
+{
+	HUB *h;
+	char packet_logger_name[MAX_SIZE];
+	char tmp[MAX_SIZE];
+	char safe_hub_name[MAX_HUBNAME_LEN + 1];
+	UCHAR hash[SHA1_SIZE];
+	IP ip6;
+	// 引数チェック
+	if (cedar == NULL || option == NULL || HubName == NULL)
+	{
+		return NULL;
+	}
+
+	h = ZeroMalloc(sizeof(HUB));
+	Hash(h->HashedPassword, "", 0, true);
+	HashPassword(h->SecurePassword, ADMINISTRATOR_USERNAME, "");
+	h->lock = NewLock();
+	h->lock_online = NewLock();
+	h->ref = NewRef();
+	h->Cedar = cedar;
+	AddRef(h->Cedar->ref);
+	h->Type = HUB_TYPE_STANDALONE;
+
+	ConvertSafeFileName(safe_hub_name, sizeof(safe_hub_name), HubName);
+	h->Name = CopyStr(safe_hub_name);
+
+	h->AdminOptionList = NewList(CompareAdminOption);
+	AddHubAdminOptionsDefaults(h, true);
+
+	h->LastCommTime = SystemTime64();
+	h->LastLoginTime = SystemTime64();
+	h->NumLogin = 0;
+
+	h->TrafficLock = NewLock();
+
+	h->HubDb = NewHubDb();
+
+	h->SessionList = NewList(NULL);
+	h->SessionCounter = NewCounter();
+	h->NumSessions = NewCounter();
+	h->NumSessionsClient = NewCounter();
+	h->NumSessionsBridge = NewCounter();
+	h->MacTable = NewList(CompareMacTable);
+	h->IpTable = NewList(CompareIpTable);
+	h->MonitorList = NewList(NULL);
+	h->LinkList = NewList(NULL);
+
+	h->Traffic = NewTraffic();
+	h->OldTraffic = NewTraffic();
+
+	h->Option = ZeroMalloc(sizeof(HUB_OPTION));
+	Copy(h->Option, option, sizeof(HUB_OPTION));
+
+	if (h->Option->VlanTypeId == 0)
+	{
+		h->Option->VlanTypeId = MAC_PROTO_TAGVLAN;
+	}
+
+	Rand(h->HubSignature, sizeof(h->HubSignature));
+
+	// SecureNAT 関係
+	h->EnableSecureNAT = false;
+	h->SecureNAT = NULL;
+	h->SecureNATOption = ZeroMalloc(sizeof(VH_OPTION));
+	NiSetDefaultVhOption(NULL, h->SecureNATOption);
+
+	if (h->Cedar != NULL && h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption, true);
+	}
+
+	// HUB 用の一時的な MAC アドレスを生成する
+	GenerateMachineUniqueHash(hash);
+	GenHubMacAddress(h->HubMacAddr, h->Name);
+	GenHubIpAddress(&h->HubIp, h->Name);
+
+	// HUB 用 IPv6 アドレス
+	GenerateEui64LocalAddress(&ip6, h->HubMacAddr);
+	IPToIPv6Addr(&h->HubIpV6, &ip6);
+
+	h->RadiusOptionLock = NewLock();
+	h->RadiusServerPort = RADIUS_DEFAULT_PORT;
+
+	h->TicketList = NewList(NULL);
+
+	InitAccessList(h);
+
+	// デフォルトのログ設定
+	h->LogSetting.SaveSecurityLog = true;
+	h->LogSetting.SavePacketLog = false;
+	h->LogSetting.PacketLogConfig[PACKET_LOG_TCP_CONN] =
+		h->LogSetting.PacketLogConfig[PACKET_LOG_DHCP] = PACKET_LOG_HEADER;
+	h->LogSetting.SecurityLogSwitchType = LOG_SWITCH_DAY;
+	h->LogSetting.PacketLogSwitchType = LOG_SWITCH_DAY;
+
+	MakeDir(HUB_SECURITY_LOG_DIR_NAME);
+	MakeDir(HUB_PACKET_LOG_DIR_NAME);
+
+	// パケットロガーの開始
+	Format(packet_logger_name, sizeof(packet_logger_name), HUB_PACKET_LOG_FILE_NAME, h->Name);
+	h->PacketLogger = NewLog(packet_logger_name, HUB_PACKET_LOG_PREFIX, h->LogSetting.PacketLogSwitchType);
+
+	// セキュリティロガーの開始
+	Format(tmp, sizeof(tmp), HUB_SECURITY_LOG_FILE_NAME, h->Name);
+	h->SecurityLogger = NewLog(tmp, HUB_SECURITY_LOG_PREFIX, h->LogSetting.SecurityLogSwitchType);
+
+	if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		h->FarmMember = true;
+	}
+
+	// HUB の開始
+	SetHubOnline(h);
+
+	if (h->Cedar->Bridge)
+	{
+		h->Option->NoArpPolling = true;
+	}
+
+	if (h->Option->NoArpPolling == false && h->Option->NoIpTable == false)
+	{
+		StartHubWatchDog(h);
+		h->WatchDogStarted = true;
+	}
+
+	SLog(h->Cedar, "LS_HUB_START", h->Name);
+
+	MacToStr(tmp, sizeof(tmp), h->HubMacAddr);
+	SLog(h->Cedar, "LS_HUB_MAC", h->Name, tmp);
+
+	return h;
+}
+
+// HUBDB の削除
+void DeleteHubDb(HUBDB *d)
+{
+	// 引数チェック
+	if (d == NULL)
+	{
+		return;
+	}
+
+	LockList(d->UserList);
+	{
+		LockList(d->GroupList);
+		{
+			// すべてのユーザーとグループを解放
+			UINT i;
+			USER **users;
+			USERGROUP **groups;
+
+			users = ToArray(d->UserList);
+			groups = ToArray(d->GroupList);
+
+			for (i = 0;i < LIST_NUM(d->UserList);i++)
+			{
+				ReleaseUser(users[i]);
+			}
+			for (i = 0;i < LIST_NUM(d->GroupList);i++)
+			{
+				ReleaseGroup(groups[i]);
+			}
+
+			Free(users);
+			Free(groups);
+		}
+		UnlockList(d->GroupList);
+	}
+	UnlockList(d->UserList);
+
+	// ルート証明書一覧を解放
+	LockList(d->RootCertList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(d->RootCertList);i++)
+		{
+			X *x = LIST_DATA(d->RootCertList, i);
+			FreeX(x);
+		}
+	}
+	UnlockList(d->RootCertList);
+
+	// CRL を解放
+	LockList(d->CrlList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(d->CrlList);i++)
+		{
+			CRL *crl = LIST_DATA(d->CrlList, i);
+			FreeCrl(crl);
+		}
+	}
+	UnlockList(d->CrlList);
+
+	ReleaseList(d->GroupList);
+	ReleaseList(d->UserList);
+	ReleaseList(d->RootCertList);
+	ReleaseList(d->CrlList);
+	Free(d);
+}
+
+// HUB のログ設定を取得する
+void GetHubLogSetting(HUB *h, HUB_LOG *setting)
+{
+	// 引数チェック
+	if (setting == NULL || h == NULL)
+	{
+		return;
+	}
+
+	Copy(setting, &h->LogSetting, sizeof(HUB_LOG));
+}
+
+// HUB のログ設定を更新する
+void SetHubLogSettingEx(HUB *h, HUB_LOG *setting, bool no_change_switch_type)
+{
+	UINT i1, i2;
+	// 引数チェック
+	if (setting == NULL || h == NULL)
+	{
+		return;
+	}
+
+	i1 = h->LogSetting.PacketLogSwitchType;
+	i2 = h->LogSetting.SecurityLogSwitchType;
+
+	Copy(&h->LogSetting, setting, sizeof(HUB_LOG));
+
+	if (no_change_switch_type)
+	{
+		h->LogSetting.PacketLogSwitchType = i1;
+		h->LogSetting.SecurityLogSwitchType = i2;
+	}
+
+	// パケットロガー設定
+	SetLogSwitchType(h->PacketLogger, setting->PacketLogSwitchType);
+	SetLogSwitchType(h->SecurityLogger, setting->SecurityLogSwitchType);
+}
+void SetHubLogSetting(HUB *h, HUB_LOG *setting)
+{
+	SetHubLogSettingEx(h, setting, false);
+}
+
+// HUB に信頼するルート証明書を追加する
+void AddRootCert(HUB *hub, X *x)
+{
+	HUBDB *db;
+	// 引数チェック
+	if (hub == NULL || x == NULL)
+	{
+		return;
+	}
+
+	db = hub->HubDb;
+	if (db != NULL)
+	{
+		LockList(db->RootCertList);
+		{
+			if (LIST_NUM(db->RootCertList) < MAX_HUB_CERTS)
+			{
+				UINT i;
+				bool ok = true;
+
+				for (i = 0;i < LIST_NUM(db->RootCertList);i++)
+				{
+					X *exist_x = LIST_DATA(db->RootCertList, i);
+					if (CompareX(exist_x, x))
+					{
+						ok = false;
+						break;
+					}
+				}
+
+				if (ok)
+				{
+					Insert(db->RootCertList, CloneX(x));
+				}
+			}
+		}
+		UnlockList(db->RootCertList);
+	}
+}
+
+// 証明書リストの比較
+int CompareCert(void *p1, void *p2)
+{
+	X *x1, *x2;
+	wchar_t tmp1[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	x1 = *(X **)p1;
+	x2 = *(X **)p2;
+	if (x1 == NULL || x2 == NULL)
+	{
+		return 0;
+	}
+
+	GetPrintNameFromX(tmp1, sizeof(tmp1), x1);
+	GetPrintNameFromX(tmp2, sizeof(tmp2), x2);
+
+	return UniStrCmpi(tmp1, tmp2);
+}
+
+// 新しい HUBDB の作成
+HUBDB *NewHubDb()
+{
+	HUBDB *d = ZeroMalloc(sizeof(HUBDB));
+
+	d->GroupList = NewList(CompareGroupName);
+	d->UserList = NewList(CompareUserName);
+	d->RootCertList = NewList(CompareCert);
+	d->CrlList = NewList(NULL);
+
+	return d;
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Hub.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Hub.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Hub.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,510 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Hub.h
+// Hub.c のヘッダ
+
+#ifndef	HUB_H
+#define	HUB_H
+
+
+
+// SoftEther リンク制御パケット
+struct SE_LINK
+{
+	UCHAR DestMacAddress[6];			// 宛先 MAC アドレス
+	UCHAR SrcMacAddress[6];				// 送信元 MAC アドレス
+	UCHAR SignatureS;					// 'S'
+	UCHAR SignatureE;					// 'E'
+	UCHAR Padding[2];					// パディング
+	UINT Type;							// 種類
+	UCHAR HubSignature[16];				// HUB シグネチャ
+	UINT TransactionId;					// トランザクション ID
+	UINT Data;							// データ
+	UCHAR Dummy[20];					// ダミー
+	UCHAR Checksum[SHA1_SIZE];			// チェックサム
+};
+
+
+// テストパケット受信記録
+struct TEST_HISTORY
+{
+	SESSION *s1;
+	SESSION *s2;
+};
+
+// リンクテスト用状態マシン
+struct SE_TEST
+{
+	LOCK *lock;							// ロック
+	UINT64 LastTestPacketSentTime;		// 最後にテストパケットを送信した時刻
+	UINT NextTestPacketSendInterval;	// 次のテストパケット送信間隔
+	bool CurrentTesting;				// 現在テストパケットを送信してテスト中
+	UINT TransactionId;					// トランザクション ID
+	LIST *TestHistory;					// 受信履歴
+};
+
+// マクロ
+#define	NO_ACCOUNT_DB(h)		((h)->FarmMember)
+
+// スタンドアロンまたはファームマスタ HUB の場合のデータベース
+struct HUBDB
+{
+	LIST *UserList;						// ユーザーリスト
+	LIST *GroupList;					// グループリスト
+	LIST *RootCertList;					// 信頼する証明書リスト
+	LIST *CrlList;						// CRL リスト
+};
+
+// トラフィック リミッタ
+struct TRAFFIC_LIMITER
+{
+	UINT64 LastTime;					// 最後に測定した時刻
+	UINT64 Value;						// 現在の値
+};
+
+// エンドポイントごとのブロードキャスト数記録
+struct STORM
+{
+	UCHAR MacAddress[6];				// MAC アドレス
+	UCHAR Padding[2];					// パディング
+	IP SrcIp;							// 送信元 IP アドレス
+	IP DestIp;							// 宛先 IP アドレス
+	UINT64 CheckStartTick;				// チェックを開始した時刻
+	UINT CurrentBroadcastNum;			// 現在のブロードキャスト個数
+	UINT DiscardValue;					// ブロードキャストパケットを破棄する割合
+};
+
+// HUB 用パケットアダプタ情報構造体
+struct HUB_PA
+{
+	CANCEL *Cancel;						// キャンセルオブジェクト
+	QUEUE *PacketQueue;					// パケットキュー
+	bool MonitorPort;					// モニタポート
+	UINT64 Now;							// 現在時刻
+	TRAFFIC_LIMITER UploadLimiter;		// アップロード帯域幅制限
+	TRAFFIC_LIMITER DownloadLimiter;	// ダウンロード帯域幅制限
+	SESSION *Session;					// セッション
+	LIST *StormList;					// ブロードキャスト嵐記録用リスト
+	UINT UsernameHash;					// ユーザー名ハッシュ
+	UINT GroupnameHash;					// グループ名ハッシュ
+};
+
+// HUB オプション
+struct HUB_OPTION
+{
+	// 標準オプション
+	UINT MaxSession;					// 最大同時接続数
+	bool NoEnum;						// 列挙の対象外
+	// 拡張オプション
+	bool NoArpPolling;					// ARP ポーリングしない
+	bool NoIPv6AddrPolling;				// IPv6 アドレスポーリングしない
+	bool NoIpTable;						// IP アドレステーブルを生成しない
+	bool NoMacAddressLog;				// MAC アドレスの登録ログを書き込まない
+	bool ManageOnlyPrivateIP;			// プライベート IP のみを管理対象にする
+	bool ManageOnlyLocalUnicastIPv6;	// ローカルユニキャスト IPv6 アドレスのみを管理対象にする
+	bool DisableIPParsing;				// IP 解釈を禁止する
+	bool YieldAfterStorePacket;			// パケットをストアした後イールドする
+	bool NoSpinLockForPacketDelay;		// スピンロックを使用しない
+	UINT BroadcastStormDetectionThreshold;	// ブロードキャスト数制限閾値
+	bool FilterPPPoE;					// PPPoE をフィルタリングする (0x8863, 0x8864)
+	bool FilterOSPF;					// OSPF をフィルタリングする (ip_proto=89)
+	bool FilterIPv4;					// IPv4 パケットをフィルタリングする
+	bool FilterIPv6;					// IPv6 パケットをフィルタリングする
+	bool FilterNonIP;					// 非 IP パケットをすべてフィルタリング
+	bool FilterBPDU;					// BPDU パケットをフィルタリングする
+	UINT ClientMinimumRequiredBuild;	// クライアントのビルド番号が一定以下であれば拒否
+	bool NoIPv6DefaultRouterInRAWhenIPv6;	// IPv6 ルータ広告からデフォルトルータ指定を削除 (IPv6 物理接続時のみ)
+	bool NoIPv4PacketLog;				// IPv4 パケットのパケットログを保存しない
+	bool NoIPv6PacketLog;				// IPv6 パケットのパケットログを保存しない
+	bool NoLookBPDUBridgeId;			// スイッチングのために BPDU ブリッジ ID を見ない
+	bool NoManageVlanId;				// VLAN ID を管理しない
+	UINT VlanTypeId;					// VLAN パケットの Type ID (通常は 0x8100)
+	bool FixForDLinkBPDU;				// D-Link の変な挙動をする BPDU のための fix を適用する
+	UINT RequiredClientId;				// クライアント ID
+};
+
+// MAC テーブルエントリ
+struct MAC_TABLE_ENTRY
+{
+	UCHAR MacAddress[6];				// MAC アドレス
+	UCHAR Padding[2];
+	UINT VlanId;						// VLAN ID
+	SESSION *Session;					// セッション
+	HUB_PA *HubPa;						// HUB パケットアダプタ
+	UINT64 CreatedTime;					// 作成日時
+	UINT64 UpdatedTime;					// 更新日時
+};
+
+// IP テーブルエントリ
+struct IP_TABLE_ENTRY
+{
+	IP Ip;								// IP アドレス
+	SESSION *Session;					// セッション
+	bool DhcpAllocated;					// DHCP によって割り当て済み
+	UINT64 CreatedTime;					// 作成日時
+	UINT64 UpdatedTime;					// 更新日時
+	UCHAR MacAddress[6];				// MAC アドレス
+};
+
+// ループリスト
+struct LOOP_LIST
+{
+	UINT NumSessions;
+	SESSION **Session;
+};
+
+// アクセスリスト
+struct ACCESS
+{
+	// IPv4
+	UINT Id;							// ID
+	wchar_t Note[MAX_ACCESSLIST_NOTE_LEN + 1];	// メモ
+	bool Active;						// 有効フラグ
+	UINT Priority;						// 優先順位
+	bool Discard;						// 破棄フラグ
+	UINT SrcIpAddress;					// 送信元 IP アドレス
+	UINT SrcSubnetMask;					// 送信元サブネットマスク
+	UINT DestIpAddress;					// 宛先 IP アドレス
+	UINT DestSubnetMask;				// 宛先サブネットマスク
+	UINT Protocol;						// プロトコル
+	UINT SrcPortStart;					// 送信元ポート番号開始点
+	UINT SrcPortEnd;					// 送信元ポート番号終了点
+	UINT DestPortStart;					// 宛先ポート番号開始点
+	UINT DestPortEnd;					// 宛先ポート番号終了点
+	UINT SrcUsernameHash;				// 送信元ユーザー名ハッシュ
+	char SrcUsername[MAX_USERNAME_LEN + 1];
+	UINT DestUsernameHash;				// 宛先ユーザー名ハッシュ
+	char DestUsername[MAX_USERNAME_LEN + 1];
+	bool CheckSrcMac;					// 送信元 MAC アドレスの設定の有無
+	UCHAR SrcMacAddress[6];				// 送信元 MAC アドレス
+	UCHAR SrcMacMask[6];				// 送信元 MAC アドレスマスク
+	bool CheckDstMac;					// 宛先 MAC アドレスの設定の有無
+	UCHAR DstMacAddress[6];				// 宛先 MAC アドレス
+	UCHAR DstMacMask[6];				// 宛先 MAC アドレスマスク
+	bool CheckTcpState;					// TCP コネクションの状態
+	bool Established;					// Establieshed(TCP)
+	UINT Delay;							// 遅延
+	UINT Jitter;						// ジッタ
+	UINT Loss;							// パケットロス
+
+	// IPv6
+	bool IsIPv6;						// IPv6 かどうか
+	IPV6_ADDR SrcIpAddress6;			// 送信元 IP アドレス (IPv6)
+	IPV6_ADDR SrcSubnetMask6;			// 送信元サブネットマスク (IPv6)
+	IPV6_ADDR DestIpAddress6;			// 宛先 IP アドレス (IPv6)
+	IPV6_ADDR DestSubnetMask6;			// 宛先サブネットマスク (IPv6)
+};
+
+// チケット
+struct TICKET
+{
+	UINT64 CreatedTick;						// 作成日時
+	UCHAR Ticket[SHA1_SIZE];				// チケット
+	char Username[MAX_USERNAME_LEN + 1];	// ユーザー名
+	char UsernameReal[MAX_USERNAME_LEN + 1];	// 本当のユーザー名
+	char GroupName[MAX_USERNAME_LEN + 1];	// グループ名
+	char SessionName[MAX_SESSION_NAME_LEN + 1];	// セッション名
+	POLICY Policy;							// ポリシー
+};
+
+// トラフィック差分
+struct TRAFFIC_DIFF
+{
+	UINT Type;							// 種別
+	TRAFFIC Traffic;					// トラフィック
+	char *HubName;						// HUB 名
+	char *Name;							// 名前
+};
+
+// 管理オプション
+struct ADMIN_OPTION
+{
+	char Name[MAX_ADMIN_OPTION_NAME_LEN + 1];	// 名前
+	UINT Value;									// データ
+};
+
+// 証明書無効エントリ
+struct CRL
+{
+	X_SERIAL *Serial;					// シリアル番号
+	NAME *Name;							// 名前情報
+	UCHAR DigestMD5[MD5_SIZE];			// MD5 ハッシュ
+	UCHAR DigestSHA1[SHA1_SIZE];		// SHA-1 ハッシュ
+};
+
+// アクセスコントロール
+struct AC
+{
+	UINT Id;							// ID
+	UINT Priority;						// 優先順位
+	bool Deny;							// アクセスを拒否
+	bool Masked;						// マスクされているかどうか
+	IP IpAddress;						// IP アドレス
+	IP SubnetMask;						// サブネットマスク
+};
+
+// HUB 構造体
+struct HUB
+{
+	LOCK *lock;							// ロック
+	LOCK *lock_online;					// オンライン用ロック
+	REF *ref;							// 参照カウンタ
+	CEDAR *Cedar;						// Cedar
+	UINT Type;							// 種類
+	HUBDB *HubDb;						// データベース
+	char *Name;							// HUB の名前
+	LOCK *RadiusOptionLock;				// Radius オプション用ロック
+	char *RadiusServerName;				// Radius サーバー名
+	UINT RadiusServerPort;				// Radius サーバーポート番号
+	UINT RadiusRetryInterval;			// Radius 再試行間隔
+	BUF *RadiusSecret;					// Radius 共有鍵
+	volatile bool Halt;					// 停止フラグ
+	bool Offline;						// オフライン
+	bool BeingOffline;					// オフライン化中
+	LIST *SessionList;					// セッションリスト
+	COUNTER *SessionCounter;			// セッション番号生成カウンタ
+	TRAFFIC *Traffic;					// トラフィック情報
+	TRAFFIC *OldTraffic;				// 古いトラフィック情報
+	LOCK *TrafficLock;					// トラフィックロック
+	COUNTER *NumSessions;				// 現在のセッション数
+	COUNTER *NumSessionsClient;			// 現在のセッション数 (クライアント)
+	COUNTER *NumSessionsBridge;			// 現在のセッション数 (ブリッジ)
+	HUB_OPTION *Option;					// HUB オプション
+	LIST *MacTable;						// MAC アドレステーブル
+	LIST *IpTable;						// IP アドレステーブル
+	LIST *MonitorList;					// モニタポートセッションリスト
+	LIST *LinkList;						// リンクリスト
+	UCHAR HubSignature[16];				// HUB シグネチャ
+	UCHAR HubMacAddr[6];				// HUB の MAC アドレス
+	IP HubIp;							// HUB の IP アドレス (IPv4)
+	IPV6_ADDR HubIpV6;					// HUB の IP アドレス (IPv6)
+	UINT HubIP6Id;						// HUB の IPv6 パケット ID
+	UCHAR Padding[2];					// パディング
+	LOCK *LoopListLock;					// ループリスト用ロック
+	UINT NumLoopList;					// ループリスト数
+	LOOP_LIST **LoopLists;				// ループリスト
+	LIST *AccessList;					// アクセスリスト
+	HUB_LOG LogSetting;					// ログ設定
+	LOG *PacketLogger;					// パケットロガー
+	LOG *SecurityLogger;				// セキュリティロガー
+	UCHAR HashedPassword[SHA1_SIZE];	// パスワード
+	UCHAR SecurePassword[SHA1_SIZE];	// セキュアパスワード
+	LIST *TicketList;					// チケットリスト
+	bool FarmMember;					// ファームメンバー
+	UINT64 LastIncrementTraffic;		// トラフィック報告時刻
+	UINT64 LastSendArpTick;				// 最後の ARP 送信時刻
+	SNAT *SecureNAT;					// SecureNAT
+	bool EnableSecureNAT;				// SecureNAT 有効/無効フラグ
+	VH_OPTION *SecureNATOption;			// SecureNAT のオプション
+	THREAD *WatchDogThread;				// 番犬スレッド
+	EVENT *WatchDogEvent;				// 番犬イベント
+	bool WatchDogStarted;				// 番犬スレッドが使用されているかどうか
+	volatile bool HaltWatchDog;			// 番犬スレッドの停止
+	LIST *AdminOptionList;				// 管理オプションリスト
+	UINT64 CreatedTime;					// 作成日時
+	UINT64 LastCommTime;				// 最終通信日時
+	UINT64 LastLoginTime;				// 最終ログイン日時
+	UINT NumLogin;						// ログイン回数
+	bool HubIsOnlineButHalting;			// 仮想 HUB は本当はオンラインだが停止のためにオフライン化してある
+	UINT FarmMember_MaxSessionClient;	// クラスタメンバ用 最大クライアント接続セッション数
+	UINT FarmMember_MaxSessionBridge;	// クラスタメンバ用 最大ブリッジ接続セッション数
+	bool FarmMember_MaxSessionClientBridgeApply;	// FarmMember_MaxSession* を適用する
+	UINT CurrentVersion;				// 現在のバージョン
+	UINT LastVersion;					// 最後に更新通知を発行したときのバージョン
+	wchar_t *Msg;						// クライアントが接続してきたときに表示するメッセージ
+};
+
+
+// グローバル変数
+extern ADMIN_OPTION admin_options[];
+extern UINT num_admin_options;
+
+
+// 関数プロトタイプ
+HUBDB *NewHubDb();
+void DeleteHubDb(HUBDB *d);
+HUB *NewHub(CEDAR *cedar, char *HubName, HUB_OPTION *option);
+void SetHubMsg(HUB *h, wchar_t *msg);
+wchar_t *GetHubMsg(HUB *h);
+void GenHubMacAddress(UCHAR *mac, char *name);
+void GenHubIpAddress(IP *ip, char *name);
+bool IsHubIpAddress(IP *ip);
+bool IsHubIpAddress32(UINT ip32);
+bool IsHubIpAddress64(IPV6_ADDR *addr);
+bool IsHubMacAddress(UCHAR *mac);
+void ReleaseHub(HUB *h);
+void CleanupHub(HUB *h);
+int CompareHub(void *p1, void *p2);
+void LockHubList(CEDAR *cedar);
+void UnlockHubList(CEDAR *cedar);
+HUB *GetHub(CEDAR *cedar, char *name);
+bool IsHub(CEDAR *cedar, char *name);
+void StopHub(HUB *h);
+void AddSession(HUB *h, SESSION *s);
+void DelSession(HUB *h, SESSION *s);
+void StopAllSession(HUB *h);
+bool HubPaInit(SESSION *s);
+void HubPaFree(SESSION *s);
+CANCEL *HubPaGetCancel(SESSION *s);
+UINT HubPaGetNextPacket(SESSION *s, void **data);
+bool HubPaPutPacket(SESSION *s, void *data, UINT size);
+PACKET_ADAPTER *GetHubPacketAdapter();
+int CompareMacTable(void *p1, void *p2);
+void StorePacket(HUB *hub, SESSION *s, PKT *packet);
+bool StorePacketFilter(SESSION *s, PKT *packet);
+void StorePacketToHubPa(HUB_PA *dest, SESSION *src, void *data, UINT size, PKT *packet);
+void SetHubOnline(HUB *h);
+void SetHubOffline(HUB *h);
+SESSION *GetSessionByPtr(HUB *hub, void *ptr);
+SESSION *GetSessionByName(HUB *hub, char *name);
+int CompareIpTable(void *p1, void *p2);
+bool StorePacketFilterByPolicy(SESSION *s, PKT *p);
+bool DeleteIPv6DefaultRouterInRA(PKT *p);
+bool StorePacketFilterByTrafficLimiter(SESSION *s, PKT *p);
+void IntoTrafficLimiter(TRAFFIC_LIMITER *tr, PKT *p);
+bool IsMostHighestPriorityPacket(SESSION *s, PKT *p);
+bool IsPriorityPacketForQoS(PKT *p);
+int CompareStormList(void *p1, void *p2);
+STORM *SearchStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip);
+STORM *AddStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip);
+bool CheckBroadcastStorm(SESSION *s, PKT *p);
+void AddRootCert(HUB *hub, X *x);
+int CmpAccessList(void *p1, void *p2);
+void InitAccessList(HUB *hub);
+void FreeAccessList(HUB *hub);
+void AddAccessList(HUB *hub, ACCESS *a);
+UINT UsernameToInt(char *name);
+bool ApplyAccessListToStoredPacket(HUB *hub, SESSION *s, PKT *p);
+bool ApplyAccessListToForwardPacket(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *p);
+bool IsPacketMaskedByAccessList(SESSION *s, PKT *p, ACCESS *a, UINT dest_username, UINT dest_groupname);
+void GetAccessListStr(char *str, UINT size, ACCESS *a);
+void DeleteOldIpTableEntry(LIST *o);
+void SetRadiusServer(HUB *hub, char *name, UINT port, char *secret);
+void SetRadiusServerEx(HUB *hub, char *name, UINT port, char *secret, UINT interval);
+bool GetRadiusServer(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size);
+bool GetRadiusServerEx(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval);
+int CompareCert(void *p1, void *p2);
+void GetHubLogSetting(HUB *h, HUB_LOG *setting);
+void SetHubLogSetting(HUB *h, HUB_LOG *setting);
+void SetHubLogSettingEx(HUB *h, HUB_LOG *setting, bool no_change_switch_type);
+void DeleteExpiredIpTableEntry(LIST *o);
+void DeleteExpiredMacTableEntry(LIST *o);
+void AddTrafficDiff(HUB *h, char *name, UINT type, TRAFFIC *traffic);
+void IncrementHubTraffic(HUB *h);
+void EnableSecureNAT(HUB *h, bool enable);
+void EnableSecureNATEx(HUB *h, bool enable, bool no_change);
+void StartHubWatchDog(HUB *h);
+void StopHubWatchDog(HUB *h);
+void HubWatchDogThread(THREAD *t, void *param);
+int CompareAdminOption(void *p1, void *p2);
+UINT GetHubAdminOptionEx(HUB *h, char *name, UINT default_value);
+UINT GetHubAdminOption(HUB *h, char *name);
+void DeleteAllHubAdminOption(HUB *h, bool lock);
+void AddHubAdminOptionsDefaults(HUB *h, bool lock);
+bool IsCertMatchCrl(X *x, CRL *crl);
+bool IsCertMatchCrlList(X *x, LIST *o);
+wchar_t *GenerateCrlStr(CRL *crl);
+bool IsValidCertInHub(HUB *h, X *x);
+void FreeCrl(CRL *crl);
+CRL *CopyCrl(CRL *crl);
+int CmpAc(void *p1, void *p2);
+LIST *NewAcList();
+void AddAc(LIST *o, AC *ac);
+bool DelAc(LIST *o, UINT id);
+AC *GetAc(LIST *o, UINT id);
+void SetAc(LIST *o, UINT id, AC *ac);
+void DelAllAc(LIST *o);
+void SetAcList(LIST *o, LIST *src);
+void NormalizeAcList(LIST *o);
+char *GenerateAcStr(AC *ac);
+void FreeAcList(LIST *o);
+LIST *CloneAcList(LIST *o);
+bool IsIPPrivate(IP *ip);
+bool IsIPManagementTargetForHUB(IP *ip, HUB *hub);
+wchar_t *GetHubAdminOptionHelpString(char *name);
+void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name);
+ADMIN_OPTION *NewAdminOption(char *name, UINT value);
+void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao);
+UINT GetHubAdminOptionData(RPC_ADMIN_OPTION *ao, char *name);
+void GetHubAdminOptionDataAndSet(RPC_ADMIN_OPTION *ao, char *name, UINT *dest);
+bool IsURLMsg(wchar_t *str, char *url, UINT url_size);
+
+
+#endif	// HUB_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Layer3.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Layer3.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Layer3.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2167 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Layer3.c
+// Layer-3 スイッチ モジュール
+
+#include "CedarPch.h"
+
+static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+// IP キューの処理
+void L3PollingIpQueue(L3IF *f)
+{
+	L3PACKET *p;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	// 別のセッションから来たパケットを処理する
+	while (p = GetNext(f->IpPacketQueue))
+	{
+		PKT *pkt = p->Packet;
+
+		// IP パケットとして送信する
+		L3SendIp(f, p);
+	}
+}
+
+// IP パケットの処理
+void L3RecvIp(L3IF *f, PKT *p, bool self)
+{
+	IPV4_HEADER *ip;
+	UINT header_size;
+	UINT next_hop = 0;
+	L3IF *dst;
+	L3PACKET *packet;
+	UINT new_ttl = 0;
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+
+	ip = p->L3.IPv4Header;
+	header_size = IPV4_GET_HEADER_LEN(p->L3.IPv4Header) * 4;
+
+	// チェックサムの計算
+	if (IpCheckChecksum(ip) == false)
+	{
+		// チェックサムが一致しない
+		goto FREE_PACKET;
+	}
+
+	// ARP テーブルに登録
+	L3KnownArp(f, ip->SrcIP, p->MacAddressSrc);
+
+	if (p->BroadcastPacket)
+	{
+		// ブロードキャストパケットの場合はルーティングしない
+		goto FREE_PACKET;
+	}
+
+	// TTL を計算
+	if (ip->TimeToLive >= 1)
+	{
+		new_ttl = ip->TimeToLive - 1;
+	}
+	else
+	{
+		new_ttl = 0;
+	}
+
+	if (new_ttl == 0)
+	{
+		if (ip->DstIP != f->IpAddress)
+		{
+			UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);
+			UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;
+			UCHAR *buf;
+			IPV4_HEADER *ipv4;
+			ICMP_HEADER *icmpv4;
+			UCHAR *data;
+			PKT *pkt;
+			UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);
+
+			// TTL 切れが発生したことを知らせる ICMP メッセージを生成する
+			buf = ZeroMalloc(icmp_packet_total_size);
+			ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));
+			icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));
+			data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;
+
+			IPV4_SET_VERSION(ipv4, 4);
+			IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);
+			ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));
+			ipv4->TimeToLive = 0xff;
+			ipv4->Protocol = IP_PROTO_ICMPV4;
+			ipv4->SrcIP = f->IpAddress;
+			ipv4->DstIP = ip->SrcIP;
+			ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
+
+			icmpv4->Type = 11;
+			Copy(data, ip, data_size);
+			icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);
+
+			buf[12] = 0x08;
+			buf[13] = 0x00;
+
+			pkt = ParsePacket(buf, icmp_packet_total_size);
+			if (pkt == NULL)
+			{
+				Free(buf);
+			}
+			else
+			{
+				L3RecvIp(f, pkt, true);
+			}
+
+			// TTL が切れたパケット本体は破棄する
+			goto FREE_PACKET;
+		}
+	}
+
+	// 書き換える
+	p->L3.IPv4Header->TimeToLive = (UCHAR)new_ttl;
+
+	// 宛先 IP アドレスに対するインターフェイスを取得する
+	dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);
+
+	if (dst == NULL && self == false)
+	{
+		UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);
+		UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;
+		UCHAR *buf;
+		IPV4_HEADER *ipv4;
+		ICMP_HEADER *icmpv4;
+		UCHAR *data;
+		PKT *pkt;
+			UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);
+
+		// ルートが見つからない旨を ICMP で応答する
+		buf = ZeroMalloc(icmp_packet_total_size);
+		ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));
+		icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));
+		data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;
+
+		IPV4_SET_VERSION(ipv4, 4);
+		IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);
+		ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));
+		ipv4->TimeToLive = 0xff;
+		ipv4->Protocol = IP_PROTO_ICMPV4;
+		ipv4->SrcIP = f->IpAddress;
+		ipv4->DstIP = ip->SrcIP;
+		ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
+
+		icmpv4->Type = 3;
+		Copy(data, ip, data_size);
+		icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);
+
+		buf[12] = 0x08;
+		buf[13] = 0x00;
+
+		pkt = ParsePacket(buf, icmp_packet_total_size);
+		if (pkt == NULL)
+		{
+			Free(buf);
+		}
+		else
+		{
+			L3RecvIp(f, pkt, true);
+		}
+
+		// ルートが見つからないパケット本体は破棄する
+		goto FREE_PACKET;
+	}
+
+	if (dst != NULL && ip->DstIP == dst->IpAddress)
+	{
+		bool free_packet = true;
+		// 自分宛の IP パケットが届いた
+		if (p->TypeL4 == L4_ICMPV4)
+		{
+			ICMP_HEADER *icmp = p->L4.ICMPHeader;
+			if (icmp->Type == ICMP_TYPE_ECHO_REQUEST)
+			{
+				// この IP パケットの宛先と送信元を書き換えて返信する
+				UINT src_ip, dst_ip;
+				src_ip = p->L3.IPv4Header->DstIP;
+				dst_ip = p->L3.IPv4Header->SrcIP;
+
+				p->L3.IPv4Header->DstIP = dst_ip;
+				p->L3.IPv4Header->SrcIP = src_ip;
+
+				ip->TimeToLive = 0xff;
+
+				// チェックサムを再計算する
+				ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
+				icmp->Checksum = 0;
+				icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
+				icmp->Checksum = IpChecksum(icmp, p->PacketSize - sizeof(MAC_HEADER) - header_size);
+
+				dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);
+
+				free_packet = false;
+			}
+		}
+
+		if (free_packet)
+		{
+			goto FREE_PACKET;
+		}
+	}
+
+	if (dst == NULL)
+	{
+		// 宛先が存在しない
+		goto FREE_PACKET;
+	}
+
+	// IP チェックサムの再計算
+	ip->Checksum = 0;
+	ip->Checksum = IpChecksum(ip, header_size);
+
+	// Layer-3 パケットとして処理する
+	packet = ZeroMalloc(sizeof(L3PACKET));
+	packet->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;
+	packet->NextHopIp = next_hop;
+	packet->Packet = p;
+
+	// 宛先セッションにストアする
+	L3StoreIpPacketToIf(f, dst, packet);
+
+	return;
+
+FREE_PACKET:
+	// パケットの解放
+	Free(p->PacketData);
+	FreePacket(p);
+	return;
+}
+
+// レイヤ 2 パケットの処理
+void L3RecvL2(L3IF *f, PKT *p)
+{
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// 自分が送信したパケットか、ユニキャストパケットで自分宛で無いパケット
+	// はすべて無視する
+	if (Cmp(p->MacAddressSrc, f->MacAddress, 6) == 0 ||
+		(p->BroadcastPacket == false && Cmp(p->MacAddressDest, f->MacAddress, 6) != 0))
+	{
+		// パケット解放
+		Free(p->PacketData);
+		FreePacket(p);
+		return;
+	}
+
+	if (p->TypeL3 == L3_ARPV4)
+	{
+		// ARP パケットを受信した
+		L3RecvArp(f, p);
+
+		// パケット解放
+		Free(p->PacketData);
+		FreePacket(p);
+	}
+	else if (p->TypeL3 == L3_IPV4)
+	{
+		// IP パケットを受信した
+		L3RecvIp(f, p, false);
+	}
+	else
+	{
+		// パケット解放
+		Free(p->PacketData);
+		FreePacket(p);
+	}
+}
+
+// IP パケットを別のインターフェイスにストアする
+void L3StoreIpPacketToIf(L3IF *src_if, L3IF *dst_if, L3PACKET *p)
+{
+	// 引数チェック
+	if (src_if == NULL || p == NULL || dst_if == NULL)
+	{
+		return;
+	}
+
+	// ストア先セッションのキューに追加する
+	InsertQueue(dst_if->IpPacketQueue, p);
+
+	// ストア先セッションの Cancel オブジェクトを叩くことにする
+	AddCancelList(src_if->CancelList, dst_if->Session->Cancel1);
+}
+
+// パケットを書き込む (新しいパケットが届いたので処理する)
+void L3PutPacket(L3IF *f, void *data, UINT size)
+{
+	PKT *p;
+	L3SW *s;
+	if (f == NULL)
+	{
+		return;
+	}
+
+	s = f->Switch;
+
+	if (data != NULL)
+	{
+		// 次のパケットを処理する
+		if (f->CancelList == NULL)
+		{
+			f->CancelList = NewCancelList();
+		}
+
+		// パケット解析
+		p = ParsePacket(data, size);
+
+		if (p == NULL)
+		{
+			// パケット解析失敗
+			Free(data);
+		}
+		else
+		{
+			// パケット解析成功
+			Lock(s->lock);
+			{
+				L3RecvL2(f, p);
+			}
+			Unlock(s->lock);
+		}
+	}
+	else
+	{
+		// すべてのパケットの処理が終わったらキャンセルリストをキャンセル処理する
+		if (f->CancelList != NULL)
+		{
+			CancelList(f->CancelList);
+			ReleaseCancelList(f->CancelList);
+			f->CancelList = NULL;
+		}
+	}
+}
+
+// 待機している IP パケットのうち送信先 MAC アドレスが解決したものを送信する
+void L3SendWaitingIp(L3IF *f, UCHAR *mac, UINT ip, L3ARPENTRY *a)
+{
+	UINT i;
+	LIST *o = NULL;
+	// 引数チェック
+	if (f == NULL || mac == NULL || a == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+	{
+		L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+
+		if (p->NextHopIp == ip)
+		{
+			if (o == NULL)
+			{
+				o = NewListFast(NULL);
+			}
+			Add(o, p);
+		}
+	}
+
+	if (o != NULL)
+	{
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			L3PACKET *p = LIST_DATA(o, i);
+
+			// 送信
+			L3SendIpNow(f, a, p);
+
+			Delete(f->IpWaitList, p);
+			Free(p->Packet->PacketData);
+			FreePacket(p->Packet);
+			Free(p);
+		}
+
+		ReleaseList(o);
+	}
+}
+
+// ARP テーブルに登録する
+void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac)
+{
+	L3ARPENTRY *a, t;
+	// 引数チェック
+	if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	t.IpAddress = ip;
+
+	a = Search(f->ArpTable, &t);
+
+	if (a == NULL)
+	{
+		// リストに登録されていないので登録する
+		a = ZeroMalloc(sizeof(L3ARPENTRY));
+		a->IpAddress = ip;
+		Copy(a->MacAddress, mac, 6);
+		Insert(f->ArpTable, a);
+	}
+
+	// 有効期限を延長する
+	a->Expire = Tick64() + ARP_ENTRY_EXPIRES;
+
+	// 待機している IP パケットを送信させる
+	L3SendWaitingIp(f, mac, ip, a);
+}
+
+// ARP テーブルを知ったときに呼ばれる関数
+void L3KnownArp(L3IF *f, UINT ip, UCHAR *mac)
+{
+	L3ARPWAIT t, *w;
+	// 引数チェック
+	if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)
+	{
+		return;
+	}
+
+	// この IP アドレスへの ARP 問い合わせテーブルを削除する
+	Zero(&t, sizeof(t));
+	t.IpAddress = ip;
+	w = Search(f->IpWaitList, &t);
+	if (w != NULL)
+	{
+		Delete(f->IpWaitList, w);
+		Free(w);
+	}
+
+	// ARP テーブルに登録する
+	L3InsertArpTable(f, ip, mac);
+}
+
+// ARP を発行する
+void L3SendArp(L3IF *f, UINT ip)
+{
+	L3ARPWAIT t, *w;
+	// 引数チェック
+	if (f == NULL || ip == 0 || ip == 0xffffffff)
+	{
+		return;
+	}
+
+	// すでに登録されていないかどうか調べる
+	Zero(&t, sizeof(t));
+	t.IpAddress = ip;
+	w = Search(f->ArpWaitTable, &t);
+
+	if (w != NULL)
+	{
+		// すでに待機リストに登録されているので何もしない
+		return;
+	}
+	else
+	{
+		// 新しくリストに登録する
+		w = ZeroMalloc(sizeof(L3ARPWAIT));
+		w->Expire = Tick64() + ARP_REQUEST_GIVEUP;
+		w->IpAddress = ip;
+		Insert(f->ArpWaitTable, w);
+	}
+}
+
+// ARP 要求を受信した
+void L3RecvArpRequest(L3IF *f, PKT *p)
+{
+	ARPV4_HEADER *a;
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+
+	a = p->L3.ARPv4Header;
+
+	L3KnownArp(f, a->SrcIP, a->SrcAddress);
+
+	if (a->TargetIP == f->IpAddress)
+	{
+		// 自分宛の ARP パケットの場合のみ応答する
+		L3SendArpResponseNow(f, a->SrcAddress, a->SrcIP, f->IpAddress);
+	}
+}
+
+// ARP 応答を受信した
+void L3RecvArpResponse(L3IF *f, PKT *p)
+{
+	ARPV4_HEADER *a;
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+
+	a = p->L3.ARPv4Header;
+
+	L3KnownArp(f, a->SrcIP, a->SrcAddress);
+}
+
+// ARP パケットを受信した
+void L3RecvArp(L3IF *f, PKT *p)
+{
+	ARPV4_HEADER *a;
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+
+	a = p->L3.ARPv4Header;
+
+	if (Endian16(a->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET ||
+		Endian16(a->ProtocolType) != MAC_PROTO_IPV4 ||
+		a->HardwareSize != 6 || a->ProtocolSize != 4)
+	{
+		return;
+	}
+	if (Cmp(a->SrcAddress, p->MacAddressSrc, 6) != 0)
+	{
+		return;
+	}
+
+	switch (Endian16(a->Operation))
+	{
+	case ARP_OPERATION_REQUEST:
+		// ARP 要求が届いた
+		L3RecvArpRequest(f, p);
+		break;
+
+	case ARP_OPERATION_RESPONSE:
+		// ARP 応答が届いた
+		L3RecvArpResponse(f, p);
+		break;
+	}
+}
+
+// IP パケットを送信する
+void L3SendIp(L3IF *f, L3PACKET *p)
+{
+	L3ARPENTRY *a = NULL;
+	bool broadcast = false;
+	IPV4_HEADER *ip;
+	bool for_me = false;
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+	if (p->Packet->TypeL3 != L3_IPV4)
+	{
+		return;
+	}
+
+	ip = p->Packet->L3.IPv4Header;
+
+	// ブロードキャストかどうか判定
+	if (p->NextHopIp == 0xffffffff ||
+		((p->NextHopIp & f->SubnetMask) == (f->IpAddress & f->SubnetMask)) &&
+		((p->NextHopIp & (~f->SubnetMask)) == (~f->SubnetMask)))
+	{
+		broadcast = true;
+	}
+
+	if (broadcast == false && ip->DstIP == f->IpAddress)
+	{
+		// me?
+	}
+	else if (broadcast == false)
+	{
+		// ユニキャストの場合 ARP エントリに入っているかどうか調べる
+		a = L3SearchArpTable(f, p->NextHopIp);
+
+		if (a == NULL)
+		{
+			// ARP エントリに入っていないので、すぐに送信せずに
+			// IP 待ちリストに挿入する
+			p->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;
+
+			Insert(f->IpWaitList, p);
+
+			// ARP を発行しておく
+			L3SendArp(f, p->NextHopIp);
+			return;
+		}
+	}
+
+	if (for_me == false)
+	{
+		// IP パケットを送信する
+		L3SendIpNow(f, a, p);
+	}
+
+	// パケットを解放する
+	Free(p->Packet->PacketData);
+	FreePacket(p->Packet);
+	Free(p);
+}
+
+// IP パケットをすぐに送信する
+void L3SendIpNow(L3IF *f, L3ARPENTRY *a, L3PACKET *p)
+{
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+
+	L3SendL2Now(f, a != NULL ? a->MacAddress : broadcast, f->MacAddress, Endian16(p->Packet->MacHeader->Protocol),
+		p->Packet->L3.PointerL3, p->Packet->PacketSize - sizeof(MAC_HEADER));
+}
+
+// ARP テーブルを検索する
+L3ARPENTRY *L3SearchArpTable(L3IF *f, UINT ip)
+{
+	L3ARPENTRY *e, t;
+	// 引数チェック
+	if (f == NULL || ip == 0 || ip == 0xffffffff)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	t.IpAddress = ip;
+
+	e = Search(f->ArpTable, &t);
+
+	return e;
+}
+
+// ARP 要求パケットを送信する
+void L3SendArpRequestNow(L3IF *f, UINT dest_ip)
+{
+	ARPV4_HEADER arp;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	// ARP ヘッダを構築
+	arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+	arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+	arp.HardwareSize = 6;
+	arp.ProtocolSize = 4;
+	arp.Operation = Endian16(ARP_OPERATION_REQUEST);
+	Copy(arp.SrcAddress, f->MacAddress, 6);
+	arp.SrcIP = f->IpAddress;
+	Zero(&arp.TargetAddress, 6);
+	arp.TargetIP = dest_ip;
+
+	// 送信
+	L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// ARP 応答パケットを送信する
+void L3SendArpResponseNow(L3IF *f, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)
+{
+	ARPV4_HEADER arp;
+	// 引数チェック
+	if (f == NULL || dest_mac == NULL)
+	{
+		return;
+	}
+
+	// ヘッダ構築
+	arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+	arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+	arp.HardwareSize = 6;
+	arp.ProtocolSize = 4;
+	arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+	Copy(arp.SrcAddress, f->MacAddress, 6);
+	Copy(arp.TargetAddress, dest_mac, 6);
+	arp.SrcIP = src_ip;
+	arp.TargetIP = dest_ip;
+
+	// 送信
+	L3SendL2Now(f, dest_mac, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// インターフェイスの MAC アドレスの生成
+void L3GenerateMacAddress(L3IF *f)
+{
+	BUF *b;
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, f->Switch->Name, StrLen(f->Switch->Name));
+	WriteBuf(b, f->HubName, StrLen(f->HubName));
+	WriteBuf(b, &f->IpAddress, sizeof(f->IpAddress));
+
+	GenMacAddress(f->MacAddress);
+	Hash(hash, b->Buf, b->Size, true);
+	Copy(f->MacAddress + 2, hash, 4);
+	f->MacAddress[1] = 0xA3;
+	FreeBuf(b);
+}
+
+// L2 パケットをすぐに送信する
+void L3SendL2Now(L3IF *f, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)
+{
+	UCHAR *buf;
+	MAC_HEADER *mac_header;
+	PKT *p;
+	// 引数チェック
+	if (f == NULL || dest_mac == NULL || src_mac == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// バッファ生成
+	buf = Malloc(MAC_HEADER_SIZE + size);
+
+	// MAC ヘッダ
+	mac_header = (MAC_HEADER *)&buf[0];
+	Copy(mac_header->DestAddress, dest_mac, 6);
+	Copy(mac_header->SrcAddress, src_mac, 6);
+	mac_header->Protocol = Endian16(protocol);
+
+	// データのコピー
+	Copy(&buf[sizeof(MAC_HEADER)], data, size);
+
+	// サイズ
+	size += sizeof(MAC_HEADER);
+
+	// パケット生成
+	p = ZeroMalloc(sizeof(PKT));
+	p->PacketData = buf;
+	p->PacketSize = size;
+
+	// キューに追加する
+	InsertQueue(f->SendQueue, p);
+}
+
+// ARP 解決待ちリストのポーリング
+void L3PollingArpWaitTable(L3IF *f)
+{
+	UINT i;
+	LIST *o = NULL;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)
+	{
+		L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);
+
+		if (w->Expire <= Tick64())
+		{
+			// ARP 要求テーブルが期限切れである
+			if (o == NULL)
+			{
+				o = NewListFast(NULL);
+			}
+
+			Insert(o, w);
+		}
+		else if ((w->LastSentTime + ARP_REQUEST_TIMEOUT) <= Tick64())
+		{
+			// 次の ARP 要求パケットを送信する
+			w->LastSentTime = Tick64();
+
+			L3SendArpRequestNow(f, w->IpAddress);
+		}
+	}
+
+	if (o != NULL)
+	{
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			L3ARPWAIT *w = LIST_DATA(o, i);
+
+			Delete(f->ArpWaitTable, w);
+			Free(w);
+		}
+
+		ReleaseList(o);
+	}
+}
+
+// 古い ARP テーブルの清掃
+void L3DeleteOldArpTable(L3IF *f)
+{
+	UINT i;
+	LIST *o = NULL;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	if ((f->LastDeleteOldArpTable + ARP_ENTRY_POLLING_TIME) > Tick64())
+	{
+		return;
+	}
+	f->LastDeleteOldArpTable = Tick64();
+
+	for (i = 0;i < LIST_NUM(f->ArpTable);i++)
+	{
+		L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);
+
+		if (a->Expire <= Tick64())
+		{
+			// 有効期限切れ
+			if (o == NULL)
+			{
+				o = NewListFast(NULL);
+			}
+
+			Insert(o, a);
+		}
+	}
+
+	if (o != NULL)
+	{
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			L3ARPENTRY *a = LIST_DATA(o, i);
+
+			Delete(f->ArpTable, a);
+			Free(a);
+		}
+
+		ReleaseList(o);
+	}
+}
+
+// IP 待ちリストの清掃
+void L3DeleteOldIpWaitList(L3IF *f)
+{
+	UINT i;
+	LIST *o = NULL;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+	{
+		L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+
+		if (p->Expire <= Tick64())
+		{
+			if (o == NULL)
+			{
+				o = NewListFast(NULL);
+			}
+
+			Insert(o, p);
+		}
+	}
+
+	if (o != NULL)
+	{
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			L3PACKET *p = LIST_DATA(o, i);
+
+			Delete(f->IpWaitList, p);
+
+			Free(p->Packet->PacketData);
+			FreePacket(p->Packet);
+			Free(p);
+		}
+
+		ReleaseList(o);
+	}
+}
+
+// ビーコン送信
+void L3PollingBeacon(L3IF *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	if (f->LastBeaconSent == 0 ||
+		(f->LastBeaconSent + BEACON_SEND_INTERVAL) <= Tick64())
+	{
+		UINT dest_ip;
+		UCHAR *udp_buf;
+		UINT udp_buf_size;
+		ARPV4_HEADER arp;
+		IPV4_HEADER *ip;
+		UDP_HEADER *udp;
+		static char beacon_str[] =
+			"SoftEther UT-VPN Virtual Layer-3 Switch Beacon";
+
+		// UDP を送信
+		dest_ip = (f->IpAddress & f->SubnetMask) | (~f->SubnetMask);
+		udp_buf_size = sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + sizeof(beacon_str);
+		udp_buf = ZeroMalloc(udp_buf_size);
+
+		ip = (IPV4_HEADER *)udp_buf;
+		udp = (UDP_HEADER *)(udp_buf + sizeof(IPV4_HEADER));
+		udp->DstPort = Endian16(7);
+		udp->SrcPort = Endian16(7);
+		udp->PacketLength = Endian16(sizeof(UDP_HEADER) + sizeof(beacon_str));
+
+		Copy(udp_buf + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER), beacon_str, sizeof(beacon_str));
+
+		udp->Checksum = IpChecksum(udp, sizeof(UDP_HEADER) + sizeof(beacon_str));
+
+		ip->DstIP = dest_ip;
+		IPV4_SET_VERSION(ip, 4);
+		IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
+		ip->TypeOfService = DEFAULT_IP_TOS;
+		ip->TotalLength = Endian16((USHORT)(udp_buf_size));
+		ip->TimeToLive = DEFAULT_IP_TTL;
+		ip->Protocol = IP_PROTO_UDP;
+		ip->SrcIP = f->IpAddress;
+		ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
+
+		L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_IPV4, udp_buf, udp_buf_size);
+
+		Free(udp_buf);
+
+		// ARP ヘッダを構築
+		arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+		arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+		arp.HardwareSize = 6;
+		arp.ProtocolSize = 4;
+		arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+		Copy(arp.SrcAddress, f->MacAddress, 6);
+		arp.SrcIP = f->IpAddress;
+		arp.TargetAddress[0] =
+			arp.TargetAddress[1] =
+			arp.TargetAddress[2] =
+			arp.TargetAddress[3] =
+			arp.TargetAddress[4] =
+			arp.TargetAddress[5] = 0xff;
+		arp.TargetIP = dest_ip;
+
+		// 送信
+		L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+
+		f->LastBeaconSent = Tick64();
+	}
+}
+
+// ポーリング処理
+void L3Polling(L3IF *f)
+{
+	L3SW *s;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	s = f->Switch;
+
+	// ポーリング処理の途中ではスイッチ全体にロックをかける
+	Lock(s->lock);
+	{
+		// ビーコン送信
+		L3PollingBeacon(f);
+
+		// IP キューの処理
+		L3PollingIpQueue(f);
+
+		// 古い ARP テーブルの清掃
+		L3DeleteOldArpTable(f);
+
+		// ARP 解決待ちリストのポーリング
+		L3PollingArpWaitTable(f);
+
+		// IP 待ちリストの清掃
+		L3DeleteOldIpWaitList(f);
+	}
+	Unlock(s->lock);
+}
+
+// 次のパケットを取得する
+UINT L3GetNextPacket(L3IF *f, void **data)
+{
+	UINT ret = 0;
+	// 引数チェック
+	if (f == NULL || data == NULL)
+	{
+		return 0;
+	}
+
+START:
+	// 送信キューを調べる
+	LockQueue(f->SendQueue);
+	{
+		PKT *p = GetNext(f->SendQueue);
+
+		if (p != NULL)
+		{
+			// パケットがあった
+			ret = p->PacketSize;
+			*data = p->PacketData;
+			// パケット構造体は破棄して良い
+			Free(p);
+		}
+	}
+	UnlockQueue(f->SendQueue);
+
+	if (ret == 0)
+	{
+		// ポーリング処理
+		L3Polling(f);
+
+        // ポーリング処理の結果、新たにパケットがキューに入っていないか
+		// どうか調べる
+		if (f->SendQueue->num_item != 0)
+		{
+			// キューに入っていたら早速そのパケットを取得させる
+			goto START;
+		}
+	}
+
+	return ret;
+}
+
+// 指定した IP アドレス宛のパケットをどのインターフェイスに投げれば良いか決める
+L3IF *L3GetNextIf(L3SW *s, UINT ip, UINT *next_hop)
+{
+	UINT i;
+	L3IF *f;
+	UINT next_hop_ip = 0;
+	// 引数チェック
+	if (s == NULL || ip == 0 || ip == 0xffffffff)
+	{
+		return NULL;
+	}
+
+	f = NULL;
+
+	// まず各インターフェイスの所属しているネットワークに指定した IP アドレスが
+	// 含まれるものが無いかどうか調べる
+	for (i = 0;i < LIST_NUM(s->IfList);i++)
+	{
+		L3IF *ff = LIST_DATA(s->IfList, i);
+
+		if ((ff->IpAddress & ff->SubnetMask) == (ip & ff->SubnetMask))
+		{
+			f = ff;
+			next_hop_ip = ip;
+			break;
+		}
+	}
+
+	if (f == NULL)
+	{
+		// 見つからなかったらルーティングテーブルを探す
+		L3TABLE *t = L3GetBestRoute(s, ip);
+
+		if (t == NULL)
+		{
+			// それでも見つからなかった
+			return NULL;
+		}
+		else
+		{
+			// 見つかったルートの NextHop のルータの IP アドレスを持つ
+			// インターフェイスを探す
+			for (i = 0;i < LIST_NUM(s->IfList);i++)
+			{
+				L3IF *ff = LIST_DATA(s->IfList, i);
+
+				if ((ff->IpAddress & ff->SubnetMask) == (t->GatewayAddress & ff->SubnetMask))
+				{
+					f = ff;
+					next_hop_ip = t->GatewayAddress;
+					break;
+				}
+			}
+		}
+	}
+
+	if (f == NULL)
+	{
+		// 結局宛先インターフェイスが不明であった
+		return NULL;
+	}
+
+	if (next_hop != NULL)
+	{
+		*next_hop = next_hop_ip;
+	}
+
+	return f;
+}
+
+// 指定した IP アドレス宛の最適なルーティングテーブルエントリを取得する
+L3TABLE *L3GetBestRoute(L3SW *s, UINT ip)
+{
+	UINT i;
+	UINT max_mask = 0;
+	UINT min_metric = INFINITE;
+	L3TABLE *ret = NULL;
+	// 引数チェック
+	if (s == NULL || ip == 0)
+	{
+		return NULL;
+	}
+
+	// 第一条件: サブネットマスクが最も大きいものを選択
+	// 第二条件: メトリックが最も小さいものを選択
+	for (i = 0;i < LIST_NUM(s->TableList);i++)
+	{
+		L3TABLE *t = LIST_DATA(s->TableList, i);
+
+		if ((t->NetworkAddress & t->SubnetMask) == (ip & t->SubnetMask))
+		{
+			if (t->SubnetMask >= max_mask)
+			{
+				max_mask = t->SubnetMask;
+				if (min_metric >= t->Metric)
+				{
+					min_metric = t->Metric;
+					ret = t;
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+// Layer-3 インターフェイスの初期化
+void L3InitInterface(L3IF *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	// MAC アドレス生成
+	L3GenerateMacAddress(f);
+
+	// リスト生成
+	f->ArpTable = NewList(CmpL3ArpEntry);
+	f->ArpWaitTable = NewList(CmpL3ArpWaitTable);
+	f->IpPacketQueue = NewQueue();
+	f->IpWaitList = NewList(NULL);
+	f->SendQueue = NewQueue();
+}
+
+// Layer-3 インターフェイスの解放
+void L3FreeInterface(L3IF *f)
+{
+	UINT i;
+	L3PACKET *p;
+	PKT *pkt;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(f->ArpTable);i++)
+	{
+		L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);
+		Free(a);
+	}
+	ReleaseList(f->ArpTable);
+	f->ArpTable = NULL;
+
+	for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)
+	{
+		L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);
+		Free(w);
+	}
+	ReleaseList(f->ArpWaitTable);
+	f->ArpWaitTable = NULL;
+
+	while (p = GetNext(f->IpPacketQueue))
+	{
+		Free(p->Packet->PacketData);
+		FreePacket(p->Packet);
+		Free(p);
+	}
+	ReleaseQueue(f->IpPacketQueue);
+	f->IpPacketQueue = NULL;
+
+	for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+	{
+		L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+		Free(p->Packet->PacketData);
+		FreePacket(p->Packet);
+		Free(p);
+	}
+	ReleaseList(f->IpWaitList);
+	f->IpWaitList = NULL;
+
+	while (pkt = GetNext(f->SendQueue))
+	{
+		Free(pkt->PacketData);
+		FreePacket(pkt);
+	}
+	ReleaseQueue(f->SendQueue);
+	f->SendQueue = NULL;
+}
+
+// Layer-3 インターフェイスのスレッド
+void L3IfThread(THREAD *t, void *param)
+{
+	L3IF *f;
+	CONNECTION *c;
+	SESSION *s;
+	POLICY *policy;
+	char tmp[MAX_SIZE];
+	char name[MAX_SIZE];
+	char username[MAX_SIZE];
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	f = (L3IF *)param;
+
+	StrCpy(username, sizeof(username), L3_USERNAME);
+	if (f->Switch != NULL)
+	{
+		StrCat(username, sizeof(username), f->Switch->Name);
+	}
+
+	// コネクションの作成
+	c = NewServerConnection(f->Switch->Cedar, NULL, t);
+	c->Protocol = CONNECTION_HUB_LAYER3;
+
+	// セッションの作成
+	policy = ClonePolicy(GetDefaultPolicy());
+	// ポリシーではブロードキャスト数を制限しない
+	policy->NoBroadcastLimiter = true;
+	s = NewServerSession(f->Switch->Cedar, c, f->Hub, username, policy);
+	c->Session = s;
+
+	ReleaseConnection(c);
+
+	// セッション名を決定する
+	GetMachineHostName(tmp, sizeof(tmp));
+	if (f->Switch->Cedar->Server->ServerType == SERVER_TYPE_STANDALONE)
+	{
+		Format(name, sizeof(name), "SID-L3-%s-%u", f->Switch->Name, Inc(f->Hub->SessionCounter));
+	}
+	else
+	{
+		Format(name, sizeof(name), "SID-L3-%s-%s-%u", tmp, f->Switch->Name, Inc(f->Hub->SessionCounter));
+	}
+	ConvertSafeFileName(name, sizeof(name), name);
+	StrUpper(name);
+
+	Free(s->Name);
+	s->Name = CopyStr(name);
+
+	s->L3SwitchMode = true;
+	s->L3If = f;
+
+	if (s->Username != NULL)
+	{
+		Free(s->Username);
+	}
+	s->Username = CopyStr(username);
+
+	StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username);
+
+	f->Session = s;
+	AddRef(s->ref);
+
+	// 初期化完了を通知
+	NoticeThreadInit(t);
+
+	// セッションメイン処理
+	SessionMain(s);
+
+	// セッションの解放
+	ReleaseSession(s);
+}
+
+// すべての Layer-3 インターフェイスの初期化をする
+void L3InitAllInterfaces(L3SW *s)
+{
+	UINT i;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(s->IfList);i++)
+	{
+		L3IF *f = LIST_DATA(s->IfList, i);
+		THREAD *t;
+
+		L3InitInterface(f);
+
+		f->Hub = GetHub(s->Cedar, f->HubName);
+		t = NewThread(L3IfThread, f);
+		WaitThreadInit(t);
+		ReleaseThread(t);
+	}
+}
+
+// すべての Layer-3 インターフェイスの解放をする
+void L3FreeAllInterfaces(L3SW *s)
+{
+	UINT i;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(s->IfList);i++)
+	{
+		L3IF *f = LIST_DATA(s->IfList, i);
+
+		ReleaseHub(f->Hub);
+		f->Hub = NULL;
+		ReleaseSession(f->Session);
+		f->Session = NULL;
+
+		L3FreeInterface(f);
+	}
+}
+
+// Layer-3 テスト
+void L3Test(SERVER *s)
+{
+	L3SW *ss = L3AddSw(s->Cedar, "TEST");
+	L3AddIf(ss, "DEFAULT", 0x0101a8c0, 0x00ffffff);
+	L3AddIf(ss, "DEFAULT2", 0x0102a8c0, 0x00ffffff);
+	L3SwStart(ss);
+	ReleaseL3Sw(ss);
+}
+
+// Layer-3 スイッチスレッド
+void L3SwThread(THREAD *t, void *param)
+{
+	L3SW *s;
+	bool shutdown_now = false;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	s = (L3SW *)param;
+
+	s->Active = true;
+
+	NoticeThreadInit(t);
+
+	// 動作開始
+	SLog(s->Cedar, "L3_SWITCH_START", s->Name);
+
+	while (s->Halt == false)
+	{
+		if (s->Online == false)
+		{
+			// 現在 L3 スイッチはオフラインなので、一定時間ごとにオンライン化
+			// を試みる
+			LockList(s->Cedar->HubList);
+			{
+				Lock(s->lock);
+				{
+					UINT i;
+					UINT n = 0;
+					bool all_exists = true;
+					if (LIST_NUM(s->IfList) == 0)
+					{
+						// 1 つもインターフェイスが無い場合は動作しない
+						all_exists = false;
+					}
+					for (i = 0;i < LIST_NUM(s->IfList);i++)
+					{
+						L3IF *f = LIST_DATA(s->IfList, i);
+						HUB *h = GetHub(s->Cedar, f->HubName);
+
+						if (h != NULL)
+						{
+							if (h->Offline || h->Type == HUB_TYPE_FARM_DYNAMIC)
+							{
+								all_exists = false;
+							}
+							else
+							{
+								n++;
+							}
+							ReleaseHub(h);
+						}
+						else
+						{
+							all_exists = false;
+						}
+					}
+
+					if (all_exists && n >= 1)
+					{
+						// すべてのインターフェイスの仮想 HUB が有効になったので
+						// 動作を開始する
+						SLog(s->Cedar, "L3_SWITCH_ONLINE", s->Name);
+						L3InitAllInterfaces(s);
+						s->Online = true;
+					}
+				}
+				Unlock(s->lock);
+			}
+			UnlockList(s->Cedar->HubList);
+		}
+		else
+		{
+			// 一定時間ごとにすべてのセッションが終了していないかどうか調査する
+			UINT i;
+			bool any_halted = false;
+			LIST *o = NULL;
+
+SHUTDOWN:
+
+			Lock(s->lock);
+			{
+				for (i = 0;i < LIST_NUM(s->IfList);i++)
+				{
+					L3IF *f = LIST_DATA(s->IfList, i);
+					if (f->Session->Halt || f->Hub->Offline != false)
+					{
+						any_halted = true;
+						break;
+					}
+				}
+
+				if (shutdown_now)
+				{
+					any_halted = true;
+				}
+
+				if (any_halted)
+				{
+					SLog(s->Cedar, "L3_SWITCH_OFFLINE", s->Name);
+					o = NewListFast(NULL);
+					// 1 つでも終了したセッションがあれば、すべてのセッションを終了する
+					for (i = 0;i < LIST_NUM(s->IfList);i++)
+					{
+						L3IF *f = LIST_DATA(s->IfList, i);
+						Insert(o, f->Session);
+					}
+
+					// オフラインに戻す
+					s->Online = false;
+				}
+			}
+			Unlock(s->lock);
+
+			if (o != NULL)
+			{
+				UINT i;
+				for (i = 0;i < LIST_NUM(o);i++)
+				{
+					SESSION *s = LIST_DATA(o, i);
+					StopSession(s);
+				}
+				L3FreeAllInterfaces(s);
+				ReleaseList(o);
+				o = NULL;
+			}
+		}
+
+		SleepThread(50);
+	}
+
+	if (s->Online != false)
+	{
+		shutdown_now = true;
+		goto SHUTDOWN;
+	}
+
+	// 動作停止
+	SLog(s->Cedar, "L3_SWITCH_STOP", s->Name);
+}
+
+// Layer-3 スイッチを開始する
+void L3SwStart(L3SW *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Lock(s->lock);
+	{
+		if (s->Active == false)
+		{
+			// 登録されている IF 数が 1 以上でないと開始しない
+			if (LIST_NUM(s->IfList) >= 1)
+			{
+				s->Halt = false;
+
+				// スレッド作成
+				s->Thread = NewThread(L3SwThread, s);
+				WaitThreadInit(s->Thread);
+			}
+		}
+	}
+	Unlock(s->lock);
+}
+
+// Layer-3 スイッチを停止する
+void L3SwStop(L3SW *s)
+{
+	THREAD *t = NULL;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Lock(s->lock);
+	{
+		if (s->Active == false)
+		{
+			Unlock(s->lock);
+			return;
+		}
+
+		s->Halt = true;
+
+		t = s->Thread;
+
+		s->Active = false;
+	}
+	Unlock(s->lock);
+
+	WaitThread(t, INFINITE);
+	ReleaseThread(t);
+}
+
+// Layer-3 スイッチを追加する
+L3SW *L3AddSw(CEDAR *c, char *name)
+{
+	L3SW *s = NULL;
+	// 引数チェック
+	if (c == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	LockList(c->L3SwList);
+	{
+		s = L3GetSw(c, name);
+
+		if (s == NULL)
+		{
+			s = NewL3Sw(c, name);
+
+			Insert(c->L3SwList, s);
+
+			AddRef(s->ref);
+		}
+		else
+		{
+			ReleaseL3Sw(s);
+			s = NULL;
+		}
+	}
+	UnlockList(c->L3SwList);
+
+	return s;
+}
+
+// Layer-3 スイッチを削除する
+bool L3DelSw(CEDAR *c, char *name)
+{
+	L3SW *s;
+	bool ret = false;
+	// 引数チェック
+	if (c == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	LockList(c->L3SwList);
+	{
+		s = L3GetSw(c, name);
+
+		if (s != NULL)
+		{
+			// 停止して削除
+			L3SwStop(s);
+			Delete(c->L3SwList, s);
+			ReleaseL3Sw(s);
+			ReleaseL3Sw(s);
+
+			ret = true;
+		}
+	}
+	UnlockList(c->L3SwList);
+
+	return ret;
+}
+
+
+// ルーティングテーブルの削除
+bool L3DelTable(L3SW *s, L3TABLE *tbl)
+{
+	bool ret = false;
+	// 引数チェック
+	if (s == NULL || tbl == NULL)
+	{
+		return false;
+	}
+
+	Lock(s->lock);
+	{
+		if (s->Active == false)
+		{
+			L3TABLE *t = Search(s->TableList, tbl);
+
+			if (t != NULL)
+			{
+				Delete(s->TableList, t);
+				Free(t);
+
+				ret = true;
+			}
+		}
+	}
+	Unlock(s->lock);
+
+	return ret;
+}
+
+// ルーティングテーブルの追加
+bool L3AddTable(L3SW *s, L3TABLE *tbl)
+{
+	bool ret = false;
+	// 引数チェック
+	if (s == NULL || tbl == NULL)
+	{
+		return false;
+	}
+
+	if (tbl->Metric == 0 || tbl->GatewayAddress == 0 || tbl->GatewayAddress == 0xffffffff)
+	{
+		return false;
+	}
+
+	Lock(s->lock);
+	{
+		if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_table"))
+		{
+			// 数が多すぎる
+		}
+		else
+		{
+			// 作成
+			if (s->Active == false)
+			{
+				if (Search(s->TableList, tbl) == NULL)
+				{
+					L3TABLE *t = ZeroMalloc(sizeof(L3TABLE));
+
+					Copy(t, tbl, sizeof(L3TABLE));
+
+					Insert(s->TableList, t);
+
+					ret = true;
+				}
+			}
+		}
+	}
+	Unlock(s->lock);
+
+	return ret;
+}
+
+// L3 スイッチを取得する
+L3SW *L3GetSw(CEDAR *c, char *name)
+{
+	L3SW t, *s;
+	// 引数チェック
+	if (c == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.Name, sizeof(t.Name), name);
+
+	LockList(c->L3SwList);
+	{
+		s = Search(c->L3SwList, &t);
+	}
+	UnlockList(c->L3SwList);
+
+	if (s != NULL)
+	{
+		AddRef(s->ref);
+	}
+
+	return s;
+}
+
+// L3 スイッチから指定した仮想 HUB に接続されているインターフェイスを取得する
+L3IF *L3SearchIf(L3SW *s, char *hubname)
+{
+	L3IF t, *f;
+	// 引数チェック
+	if (s == NULL || hubname == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+	f = Search(s->IfList, &t);
+
+	return f;
+}
+
+// インターフェイスの削除
+bool L3DelIf(L3SW *s, char *hubname)
+{
+	L3IF *f;
+	bool ret = false;
+	// 引数チェック
+	if (s == NULL || hubname == NULL)
+	{
+		return false;
+	}
+
+	Lock(s->lock);
+	{
+		if (s->Active == false)
+		{
+			f = L3SearchIf(s, hubname);
+
+			if (f != NULL)
+			{
+				// 削除する
+				Delete(s->IfList, f);
+				Free(f);
+
+				ret = true;
+			}
+		}
+	}
+	Unlock(s->lock);
+
+	return ret;
+}
+
+// インターフェイスの追加
+bool L3AddIf(L3SW *s, char *hubname, UINT ip, UINT subnet)
+{
+	L3IF *f;
+	bool ret = false;
+	// 引数チェック
+	if (s == NULL || hubname == NULL || IsSafeStr(hubname) == false ||
+		ip == 0 || ip == 0xffffffff)
+	{
+		return false;
+	}
+
+	Lock(s->lock);
+	{
+		if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_if"))
+		{
+			// 数が多すぎる
+		}
+		else
+		{
+			if (s->Active == false)
+			{
+				// 同じ仮想 HUB にすでにインターフェイスが入っていないかどうか調べる
+				if (L3SearchIf(s, hubname) == NULL)
+				{
+					// 追加
+					f = ZeroMalloc(sizeof(L3IF));
+
+					f->Switch = s;
+					StrCpy(f->HubName, sizeof(f->HubName), hubname);
+					f->IpAddress = ip;
+					f->SubnetMask = subnet;
+
+					Insert(s->IfList, f);
+
+					ret = true;
+				}
+			}
+		}
+	}
+	Unlock(s->lock);
+
+	return ret;
+}
+
+// L3 スイッチのクリーンアップ
+void CleanupL3Sw(L3SW *s)
+{
+	UINT i;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(s->IfList);i++)
+	{
+		L3IF *f = LIST_DATA(s->IfList, i);
+		Free(f);
+	}
+	ReleaseList(s->IfList);
+
+	for (i = 0;i < LIST_NUM(s->TableList);i++)
+	{
+		L3TABLE *t = LIST_DATA(s->TableList, i);
+		Free(t);
+	}
+	ReleaseList(s->TableList);
+
+	DeleteLock(s->lock);
+	Free(s);
+}
+
+// L3 スイッチの解放
+void ReleaseL3Sw(L3SW *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (Release(s->ref) == 0)
+	{
+		CleanupL3Sw(s);
+	}
+}
+
+// 新しい L3 スイッチを作成する
+L3SW *NewL3Sw(CEDAR *c, char *name)
+{
+	L3SW *o;
+	// 引数チェック
+	if (c == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	o = ZeroMalloc(sizeof(L3SW));
+
+	StrCpy(o->Name, sizeof(o->Name), name);
+
+	o->lock = NewLock();
+	o->ref = NewRef();
+	o->Cedar = c;
+	o->Active = false;
+
+	o->IfList = NewList(CmpL3If);
+	o->TableList = NewList(CmpL3Table);
+
+	return o;
+}
+
+// Cedar にあるすべての L3 スイッチを停止する
+void L3FreeAllSw(CEDAR *c)
+{
+	LIST *o;
+	UINT i;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	o = NewListFast(NULL);
+
+	LockList(c->L3SwList);
+	{
+		for (i = 0;i < LIST_NUM(c->L3SwList);i++)
+		{
+			L3SW *s = LIST_DATA(c->L3SwList, i);
+			Insert(o, CopyStr(s->Name));
+		}
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			char *name = LIST_DATA(o, i);
+
+			L3DelSw(c, name);
+
+			Free(name);
+		}
+
+		ReleaseList(o);
+	}
+	UnlockList(c->L3SwList);
+}
+
+// Cedar の L3 スイッチ機能を停止する
+void FreeCedarLayer3(CEDAR *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	ReleaseList(c->L3SwList);
+	c->L3SwList = NULL;
+}
+
+// Cedar の L3 スイッチ機能を開始する
+void InitCedarLayer3(CEDAR *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	c->L3SwList = NewList(CmpL3Sw);
+}
+
+// インターフェイス比較関数
+int CmpL3If(void *p1, void *p2)
+{
+	L3IF *f1, *f2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	f1 = *(L3IF **)p1;
+	f2 = *(L3IF **)p2;
+	if (f1 == NULL || f2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(f1->HubName, f2->HubName);
+}
+
+// ルーティングテーブル比較関数
+int CmpL3Table(void *p1, void *p2)
+{
+	L3TABLE *t1, *t2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	t1 = *(L3TABLE **)p1;
+	t2 = *(L3TABLE **)p2;
+	if (t1 == NULL || t2 == NULL)
+	{
+		return 0;
+	}
+
+	if (t1->NetworkAddress > t2->NetworkAddress)
+	{
+		return 1;
+	}
+	else if (t1->NetworkAddress < t2->NetworkAddress)
+	{
+		return -1;
+	}
+	else if (t1->SubnetMask > t2->SubnetMask)
+	{
+		return 1;
+	}
+	else if (t1->SubnetMask < t2->SubnetMask)
+	{
+		return -1;
+	}
+	else if (t1->GatewayAddress > t2->GatewayAddress)
+	{
+		return 1;
+	}
+	else if (t1->GatewayAddress < t2->GatewayAddress)
+	{
+		return -1;
+	}
+	else if (t1->Metric > t2->Metric)
+	{
+		return 1;
+	}
+	else if (t1->Metric < t2->Metric)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// L3SW 比較関数
+int CmpL3Sw(void *p1, void *p2)
+{
+	L3SW *s1, *s2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(L3SW **)p1;
+	s2 = *(L3SW **)p2;
+	if (s1 == NULL || s2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(s1->Name, s2->Name);
+}
+
+// ARP 待機エントリ比較関数
+int CmpL3ArpWaitTable(void *p1, void *p2)
+{
+	L3ARPWAIT *w1, *w2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	w1 = *(L3ARPWAIT **)p1;
+	w2 = *(L3ARPWAIT **)p2;
+	if (w1 == NULL || w2 == NULL)
+	{
+		return 0;
+	}
+	if (w1->IpAddress > w2->IpAddress)
+	{
+		return 1;
+	}
+	else if (w1->IpAddress < w2->IpAddress)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// ARP エントリ比較関数
+int CmpL3ArpEntry(void *p1, void *p2)
+{
+	L3ARPENTRY *e1, *e2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	e1 = *(L3ARPENTRY **)p1;
+	e2 = *(L3ARPENTRY **)p2;
+	if (e1 == NULL || e2 == NULL)
+	{
+		return 0;
+	}
+	if (e1->IpAddress > e2->IpAddress)
+	{
+		return 1;
+	}
+	else if (e1->IpAddress < e2->IpAddress)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Layer3.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Layer3.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Layer3.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,222 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Layer3.h
+// Layer3.c のヘッダ
+
+#ifndef	LAYER3_H
+#define	LAYER3_H
+
+// 定数
+#define	L3_USERNAME					"L3SW_"
+
+
+// L3 ARP テーブルエントリ
+struct L3ARPENTRY
+{
+	UINT IpAddress;					// IP アドレス
+	UCHAR MacAddress[6];			// MAC アドレス
+	UCHAR Padding[2];
+	UINT64 Expire;					// 有効期限
+};
+
+// L3 ARP 解決待ちリストエントリ
+struct L3ARPWAIT
+{
+	UINT IpAddress;					// IP アドレス
+	UINT64 LastSentTime;			// 最後に ARP を送信した時刻
+	UINT64 Expire;					// 有効期限
+};
+
+// L3 IP パケットテーブル
+struct L3PACKET
+{
+	PKT *Packet;					// パケットデータ本体
+	UINT64 Expire;					// 有効期限
+	UINT NextHopIp;					// ローカル配信宛先 IP アドレス
+};
+
+// L3 ルーティングテーブル定義
+struct L3TABLE
+{
+	UINT NetworkAddress;			// ネットワークアドレス
+	UINT SubnetMask;				// サブネットマスク
+	UINT GatewayAddress;			// ゲートウェイアドレス
+	UINT Metric;					// メトリック
+};
+
+// L3 インターフェイス定義
+struct L3IF
+{
+	L3SW *Switch;					// Layer-3 スイッチ
+	char HubName[MAX_HUBNAME_LEN + 1];	// 仮想 HUB 名
+	UINT IpAddress;					// IP アドレス
+	UINT SubnetMask;				// サブネットマスク
+
+	HUB *Hub;						// 仮想 HUB
+	SESSION *Session;				// セッション
+	LIST *ArpTable;					// ARP テーブル
+	LIST *ArpWaitTable;				// ARP 待機テーブル
+	QUEUE *IpPacketQueue;			// IP パケットキュー (他のインターフェイスからの受信用)
+	LIST *IpWaitList;				// IP 待機リスト
+	QUEUE *SendQueue;				// 送信キュー
+	UCHAR MacAddress[6];			// MAC アドレス
+	UCHAR Padding[2];
+	UINT64 LastDeleteOldArpTable;	// 古い ARP テーブルを清掃した時刻
+	LIST *CancelList;				// キャンセルリスト
+	UINT64 LastBeaconSent;			// 最後にビーコンを送信した時刻
+};
+
+// L3 スイッチ定義
+struct L3SW
+{
+	char Name[MAX_HUBNAME_LEN + 1];	// 名前
+	LOCK *lock;						// ロック
+	REF *ref;						// 参照カウンタ
+	CEDAR *Cedar;					// Cedar
+	bool Active;					// 動作中フラグ
+	bool Online;					// オンラインフラグ
+	volatile bool Halt;				// 停止フラグ
+	LIST *IfList;					// インターフェイスリスト
+	LIST *TableList;				// ルーティングテーブルリスト
+	THREAD *Thread;					// スレッド
+};
+
+
+
+// 関数プロトタイプ
+int CmpL3Sw(void *p1, void *p2);
+int CmpL3ArpEntry(void *p1, void *p2);
+int CmpL3ArpWaitTable(void *p1, void *p2);
+int CmpL3Table(void *p1, void *p2);
+int CmpL3If(void *p1, void *p2);
+void InitCedarLayer3(CEDAR *c);
+void FreeCedarLayer3(CEDAR *c);
+L3SW *NewL3Sw(CEDAR *c, char *name);
+void ReleaseL3Sw(L3SW *s);
+void CleanupL3Sw(L3SW *s);
+bool L3AddIf(L3SW *s, char *hubname, UINT ip, UINT subnet);
+bool L3DelIf(L3SW *s, char *hubname);
+bool L3AddTable(L3SW *s, L3TABLE *tbl);
+bool L3DelTable(L3SW *s, L3TABLE *tbl);
+L3IF *L3SearchIf(L3SW *s, char *hubname);
+L3SW *L3GetSw(CEDAR *c, char *name);
+L3SW *L3AddSw(CEDAR *c, char *name);
+bool L3DelSw(CEDAR *c, char *name);
+void L3FreeAllSw(CEDAR *c);
+void L3SwStart(L3SW *s);
+void L3SwStop(L3SW *s);
+void L3SwThread(THREAD *t, void *param);
+void L3Test(SERVER *s);
+void L3InitAllInterfaces(L3SW *s);
+void L3FreeAllInterfaces(L3SW *s);
+void L3IfThread(THREAD *t, void *param);
+void L3InitInterface(L3IF *f);
+void L3FreeInterface(L3IF *f);
+L3IF *L3GetNextIf(L3SW *s, UINT ip, UINT *next_hop);
+L3TABLE *L3GetBestRoute(L3SW *s, UINT ip);
+UINT L3GetNextPacket(L3IF *f, void **data);
+void L3Polling(L3IF *f);
+void L3PollingBeacon(L3IF *f);
+void L3DeleteOldArpTable(L3IF *f);
+void L3DeleteOldIpWaitList(L3IF *f);
+void L3PollingArpWaitTable(L3IF *f);
+void L3SendL2Now(L3IF *f, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size);
+void L3SendArpRequestNow(L3IF *f, UINT dest_ip);
+void L3SendArpResponseNow(L3IF *f, UCHAR *dest_mac, UINT dest_ip, UINT src_ip);
+void L3GenerateMacAddress(L3IF *f);
+L3ARPENTRY *L3SearchArpTable(L3IF *f, UINT ip);
+void L3SendIpNow(L3IF *f, L3ARPENTRY *a, L3PACKET *p);
+void L3SendIp(L3IF *f, L3PACKET *p);
+void L3RecvArp(L3IF *f, PKT *p);
+void L3RecvArpRequest(L3IF *f, PKT *p);
+void L3RecvArpResponse(L3IF *f, PKT *p);
+void L3KnownArp(L3IF *f, UINT ip, UCHAR *mac);
+void L3SendArp(L3IF *f, UINT ip);
+void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac);
+void L3SendWaitingIp(L3IF *f, UCHAR *mac, UINT ip, L3ARPENTRY *a);
+void L3PutPacket(L3IF *f, void *data, UINT size); 
+void L3RecvL2(L3IF *f, PKT *p);
+void L3StoreIpPacketToIf(L3IF *src_if, L3IF *dst_if, L3PACKET *p);
+void L3RecvIp(L3IF *f, PKT *p, bool self);
+void L3PollingIpQueue(L3IF *f);
+
+
+#endif	// LAYER3_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Link.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Link.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Link.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,649 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Link.c
+// HUB 間リンク接続
+
+#include "CedarPch.h"
+
+// リンクサーバースレッド
+void LinkServerSessionThread(THREAD *t, void *param)
+{
+	LINK *k = (LINK *)param;
+	CONNECTION *c;
+	SESSION *s;
+	POLICY *policy;
+	wchar_t name[MAX_SIZE];
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// サーバーコネクションの作成
+	c = NewServerConnection(k->Cedar, NULL, t);
+	c->Protocol = CONNECTION_HUB_LINK_SERVER;
+
+	// ポリシーの作成
+	policy = ZeroMalloc(sizeof(POLICY));
+	Copy(policy, k->Policy, sizeof(POLICY));
+
+	// サーバーセッションの作成
+	s = NewServerSession(k->Cedar, c, k->Hub, LINK_USER_NAME, policy);
+	s->LinkModeServer = true;
+	s->Link = k;
+	c->Session = s;
+	ReleaseConnection(c);
+
+	// ユーザー名
+	s->Username = CopyStr(LINK_USER_NAME_PRINT);
+
+	k->ServerSession = s;
+	AddRef(k->ServerSession->ref);
+
+	// 初期化完了を通知
+	NoticeThreadInit(t);
+
+	UniStrCpy(name, sizeof(name), k->Option->AccountName);
+	HLog(s->Hub, "LH_LINK_START", name, s->Name);
+
+	// セッションのメイン関数
+	SessionMain(s);
+
+	HLog(s->Hub, "LH_LINK_STOP", name);
+
+	ReleaseSession(s);
+}
+
+// パケットアダプタ初期化
+bool LinkPaInit(SESSION *s)
+{
+	LINK *k;
+	THREAD *t;
+	// 引数チェック
+	if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+	{
+		return false;
+	}
+
+	// 送信パケットキューの作成
+	k->SendPacketQueue = NewQueue();
+
+	// リンクサーバースレッドの作成
+	t = NewThread(LinkServerSessionThread, (void *)k);
+	WaitThreadInit(t);
+
+	ReleaseThread(t);
+
+	return true;
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *LinkPaGetCancel(SESSION *s)
+{
+	LINK *k;
+	// 引数チェック
+	if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+	{
+		return NULL;
+	}
+
+	return NULL;
+}
+
+// 次のパケットを取得
+UINT LinkPaGetNextPacket(SESSION *s, void **data)
+{
+	LINK *k;
+	UINT ret = 0;
+	// 引数チェック
+	if (s == NULL || data == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+	{
+		return INFINITE;
+	}
+
+	// キューにパケットが溜まっているかどうか調べる
+	LockQueue(k->SendPacketQueue);
+	{
+		BLOCK *block = GetNext(k->SendPacketQueue);
+
+		if (block != NULL)
+		{
+			// パケットがあった
+			*data = block->Buf;
+			ret = block->Size;
+			// 構造体のメモリは破棄する
+			Free(block);
+		}
+	}
+	UnlockQueue(k->SendPacketQueue);
+
+	return ret;
+}
+
+// 受信したパケットを書き込み
+bool LinkPaPutPacket(SESSION *s, void *data, UINT size)
+{
+	LINK *k;
+	BLOCK *block;
+	SESSION *server_session;
+	CONNECTION *server_connection;
+	// 引数チェック
+	if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+	{
+		return false;
+	}
+
+	server_session = k->ServerSession;
+	server_connection = server_session->Connection;
+
+	// ここにはリンク接続先の HUB から届いたパケットが来るので
+	// サーバーセッションの ReceivedBlocks に届けてあげる
+	if (data != NULL)
+	{
+		block = NewBlock(data, size, 0);
+
+		LockQueue(server_connection->ReceivedBlocks);
+		{
+			InsertQueue(server_connection->ReceivedBlocks, block);
+		}
+		UnlockQueue(server_connection->ReceivedBlocks);
+	}
+	else
+	{
+		// data == NULL のとき、すべてのパケットを格納し終わったので
+		// Cancel を発行する
+		Cancel(server_session->Cancel1);
+
+		if (k->Hub != NULL && k->Hub->Option != NULL && k->Hub->Option->YieldAfterStorePacket)
+		{
+			YieldCpu();
+		}
+	}
+
+	return true;
+}
+
+// パケットアダプタの解放
+void LinkPaFree(SESSION *s)
+{
+	LINK *k;
+	// 引数チェック
+	if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+	{
+		return;
+	}
+
+	// サーバーセッションの停止
+	StopSession(k->ServerSession);
+	ReleaseSession(k->ServerSession);
+
+	// 送信パケットキューの解放
+	LockQueue(k->SendPacketQueue);
+	{
+		BLOCK *block;
+		while (block = GetNext(k->SendPacketQueue))
+		{
+			FreeBlock(block);
+		}
+	}
+	UnlockQueue(k->SendPacketQueue);
+
+	ReleaseQueue(k->SendPacketQueue);
+}
+
+// パケットアダプタ
+PACKET_ADAPTER *LinkGetPacketAdapter()
+{
+	return NewPacketAdapter(LinkPaInit, LinkPaGetCancel, LinkPaGetNextPacket,
+		LinkPaPutPacket, LinkPaFree);
+}
+
+// すべてのリンクの解放
+void ReleaseAllLink(HUB *h)
+{
+	LINK **kk;
+	UINT num, i;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->LinkList);
+	{
+		num = LIST_NUM(h->LinkList);
+		kk = ToArray(h->LinkList);
+		DeleteAll(h->LinkList);
+	}
+	UnlockList(h->LinkList);
+
+	for (i = 0;i < num;i++)
+	{
+		LINK *k = kk[i];
+
+		ReleaseLink(k);
+	}
+
+	Free(kk);
+}
+
+// リンクの解放
+void ReleaseLink(LINK *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	if (Release(k->ref) == 0)
+	{
+		CleanupLink(k);
+	}
+}
+
+// リンクのクリーンアップ
+void CleanupLink(LINK *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	DeleteLock(k->lock);
+	if (k->ClientSession)
+	{
+		ReleaseSession(k->ClientSession);
+	}
+	Free(k->Option);
+	CiFreeClientAuth(k->Auth);
+	Free(k->Policy);
+
+	if (k->ServerCert != NULL)
+	{
+		FreeX(k->ServerCert);
+	}
+
+	Free(k);
+}
+
+// リンクをオンラインにする
+void SetLinkOnline(LINK *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	if (k->Offline == false)
+	{
+		return;
+	}
+
+	k->Offline = false;
+	StartLink(k);
+}
+
+// リンクをオフラインにする
+void SetLinkOffline(LINK *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	if (k->Offline)
+	{
+		return;
+	}
+
+	StopLink(k);
+	k->Offline = true;
+}
+
+// リンクの削除
+void DelLink(HUB *hub, LINK *k)
+{
+	// 引数チェック
+	if (hub == NULL || k == NULL)
+	{
+		return;
+	}
+
+	LockList(hub->LinkList);
+	{
+		if (Delete(hub->LinkList, k))
+		{
+			ReleaseLink(k);
+		}
+	}
+	UnlockList(hub->LinkList);
+}
+
+// すべてのリンクの開始
+void StartAllLink(HUB *h)
+{
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->LinkList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *k = (LINK *)LIST_DATA(h->LinkList, i);
+
+			if (k->Offline == false)
+			{
+				StartLink(k);
+			}
+		}
+	}
+	UnlockList(h->LinkList);
+}
+
+// すべてのリンクの停止
+void StopAllLink(HUB *h)
+{
+	LINK **link_list;
+	UINT num_link;
+	UINT i;
+	// 引数チェック
+	if (h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->LinkList);
+	{
+		link_list = ToArray(h->LinkList);
+		num_link = LIST_NUM(h->LinkList);
+		for (i = 0;i < num_link;i++)
+		{
+			AddRef(link_list[i]->ref);
+		}
+	}
+	UnlockList(h->LinkList);
+
+	for (i = 0;i < num_link;i++)
+	{
+		StopLink(link_list[i]);
+		ReleaseLink(link_list[i]);
+	}
+
+	Free(link_list);
+}
+
+// リンクの開始
+void StartLink(LINK *k)
+{
+	PACKET_ADAPTER *pa;
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	LockLink(k);
+	{
+		if (k->Started || k->Halting)
+		{
+			UnlockLink(k);
+			return;
+		}
+		k->Started = true;
+	}
+	UnlockLink(k);
+
+	// クライアントセッション接続
+	pa = LinkGetPacketAdapter();
+	pa->Param = (void *)k;
+	LockLink(k);
+	{
+		k->ClientSession = NewClientSession(k->Cedar, k->Option, k->Auth, pa);
+	}
+	UnlockLink(k);
+}
+
+// リンクの停止
+void StopLink(LINK *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	LockLink(k);
+	{
+		if (k->Started == false)
+		{
+			UnlockLink(k);
+			return;
+		}
+		k->Started = false;
+		k->Halting = true;
+	}
+	UnlockLink(k);
+
+	if (k->ClientSession != NULL)
+	{
+		// クライアントセッション切断
+		StopSession(k->ClientSession);
+
+		LockLink(k);
+		{
+			ReleaseSession(k->ClientSession);
+			k->ClientSession = NULL;
+		}
+		UnlockLink(k);
+	}
+
+	LockLink(k);
+	{
+		k->Halting = false;
+	}
+	UnlockLink(k);
+}
+
+// リンクのロック
+void LockLink(LINK *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	Lock(k->lock);
+}
+
+// ロックのリンク解除
+void UnlockLink(LINK *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	Unlock(k->lock);
+}
+
+// リンク用ポリシーの正規化
+void NormalizeLinkPolicy(POLICY *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	p->Access = true;
+	p->NoBridge = p->NoRouting = p->PrivacyFilter =
+		p->MonitorPort = false;
+	p->MaxConnection = 32;
+	p->TimeOut = 20;
+	p->FixPassword = false;
+}
+
+// リンクの作成
+LINK *NewLink(CEDAR *cedar, HUB *hub, CLIENT_OPTION *option, CLIENT_AUTH *auth, POLICY *policy)
+{
+	CLIENT_OPTION *o;
+	LINK *k;
+	CLIENT_AUTH *a;
+	// 引数チェック
+	if (cedar == NULL || hub == NULL || option == NULL || auth == NULL || policy == NULL)
+	{
+		return NULL;
+	}
+	if (hub->Halt)
+	{
+		return NULL;
+	}
+
+	if (LIST_NUM(hub->LinkList) >= MAX_HUB_LINKS)
+	{
+		return NULL;
+	}
+
+	if (UniIsEmptyStr(option->AccountName))
+	{
+		return NULL;
+	}
+
+	// 認証方法の制限
+	if (auth->AuthType != CLIENT_AUTHTYPE_ANONYMOUS && auth->AuthType != CLIENT_AUTHTYPE_PASSWORD &&
+		auth->AuthType != CLIENT_AUTHTYPE_PLAIN_PASSWORD && auth->AuthType != CLIENT_AUTHTYPE_CERT)
+	{
+		// 匿名認証、パスワード認証、プレーンパスワード、証明書認証以外の認証方法は使用できない
+		return NULL;
+	}
+
+	// クライアントオプションのコピー (改変用)
+	o = ZeroMalloc(sizeof(CLIENT_OPTION));
+	Copy(o, option, sizeof(CLIENT_OPTION));
+	StrCpy(o->DeviceName, sizeof(o->DeviceName), LINK_DEVICE_NAME);
+
+	o->RequireBridgeRoutingMode = true;	// ブリッジモードを要求する
+	o->RequireMonitorMode = false;	// モニタモードは要求しない
+
+	o->NumRetry = INFINITE;			// 接続の再試行は無限に行う
+	o->RetryInterval = 10;			// 再試行間隔は 10 秒
+	o->NoRoutingTracking = true;	// ルーティング追跡停止
+
+	// 認証データのコピー
+	a = CopyClientAuth(auth);
+	a->SecureSignProc = NULL;
+	a->CheckCertProc = NULL;
+
+	// リンク オブジェクト
+	k = ZeroMalloc(sizeof(LINK));
+	k->lock = NewLock();
+	k->ref = NewRef();
+
+	k->Cedar = cedar;
+	k->Option = o;
+	k->Auth = a;
+	k->Hub = hub;
+
+	// ポリシーのコピー
+	k->Policy = ZeroMalloc(sizeof(POLICY));
+	Copy(k->Policy, policy, sizeof(POLICY));
+
+	// ポリシーの正規化
+	NormalizeLinkPolicy(k->Policy);
+
+	// HUB のリンクリストに登録する
+	LockList(hub->LinkList);
+	{
+		Add(hub->LinkList, k);
+		AddRef(k->ref);
+	}
+	UnlockList(hub->LinkList);
+
+	return k;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Link.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Link.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Link.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,132 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Link.h
+// Link.c のヘッダ
+
+#ifndef	LINK_H
+#define	LINK_H
+
+struct LINK
+{
+	bool Started;					// 開始フラグ
+	volatile bool Halting;			// 停止フラグ
+	bool Offline;					// オフライン
+	REF *ref;						// 参照カウンタ
+	LOCK *lock;						// ロック
+	CEDAR *Cedar;					// Cedar
+	HUB *Hub;						// HUB
+	SESSION *ClientSession;			// クライアントセッション
+	SESSION *ServerSession;			// サーバーセッション
+	CLIENT_OPTION *Option;			// クライアントオプション
+	CLIENT_AUTH *Auth;				// 認証データ
+	POLICY *Policy;					// ポリシー
+	QUEUE *SendPacketQueue;			// 送信パケットキュー
+	UINT LastError;					// 最後のエラー
+	bool CheckServerCert;			// サーバー証明書をチェックする
+	X *ServerCert;					// サーバー証明書
+};
+
+
+PACKET_ADAPTER *LinkGetPacketAdapter();
+bool LinkPaInit(SESSION *s);
+CANCEL *LinkPaGetCancel(SESSION *s);
+UINT LinkPaGetNextPacket(SESSION *s, void **data);
+bool LinkPaPutPacket(SESSION *s, void *data, UINT size);
+void LinkPaFree(SESSION *s);
+
+void LinkServerSessionThread(THREAD *t, void *param);
+LINK *NewLink(CEDAR *cedar, HUB *hub, CLIENT_OPTION *option, CLIENT_AUTH *auth, POLICY *policy);
+void StartLink(LINK *k);
+void StopLink(LINK *k);
+void DelLink(HUB *hub, LINK *k);
+void LockLink(LINK *k);
+void UnlockLink(LINK *k);
+void StopAllLink(HUB *h);
+void StartAllLink(HUB *h);
+void SetLinkOnline(LINK *k);
+void SetLinkOffline(LINK *k);
+void ReleaseLink(LINK *k);
+void CleanupLink(LINK *k);
+void ReleaseAllLink(HUB *h);
+void NormalizeLinkPolicy(POLICY *p);
+
+#endif	// LINK_H
+
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Listener.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Listener.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Listener.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,823 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Listener.c
+// リスナー モジュール
+
+#include "CedarPch.h"
+
+// UDP パケットを 1 つ受信した
+void UDPReceivedPacket(CEDAR *cedar, SOCK *s, IP *ip, UINT port, void *data, UINT size)
+{
+	SESSION *session;
+	UINT *key32;
+	UCHAR *buf;
+	CONNECTION *c;
+	// 引数チェック
+	if (s == NULL || ip == NULL || data == NULL || size == 0 || cedar == NULL)
+	{
+		return;
+	}
+
+	if (size < 16)
+	{
+		// パケットサイズが足らないので無視
+		return;
+	}
+	buf = (UCHAR *)data;
+	key32 = (UINT *)(buf + 4);
+
+
+	// Key32 の値からセッションを取得
+	session = GetSessionFromUDPEntry(cedar, Endian32(*key32));
+	if (session == NULL)
+	{
+		Debug("Invalid UDP Session Key 32: 0x%X\n", *key32);
+		return;
+	}
+
+	c = session->Connection;
+
+	// データを書き込む
+	PutUDPPacketData(c, buf, size);
+
+	// コネクションに関連付けられている UDP ソケットを書き換える
+	Lock(c->lock);
+	{
+		if (c->Protocol == CONNECTION_UDP)
+		{
+			if (c->Udp->s != s)
+			{
+				if (c->Udp->s != NULL)
+				{
+					ReleaseSock(c->Udp->s);
+				}
+				AddRef(s->ref);
+				c->Udp->s = s;
+			}
+			Copy(&c->Udp->ip, ip, sizeof(UINT));
+			c->Udp->port = port;
+		}
+	}
+	Unlock(c->lock);
+
+	// キャンセル発動
+	Cancel(session->Cancel1);
+
+	// セッションを解放
+	ReleaseSession(session);
+}
+
+// Accept された TCP コネクションを処理するスレッド
+void TCPAcceptedThread(THREAD *t, void *param)
+{
+	TCP_ACCEPTED_PARAM *data;
+	LISTENER *r;
+	SOCK *s;
+	CONNECTION *c;
+	bool flag1;
+	char tmp[128];
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// 初期化
+	data = (TCP_ACCEPTED_PARAM *)param;
+	r = data->r;
+	s = data->s;
+	AddRef(r->ref);
+	AddRef(s->ref);
+
+	// コネクションの作成
+	c = NewServerConnection(r->Cedar, s, t);
+
+	// Cedar に一時コネクションとして登録する
+	AddConnection(c->Cedar, c);
+
+	NoticeThreadInit(t);
+
+	AcceptInit(s);
+	StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname);
+	IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+	SLog(r->Cedar, "LS_LISTENER_ACCEPT", r->Port, tmp, s->RemoteHostname, s->RemotePort);
+
+	// 受付
+	ConnectionAccept(c);
+	flag1 = c->flag1;
+
+	// 解放
+	SLog(r->Cedar, "LS_CONNECTION_END_1", c->Name);
+	ReleaseConnection(c);
+
+	// 解放
+	if (flag1 == false)
+	{
+		Debug("%s %u flag1 == false\n", __FILE__, __LINE__);
+		IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+		SLog(r->Cedar, "LS_LISTENER_DISCONNECT", tmp, s->RemotePort);
+		Disconnect(s);
+	}
+	ReleaseSock(s);
+	ReleaseListener(r);
+}
+
+// TCP で Accept されたコネクションがある場合はここに飛ぶ
+void TCPAccepted(LISTENER *r, SOCK *s)
+{
+	TCP_ACCEPTED_PARAM *data;
+	THREAD *t;
+	char tmp[MAX_SIZE];
+	UINT num_clients_from_this_ip = 0;
+	CEDAR *cedar;
+	// 引数チェック
+	if (r == NULL || s == NULL)
+	{
+		return;
+	}
+
+	cedar = r->Cedar;
+
+	num_clients_from_this_ip = GetNumIpClient(&s->RemoteIP);
+
+	IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+
+	data = ZeroMalloc(sizeof(TCP_ACCEPTED_PARAM));
+	data->r = r;
+	data->s = s;
+
+	if (r->ThreadProc == TCPAcceptedThread)
+	{
+		Inc(cedar->AcceptingSockets);
+	}
+
+	t = NewThread(r->ThreadProc, data);
+	WaitThreadInit(t);
+	Free(data);
+	ReleaseThread(t);
+}
+
+// UDP リスナーメインループ
+void ListenerUDPMainLoop(LISTENER *r)
+{
+	UCHAR *data;
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	Debug("ListenerUDPMainLoop Starts.\n");
+	r->Status = LISTENER_STATUS_TRYING;
+
+	while (true)
+	{
+		// UDP ポートでの待機を試みる
+		while (true)
+		{
+			// 停止フラグ検査
+			if (r->Halt)
+			{
+				// 停止
+				return;
+			}
+
+			Debug("NewUDP()\n");
+			r->Sock = NewUDP(r->Port);
+			if (r->Sock != NULL)
+			{
+				// 待機成功
+				break;
+			}
+
+			// 待機失敗
+			Debug("Failed to NewUDP.\n");
+			Wait(r->Event, LISTEN_RETRY_TIME);
+
+			// 停止フラグ検査
+			if (r->Halt)
+			{
+				Debug("UDP Halt.\n");
+				return;
+			}
+		}
+
+		r->Status = LISTENER_STATUS_LISTENING;
+		Debug("Start Listening at UDP Port %u.\n", r->Sock->LocalPort);
+
+		// 停止フラグ検査
+		if (r->Halt)
+		{
+			// 停止
+			goto STOP;
+		}
+
+		// バッファ領域の確保
+		data = Malloc(UDP_PACKET_SIZE);
+
+		// 次のパケットを読み込む
+		while (true)
+		{
+			IP src_ip;
+			UINT src_port;
+			UINT size;
+			SOCKSET set;
+
+			InitSockSet(&set);
+			AddSockSet(&set, r->Sock);
+			Select(&set, SELECT_TIME, NULL, NULL);
+
+			size = RecvFrom(r->Sock, &src_ip, &src_port, data, UDP_PACKET_SIZE);
+			if (((size == 0) && (r->Sock->IgnoreRecvErr == false)) || r->Halt)
+			{
+				// エラーが発生した
+STOP:
+				Disconnect(r->Sock);
+				ReleaseSock(r->Sock);
+				r->Sock = NULL;
+				Debug("UDP Listen Stopped.\n");
+				Free(data);
+				break;
+			}
+
+			// UDP パケットを 1 つ受信した
+			if (size != SOCK_LATER)
+			{
+				UDPReceivedPacket(r->Cedar, r->Sock, &src_ip, src_port, data, size);
+			}
+		}
+	}
+}
+
+// TCP リスナーメインループ
+void ListenerTCPMainLoop(LISTENER *r)
+{
+	SOCK *new_sock;
+	SOCK *s;
+	UINT num_failed;
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	Debug("ListenerTCPMainLoop Starts.\n");
+	r->Status = LISTENER_STATUS_TRYING;
+
+	while (true)
+	{
+		bool first_failed = true;
+		Debug("Status = LISTENER_STATUS_TRYING\n");
+		r->Status = LISTENER_STATUS_TRYING;
+
+		// Listen を試みる
+		while (true)
+		{
+			UINT interval;
+			// 停止フラグ検査
+			if (r->Halt)
+			{
+				// 停止
+				return;
+			}
+
+			if (r->ShadowIPv6 == false)
+			{
+				s = ListenEx(r->Port, r->LocalOnly);
+			}
+			else
+			{
+				s = ListenEx6(r->Port, r->LocalOnly);
+			}
+
+			if (s != NULL)
+			{
+				// Listen 成功
+				AddRef(s->ref);
+				r->Sock = s;
+				if (r->ShadowIPv6 == false)
+				{
+					SLog(r->Cedar, "LS_LISTENER_START_2", r->Port);
+				}
+				break;
+			}
+
+			// Listen 失敗
+			if (first_failed)
+			{
+				first_failed = false;
+				if (r->ShadowIPv6 == false)
+				{
+					SLog(r->Cedar, "LS_LISTENER_START_3", r->Port, LISTEN_RETRY_TIME / 1000);
+				}
+			}
+
+			interval = LISTEN_RETRY_TIME;
+
+			if (r->ShadowIPv6)
+			{
+				if (IsIPv6Supported() == false)
+				{
+					interval = LISTEN_RETRY_TIME_NOIPV6;
+
+					Debug("IPv6 is not supported.\n");
+				}
+			}
+
+			Wait(r->Event, interval);
+
+			// 停止フラグ検査
+			if (r->Halt)
+			{
+				// 停止
+				Debug("Listener Halt.\n");
+				return;
+			}
+		}
+
+		r->Status = LISTENER_STATUS_LISTENING;
+		Debug("Status = LISTENER_STATUS_LISTENING\n");
+
+		// 停止フラグ検査
+		if (r->Halt)
+		{
+			// 停止
+			goto STOP;
+		}
+
+		num_failed = 0;
+
+		// Accpet ループ
+		while (true)
+		{
+			// Accept を行う
+			Debug("Accept()\n");
+			new_sock = Accept(r->Sock);
+			if (new_sock != NULL)
+			{
+				// Accept 成功
+				Debug("Accepted.\n");
+				TCPAccepted(r, new_sock);
+				ReleaseSock(new_sock);
+			}
+			else
+			{
+				if (r->Halt == false)
+				{
+					if ((++num_failed) <= 5)
+					{
+						continue;
+					}
+				}
+STOP:
+				Debug("Accept Canceled.\n");
+				// Accept に失敗した (ソケットが破壊された)
+				// Listen しているソケットを閉じる
+				Disconnect(s);
+				ReleaseSock(s);
+				break;
+			}
+		}
+
+		// 停止フラグ検査
+		if (r->Halt)
+		{
+			// 停止
+			Debug("Listener Halt.\n");
+			return;
+		}
+	}
+}
+
+// リスナーのスレッド
+void ListenerThread(THREAD *thread, void *param)
+{
+	LISTENER *r;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// 初期化
+	r = (LISTENER *)param;
+	AddRef(r->ref);
+	r->Thread = thread;
+	AddRef(thread->ref);
+	NoticeThreadInit(thread);
+
+	// メインループ
+	switch (r->Protocol)
+	{
+	case LISTENER_TCP:
+		// TCP プロトコル
+		ListenerTCPMainLoop(r);
+		break;
+
+	case LISTENER_UDP:
+		// UDP プロトコル
+		ListenerUDPMainLoop(r);
+		break;
+	}
+
+	// 解放
+	ReleaseListener(r);
+}
+
+// リスナーの停止
+void StopListener(LISTENER *r)
+{
+	UINT port;
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	if (r->Halt)
+	{
+		return;
+	}
+
+	port = r->Port;
+
+	// 停止フラグセット
+	r->Halt = true;
+
+	if (r->ShadowIPv6 == false)
+	{
+		SLog(r->Cedar, "LS_LISTENER_STOP_1", port);
+	}
+
+	// ソケットを閉じる
+	Disconnect(r->Sock);
+
+	// イベントのセット
+	Set(r->Event);
+
+	// スレッドが停止するまで待機
+	WaitThread(r->Thread, INFINITE);
+
+	// 影のリスナーを停止させる
+	if (r->ShadowIPv6 == false)
+	{
+		if (r->ShadowListener != NULL)
+		{
+			StopListener(r->ShadowListener);
+
+			ReleaseListener(r->ShadowListener);
+
+			r->ShadowListener = NULL;
+		}
+	}
+
+	if (r->ShadowIPv6 == false)
+	{
+		SLog(r->Cedar, "LS_LISTENER_STOP_2", port);
+	}
+}
+
+// リスナーのクリーンアップ
+void CleanupListener(LISTENER *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	if (r->Sock != NULL)
+	{
+		ReleaseSock(r->Sock);
+	}
+
+	DeleteLock(r->lock);
+	ReleaseThread(r->Thread);
+	ReleaseEvent(r->Event);
+
+	ReleaseCedar(r->Cedar);
+
+	Free(r);
+}
+
+// リスナーの解放
+void ReleaseListener(LISTENER *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	if (Release(r->ref) == 0)
+	{
+		CleanupListener(r);
+	}
+}
+
+// UDP エントリリストの比較関数
+int CompareUDPEntry(void *p1, void *p2)
+{
+	UDP_ENTRY *e1, *e2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	e1 = *(UDP_ENTRY **)p1;
+	e2 = *(UDP_ENTRY **)p2;
+	if (e1 == NULL || e2 == NULL)
+	{
+		return 0;
+	}
+
+	if (e1->SessionKey32 > e2->SessionKey32)
+	{
+		return 1;
+	}
+	else if (e1->SessionKey32 == e2->SessionKey32)
+	{
+		return 0;
+	}
+	else
+	{
+		return -1;
+	}
+}
+
+// リスナーの比較関数
+int CompareListener(void *p1, void *p2)
+{
+	LISTENER *r1, *r2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	r1 = *(LISTENER **)p1;
+	r2 = *(LISTENER **)p2;
+	if (r1 == NULL || r2 == NULL)
+	{
+		return 0;
+	}
+
+	if (r1->Protocol > r2->Protocol)
+	{
+		return 1;
+	}
+	else if (r1->Protocol < r2->Protocol)
+	{
+		return -1;
+	}
+	else if (r1->Port > r2->Port)
+	{
+		return 1;
+	}
+	else if (r1->Port < r2->Port)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// 新しいリスナーの作成
+LISTENER *NewListener(CEDAR *cedar, UINT proto, UINT port)
+{
+	return NewListenerEx(cedar, proto, port, TCPAcceptedThread, NULL);
+}
+LISTENER *NewListenerEx(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param)
+{
+	return NewListenerEx2(cedar, proto, port, proc, thread_param, false);
+}
+LISTENER *NewListenerEx2(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only)
+{
+	return NewListenerEx3(cedar, proto, port, proc, thread_param, local_only, false);
+}
+LISTENER *NewListenerEx3(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6)
+{
+	LISTENER *r;
+	THREAD *t;
+	// 引数チェック
+	if (port == 0 || cedar == NULL)
+	{
+		return NULL;
+	}
+	// プロトコル番号のチェック
+	if (proto != LISTENER_TCP && proto != LISTENER_UDP)
+	{
+		return NULL;
+	}
+
+	r = ZeroMalloc(sizeof(LISTENER));
+
+	r->ThreadProc = proc;
+	r->ThreadParam = thread_param;
+	r->Cedar = cedar;
+	AddRef(r->Cedar->ref);
+	r->lock = NewLock();
+	r->ref = NewRef();
+	r->Protocol = proto;
+	r->Port = port;
+	r->Event = NewEvent();
+	r->LocalOnly = local_only;
+	r->ShadowIPv6 = shadow_ipv6;
+
+	if (r->ShadowIPv6 == false)
+	{
+		SLog(cedar, "LS_LISTENER_START_1", port);
+	}
+
+	// スレッドの作成
+	t = NewThread(ListenerThread, r);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+
+	if (r->ShadowIPv6 == false)
+	{
+		if (r->Cedar->DisableIPv6Listener == false)
+		{
+			// 影のリスナーを追加する
+			r->ShadowListener = NewListenerEx3(cedar, proto, port, proc, thread_param,
+				local_only, true);
+		}
+	}
+
+	if (r->ShadowIPv6 == false)
+	{
+		// Cedar に追加
+		AddListener(cedar, r);
+	}
+
+	return r;
+}
+
+// セッションキーからセッションを取得する
+SESSION *GetSessionFromUDPEntry(CEDAR *cedar, UINT key32)
+{
+	UDP_ENTRY *e, t;
+	SESSION *s;
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return NULL;
+	}
+
+	t.SessionKey32 = key32;
+
+	LockList(cedar->UDPEntryList);
+	{
+		e = Search(cedar->UDPEntryList, &t);
+		if (e == NULL)
+		{
+			UnlockList(cedar->UDPEntryList);
+			return NULL;
+		}
+		s = e->Session;
+		AddRef(s->ref);
+	}
+	UnlockList(cedar->UDPEntryList);
+
+	return s;
+}
+
+// UDP セッションを UDP エントリから削除する
+void DelUDPEntry(CEDAR *cedar, SESSION *session)
+{
+	UINT num, i;
+	// 引数チェック
+	if (cedar == NULL || session == NULL)
+	{
+		return;
+	}
+
+	LockList(cedar->UDPEntryList);
+	{
+		num = LIST_NUM(cedar->UDPEntryList);
+		for (i = 0;i < num;i++)
+		{
+			UDP_ENTRY *e = LIST_DATA(cedar->UDPEntryList, i);
+			if (e->Session == session)
+			{
+				ReleaseSession(e->Session);
+				Delete(cedar->UDPEntryList, e);
+				Free(e);
+				UnlockList(cedar->UDPEntryList);
+				Debug("UDP_Entry Deleted.\n");
+				return;
+			}
+		}
+	}
+	UnlockList(cedar->UDPEntryList);
+}
+
+// UDP セッションを UDP エントリに追加する
+void AddUDPEntry(CEDAR *cedar, SESSION *session)
+{
+	UDP_ENTRY *e;
+	// 引数チェック
+	if (cedar == NULL || session == NULL)
+	{
+		return;
+	}
+
+	e = ZeroMalloc(sizeof(UDP_ENTRY));
+	e->Session = session;
+	e->SessionKey32 = session->SessionKey32;
+	AddRef(session->ref);
+
+	LockList(cedar->UDPEntryList);
+	{
+		Add(cedar->UDPEntryList, e);
+	}
+	UnlockList(cedar->UDPEntryList);
+
+	Debug("UDP_Entry Added.\n");
+}
+
+// UDP エントリのクリア
+void CleanupUDPEntry(CEDAR *cedar)
+{
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return;
+	}
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Listener.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Listener.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Listener.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,147 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Listener.h
+// Listener.c のヘッダ
+
+#ifndef	LISTENER_H
+#define	LISTENER_H
+
+
+// 新しいコネクションを受け付けた際に呼び出す関数
+typedef void (NEW_CONNECTION_PROC)(CONNECTION *c);
+
+
+// リスナー構造体
+struct LISTENER
+{
+	LOCK *lock;						// ロック
+	REF *ref;						// 参照カウンタ
+	CEDAR *Cedar;					// Cedar
+	UINT Protocol;					// プロトコル
+	UINT Port;						// ポート番号
+	THREAD *Thread;					// 動作スレッド
+	SOCK *Sock;						// ソケット
+	EVENT *Event;					// イベント
+	volatile bool Halt;				// 停止フラグ
+	UINT Status;					// 状態
+	THREAD_PROC *ThreadProc;		// スレッドプロシージャ
+	void *ThreadParam;				// スレッドパラメータ
+	bool LocalOnly;					// localhost からのみ接続できる
+	bool ShadowIPv6;				// 影の IPv6 リスナーであることを示すフラグ
+	LISTENER *ShadowListener;		// 管理している影の IPv6 リスナーへの参照
+};
+
+// TCPAcceptedThread のパラメータ
+struct TCP_ACCEPTED_PARAM
+{
+	LISTENER *r;
+	SOCK *s;
+};
+
+// UDP エントリ
+struct UDP_ENTRY
+{
+	UINT SessionKey32;				// 32bit セッションキー
+	SESSION *Session;		// セッションへの参照
+};
+
+
+// 関数プロトタイプ
+LISTENER *NewListener(CEDAR *cedar, UINT proto, UINT port);
+LISTENER *NewListenerEx(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param);
+LISTENER *NewListenerEx2(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only);
+LISTENER *NewListenerEx3(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6);
+void ReleaseListener(LISTENER *r);
+void CleanupListener(LISTENER *r);
+void ListenerThread(THREAD *thread, void *param);
+void ListenerTCPMainLoop(LISTENER *r);
+void StopListener(LISTENER *r);
+int CompareListener(void *p1, void *p2);
+void TCPAccepted(LISTENER *r, SOCK *s);
+void TCPAcceptedThread(THREAD *t, void *param);
+void ListenerUDPMainLoop(LISTENER *r);
+void UDPReceivedPacket(CEDAR *cedar, SOCK *s, IP *ip, UINT port, void *data, UINT size);
+int CompareUDPEntry(void *p1, void *p2);
+void CleanupUDPEntry(CEDAR *cedar);
+void AddUDPEntry(CEDAR *cedar, SESSION *session);
+void DelUDPEntry(CEDAR *cedar, SESSION *session);
+SESSION *GetSessionFromUDPEntry(CEDAR *cedar, UINT key32);
+
+#endif	// LISTENER_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Logging.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Logging.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Logging.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1958 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Logging.c
+// ログ保存モジュール
+
+#include "CedarPch.h"
+
+static char *delete_targets[] =
+{
+	"backup.vpn_bridge.config",
+	"backup.vpn_client.config",
+	"backup.vpn_server.config",
+	"backup.etherlogger.config",
+	"packet_log",
+	"etherlogger_log",
+	"secure_nat_log",
+	"security_log",
+	"server_log",
+	"bridge_log",
+};
+
+// syslog の送信
+void SendSysLog(SLOG *g, wchar_t *str)
+{
+	UCHAR *buf;
+	UINT buf_size;
+	// 引数チェック
+	if (g == NULL || str == NULL)
+	{
+		return;
+	}
+
+	buf_size = CalcUniToUtf8(str);
+	buf = ZeroMalloc(buf_size);
+	UniToUtf8(buf, buf_size, str);
+
+	if (buf_size >= 1024)
+	{
+		buf_size = 1023;
+	}
+
+	Lock(g->lock);
+	{
+		if (Tick64() >= g->NextPollIp)
+		{
+			IP ip;
+
+			if (GetIP(&ip, g->HostName))
+			{
+				g->NextPollIp = Tick64() + SYSLOG_POLL_IP_INTERVAL;
+				Copy(&g->DestIp, &ip, sizeof(IP));
+			}
+			else
+			{
+				g->NextPollIp = Tick64() + SYSLOG_POLL_IP_INTERVAL_NG;
+			}
+		}
+
+		if (g->DestPort != 0 && IsZeroIp(&g->DestIp) == false)
+		{
+			SendTo(g->Udp, &g->DestIp, g->DestPort, buf, buf_size);
+		}
+	}
+	Unlock(g->lock);
+
+	Free(buf);
+}
+
+// syslog クライアントの解放
+void FreeSysLog(SLOG *g)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	DeleteLock(g->lock);
+	ReleaseSock(g->Udp);
+	Free(g);
+}
+
+// syslog クライアントの設定
+void SetSysLog(SLOG *g, char *hostname, UINT port)
+{
+	IP ip;
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+	if (port == 0)
+	{
+		port = SYSLOG_PORT;
+	}
+
+	if (hostname == NULL)
+	{
+		hostname = "";
+	}
+
+	Zero(&ip, sizeof(IP));
+	GetIP(&ip, hostname);
+
+	Lock(g->lock);
+	{
+		Copy(&g->DestIp, &ip, sizeof(IP));
+		g->DestPort = port;
+		StrCpy(g->HostName, sizeof(g->HostName), hostname);
+		g->NextPollIp = Tick64() + IsZeroIp(&ip) ? SYSLOG_POLL_IP_INTERVAL_NG : SYSLOG_POLL_IP_INTERVAL;
+	}
+	Unlock(g->lock);
+}
+
+// syslog クライアントの作成
+SLOG *NewSysLog(char *hostname, UINT port)
+{
+	// 引数チェック
+	SLOG *g = ZeroMalloc(sizeof(SLOG));
+
+	g->lock = NewLock();
+	g->Udp = NewUDP(0);
+
+	SetSysLog(g, hostname, port);
+
+	return g;
+}
+
+// ディスクに十分な空き容量があるかチェックする
+bool CheckEraserDiskFreeSpace(ERASER *e)
+{
+	UINT64 s;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return true;
+	}
+
+	// ディスクの空き容量を取得する
+	if (GetDiskFree(e->DirName, &s, NULL, NULL) == false)
+	{
+		// 取得失敗
+		return true;
+	}
+
+	if (e->MinFreeSpace > s)
+	{
+		// 空き容量が指定されたバイト数未満である
+		return false;
+	}
+
+	// 十分空いている
+	return true;
+}
+
+// 削除対象ファイルリストを解放する
+void FreeEraseFileList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		ERASE_FILE *f = LIST_DATA(o, i);
+		Free(f->FullPath);
+		Free(f);
+	}
+
+	ReleaseList(o);
+}
+
+// 削除対象ファイルリストを表示する
+void PrintEraseFileList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		ERASE_FILE *f = LIST_DATA(o, i);
+		Print("%I64u - %s\n", f->UpdateTime, f->FullPath);
+	}
+}
+
+// 指定されたディレクトリの削除対象ファイルリストを生成する
+void EnumEraseFile(LIST *o, char *dirname)
+{
+	DIRLIST *dir;
+	UINT i;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (o == NULL || dirname == NULL)
+	{
+		return;
+	}
+
+	// 列挙
+	dir = EnumDir(dirname);
+
+	for (i = 0;i < dir->NumFiles;i++)
+	{
+		DIRENT *e = dir->File[i];
+		Format(tmp, sizeof(tmp), "%s/%s", dirname, e->FileName);
+		NormalizePath(tmp, sizeof(tmp), tmp);
+
+		if (e->Folder == false)
+		{
+			// ファイル
+			ERASE_FILE *f;
+
+			if (EndWith(tmp, ".log") || EndWith(tmp, ".config"))
+			{
+				// ログファイルと .config ファイルのみを対象とする
+				f = ZeroMalloc(sizeof(ERASE_FILE));
+				f->FullPath = CopyStr(tmp);
+				f->UpdateTime = e->UpdateDate;
+
+				Add(o, f);
+			}
+		}
+		else
+		{
+			// フォルダ
+			EnumEraseFile(o, tmp);
+		}
+	}
+
+	FreeDir(dir);
+}
+
+// 削除対象ファイルリストを生成する
+LIST *GenerateEraseFileList(ERASER *e)
+{
+	LIST *o;
+	UINT i;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(CompareEraseFile);
+
+	// 各ディレクトリを走査する
+	for (i = 0;i < sizeof(delete_targets) / sizeof(delete_targets[0]);i++)
+	{
+		char dirname[MAX_PATH];
+		Format(dirname, sizeof(dirname), "%s/%s", e->DirName, delete_targets[i]);
+
+		EnumEraseFile(o, dirname);
+	}
+
+	// ソートする
+	Sort(o);
+
+	return o;
+}
+
+// 不要ファイルの消去処理
+void EraserMain(ERASER *e)
+{
+	LIST *o;
+	UINT i;
+	bool ok = false;
+	char bs[64];
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	// まず空き容量をチェック
+	if (CheckEraserDiskFreeSpace(e))
+	{
+		// 十分空いている
+		return;
+	}
+
+	ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
+
+	// ファイル一覧の生成
+	o = GenerateEraseFileList(e);
+
+	// ファイルを古い順に 1 つずつ削除してみる
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		ERASE_FILE *f = LIST_DATA(o, i);
+
+		// ファイルを削除する
+		if (FileDelete(f->FullPath))
+		{
+			ELog(e, "LE_DELETE", bs, f->FullPath);
+		}
+
+		// 削除したあと空き容量を確認してみる
+		if (CheckEraserDiskFreeSpace(e))
+		{
+			// 空き容量が回復した
+			ok = true;
+			break;
+		}
+	}
+
+	// ファイル一覧の解放
+	FreeEraseFileList(o);
+
+	if (e->LastFailed == false && ok == false)
+	{
+		// 空き容量が足りないがこれ以上ファイルを削除できない状態になってしまった
+		ELog(e, "LE_NOT_ENOUGH_FREE", bs);
+	}
+
+	e->LastFailed = ok ? false : true;
+}
+
+// 削除するファイル項目の比較
+int CompareEraseFile(void *p1, void *p2)
+{
+	ERASE_FILE *f1, *f2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	f1 = *(ERASE_FILE **)p1;
+	f2 = *(ERASE_FILE **)p2;
+	if (f1 == NULL || f2 == NULL)
+	{
+		return 0;
+	}
+	if (f1->UpdateTime > f2->UpdateTime)
+	{
+		return 1;
+	}
+	else if (f1->UpdateTime == f2->UpdateTime)
+	{
+		return 0;
+	}
+	else
+	{
+		return -1;
+	}
+}
+
+// 自動ファイル削除器スレッド
+void EraserThread(THREAD *t, void *p)
+{
+	ERASER *e = (ERASER *)p;
+	char bs[64];
+	// 引数チェック
+	if (t == NULL || e == NULL)
+	{
+		return;
+	}
+
+	// 監視を開始
+	ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
+	ELog(e, "LE_START", e->DirName, bs);
+
+	while (e->Halt == false)
+	{
+		// 一定間隔ごとにディスクの空き容量をチェックする
+		EraserMain(e);
+
+		Wait(e->HaltEvent, DISK_FREE_CHECK_INTERVAL);
+	}
+}
+
+// 新しい自動ファイル削除器の作成
+ERASER *NewEraser(LOG *log, UINT64 min_size)
+{
+	ERASER *e;
+	char dir[MAX_PATH];
+
+	if (min_size == 0)
+	{
+		min_size = DISK_FREE_SPACE_DEFAULT;
+	}
+
+	if (min_size < DISK_FREE_SPACE_MIN)
+	{
+		min_size = DISK_FREE_SPACE_MIN;
+	}
+
+	e = ZeroMalloc(sizeof(ERASER));
+
+	GetExeDir(dir, sizeof(dir));
+
+	e->Log = log;
+	e->MinFreeSpace = min_size;
+	e->DirName = CopyStr(dir);
+	e->HaltEvent = NewEvent();
+
+	e->Thread = NewThread(EraserThread, e);
+
+	return e;
+}
+
+// 自動ファイル削除器の解放
+void FreeEraser(ERASER *e)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	e->Halt = true;
+	Set(e->HaltEvent);
+	WaitThread(e->Thread, INFINITE);
+	ReleaseThread(e->Thread);
+	ReleaseEvent(e->HaltEvent);
+
+	Free(e->DirName);
+	Free(e);
+}
+
+// デバッグログをとる (可変長引数)
+void DebugLog(CEDAR *c, char *fmt, ...)
+{
+	char buf[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+	if (c->DebugLog == NULL)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	FormatArgs(buf, sizeof(buf), fmt, args);
+
+	InsertStringRecord(c->DebugLog, buf);
+	va_end(args);
+}
+
+// 自動ファイル削除器のログをとる
+void ELog(ERASER *e, char *name, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	va_start(args, name);
+	UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+	InsertUnicodeRecord(e->Log, buf);
+
+	if (IsDebug())
+	{
+		UniPrint(L"LOG: %s\n", buf);
+	}
+	va_end(args);
+}
+
+// サーバーのログをとる
+void ServerLog(CEDAR *c, wchar_t *fmt, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	UniFormatArgs(buf, sizeof(buf), fmt, args);
+
+	WriteServerLog(c, buf);
+	va_end(args);
+}
+void SLog(CEDAR *c, char *name, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	va_start(args, name);
+	UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+	WriteServerLog(c, buf);
+	va_end(args);
+}
+
+// クライアントログ
+void CLog(CLIENT *c, char *name, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	if (c == NULL || c->NoSaveLog)
+	{
+		return;
+	}
+
+	va_start(args, name);
+	UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+	WriteClientLog(c, buf);
+	va_end(args);
+}
+
+// HUB のセキュリティログをとる
+void HubLog(HUB *h, wchar_t *fmt, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	UniFormatArgs(buf, sizeof(buf), fmt, args);
+
+	WriteHubLog(h, buf);
+	va_end(args);
+}
+void ALog(ADMIN *a, HUB *h, char *name, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	wchar_t tmp[MAX_SIZE * 2];
+	va_list args;
+	RPC *r;
+	// 引数チェック
+	if (a == NULL || name == NULL)
+	{
+		return;
+	}
+
+	r = a->Rpc;
+
+	va_start(args, name);
+	UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+	if (h == NULL)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_1"), r->Name);
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_2"), r->Name, h->Name);
+	}
+
+	UniStrCat(tmp, sizeof(tmp), buf);
+
+	if (h == NULL)
+	{
+		WriteServerLog(((ADMIN *)r->Param)->Server->Cedar, tmp);
+	}
+	else
+	{
+		WriteHubLog(h, tmp);
+	}
+	va_end(args);
+}
+void HLog(HUB *h, char *name, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	va_start(args, name);
+	UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+	WriteHubLog(h, buf);
+	va_end(args);
+}
+void NLog(VH *v, char *name, ...)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	static wchar_t snat_prefix[] = L"SecureNAT: ";
+	va_list args;
+	// 引数チェック
+	if (name == NULL || v == NULL || v->nat == NULL || v->nat->SecureNAT == NULL)
+	{
+		return;
+	}
+
+	va_start(args, name);
+	Copy(buf, snat_prefix, sizeof(snat_prefix));
+	UniFormatArgs(&buf[11], sizeof(buf) - 12 * sizeof(wchar_t), _UU(name), args);
+
+	WriteHubLog(v->nat->SecureNAT->Hub, buf);
+	va_end(args);
+}
+
+// HUB のセキュリティログを保存する
+void WriteHubLog(HUB *h, wchar_t *str)
+{
+	wchar_t buf[MAX_SIZE * 2];
+	SERVER *s;
+	// 引数チェック
+	if (h == NULL || str == NULL)
+	{
+		return;
+	}
+
+	s = h->Cedar->Server;
+
+	UniFormat(buf, sizeof(buf), L"[HUB \"%S\"] %s", h->Name, str);
+
+	WriteServerLog(h->Cedar, buf);
+
+	if (h->LogSetting.SaveSecurityLog == false)
+	{
+		return;
+	}
+
+	InsertUnicodeRecord(h->SecurityLogger, str);
+}
+
+// クライアントログを保存する
+void WriteClientLog(CLIENT *c, wchar_t *str)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	InsertUnicodeRecord(c->Logger, str);
+}
+
+// サーバーのセキュリティログを保存する
+void WriteServerLog(CEDAR *c, wchar_t *str)
+{
+	SERVER *s;
+	// 引数チェック
+	if (c == NULL || str == NULL)
+	{
+		return;
+	}
+
+	s = c->Server;
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (IsDebug())
+	{
+		UniPrint(L"LOG: %s\n", str);
+	}
+
+	InsertUnicodeRecord(s->Logger, str);
+}
+
+// 複数行にわたるログを書き出す
+void WriteMultiLineLog(LOG *g, BUF *b)
+{
+	// 引数チェック
+	if (g == NULL || b == NULL)
+	{
+		return;
+	}
+
+	SeekBuf(b, 0, 0);
+
+	while (true)
+	{
+		char *s = CfgReadNextLine(b);
+		if (s == NULL)
+		{
+			break;
+		}
+
+		if (IsEmptyStr(s) == false)
+		{
+			InsertStringRecord(g, s);
+		}
+
+		Free(s);
+	}
+}
+
+// セキュリティログをとる (可変長引数) ※ 廃止
+void SecLog(HUB *h, char *fmt, ...)
+{
+	char buf[MAX_SIZE * 2];
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+
+	if (h->LogSetting.SaveSecurityLog == false)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	FormatArgs(buf, sizeof(buf), fmt, args);
+
+	WriteSecurityLog(h, buf);
+	va_end(args);
+}
+
+// セキュリティログをとる
+void WriteSecurityLog(HUB *h, char *str)
+{
+	// 引数チェック
+	if (h == NULL || str == NULL)
+	{
+		return;
+	}
+
+	InsertStringRecord(h->SecurityLogger, str);
+}
+
+// パケットログをとる
+void PacketLog(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *packet)
+{
+	UINT level;
+	PKT *p;
+	PACKET_LOG *pl;
+	SERVER *s;
+	bool no_log = false;
+	// 引数チェック
+	if (hub == NULL || src_session == NULL || packet == NULL)
+	{
+		return;
+	}
+
+	s = hub->Cedar->Server;
+
+	if (hub->LogSetting.SavePacketLog == false)
+	{
+		// パケットログをとらない
+		return;
+	}
+
+	if (Cmp(hub->HubMacAddr, packet->MacAddressSrc, 6) == 0 ||
+		Cmp(hub->HubMacAddr, packet->MacAddressDest, 6) == 0)
+	{
+		return;
+	}
+
+	// ロギングレベルの決定
+	level = CalcPacketLoggingLevel(hub, packet);
+	if (level == PACKET_LOG_NONE)
+	{
+		// 保存しない
+		return;
+	}
+
+	if (hub->Option != NULL)
+	{
+		if (hub->Option->NoIPv4PacketLog && (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4))
+		{
+			// IPv4 パケットログを一切保存しない
+			return;
+		}
+
+		if (hub->Option->NoIPv6PacketLog && packet->TypeL3 == L3_IPV6)
+		{
+			// IPv6 パケットログを一切保存しない
+			return;
+		}
+	}
+
+	if (s->Cedar->Bridge == false)
+	{
+		if (s->LicenseSystem != NULL && s->LicenseSystem->Status != NULL)
+		{
+			if (s->LicenseSystem->Status->AllowEnterpriseFunction == false &&
+				s->LicenseSystem->Status->Edition != 0)
+			{
+				// VPN Server の製品エディションが低い場合はパケットログのうち一部
+				// を保存しない
+				no_log = true;
+			}
+		}
+	}
+
+	// パケットのクローン
+	p = ClonePacket(packet, level == PACKET_LOG_ALL ? true : false);
+
+	// 情報の取得
+	pl = ZeroMalloc(sizeof(PACKET_LOG));
+	pl->Cedar = hub->Cedar;
+	pl->Packet = p;
+	pl->NoLog = no_log;
+	if (src_session != NULL)
+	{
+		pl->SrcSessionName = CopyStr(src_session->Name);
+	}
+	else
+	{
+		pl->SrcSessionName = CopyStr("");
+	}
+	if (dest_session != NULL)
+	{
+		pl->DestSessionName = CopyStr(dest_session->Name);
+	}
+	else
+	{
+		pl->DestSessionName = CopyStr("");
+	}
+
+	if (src_session->LoggingRecordCount != NULL)
+	{
+		UINT n = 0;
+		while (src_session->LoggingRecordCount->c >= 30000)
+		{
+			SleepThread(50);
+			n++;
+			if (n >= 5)
+			{
+				break;
+			}
+		}
+	}
+
+	pl->SrcSession = src_session;
+	AddRef(src_session->ref);
+
+	Inc(src_session->LoggingRecordCount);
+
+	// パケットログの挿入
+	InsertRecord(hub->PacketLogger, pl, PacketLogParseProc);
+}
+
+// 指定されたパケットのロギングレベルを計算する
+UINT CalcPacketLoggingLevelEx(HUB_LOG *g, PKT *packet)
+{
+	UINT ret = 0;
+	// 引数チェック
+	if (g == NULL || packet == NULL)
+	{
+		return PACKET_LOG_NONE;
+	}
+
+	// Ethernet ログ
+	ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ETHERNET]);
+
+	switch (packet->TypeL3)
+	{
+	case L3_ARPV4:
+		// ARP
+		ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ARP]);
+		break;
+
+	case L3_IPV4:
+		// IPv4
+		ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
+
+		switch (packet->TypeL4)
+		{
+		case L4_ICMPV4:
+			// ICMPv4
+			ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
+			break;
+
+		case L4_TCP:
+			// TCPv4
+			ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
+
+			if (packet->L4.TCPHeader->Flag & TCP_SYN ||
+				packet->L4.TCPHeader->Flag & TCP_RST ||
+				packet->L4.TCPHeader->Flag & TCP_FIN)
+			{
+				// TCP SYN LOG
+				ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+			}
+
+			break;
+
+		case L4_UDP:
+			// UDPv4
+			ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
+
+			switch (packet->TypeL7)
+			{
+			case L7_DHCPV4:
+				// DHCPv4
+				ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_DHCP]);
+				break;
+			}
+
+			break;
+		}
+
+		break;
+
+	case L3_IPV6:
+		// IPv6
+		ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
+
+		switch (packet->TypeL4)
+		{
+		case L4_ICMPV6:
+			// ICMPv6
+			ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
+			break;
+
+		case L4_TCP:
+			// TCPv6
+			ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
+
+			if (packet->L4.TCPHeader->Flag & TCP_SYN ||
+				packet->L4.TCPHeader->Flag & TCP_RST ||
+				packet->L4.TCPHeader->Flag & TCP_FIN)
+			{
+				// TCP SYN LOG
+				ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+			}
+
+			break;
+
+		case L4_UDP:
+			// UDPv6
+			ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
+
+			break;
+		}
+
+		break;
+	}
+
+	return ret;
+}
+UINT CalcPacketLoggingLevel(HUB *hub, PKT *packet)
+{
+	// 引数チェック
+	if (hub == NULL || packet == NULL)
+	{
+		return PACKET_LOG_NONE;
+	}
+
+	return CalcPacketLoggingLevelEx(&hub->LogSetting, packet);
+}
+
+// パケットログエントリを文字列に変換するプロシージャ
+char *PacketLogParseProc(RECORD *rec)
+{
+	PACKET_LOG *pl;
+	PKT *p;
+	char *s;
+	TOKEN_LIST *t;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (rec == NULL)
+	{
+		return NULL;
+	}
+
+	pl = (PACKET_LOG *)rec->Data;
+	p = pl->Packet;
+
+	// 各部を生成する
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = 16;
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+	// 送信元セッション
+	t->Token[0] = pl->SrcSessionName;
+
+	// 宛先セッション
+	t->Token[1] = pl->DestSessionName;
+
+	// 送信元 MAC アドレス
+	BinToStr(tmp, sizeof(tmp), p->MacAddressSrc, 6);
+
+	t->Token[2] = CopyStr(tmp);
+	// 宛先 MAC アドレス
+	BinToStr(tmp, sizeof(tmp), p->MacAddressDest, 6);
+
+	t->Token[3] = CopyStr(tmp);
+
+	// MAC プロトコル
+	snprintf(tmp, sizeof(tmp), "0x%04X", Endian16(p->MacHeader->Protocol));
+	t->Token[4] = CopyStr(tmp);
+
+	// パケットサイズ
+	ToStr(tmp, p->PacketSize);
+	t->Token[5] = CopyStr(tmp);
+
+	// パケットログ本体は実装されていない
+	t->Token[6] = CopyUniToUtf(_UU("LH_PACKET_LOG_NO_LOG"));
+
+	s = GenCsvLine(t);
+	FreeToken(t);
+
+	// パケットデータを破棄する
+	if (pl->PurePacket == false)
+	{
+		FreeClonePacket(p);
+	}
+	else
+	{
+		Free(p->PacketData);
+		FreePacket(p);
+	}
+
+	// セッションを解放する
+	if (pl->SrcSession != NULL)
+	{
+		Dec(pl->SrcSession->LoggingRecordCount);
+		ReleaseSession(pl->SrcSession);
+	}
+
+	// PACKET_LOG を破棄する
+	Free(pl);
+
+	return s;
+}
+
+// TCP フラグを文字列に変換
+char *TcpFlagStr(UCHAR flag)
+{
+	char tmp[MAX_SIZE];
+	StrCpy(tmp, sizeof(tmp), "");
+
+	if (flag & TCP_FIN)
+	{
+		StrCat(tmp, sizeof(tmp), "FIN+");
+	}
+
+	if (flag & TCP_SYN)
+	{
+		StrCat(tmp, sizeof(tmp), "SYN+");
+	}
+
+	if (flag & TCP_RST)
+	{
+		StrCat(tmp, sizeof(tmp), "RST+");
+	}
+
+	if (flag & TCP_PSH)
+	{
+		StrCat(tmp, sizeof(tmp), "PSH+");
+	}
+
+	if (flag & TCP_ACK)
+	{
+		StrCat(tmp, sizeof(tmp), "ACK+");
+	}
+
+	if (flag & TCP_URG)
+	{
+		StrCat(tmp, sizeof(tmp), "URG+");
+	}
+
+	if (StrLen(tmp) >= 1)
+	{
+		if (tmp[StrLen(tmp) - 1] == '+')
+		{
+			tmp[StrLen(tmp) - 1] = 0;
+		}
+	}
+
+	return CopyStr(tmp);
+}
+
+// ポート文字列の生成
+char *PortStr(CEDAR *cedar, UINT port, bool udp)
+{
+	char tmp[MAX_SIZE];
+	char *name;
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return NULL;
+	}
+
+	name = GetSvcName(cedar, udp, port);
+
+	if (name == NULL)
+	{
+		snprintf(tmp, sizeof(tmp), "%u", port);
+	}
+	else
+	{
+		snprintf(tmp, sizeof(tmp), "%s(%u)", name, port);
+	}
+
+	return CopyStr(tmp);
+}
+
+// カンマで区切られた文字列を生成する
+char *GenCsvLine(TOKEN_LIST *t)
+{
+	UINT i;
+	BUF *b;
+	char *ret;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		if (t->Token[i] != NULL)
+		{
+			ReplaceForCsv(t->Token[i]);
+			if (StrLen(t->Token[i]) == 0)
+			{
+				WriteBuf(b, "-", 1);
+			}
+			else
+			{
+				WriteBuf(b, t->Token[i], StrLen(t->Token[i]));
+			}
+		}
+		else
+		{
+			WriteBuf(b, "-", 1);
+		}
+		if (i != (t->NumTokens - 1))
+		{
+			WriteBuf(b, ",", 1);
+		}
+	}
+	WriteBuf(b, "\0", 1);
+
+	ret = (char *)b->Buf;
+
+	Free(b);
+
+	return ret;
+}
+
+// CSV の中に入る文字列を正しく置換する
+void ReplaceForCsv(char *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	// 空白があればトリミングする
+	Trim(str);
+	len = StrLen(str);
+
+	for (i = 0;i < len;i++)
+	{
+		// カンマをアンダーバーに変換する
+		if (str[i] == ',')
+		{
+			str[i] = '_';
+		}
+	}
+}
+
+// ログのディレクトリ名を設定
+void SetLogDirName(LOG *g, char *dir)
+{
+	// 引数チェック
+	if (g == NULL || dir == NULL)
+	{
+		return;
+	}
+
+	LockLog(g);
+	{
+		if (g->DirName != NULL)
+		{
+			Free(g->DirName);
+		}
+		g->DirName = CopyStr(dir);
+	}
+	UnlockLog(g);
+}
+
+// ログの名前を設定
+void SetLogPrefix(LOG *g, char *prefix)
+{
+	// 引数チェック
+	if (g == NULL || prefix == NULL)
+	{
+		return;
+	}
+
+	LockLog(g);
+	{
+		if (g->DirName != NULL)
+		{
+			Free(g->Prefix);
+		}
+		g->DirName = CopyStr(prefix);
+	}
+	UnlockLog(g);
+}
+
+// ログのスイッチ種類を設定
+void SetLogSwitchType(LOG *g, UINT switch_type)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	LockLog(g);
+	{
+		g->SwitchType = switch_type;
+	}
+	UnlockLog(g);
+}
+
+// 文字列レコードの解析
+char *StringRecordParseProc(RECORD *rec)
+{
+	// 引数チェック
+	if (rec == NULL)
+	{
+		return NULL;
+	}
+
+	return (char *)rec->Data;
+}
+
+// ログに Unicode 文字列レコードを追加
+void InsertUnicodeRecord(LOG *g, wchar_t *unistr)
+{
+	char *str;
+	UINT size;
+	// 引数チェック
+	if (g == NULL || unistr == NULL)
+	{
+		return;
+	}
+
+	size = CalcUniToUtf8(unistr) + 32;
+	str = ZeroMalloc(size);
+
+	UniToUtf8((BYTE *)str, size, unistr);
+	InsertStringRecord(g, str);
+	Free(str);
+}
+
+// ログに文字列レコードを追加
+void InsertStringRecord(LOG *g, char *str)
+{
+	char *str_copy;
+	// 引数チェック
+	if (g == NULL || str == NULL)
+	{
+		return;
+	}
+
+	str_copy = CopyStr(str);
+
+	InsertRecord(g, str_copy, StringRecordParseProc);
+}
+
+// ログにレコードを追加
+void InsertRecord(LOG *g, void *data, RECORD_PARSE_PROC *proc)
+{
+	RECORD *rec;
+	// 引数チェック
+	if (g == NULL || data == NULL || proc == NULL)
+	{
+		return;
+	}
+
+	rec = ZeroMalloc(sizeof(RECORD));
+	rec->Tick = Tick64();
+	rec->ParseProc = proc;
+	rec->Data = data;
+
+	LockQueue(g->RecordQueue);
+	{
+		InsertQueue(g->RecordQueue, rec);
+	}
+	UnlockQueue(g->RecordQueue);
+
+	Set(g->Event);
+}
+
+// ログのロック
+void LockLog(LOG *g)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	Lock(g->lock);
+}
+
+// ログのロック解除
+void UnlockLog(LOG *g)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	Unlock(g->lock);
+}
+
+// ログファイル名の文字列部分を時刻とスイッチ規則から生成する
+void MakeLogFileNameStringFromTick(LOG *g, char *str, UINT size, UINT64 tick, UINT switch_type)
+{
+	UINT64 time;
+	SYSTEMTIME st;
+
+	// 引数チェック
+	if (str == NULL || g == NULL)
+	{
+		return;
+	}
+
+	if (g->CacheFlag)
+	{
+		if (g->LastTick == tick &&
+			g->LastSwitchType == switch_type)
+		{
+			StrCpy(str, size, g->LastStr);
+			return;
+		}
+	}
+
+	time = TickToTime(tick);
+	UINT64ToSystem(&st, SystemToLocal64(time));
+
+	switch (switch_type)
+	{
+	case LOG_SWITCH_SECOND:	// 1 秒単位
+		snprintf(str, size, "_%04u%02u%02u_%02u%02u%02u",
+			st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+		break;
+
+	case LOG_SWITCH_MINUTE:	// 1 分単位
+		snprintf(str, size, "_%04u%02u%02u_%02u%02u",
+			st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);
+		break;
+
+	case LOG_SWITCH_HOUR:	// 1 時間単位
+		snprintf(str, size, "_%04u%02u%02u_%02u", st.wYear, st.wMonth, st.wDay, st.wHour);
+		break;
+
+	case LOG_SWITCH_DAY:	// 1 日単位
+		snprintf(str, size, "_%04u%02u%02u", st.wYear, st.wMonth, st.wDay);
+		break;
+
+	case LOG_SWITCH_MONTH:	// 1 ヶ月単位
+		snprintf(str, size, "_%04u%02u", st.wYear, st.wMonth);
+		break;
+
+	default:				// 切り替え無し
+		snprintf(str, size, "");
+		break;
+	}
+
+	g->CacheFlag = true;
+	g->LastTick = tick;
+	g->LastSwitchType = switch_type;
+	StrCpy(g->LastStr, sizeof(g->LastStr), str);
+}
+
+// ログファイル名を作成する
+bool MakeLogFileName(LOG *g, char *name, UINT size, char *dir, char *prefix, UINT64 tick, UINT switch_type, UINT num, char *old_datestr)
+{
+	char tmp[MAX_SIZE];
+	char tmp2[64];
+	bool ret = false;
+	// 引数チェック
+	if (g == NULL || name == NULL || prefix == NULL || old_datestr == NULL)
+	{
+		return false;
+	}
+
+	MakeLogFileNameStringFromTick(g, tmp, sizeof(tmp), tick, switch_type);
+
+	if (num == 0)
+	{
+		tmp2[0] = 0;
+	}
+	else
+	{
+		snprintf(tmp2, sizeof(tmp2), "~%02u", num);
+	}
+
+	if (strcmp(old_datestr, tmp) != 0)
+	{
+		ret = true;
+		strcpy(old_datestr, tmp);
+	}
+
+	snprintf(name, size, "%s%s%s%s%s.log", dir,
+		StrLen(dir) == 0 ? "" : "/",
+		prefix, tmp, tmp2
+		);
+
+	return ret;
+}
+
+// ログがフラッシュされるまで待機
+void WaitLogFlush(LOG *g)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		UINT num;
+		LockQueue(g->RecordQueue);
+		{
+			num = g->RecordQueue->num_item;
+		}
+		UnlockQueue(g->RecordQueue);
+
+		if (num == 0)
+		{
+			break;
+		}
+
+		Wait(g->FlushEvent, 100);
+	}
+}
+
+// ログ記録用スレッド
+void LogThread(THREAD *thread, void *param)
+{
+	LOG *g;
+	IO *io;
+	BUF *b;
+	bool flag = false;
+	char current_file_name[MAX_SIZE];
+	char current_logfile_datename[MAX_SIZE];
+	bool last_priority_flag = false;
+	bool log_date_changed = false;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	Zero(current_file_name, sizeof(current_file_name));
+	Zero(current_logfile_datename, sizeof(current_logfile_datename));
+
+	g = (LOG *)param;
+
+	io = NULL;
+	b = NewBuf();
+
+#ifdef	OS_WIN32
+
+	// 優先順位を最低にする
+	MsSetThreadPriorityIdle();
+
+#endif	// OS_WIN32
+
+	NoticeThreadInit(thread);
+
+	while (true)
+	{
+		RECORD *rec;
+		UINT64 s = Tick64();
+
+		while (true)
+		{
+			char file_name[MAX_SIZE];
+			UINT num;
+
+			// キューの先頭からレコードを取得する
+			LockQueue(g->RecordQueue);
+			{
+				rec = GetNext(g->RecordQueue);
+				num = g->RecordQueue->num_item;
+			}
+			UnlockQueue(g->RecordQueue);
+
+#ifdef	OS_WIN32
+			if (num >= LOG_ENGINE_SAVE_START_CACHE_COUNT)
+			{
+				// 優先順位を上げる
+				if (last_priority_flag == false)
+				{
+					Debug("LOG_THREAD: MsSetThreadPriorityRealtime\n");
+					MsSetThreadPriorityRealtime();
+					last_priority_flag = true;
+				}
+			}
+
+			if (num < (LOG_ENGINE_SAVE_START_CACHE_COUNT / 2))
+			{
+				// 優先順位を戻す
+				if (last_priority_flag)
+				{
+					Debug("LOG_THREAD: MsSetThreadPriorityIdle\n");
+					MsSetThreadPriorityIdle();
+					last_priority_flag = false;
+				}
+			}
+#endif	// OS_WIN32
+
+			if (b->Size > g->MaxLogFileSize)
+			{
+				// バッファのサイズが最大ログファイルサイズを超える場合は消去する
+				ClearBuf(b);
+			}
+
+			if (b->Size >= LOG_ENGINE_BUFFER_CACHE_SIZE_MAX)
+			{
+				// バッファの中身をファイルに書き出す
+				if (io != NULL)
+				{
+					if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
+					{
+						if (g->log_number_incremented == false)
+						{
+							g->CurrentLogNumber++;
+							g->log_number_incremented = true;
+						}
+					}
+					else
+					{
+						if (FileWrite(io, b->Buf, b->Size) == false)
+						{
+							FileCloseEx(io, true);
+							// ファイルへの書き込みに失敗した場合は仕方が無い
+							// のでバッファを消して諦める
+							ClearBuf(b);
+							io = NULL;
+						}
+						else
+						{
+							g->CurrentFilePointer += (UINT64)b->Size;
+							ClearBuf(b);
+						}
+					}
+				}
+			}
+
+			if (rec == NULL)
+			{
+				if (b->Size != 0)
+				{
+					// バッファの中身をファイルに書き出す
+					if (io != NULL)
+					{
+						if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
+						{
+							if (g->log_number_incremented == false)
+							{
+								g->CurrentLogNumber++;
+								g->log_number_incremented = true;
+							}
+						}
+						else
+						{
+							if (FileWrite(io, b->Buf, b->Size) == false)
+							{
+								FileCloseEx(io, true);
+								// ファイルへの書き込みに失敗した場合は仕方が無い
+								// のでバッファを消して諦める
+								ClearBuf(b);
+								io = NULL;
+							}
+							else
+							{
+								g->CurrentFilePointer += (UINT64)b->Size;
+								ClearBuf(b);
+							}
+						}
+					}
+				}
+
+				Set(g->FlushEvent);
+				break;
+			}
+
+			// ログファイル名を生成する
+			LockLog(g);
+			{
+				log_date_changed = MakeLogFileName(g, file_name, sizeof(file_name),
+					g->DirName, g->Prefix, rec->Tick, g->SwitchType, g->CurrentLogNumber, current_logfile_datename);
+
+				if (log_date_changed)
+				{
+					UINT i;
+
+					g->CurrentLogNumber = 0;
+					MakeLogFileName(g, file_name, sizeof(file_name),
+						g->DirName, g->Prefix, rec->Tick, g->SwitchType, 0, current_logfile_datename);
+					for (i = 0;;i++)
+					{
+						char tmp[MAX_SIZE];
+						MakeLogFileName(g, tmp, sizeof(tmp),
+							g->DirName, g->Prefix, rec->Tick, g->SwitchType, i, current_logfile_datename);
+
+						if (IsFileExists(tmp) == false)
+						{
+							break;
+						}
+						StrCpy(file_name, sizeof(file_name), tmp);
+						g->CurrentLogNumber = i;
+					}
+				}
+			}
+			UnlockLog(g);
+
+			if (io != NULL)
+			{
+				if (StrCmp(current_file_name, file_name) != 0)
+				{
+					// 現在ログファイルを開いていて今回別のログファイルへの書き込みが必要になった
+					// 場合はログファイルにバッファの内容を書き込んでからログファイルを閉じる
+					// バッファの中身をファイルに書き出す
+					if (io != NULL)
+					{
+						if (log_date_changed)
+						{
+							if ((g->CurrentFilePointer + (UINT64)b->Size) <= g->MaxLogFileSize)
+							{
+								if (FileWrite(io, b->Buf, b->Size) == false)
+								{
+									FileCloseEx(io, true);
+									ClearBuf(b);
+									io = NULL;
+								}
+								else
+								{
+									g->CurrentFilePointer += (UINT64)b->Size;
+									ClearBuf(b);
+								}
+							}
+						}
+						// ファイルを閉じる
+						FileCloseEx(io, true);
+					}
+
+					g->log_number_incremented = false;
+
+					// 新しいログファイルを開くか作成する
+					StrCpy(current_file_name, sizeof(current_file_name), file_name);
+					io = FileOpen(file_name, true);
+					if (io == NULL)
+					{
+						// ログファイルを作成する
+						LockLog(g);
+						{
+							MakeDir(g->DirName);
+
+#ifdef	OS_WIN32
+							Win32SetFolderCompress(g->DirName, true);
+#endif	// OS_WIN32
+						}
+						UnlockLog(g);
+						io = FileCreate(file_name);
+						g->CurrentFilePointer = 0;
+					}
+					else
+					{
+						// ログファイルの末尾に移動する
+						g->CurrentFilePointer = FileSize64(io);
+						FileSeek(io, SEEK_END, 0);
+					}
+				}
+			}
+			else
+			{
+				// 新しいログファイルを開くか作成する
+				StrCpy(current_file_name, sizeof(current_file_name), file_name);
+				io = FileOpen(file_name, true);
+				if (io == NULL)
+				{
+					// ログファイルを作成する
+					LockLog(g);
+					{
+						MakeDir(g->DirName);
+#ifdef	OS_WIN32
+						Win32SetFolderCompress(g->DirName, true);
+#endif	// OS_WIN32
+					}
+					UnlockLog(g);
+					io = FileCreate(file_name);
+					g->CurrentFilePointer = 0;
+					if (io == NULL)
+					{
+						Debug("Logging.c: SleepThread(30);\n");
+						SleepThread(30);
+					}
+				}
+				else
+				{
+					// ログファイルの末尾に移動する
+					g->CurrentFilePointer = FileSize64(io);
+					FileSeek(io, SEEK_END, 0);
+				}
+
+				g->log_number_incremented = false;
+			}
+
+			// ログの内容をバッファに書き出す
+			WriteRecordToBuffer(b, rec);
+
+			// レコードのメモリを解放
+			Free(rec);
+
+			if (io == NULL)
+			{
+				break;
+			}
+		}
+
+		if (g->Halt)
+		{
+			// 停止フラグが立った場合
+			// すべてのレコードを保存し終えるとブレイクする
+			UINT num;
+
+			if (flag == false)
+			{
+#ifdef	OS_WIN32
+				MsSetThreadPriorityRealtime();
+#endif	// OS_WIN32
+				flag = true;
+			}
+
+			LockQueue(g->RecordQueue);
+			{
+				num = g->RecordQueue->num_item;
+			}
+			UnlockQueue(g->RecordQueue);
+
+			if (num == 0 || io == NULL)
+			{
+				break;
+			}
+		}
+		else
+		{
+			Wait(g->Event, 9821);
+		}
+	}
+
+	if (io != NULL)
+	{
+		FileCloseEx(io, true);
+	}
+
+	FreeBuf(b);
+}
+
+// ログの内容をバッファに書き出す
+void WriteRecordToBuffer(BUF *b, RECORD *r)
+{
+	UINT64 time;
+	char time_str[MAX_SIZE];
+	char date_str[MAX_SIZE];
+	char *s;
+	// 引数チェック
+	if (b == NULL || r == NULL)
+	{
+		return;
+	}
+
+	// 時刻の取得
+	time = SystemToLocal64(TickToTime(r->Tick));
+
+	// 時刻を文字列に変換
+	GetDateStr64(date_str, sizeof(date_str), time);
+	GetTimeStrMilli64(time_str, sizeof(time_str), time);
+
+	if (r->ParseProc != PacketLogParseProc)
+	{
+		// パケットログ以外
+		WriteBuf(b, date_str, StrLen(date_str));
+		WriteBuf(b, " ", 1);
+		WriteBuf(b, time_str, StrLen(time_str));
+		WriteBuf(b, " ", 1);
+	}
+	else
+	{
+		// パケットログ
+		WriteBuf(b, date_str, StrLen(date_str));
+		WriteBuf(b, ",", 1);
+		WriteBuf(b, time_str, StrLen(time_str));
+		WriteBuf(b, ",", 1);
+	}
+
+	// 本文を出力
+	s = r->ParseProc(r);
+	WriteBuf(b, s, StrLen(s));
+	Free(s);
+
+	WriteBuf(b, "\r\n", 2);
+}
+
+// ログ記録の終了
+void FreeLog(LOG *g)
+{
+	RECORD *rec;
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	// 停止フラグ
+	g->Halt = true;
+	Set(g->Event);
+
+	WaitThread(g->Thread, INFINITE);
+	ReleaseThread(g->Thread);
+
+	DeleteLock(g->lock);
+	Free(g->DirName);
+	Free(g->Prefix);
+
+	// 未処理のレコードが残っている場合は解放する
+	// (本来はここでは残っていないはず)
+	while (rec = GetNext(g->RecordQueue))
+	{
+		char *s = rec->ParseProc(rec);
+		Free(s);
+		Free(rec);
+	}
+	ReleaseQueue(g->RecordQueue);
+
+	ReleaseEvent(g->Event);
+	ReleaseEvent(g->FlushEvent);
+
+	Free(g);
+}
+
+// 新しいログ記録の開始
+LOG *NewLog(char *dir, char *prefix, UINT switch_type)
+{
+	LOG *g;
+
+	g = ZeroMalloc(sizeof(LOG));
+	g->lock = NewLock();
+	g->DirName = CopyStr(dir == NULL ? "" : dir);
+	g->Prefix = CopyStr(prefix == NULL ? "log" : prefix);
+	g->SwitchType = switch_type;
+	g->RecordQueue = NewQueue();
+	g->Event = NewEvent();
+	g->MaxLogFileSize = MAX_LOG_SIZE;
+	g->FlushEvent = NewEvent();
+
+	g->Thread = NewThread(LogThread, g);
+
+	WaitThreadInit(g->Thread);
+
+	return g;
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Logging.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Logging.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Logging.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,229 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Logging.h
+// Logging.c のヘッダ
+
+#ifndef	LOGGING_H
+#define	LOGGING_H
+
+
+#define	MAX_LOG_SIZE						1073741823ULL
+
+typedef char *(RECORD_PARSE_PROC)(RECORD *rec);
+
+// パケットログ構造体
+struct PACKET_LOG
+{
+	CEDAR *Cedar;
+	struct PKT *Packet;
+	char *SrcSessionName;
+	char *DestSessionName;
+	bool PurePacket;						// クローンしていないパケット
+	bool PurePacketNoPayload;				// クローンしていないパケット (ペイロード無し)
+	SESSION *SrcSession;
+	bool NoLog;								// ログを書かない
+};
+
+// HUB のログ保存オプション
+struct HUB_LOG
+{
+	bool SaveSecurityLog;					// セキュリティログの保存
+	UINT SecurityLogSwitchType;				// セキュリティログの切り替え種類
+	bool SavePacketLog;						// パケットログの保存
+	UINT PacketLogSwitchType;				// パケットログの切り替え種類
+	UINT PacketLogConfig[NUM_PACKET_LOG];	// パケットログ設定
+};
+
+// レコード
+struct RECORD
+{
+	UINT64 Tick;							// 時刻
+	RECORD_PARSE_PROC *ParseProc;			// パース用プロシージャ
+	void *Data;								// データ
+};
+
+// LOG オブジェクト
+struct LOG
+{
+	LOCK *lock;								// ロック
+	THREAD *Thread;							// スレッド
+	char *DirName;							// 保存先ディレクトリ名
+	char *Prefix;							// ファイル名
+	UINT SwitchType;						// ログファイルの切り替え種類
+	QUEUE *RecordQueue;						// レコードキュー
+	volatile bool Halt;						// 停止フラグ
+	EVENT *Event;							// ログ用イベント
+	EVENT *FlushEvent;						// フラッシュ完了イベント
+	bool CacheFlag;
+	UINT64 LastTick;
+	UINT LastSwitchType;
+	char LastStr[MAX_SIZE];
+	UINT64 CurrentFilePointer;				// 現在のファイルポインタ
+	UINT64 MaxLogFileSize;					// 最大ログファイルサイズ
+	UINT CurrentLogNumber;					// 現在のログファイル番号
+	bool log_number_incremented;
+};
+
+// ERASER オブジェクト
+struct ERASER
+{
+	LOG *Log;								// ロガー
+	UINT64 MinFreeSpace;					// ファイルの削除を開始するディスク空き容量
+	char *DirName;							// ディレクトリ名
+	volatile bool Halt;						// 停止フラグ
+	THREAD *Thread;							// スレッド
+	bool LastFailed;						// 最後にファイル削除に失敗したかどうか
+	EVENT *HaltEvent;						// 停止イベント
+};
+
+// 削除できるファイルの一覧
+typedef struct ERASE_FILE
+{
+	char *FullPath;							// フルパス
+	UINT64 UpdateTime;						// 更新日時
+} ERASE_FILE;
+
+// SYSLOG オブジェクト
+struct SLOG
+{
+	LOCK *lock;								// ロック
+	SOCK *Udp;								// UDP ソケット
+	IP DestIp;								// 宛先 IP アドレス
+	UINT DestPort;							// 宛先ポート番号
+	char HostName[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	UINT64 NextPollIp;						// 最後に IP アドレスを調べた日時
+};
+
+// 関数プロトタイプ
+LOG *NewLog(char *dir, char *prefix, UINT switch_type);
+void FreeLog(LOG *g);
+void LogThread(THREAD *thread, void *param);
+void WaitLogFlush(LOG *g);
+void LockLog(LOG *g);
+void UnlockLog(LOG *g);
+void InsertRecord(LOG *g, void *data, RECORD_PARSE_PROC *proc);
+void InsertStringRecord(LOG *g, char *str);
+void InsertUnicodeRecord(LOG *g, wchar_t *unistr);
+char *StringRecordParseProc(RECORD *rec);
+bool MakeLogFileName(LOG *g, char *name, UINT size, char *dir, char *prefix, UINT64 tick, UINT switch_type, UINT num, char *old_datestr);
+void MakeLogFileNameStringFromTick(LOG *g, char *str, UINT size, UINT64 tick, UINT switch_type);
+void WriteRecordToBuffer(BUF *b, RECORD *r);
+void SetLogDirName(LOG *g, char *dir);
+void SetLogPrefix(LOG *g, char *prefix);
+void SetLogSwitchType(LOG *g, UINT switch_type);
+void PacketLog(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *packet);
+char *PacketLogParseProc(RECORD *rec);
+UINT CalcPacketLoggingLevel(HUB *hub, PKT *packet);
+UINT CalcPacketLoggingLevelEx(HUB_LOG *g, PKT *packet);
+char *GenCsvLine(TOKEN_LIST *t);
+void ReplaceForCsv(char *str);
+char *PortStr(CEDAR *cedar, UINT port, bool udp);
+char *TcpFlagStr(UCHAR flag);
+void WriteSecurityLog(HUB *h, char *str);
+void SecLog(HUB *h, char *fmt, ...);
+void SiSetDefaultLogSetting(HUB_LOG *g);
+void DebugLog(CEDAR *c, char *fmt, ...);
+void HubLog(HUB *h, wchar_t *fmt, ...);
+void ServerLog(CEDAR *c, wchar_t *fmt, ...);
+void SLog(CEDAR *c, char *name, ...);
+void WriteHubLog(HUB *h, wchar_t *str);
+void HLog(HUB *h, char *name, ...);
+void NLog(VH *v, char *name, ...);
+void WriteServerLog(CEDAR *c, wchar_t *str);
+void ALog(ADMIN *a, HUB *h, char *name, ...);
+void CLog(CLIENT *c, char *name, ...);
+void WriteClientLog(CLIENT *c, wchar_t *str);
+ERASER *NewEraser(LOG *log, UINT64 min_size);
+void FreeEraser(ERASER *e);
+void ELog(ERASER *e, char *name, ...);
+void EraserThread(THREAD *t, void *p);
+void EraserMain(ERASER *e);
+bool CheckEraserDiskFreeSpace(ERASER *e);
+int CompareEraseFile(void *p1, void *p2);
+LIST *GenerateEraseFileList(ERASER *e);
+void FreeEraseFileList(LIST *o);
+void PrintEraseFileList(LIST *o);
+void EnumEraseFile(LIST *o, char *dirname);
+SLOG *NewSysLog(char *hostname, UINT port);
+void SetSysLog(SLOG *g, char *hostname, UINT port);
+void FreeSysLog(SLOG *g);
+void SendSysLog(SLOG *g, wchar_t *str);
+void WriteMultiLineLog(LOG *g, BUF *b);
+
+#endif	// LOGGING_G
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NM.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NM.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NM.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1483 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// NM.c
+// Win32 用 SoftEther UT-VPN User-mode Router Manager
+
+
+#ifdef	WIN32
+
+#define	SM_C
+#define	CM_C
+#define	NM_C
+
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "../PenCore/resource.h"
+
+// グローバル変数
+static NM *nm = NULL;
+
+
+// パスワード変更ダイアログ
+UINT NmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	RPC *r = (RPC *)param;
+	char tmp1[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	RPC_SET_PASSWORD t;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		FormatText(hWnd, 0, r->Sock->RemoteHostname);
+		FormatText(hWnd, S_TITLE, r->Sock->RemoteHostname);
+		break;
+
+	case WM_COMMAND:
+		GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+		GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+		switch (LOWORD(wParam))
+		{
+		case E_PASSWORD1:
+		case E_PASSWORD2:
+			SetEnable(hWnd, IDOK, StrCmp(tmp1, tmp2) == 0);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			Zero(&t, sizeof(t));
+			Hash(t.HashedPassword, tmp1, StrLen(tmp1), true);
+
+			if (CALL(hWnd, NcSetPassword(r, &t)))
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("NM_PASSWORD_MSG"));
+				EndDialog(hWnd, true);
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// パスワードの変更
+void NmChangePassword(HWND hWnd, RPC *r)
+{
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_NM_CHANGE_PASSWORD, NmChangePasswordProc, r);
+}
+
+// DHCP 列挙初期化
+void NmDhcpInit(HWND hWnd, SM_HUB *r)
+{
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_INTERNET);
+
+	LvInit(hWnd, L_TABLE);
+	LvInsertColumn(hWnd, L_TABLE, 0, _UU("DHCP_DHCP_ID"), 50);
+	LvInsertColumn(hWnd, L_TABLE, 1, _UU("DHCP_LEASED_TIME"), 200);
+	LvInsertColumn(hWnd, L_TABLE, 2, _UU("DHCP_EXPIRE_TIME"), 200);
+	LvInsertColumn(hWnd, L_TABLE, 3, _UU("DHCP_MAC_ADDRESS"), 130);
+	LvInsertColumn(hWnd, L_TABLE, 4, _UU("DHCP_IP_ADDRESS"), 100);
+	LvInsertColumn(hWnd, L_TABLE, 5, _UU("DHCP_HOSTNAME"), 150);
+
+	NmDhcpRefresh(hWnd, r);
+}
+
+// DHCP 列挙
+void NmDhcpRefresh(HWND hWnd, SM_HUB *r)
+{
+	LVB *b;
+	RPC_ENUM_DHCP t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+	if (CALL(hWnd, ScEnumDHCP(r->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	b = LvInsertStart();
+	
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_DHCP_ITEM *e = &t.Items[i];
+		wchar_t tmp0[MAX_SIZE];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp4[MAX_SIZE];
+		wchar_t tmp5[MAX_SIZE];
+		char str[MAX_SIZE];
+
+		// ID
+		UniToStru(tmp0, e->Id);
+
+		// 時刻
+		GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->LeasedTime), NULL);
+		GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(e->ExpireTime), NULL);
+
+		MacToStr(str, sizeof(str), e->MacAddress);
+		StrToUni(tmp3, sizeof(tmp3), str);
+
+		IPToStr32(str, sizeof(str), e->IpAddress);
+		StrToUni(tmp4, sizeof(tmp4), str);
+
+		StrToUni(tmp5, sizeof(tmp5), e->Hostname);
+
+		LvInsertAdd(b, ICO_INTERNET, NULL, 6,
+			tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+	}
+
+	LvInsertEnd(b, hWnd, L_TABLE);
+
+	FreeRpcEnumDhcp(&t);
+}
+
+// DHCP 列挙プロシージャ
+UINT NmDhcpProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *r = (SM_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		NmDhcpInit(hWnd, r);
+		SetTimer(hWnd, 1, NM_DHCP_REFRESH_TIME, NULL);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case B_REFRESH:
+			NmDhcpRefresh(hWnd, r);
+			break;
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			NmDhcpRefresh(hWnd, r);
+			SetTimer(hWnd, 1, NM_DHCP_REFRESH_TIME, NULL);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+	return 0;
+}
+
+// DHCP 列挙
+void NmDhcp(HWND hWnd, SM_HUB *r)
+{
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_NM_DHCP, NmDhcpProc, r);
+}
+
+
+// NAT 列挙初期化
+void NmNatInit(HWND hWnd, SM_HUB *r)
+{
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_PROTOCOL);
+
+	LvInit(hWnd, L_TABLE);
+	LvInsertColumn(hWnd, L_TABLE, 0, _UU("NM_NAT_ID"), 50);
+	LvInsertColumn(hWnd, L_TABLE, 1, _UU("NM_NAT_PROTOCOL"), 80);
+	LvInsertColumn(hWnd, L_TABLE, 2, _UU("NM_NAT_SRC_HOST"), 100);
+	LvInsertColumn(hWnd, L_TABLE, 3, _UU("NM_NAT_SRC_PORT"), 80);
+	LvInsertColumn(hWnd, L_TABLE, 4, _UU("NM_NAT_DST_HOST"), 150);
+	LvInsertColumn(hWnd, L_TABLE, 5, _UU("NM_NAT_DST_PORT"), 80);
+	LvInsertColumn(hWnd, L_TABLE, 6, _UU("NM_NAT_CREATED"), 200);
+	LvInsertColumn(hWnd, L_TABLE, 7, _UU("NM_NAT_LAST_COMM"), 200);
+	LvInsertColumn(hWnd, L_TABLE, 8, _UU("NM_NAT_SIZE"), 120);
+	LvInsertColumn(hWnd, L_TABLE, 9, _UU("NM_NAT_TCP_STATUS"), 120);
+
+	NmNatRefresh(hWnd, r);
+}
+
+// NAT 列挙
+void NmNatRefresh(HWND hWnd, SM_HUB *r)
+{
+	LVB *b;
+	RPC_ENUM_NAT t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+	if (CALL(hWnd, ScEnumNAT(r->Rpc, &t)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	b = LvInsertStart();
+	
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_NAT_ITEM *e = &t.Items[i];
+		wchar_t tmp0[MAX_SIZE];
+		wchar_t *tmp1 = L"";
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp4[MAX_SIZE];
+		wchar_t tmp5[MAX_SIZE];
+		wchar_t tmp6[MAX_SIZE];
+		wchar_t tmp7[MAX_SIZE];
+		wchar_t tmp8[MAX_SIZE];
+		wchar_t *tmp9 = L"";
+		char v1[128], v2[128];
+
+		// ID
+		UniToStru(tmp0, e->Id);
+
+		// プロトコル
+		switch (e->Protocol)
+		{
+		case NAT_TCP:
+			tmp1 = _UU("NM_NAT_PROTO_TCP");
+			break;
+		case NAT_UDP:
+			tmp1 = _UU("NM_NAT_PROTO_UDP");
+			break;
+		case NAT_DNS:
+			tmp1 = _UU("NM_NAT_PROTO_DNS");
+			break;
+		}
+
+		// 接続元ホスト
+		StrToUni(tmp2, sizeof(tmp2), e->SrcHost);
+
+		// 接続元ポート
+		UniToStru(tmp3, e->SrcPort);
+
+		// 接続先ホスト
+		StrToUni(tmp4, sizeof(tmp4), e->DestHost);
+
+		// 接続先ポート
+		UniToStru(tmp5, e->DestPort);
+
+		// セッション作成日時
+		GetDateTimeStrEx64(tmp6, sizeof(tmp6), SystemToLocal64(e->CreatedTime), NULL);
+
+		// 最終通信日時
+		GetDateTimeStrEx64(tmp7, sizeof(tmp7), SystemToLocal64(e->LastCommTime), NULL);
+
+		// 通信量
+		ToStr3(v1, sizeof(v1), e->RecvSize);
+		ToStr3(v2, sizeof(v2), e->SendSize);
+		UniFormat(tmp8, sizeof(tmp8), L"%S / %S", v1, v2);
+
+		// TCP 状態
+		if (e->Protocol == NAT_TCP)
+		{
+			switch (e->TcpStatus)
+			{
+			case NAT_TCP_CONNECTING:
+				tmp9 = _UU("NAT_TCP_CONNECTING");
+				break;
+			case NAT_TCP_SEND_RESET:
+				tmp9 = _UU("NAT_TCP_SEND_RESET");
+				break;
+			case NAT_TCP_CONNECTED:
+				tmp9 = _UU("NAT_TCP_CONNECTED");
+				break;
+			case NAT_TCP_ESTABLISHED:
+				tmp9 = _UU("NAT_TCP_ESTABLISHED");
+				break;
+			case NAT_TCP_WAIT_DISCONNECT:
+				tmp9 = _UU("NAT_TCP_WAIT_DISCONNECT");
+				break;
+			}
+		}
+
+		LvInsertAdd(b, ICO_PROTOCOL, NULL, 10,
+			tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+	}
+
+	LvInsertEnd(b, hWnd, L_TABLE);
+
+	FreeRpcEnumNat(&t);
+}
+
+// NAT 列挙プロシージャ
+UINT NmNatProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *r = (SM_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		NmNatInit(hWnd, r);
+		SetTimer(hWnd, 1, NM_NAT_REFRESH_TIME, NULL);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case B_REFRESH:
+			NmNatRefresh(hWnd, r);
+			break;
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			NmNatRefresh(hWnd, r);
+			SetTimer(hWnd, 1, NM_NAT_REFRESH_TIME, NULL);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+	return 0;
+}
+
+// NAT 列挙
+void NmNat(HWND hWnd, SM_HUB *r)
+{
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_NM_NAT, NmNatProc, r);
+}
+
+// ルーターの情報の表示
+bool NmInfo(HWND hWnd, SM_SERVER *s, void *param)
+{
+	LVB *b;
+	RPC_NAT_INFO t;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+
+	if (CALL(hWnd, NcGetInfo(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	StrToUni(tmp, sizeof(tmp), t.NatProductName);
+	LvInsertAdd(b, ICO_ROUTER, NULL, 2, _UU("NM_INFO_PRODUCT_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.NatVersionString);
+	LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("NM_INFO_VERSION_STR"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.NatBuildInfoString);
+	LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("NM_INFO_BUILD_INFO"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.NatHostName);
+	LvInsertAdd(b, ICO_TOWER, NULL, 2, _UU("NM_INFO_HOSTNAME"), tmp);
+
+	// OS
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsSystemName);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SYSTEM_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsProductName);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_PRODUCT_NAME"), tmp);
+
+	if (t.OsInfo.OsServicePack != 0)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("SM_OS_SP_TAG"), t.OsInfo.OsServicePack);
+		LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SERVICE_PACK"), tmp);
+	}
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVendorName);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VENDER_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVersion);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VERSION"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelName);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelVersion);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_VERSION"), tmp);
+
+	// メモリ情報
+	if (t.MemInfo.TotalMemory != 0)
+	{
+		char vv[128];
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.TotalMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.UsedMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.FreeMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.TotalPhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_PHYS"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.UsedPhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_PHYS"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.FreePhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_PHYS"), tmp);
+	}
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	FreeRpcNatInfo(&t);
+
+	return true;
+}
+
+// ルータの状況の表示
+bool NmStatus(HWND hWnd, SM_SERVER *s, void *param)
+{
+	LVB *b;
+	RPC_NAT_STATUS t;
+	wchar_t tmp[MAX_SIZE];
+	SM_HUB *h = (SM_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), h->HubName);
+
+	if (CALL(hWnd, ScGetSecureNATStatus(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	StrToUni(tmp, sizeof(tmp), h->HubName);
+	LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_HUB_COLUMN_1"), tmp);
+
+	UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumTcpSessions);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_TCP"), tmp);
+
+	UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumUdpSessions);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_UDP"), tmp);
+
+	UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_CLIENT"), t.NumDhcpClients);
+	LvInsertAdd(b, ICO_PROTOCOL_DHCP, NULL, 2, _UU("NM_STATUS_DHCP"), tmp);
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	FreeRpcNatStatus(&t);
+
+	return true;
+}
+
+// フォームの内容を VH_OPTION に変換
+void NmEditVhOptionFormToVH(HWND hWnd, VH_OPTION *t)
+{
+	char tmp[MAX_SIZE];
+	BUF *b;
+	// 引数チェック
+	if (hWnd == NULL || t == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(VH_OPTION));
+
+	GetTxtA(hWnd, E_MAC, tmp, sizeof(tmp));
+	b = StrToBin(tmp);
+	if (b != NULL)
+	{
+		if (b->Size == 6)
+		{
+			Copy(t->MacAddress, b->Buf, 6);
+		}
+		FreeBuf(b);
+	}
+
+	UINTToIP(&t->Ip, IpGet(hWnd, E_IP));
+	UINTToIP(&t->Mask, IpGet(hWnd, E_MASK));
+
+	t->UseNat = IsChecked(hWnd, R_USE_NAT);
+	t->Mtu = GetInt(hWnd, E_MTU);
+	t->NatTcpTimeout = GetInt(hWnd, E_TCP);
+	t->NatUdpTimeout = GetInt(hWnd, E_UDP);
+
+	t->UseDhcp = IsChecked(hWnd, R_USE_DHCP);
+	UINTToIP(&t->DhcpLeaseIPStart, IpGet(hWnd, E_DHCP_START));
+	UINTToIP(&t->DhcpLeaseIPEnd, IpGet(hWnd, E_DHCP_END));
+	UINTToIP(&t->DhcpSubnetMask, IpGet(hWnd, E_DHCP_MASK));
+	t->DhcpExpireTimeSpan = GetInt(hWnd, E_EXPIRES);
+	UINTToIP(&t->DhcpGatewayAddress, IpGet(hWnd, E_GATEWAY));
+	UINTToIP(&t->DhcpDnsServerAddress, IpGet(hWnd, E_DNS));
+	GetTxtA(hWnd, E_DOMAIN, t->DhcpDomainName, sizeof(t->DhcpDomainName));
+	t->SaveLog = IsChecked(hWnd, R_SAVE_LOG);
+}
+
+// 初期化
+void NmEditVhOptionInit(HWND hWnd, SM_HUB *r)
+{
+	char tmp[MAX_SIZE];
+	VH_OPTION t;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	FormatText(hWnd, S_TITLE, r->HubName);
+
+	Zero(&t, sizeof(VH_OPTION));
+	StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+	if (CALL(hWnd, ScGetSecureNATOption(r->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	if (GetCapsBool(r->p->CapsList, "b_virtual_nat_disabled"))
+	{
+		SetEnable(hWnd, R_USE_NAT, false);
+		Check(hWnd, R_USE_NAT, false);
+	}
+
+	MacToStr(tmp, sizeof(tmp), t.MacAddress);
+	SetTextA(hWnd, E_MAC, tmp);
+	IpSet(hWnd, E_IP, IPToUINT(&t.Ip));
+	IpSet(hWnd, E_MASK, IPToUINT(&t.Mask));
+
+	Check(hWnd, R_USE_NAT, t.UseNat);
+	SetIntEx(hWnd, E_MTU, t.Mtu);
+	SetIntEx(hWnd, E_TCP, t.NatTcpTimeout);
+	SetIntEx(hWnd, E_UDP, t.NatUdpTimeout);
+
+	Check(hWnd, R_USE_DHCP, t.UseDhcp);
+	IpSet(hWnd, E_DHCP_START, IPToUINT(&t.DhcpLeaseIPStart));
+	IpSet(hWnd, E_DHCP_END, IPToUINT(&t.DhcpLeaseIPEnd));
+	IpSet(hWnd, E_DHCP_MASK, IPToUINT(&t.DhcpSubnetMask));
+	SetIntEx(hWnd, E_EXPIRES, t.DhcpExpireTimeSpan);
+
+	if (IPToUINT(&t.DhcpGatewayAddress) != 0)
+	{
+		IpSet(hWnd, E_GATEWAY, IPToUINT(&t.DhcpGatewayAddress));
+	}
+
+	if (IPToUINT(&t.DhcpDnsServerAddress) != 0)
+	{
+		IpSet(hWnd, E_DNS, IPToUINT(&t.DhcpDnsServerAddress));
+	}
+
+	SetTextA(hWnd, E_DOMAIN, t.DhcpDomainName);
+	Check(hWnd, R_SAVE_LOG, t.SaveLog);
+
+	NmEditVhOptionUpdate(hWnd, r);
+
+}
+
+void NmEditVhOptionUpdate(HWND hWnd, SM_HUB *r)
+{
+	VH_OPTION t;
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	NmEditVhOptionFormToVH(hWnd, &t);
+
+	if (IsZero(t.MacAddress, 6))
+	{
+		ok = false;
+	}
+
+	if (IPToUINT(&t.Ip) == 0 || IPToUINT(&t.Mask) == 0)
+	{
+		ok = false;
+	}
+
+	if (IpIsFilled(hWnd, E_IP) == false || IpIsFilled(hWnd, E_MASK) == false)
+	{
+		ok = false;
+	}
+
+	if (IsHostIPAddress4(&t.Ip) == false || IsSubnetMask4(&t.Mask) == false)
+	{
+		ok = false;
+	}
+
+	if (t.UseNat)
+	{
+		if (t.Mtu < 64 || t.Mtu > 1500)
+		{
+			ok = false;
+		}
+
+		if (t.NatTcpTimeout < (NAT_TCP_MIN_TIMEOUT / 1000) || t.NatTcpTimeout > (NAT_TCP_MAX_TIMEOUT / 1000))
+		{
+			ok = false;
+		}
+
+		if (t.NatUdpTimeout < (NAT_UDP_MIN_TIMEOUT / 1000) || t.NatUdpTimeout > (NAT_UDP_MAX_TIMEOUT / 1000))
+		{
+			ok = false;
+		}
+	}
+
+	if (t.UseDhcp)
+	{
+		if (IpIsFilled(hWnd, E_DHCP_START) == false || IpIsFilled(hWnd, E_DHCP_END) == false ||
+			IpIsFilled(hWnd, E_DHCP_MASK) == false)
+		{
+			ok = false;
+		}
+
+		if (IpGetFilledNum(hWnd, E_GATEWAY) != 0 && IpGetFilledNum(hWnd, E_GATEWAY) != 4)
+		{
+			ok = false;
+		}
+
+		if (IpGetFilledNum(hWnd, E_DNS) != 0 && IpGetFilledNum(hWnd, E_DNS) != 4)
+		{
+			ok = false;
+		}
+
+		if (IPToUINT(&t.DhcpLeaseIPStart) == 0 || IPToUINT(&t.DhcpLeaseIPEnd) == 0 ||
+			IPToUINT(&t.DhcpSubnetMask) == 0)
+		{
+			ok = false;
+		}
+
+		if (t.DhcpExpireTimeSpan < 15)
+		{
+			ok = false;
+		}
+
+		if (Endian32(IPToUINT(&t.DhcpLeaseIPStart)) > Endian32(IPToUINT(&t.DhcpLeaseIPEnd)))
+		{
+			ok = false;
+		}
+
+		if (IsHostIPAddress4(&t.DhcpLeaseIPStart) == false ||
+			IsHostIPAddress4(&t.DhcpLeaseIPEnd) == false)
+		{
+			ok = false;
+		}
+
+		if (IsSubnetMask4(&t.DhcpSubnetMask) == false)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, E_MTU, t.UseNat);
+	SetEnable(hWnd, E_TCP, t.UseNat);
+	SetEnable(hWnd, E_UDP, t.UseNat);
+
+	SetEnable(hWnd, E_DHCP_START, t.UseDhcp);
+	SetEnable(hWnd, E_DHCP_END, t.UseDhcp);
+	SetEnable(hWnd, E_DHCP_MASK, t.UseDhcp);
+	SetEnable(hWnd, E_EXPIRES, t.UseDhcp);
+	SetEnable(hWnd, E_GATEWAY, t.UseDhcp);
+	SetEnable(hWnd, E_DNS, t.UseDhcp);
+	SetEnable(hWnd, E_DOMAIN, t.UseDhcp);
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// OK ボタン
+void NmEditVhOptionOnOk(HWND hWnd, SM_HUB *r)
+{
+	VH_OPTION t;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	NmEditVhOptionFormToVH(hWnd, &t);
+	StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+	if (CALL(hWnd, ScSetSecureNATOption(r->Rpc, &t)))
+	{
+		EndDialog(hWnd, true);
+	}
+}
+
+// 仮想ホストオプション編集ダイアログ
+UINT NmEditVhOptionProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *r = (SM_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		NmEditVhOptionInit(hWnd, r);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_MAC:
+		case E_IP:
+		case E_MASK:
+		case R_USE_NAT:
+		case E_MTU:
+		case E_TCP:
+		case E_UDP:
+		case R_SAVE_LOG:
+		case R_USE_DHCP:
+		case E_DHCP_START:
+		case E_DHCP_END:
+		case E_DHCP_MASK:
+		case E_EXPIRES:
+		case E_GATEWAY:
+		case E_DNS:
+		case E_DOMAIN:
+			NmEditVhOptionUpdate(hWnd, r);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			NmEditVhOptionOnOk(hWnd, r);
+			break;
+
+		case IDCANCEL:
+			EndDialog(hWnd, false);
+			break;
+
+		case R_USE_NAT:
+			if (IsChecked(hWnd, R_USE_NAT))
+			{
+				FocusEx(hWnd, E_MTU);
+			}
+
+			if (IsChecked(hWnd, R_USE_DHCP))
+			{
+				Focus(hWnd, E_DHCP_START);
+			}
+			break;
+		}
+
+		break;
+	}
+
+	return 0;
+}
+
+// 仮想ホストオプションの編集
+void NmEditVhOption(HWND hWnd, SM_HUB *r)
+{
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_NM_OPTION, NmEditVhOptionProc, r);
+}
+
+// クライアント設定の編集
+void NmEditClientConfig(HWND hWnd, RPC *r)
+{
+	CM_ACCOUNT a;
+	RPC_CREATE_LINK t;
+	bool ret = false;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	Zero(&a, sizeof(a));
+	Zero(&t, sizeof(t));
+
+	a.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	a.NatMode = true;
+	a.Rpc = r;
+
+	if (CALLEX(hWnd, NcGetClientConfig(r, &t)) != ERR_NO_ERROR)
+	{
+		// 新規作成
+		a.ClientOption->Port = 443;
+		a.ClientOption->RetryInterval = 15;
+		a.ClientOption->NumRetry = INFINITE;
+		a.ClientOption->AdditionalConnectionInterval = 1;
+		a.ClientOption->UseEncrypt = true;
+		a.ClientOption->NoRoutingTracking = true;
+		a.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+		a.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+	}
+	else
+	{
+		// 編集
+		a.EditMode = true;
+		Copy(a.ClientOption, t.ClientOption, sizeof(CLIENT_OPTION));
+		a.ClientAuth = CopyClientAuth(t.ClientAuth);
+
+		FreeRpcCreateLink(&t);
+	}
+
+	ret = CmEditAccountDlg(hWnd, &a);
+
+	Free(a.ServerCert);
+	Free(a.ClientOption);
+	CiFreeClientAuth(a.ClientAuth);
+}
+
+// 初期化
+void NmMainDlgInit(HWND hWnd, RPC *r)
+{
+	// 引数チェック
+	if (r == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_ROUTER);
+	FormatText(hWnd, 0, r->Sock->RemoteHostname);
+	DlgFont(hWnd, S_STATUS, 11, true);
+
+	NmMainDlgRefresh(hWnd, r);
+}
+
+// 更新
+void NmMainDlgRefresh(HWND hWnd, RPC *r)
+{
+#if	0
+	RPC_NAT_STATUS t;
+	wchar_t tmp[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	// 引数チェック
+	if (r == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(RPC_NAT_STATUS));
+
+	CALL(hWnd, NcGetStatus(r, &t));
+
+	if (t.Online == false)
+	{
+		UniStrCpy(tmp, sizeof(tmp), _UU("NM_OFFLINE"));
+
+		Enable(hWnd, B_CONNECT);
+		Disable(hWnd, B_DISCONNECT);
+	}
+	else
+	{
+		if (t.Connected)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("NM_CONNECTED"), t.Status.ServerName);
+		}
+		else
+		{
+			if (t.LastError == ERR_NO_ERROR)
+			{
+				UniStrCpy(tmp, sizeof(tmp), _UU("NM_CONNECTING"));
+			}
+			else
+			{
+				UniFormat(tmp, sizeof(tmp), _UU("NM_CONNECT_ERROR"), t.LastError, _E(t.LastError));
+			}
+		}
+		Disable(hWnd, B_CONNECT);
+		Enable(hWnd, B_DISCONNECT);
+	}
+
+	UniFormat(tmp2, sizeof(tmp2), _UU("NM_STATUS_TAG"), tmp);
+
+	SetText(hWnd, S_STATUS, tmp2);
+
+	FreeRpcNatStatus(&t);
+#endif
+}
+
+// メインダイアログプロシージャ
+UINT NmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+#if	0
+	SM_HUB *r = (SM_HUB *)param;
+	RPC_DUMMY dummy;
+	SM_SERVER sm;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		NmMainDlgInit(hWnd, r);
+
+		SetTimer(hWnd, 1, NM_REFRESH_TIME, NULL);
+
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_SETTING:
+			// 接続設定
+			NmEditClientConfig(hWnd, r);
+			break;
+
+		case B_CONNECT:
+			// 接続
+			Zero(&dummy, sizeof(dummy));
+			CALL(hWnd, NcOnline(r, &dummy));
+			NmMainDlgRefresh(hWnd, r);
+			break;
+
+		case B_DISCONNECT:
+			// 切断
+			Zero(&dummy, sizeof(dummy));
+			CALL(hWnd, NcOffline(r, &dummy));
+			NmMainDlgRefresh(hWnd, r);
+			break;
+
+		case B_OPTION:
+			// 動作設定
+			NmEditVhOption(hWnd, r->Rpc);
+			break;
+
+		case B_NAT:
+			// NAT
+			NmNat(hWnd, r);
+			break;
+
+		case B_DHCP:
+			// DHCP
+			NmDhcp(hWnd, r);
+			break;
+
+		case B_STATUS:
+			// 状況
+			Zero(&sm, sizeof(sm));
+			sm.Rpc = r;
+			SmStatusDlg(hWnd, &sm, NULL, true, true, _UU("NM_STATUS"), ICO_ROUTER,
+				NULL, NmStatus);
+			break;
+
+		case B_INFO:
+			// 情報
+			Zero(&sm, sizeof(sm));
+			sm.Rpc = r;
+			SmStatusDlg(hWnd, &sm, NULL, false, true, _UU("NM_INFO"), ICO_ROUTER,
+				NULL, NmInfo);
+			break;
+
+		case B_REFRESH:
+			// 更新
+			NmMainDlgRefresh(hWnd, r);
+			break;
+
+		case B_PASSWORD:
+			// パスワード変更
+			NmChangePassword(hWnd, r);
+			break;
+
+		case B_ABOUT:
+			// バージョン情報
+			About(hWnd, nm->Cedar, CEDAR_ROUTER_STR, BMP_SPLASH_ROUTER);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			if (IsEnable(hWnd, 0))
+			{
+				NmMainDlgRefresh(hWnd, r);
+			}
+
+			SetTimer(hWnd, 1, NM_REFRESH_TIME, NULL);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+#endif
+
+	return 0;
+}
+
+// メインダイアログ
+void NmMainDlg(RPC *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	Dialog(NULL, D_NM_MAIN, NmMainDlgProc, r);
+}
+
+// ログインダイアログ
+UINT NmLogin(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NM_LOGIN *login = (NM_LOGIN *)param;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		FormatText(hWnd, S_TITLE, login->Hostname);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			GetTxtA(hWnd, E_PASSWORD, tmp, sizeof(tmp));
+			Hash(login->hashed_password, tmp, StrLen(tmp), true);
+			EndDialog(hWnd, true);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 接続ダイアログ
+UINT NmConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NM_CONNECT *t = (NM_CONNECT *)param;
+	RPC *rpc;
+	NM_LOGIN login;
+	UINT err;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		FormatText(hWnd, S_TITLE, t->Hostname);
+		SetTimer(hWnd, 1, 50, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			while (true)
+			{
+				bool flag = false;
+RETRY_PASSWORD:
+				// パスワード入力ダイアログ
+				Zero(&login, sizeof(login));
+				login.Hostname = t->Hostname;
+				login.Port = t->Port;
+				Hash(login.hashed_password, "", 0, true);
+
+				if (flag)
+				{
+					if (Dialog(hWnd, D_NM_LOGIN, NmLogin, &login) == false)
+					{
+						EndDialog(hWnd, false);
+						break;
+					}
+				}
+
+RETRY_CONNECT:
+				Refresh(DlgItem(hWnd, S_TITLE));
+				Refresh(hWnd);
+				// 接続
+				rpc = NatAdminConnect(nm->Cedar, t->Hostname, t->Port, login.hashed_password, &err);
+				if (rpc != NULL)
+				{
+					t->Rpc = rpc;
+					EndDialog(hWnd, true);
+					break;
+				}
+
+				// エラー
+				if (err == ERR_ACCESS_DENIED || err == ERR_AUTH_FAILED)
+				{
+					if (flag)
+					{
+						if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL,
+							_E(err)) == IDCANCEL)
+						{
+							EndDialog(hWnd, false);
+							break;
+						}
+					}
+					flag = true;
+					goto RETRY_PASSWORD;
+				}
+				else
+				{
+					if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL,
+						_E(err)) == IDCANCEL)
+					{
+						EndDialog(hWnd, false);
+						break;
+					}
+					goto RETRY_CONNECT;
+				}
+			}
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// User-mode NAT プログラムに接続する
+RPC *NmConnect(char *hostname, UINT port)
+{
+	NM_CONNECT t;
+	// 引数チェック
+	if (hostname == NULL || port == 0)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Hostname = hostname;
+	t.Port = port;
+
+	Dialog(NULL, D_NM_CONNECT, NmConnectDlgProc, &t);
+
+	return t.Rpc;
+}
+
+// メイン処理
+void MainNM()
+{
+	UINT port;
+	char hostname[MAX_HOST_NAME_LEN + 1];
+	char *tmp =
+		RemoteDlg(NULL, NM_SETTING_REG_KEY, ICO_ROUTER,
+		_UU("NM_TITLE"), _UU("NM_CONNECT_TITLE"), NULL);
+	TOKEN_LIST *t;
+
+	Zero(hostname, sizeof(hostname));
+
+	if (tmp == NULL)
+	{
+		return;
+	}
+
+	t = ParseToken(tmp, ":");
+	port = DEFAULT_NAT_ADMIN_PORT;
+
+	if (t->NumTokens >= 2)
+	{
+		UINT i = ToInt(t->Token[1]);
+		if (i != 0)
+		{
+			port = i;
+		}
+	}
+	if (t->NumTokens >= 1)
+	{
+		RPC *rpc;
+		StrCpy(hostname, sizeof(hostname), t->Token[0]);
+
+		// 接続
+		Trim(hostname);
+
+		if (StrLen(hostname) != 0)
+		{
+			rpc = NmConnect(hostname, port);
+			if (rpc != NULL)
+			{
+				// 接続した
+				NmMainDlg(rpc);
+				NatAdminDisconnect(rpc);
+			}
+		}
+	}
+
+	FreeToken(t);
+
+	Free(tmp);
+}
+
+// 初期化
+void InitNM()
+{
+	if (nm != NULL)
+	{
+		// すでに初期化されている
+		return;
+	}
+
+	nm = ZeroMalloc(sizeof(NM));
+
+	InitWinUi(_UU("NM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+	nm->Cedar = NewCedar(NULL, NULL);
+
+	InitCM();
+	InitSM();
+}
+
+// 解放
+void FreeNM()
+{
+	if (nm == NULL)
+	{
+		// 初期化されていない
+		return;
+	}
+
+	FreeSM();
+	FreeCM();
+
+	ReleaseCedar(nm->Cedar);
+
+	FreeWinUi();
+
+	Free(nm);
+	nm = NULL;
+}
+
+// NM の実行
+void NMExec()
+{
+	InitNM();
+	MainNM();
+	FreeNM();
+}
+
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NM.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NM.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NM.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,89 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// NM.h
+// NM.c のヘッダ
+
+#ifndef	NM_H
+#define	NM_H
+
+// 外部向け関数
+void NMExec();
+
+#endif	// NM_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NMInner.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NMInner.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NMInner.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,141 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// NMInner.h
+// NM.c の内部向けヘッダ
+
+
+// 定数
+#define	NM_REG_KEY			"Software\\SoftEther Corporation\\UT-VPN\\User-mode Router Manager"
+#define	NM_SETTING_REG_KEY	"Software\\SoftEther Corporation\\UT-VPN\\User-mode Router Manager\\Settings"
+
+#define	NM_REFRESH_TIME			1000
+#define	NM_NAT_REFRESH_TIME		1000
+#define	NM_DHCP_REFRESH_TIME	1000
+
+// Nat Admin 構造体
+typedef struct NM
+{
+	CEDAR *Cedar;				// Cedar
+} NM;
+
+// 接続構造体
+typedef struct NM_CONNECT
+{
+	RPC *Rpc;					// RPC
+	char *Hostname;
+	UINT Port;
+} NM_CONNECT;
+
+// ログイン
+typedef struct NM_LOGIN
+{
+	char *Hostname;
+	UINT Port;
+	UCHAR hashed_password[SHA1_SIZE];
+} NM_LOGIN;
+
+// 内部向け関数
+void InitNM();
+void FreeNM();
+void MainNM();
+RPC *NmConnect(char *hostname, UINT port);
+UINT NmConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT NmLogin(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmMainDlg(RPC *r);
+UINT NmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmMainDlgInit(HWND hWnd, RPC *r);
+void NmMainDlgRefresh(HWND hWnd, RPC *r);
+void NmEditClientConfig(HWND hWnd, RPC *r);
+void NmEditVhOption(HWND hWnd, SM_HUB *r);
+UINT NmEditVhOptionProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmEditVhOptionInit(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionUpdate(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionOnOk(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionFormToVH(HWND hWnd, VH_OPTION *t);
+bool NmStatus(HWND hWnd, SM_SERVER *s, void *param);
+bool NmInfo(HWND hWnd, SM_SERVER *s, void *param);
+void NmNat(HWND hWnd, SM_HUB *r);
+UINT NmNatProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmNatInit(HWND hWnd, SM_HUB *r);
+void NmNatRefresh(HWND hWnd, SM_HUB *r);
+void NmDhcp(HWND hWnd, SM_HUB *r);
+UINT NmDhcpProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmDhcpRefresh(HWND hWnd, SM_HUB *r);
+void NmDhcpInit(HWND hWnd, SM_HUB *r);
+void NmChangePassword(HWND hWnd, RPC *r);
+UINT NmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Nat.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Nat.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Nat.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1778 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Nat.c
+// User-mode Router
+
+#include "CedarPch.h"
+
+static LOCK *nat_lock = NULL;
+static NAT *nat = NULL;
+
+
+// NAT 管理者用接続を切断
+void NatAdminDisconnect(RPC *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	EndRpc(r);
+}
+
+// NAT 管理者用接続
+RPC *NatAdminConnect(CEDAR *cedar, char *hostname, UINT port, void *hashed_password, UINT *err)
+{
+	UCHAR secure_password[SHA1_SIZE];
+	UCHAR random[SHA1_SIZE];
+	SOCK *sock;
+	RPC *rpc;
+	PACK *p;
+	UINT error;
+	// 引数チェック
+	if (cedar == NULL || hostname == NULL || port == 0 || hashed_password == NULL || err == NULL)
+	{
+		if (err != NULL)
+		{
+			*err = ERR_INTERNAL_ERROR;
+		}
+		return NULL;
+	}
+
+	// 接続
+	sock = Connect(hostname, port);
+	if (sock == NULL)
+	{
+		*err = ERR_CONNECT_FAILED;
+		return NULL;
+	}
+
+	if (StartSSL(sock, NULL, NULL) == false)
+	{
+		*err = ERR_PROTOCOL_ERROR;
+		ReleaseSock(sock);
+		return NULL;
+	}
+
+	SetTimeout(sock, 5000);
+
+	p = HttpClientRecv(sock);
+	if (p == NULL)
+	{
+		*err = ERR_DISCONNECTED;
+		ReleaseSock(sock);
+		return NULL;
+	}
+
+	if (PackGetData2(p, "auth_random", random, SHA1_SIZE) == false)
+	{
+		FreePack(p);
+		*err = ERR_PROTOCOL_ERROR;
+		ReleaseSock(sock);
+		return NULL;
+	}
+
+	FreePack(p);
+
+	SecurePassword(secure_password, hashed_password, random);
+
+	p = NewPack();
+	PackAddData(p, "secure_password", secure_password, SHA1_SIZE);
+
+	if (HttpClientSend(sock, p) == false)
+	{
+		FreePack(p);
+		*err = ERR_DISCONNECTED;
+		ReleaseSock(sock);
+		return NULL;
+	}
+
+	FreePack(p);
+
+	p = HttpClientRecv(sock);
+	if (p == NULL)
+	{
+		*err = ERR_DISCONNECTED;
+		ReleaseSock(sock);
+		return NULL;
+	}
+
+	error = GetErrorFromPack(p);
+
+	FreePack(p);
+
+	if (error != ERR_NO_ERROR)
+	{
+		*err = error;
+		ReleaseSock(sock);
+		return NULL;
+	}
+
+	SetTimeout(sock, TIMEOUT_INFINITE);
+
+	rpc = StartRpcClient(sock, NULL);
+	ReleaseSock(sock);
+
+	return rpc;
+}
+
+// RPC 関数関係マクロ
+#define	DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc)		\
+	else if (StrCmpi(name, rpc_name) == 0)								\
+	{																	\
+		data_type t;													\
+		Zero(&t, sizeof(t));											\
+		in_rpc(&t, p);													\
+		err = function(n, &t);											\
+		if (err == ERR_NO_ERROR)										\
+		{																\
+			out_rpc(ret, &t);											\
+		}																\
+		free_rpc(&t);													\
+		ok = true;														\
+	}
+#define	DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc)		\
+	else if (StrCmpi(name, rpc_name) == 0)								\
+	{																	\
+		data_type t;													\
+		Zero(&t, sizeof(t));											\
+		in_rpc(&t, p);													\
+		err = function(n, &t);											\
+		if (err == ERR_NO_ERROR)										\
+		{																\
+			out_rpc(ret, &t);											\
+		}																\
+		ok = true;														\
+	}
+#define	DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc)	\
+	UINT function(RPC *r, data_type *t)									\
+	{																	\
+		PACK *p, *ret;													\
+		UINT err;														\
+		if (r == NULL || t == NULL)										\
+		{																\
+			return ERR_INTERNAL_ERROR;									\
+		}																\
+		p = NewPack();													\
+		out_rpc(p, t);													\
+		free_rpc(t);													\
+		Zero(t, sizeof(data_type));										\
+		ret = AdminCall(r, rpc_name, p);								\
+		err = GetErrorFromPack(ret);									\
+		if (err == ERR_NO_ERROR)										\
+		{																\
+			in_rpc(t, ret);												\
+		}																\
+		FreePack(ret);													\
+		return err;														\
+	}
+#define	DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc)		\
+	UINT function(RPC *r, data_type *t)									\
+	{																	\
+		PACK *p, *ret;													\
+		UINT err;														\
+		if (r == NULL || t == NULL)										\
+		{																\
+			return ERR_INTERNAL_ERROR;									\
+		}																\
+		p = NewPack();													\
+		out_rpc(p, t);													\
+		ret = AdminCall(r, rpc_name, p);								\
+		err = GetErrorFromPack(ret);									\
+		if (err == ERR_NO_ERROR)										\
+		{																\
+			in_rpc(t, ret);												\
+		}																\
+		FreePack(ret);													\
+		return err;														\
+	}
+
+// RPC サーバー関数
+PACK *NiRpcServer(RPC *r, char *name, PACK *p)
+{
+	NAT *n = (NAT *)r->Param;
+	PACK *ret;
+	UINT err;
+	bool ok;
+	// 引数チェック
+	if (r == NULL || name == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	ret = NewPack();
+	err = ERR_NO_ERROR;
+	ok = false;
+
+	if (0) {}
+
+	// RPC 関数定義: ここから
+
+//	DECLARE_RPC("Online", RPC_DUMMY, NtOnline, InRpcDummy, OutRpcDummy)
+//	DECLARE_RPC("Offline", RPC_DUMMY, NtOffline, InRpcDummy, OutRpcDummy)
+	DECLARE_RPC("SetHostOption", VH_OPTION, NtSetHostOption, InVhOption, OutVhOption)
+	DECLARE_RPC("GetHostOption", VH_OPTION, NtGetHostOption, InVhOption, OutVhOption)
+//	DECLARE_RPC_EX("SetClientConfig", RPC_CREATE_LINK, NtSetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+//	DECLARE_RPC_EX("GetClientConfig", RPC_CREATE_LINK, NtGetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+	DECLARE_RPC_EX("GetStatus", RPC_NAT_STATUS, NtGetStatus, InRpcNatStatus, OutRpcNatStatus, FreeRpcNatStatus)
+//	DECLARE_RPC_EX("GetInfo", RPC_NAT_INFO, NtGetInfo, InRpcNatInfo, OutRpcNatInfo, FreeRpcNatInfo)
+	DECLARE_RPC_EX("EnumNatList", RPC_ENUM_NAT, NtEnumNatList, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+	DECLARE_RPC_EX("EnumDhcpList", RPC_ENUM_DHCP, NtEnumDhcpList, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+//	DECLARE_RPC("SetPassword", RPC_SET_PASSWORD, NtSetPassword, InRpcSetPassword, OutRpcSetPassword)
+
+	// RPC 関数定義: ここまで
+
+	if (ok == false)
+	{
+		err = ERR_NOT_SUPPORTED;
+	}
+
+	PackAddInt(ret, "error", err);
+
+	return ret;
+}
+
+
+
+
+// RPC 呼び出し定義ここから
+
+DECLARE_SC("Online", RPC_DUMMY, NcOnline, InRpcDummy, OutRpcDummy)
+DECLARE_SC("Offline", RPC_DUMMY, NcOffline, InRpcDummy, OutRpcDummy)
+DECLARE_SC("SetHostOption", VH_OPTION, NcSetHostOption, InVhOption, OutVhOption)
+DECLARE_SC("GetHostOption", VH_OPTION, NcGetHostOption, InVhOption, OutVhOption)
+DECLARE_SC_EX("SetClientConfig", RPC_CREATE_LINK, NcSetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetClientConfig", RPC_CREATE_LINK, NcGetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetStatus", RPC_NAT_STATUS, NcGetStatus, InRpcNatStatus, OutRpcNatStatus, FreeRpcNatStatus)
+DECLARE_SC_EX("GetInfo", RPC_NAT_INFO, NcGetInfo, InRpcNatInfo, OutRpcNatInfo, FreeRpcNatInfo)
+DECLARE_SC_EX("EnumNatList", RPC_ENUM_NAT, NcEnumNatList, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+DECLARE_SC_EX("EnumDhcpList", RPC_ENUM_DHCP, NcEnumDhcpList, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+DECLARE_SC("SetPassword", RPC_SET_PASSWORD, NcSetPassword, InRpcSetPassword, OutRpcSetPassword)
+
+// RPC 呼び出し定義ここまで
+
+
+
+// パスワードを設定する
+UINT NtSetPassword(NAT *n, RPC_SET_PASSWORD *t)
+{
+	Copy(n->HashedPassword, t->HashedPassword, SHA1_SIZE);
+
+	NiWriteConfig(n);
+
+	return ERR_NO_ERROR;
+}
+
+// オンラインにする
+UINT NtOnline(NAT *n, RPC_DUMMY *t)
+{
+	UINT ret = ERR_NO_ERROR;
+
+	Lock(n->lock);
+	{
+		if (n->Online)
+		{
+			// すでにオンラインである
+			ret = ERR_ALREADY_ONLINE;
+		}
+		else
+		{
+			if (n->ClientOption == NULL || n->ClientAuth == NULL)
+			{
+				// 設定がまだ
+				ret = ERR_ACCOUNT_NOT_PRESENT;
+			}
+			else
+			{
+				// OK
+				n->Online = true;
+
+				// 接続開始
+				n->Virtual = NewVirtualHostEx(n->Cedar, n->ClientOption, n->ClientAuth,
+					&n->Option, n);
+			}
+		}
+	}
+	Unlock(n->lock);
+
+	NiWriteConfig(n);
+
+	return ret;
+}
+
+// オフラインにする
+UINT NtOffline(NAT *n, RPC_DUMMY *t)
+{
+	UINT ret = ERR_NO_ERROR;
+
+	Lock(n->lock);
+	{
+		if (n->Online == false)
+		{
+			// オフラインである
+			ret = ERR_OFFLINE;
+		}
+		else
+		{
+			// オフラインにする
+			StopVirtualHost(n->Virtual);
+			ReleaseVirtual(n->Virtual);
+			n->Virtual = NULL;
+
+			n->Online = false;
+		}
+	}
+	Unlock(n->lock);
+
+	NiWriteConfig(n);
+
+	return ret;
+}
+
+// ホストオプションの設定
+UINT NtSetHostOption(NAT *n, VH_OPTION *t)
+{
+	UINT ret = ERR_NO_ERROR;
+
+	Lock(n->lock);
+	{
+		Copy(&n->Option, t, sizeof(VH_OPTION));
+	}
+	Unlock(n->lock);
+
+	SetVirtualHostOption(n->Virtual, t);
+
+	NiWriteConfig(n);
+
+	return ret;
+}
+
+// ホストオプションの取得
+UINT NtGetHostOption(NAT *n, VH_OPTION *t)
+{
+	UINT ret = ERR_NO_ERROR;
+
+	Lock(n->lock);
+	{
+		Copy(t, &n->Option, sizeof(VH_OPTION));
+	}
+	Unlock(n->lock);
+
+	return ret;
+}
+
+// 接続設定の設定
+UINT NtSetClientConfig(NAT *n, RPC_CREATE_LINK *t)
+{
+	Lock(n->lock);
+	{
+		if (n->ClientOption != NULL || n->ClientAuth != NULL)
+		{
+			Free(n->ClientOption);
+			CiFreeClientAuth(n->ClientAuth);
+		}
+
+		n->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+		Copy(n->ClientOption, t->ClientOption, sizeof(CLIENT_OPTION));
+		n->ClientAuth = CopyClientAuth(t->ClientAuth);
+	}
+	Unlock(n->lock);
+
+	NiWriteConfig(n);
+
+	if (n->Online)
+	{
+		NtOffline(n, NULL);
+		NtOnline(n, NULL);
+	}
+
+	return ERR_NO_ERROR;
+}
+
+// 接続設定の取得
+UINT NtGetClientConfig(NAT *n, RPC_CREATE_LINK *t)
+{
+	UINT err = ERR_NO_ERROR;
+
+	Lock(n->lock);
+	{
+		if (n->ClientOption == NULL || n->ClientAuth == NULL)
+		{
+			err = ERR_ACCOUNT_NOT_PRESENT;
+		}
+		else
+		{
+			FreeRpcCreateLink(t);
+
+			Zero(t, sizeof(RPC_CREATE_LINK));
+			t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+			Copy(t->ClientOption, n->ClientOption, sizeof(CLIENT_OPTION));
+			t->ClientAuth = CopyClientAuth(n->ClientAuth);
+		}
+	}
+	Unlock(n->lock);
+
+	return err;
+}
+
+// 状態の取得
+UINT NtGetStatus(NAT *n, RPC_NAT_STATUS *t)
+{
+	Lock(n->lock);
+	{
+		VH *v = n->Virtual;
+		FreeRpcNatStatus(t);
+		Zero(t, sizeof(RPC_NAT_STATUS));
+
+		LockVirtual(v);
+		{
+			UINT i;
+
+			LockList(v->NatTable);
+			{
+				for (i = 0;i < LIST_NUM(v->NatTable);i++)
+				{
+					NAT_ENTRY *e = LIST_DATA(v->NatTable, i);
+
+					switch (e->Protocol)
+					{
+					case NAT_TCP:
+						t->NumTcpSessions++;
+						break;
+
+					case NAT_UDP:
+						t->NumUdpSessions++;
+						break;
+					}
+				}
+			}
+			UnlockList(v->NatTable);
+
+			t->NumDhcpClients = LIST_NUM(v->DhcpLeaseList);
+		}
+		UnlockVirtual(v);
+	}
+	Unlock(n->lock);
+
+	return ERR_NO_ERROR;
+}
+
+// 情報の取得
+UINT NtGetInfo(NAT *n, RPC_NAT_INFO *t)
+{
+	OS_INFO *info;
+	FreeRpcNatInfo(t);
+	Zero(t, sizeof(RPC_NAT_INFO));
+
+	StrCpy(t->NatProductName, sizeof(t->NatProductName), CEDAR_ROUTER_STR);
+	StrCpy(t->NatVersionString, sizeof(t->NatVersionString), n->Cedar->VerString);
+	StrCpy(t->NatBuildInfoString, sizeof(t->NatBuildInfoString), n->Cedar->BuildInfo);
+	t->NatVerInt = n->Cedar->Build;
+	t->NatBuildInt = n->Cedar->Build;
+
+	GetMachineName(t->NatHostName, sizeof(t->NatHostName));
+
+	info = GetOsInfo();
+
+	CopyOsInfo(&t->OsInfo, info);
+
+	GetMemInfo(&t->MemInfo);
+
+	return ERR_NO_ERROR;
+}
+
+// NAT リストの取得
+UINT NtEnumNatList(NAT *n, RPC_ENUM_NAT *t)
+{
+	UINT ret = ERR_NO_ERROR;
+	VH *v = NULL;
+
+	Lock(n->lock);
+	{
+		v = n->Virtual;
+
+		if (n->Online == false || v == NULL)
+		{
+			ret = ERR_OFFLINE;
+		}
+		else
+		{
+			LockVirtual(v);
+			{
+				if (v->Active == false)
+				{
+					ret = ERR_OFFLINE;
+				}
+				else
+				{
+					FreeRpcEnumNat(t);
+					Zero(t, sizeof(RPC_ENUM_NAT));
+
+					LockList(v->NatTable);
+					{
+						UINT i;
+						t->NumItem = LIST_NUM(v->NatTable);
+						t->Items = ZeroMalloc(sizeof(RPC_ENUM_NAT_ITEM) * t->NumItem);
+
+						for (i = 0;i < t->NumItem;i++)
+						{
+							NAT_ENTRY *nat = LIST_DATA(v->NatTable, i);
+							RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+							e->Id = nat->Id;
+							e->Protocol = nat->Protocol;
+							e->SrcIp = nat->SrcIp;
+							e->DestIp = nat->DestIp;
+							e->SrcPort = nat->SrcPort;
+							e->DestPort = nat->DestPort;
+
+							e->CreatedTime = TickToTime(nat->CreatedTime);
+							e->LastCommTime = TickToTime(nat->LastCommTime);
+
+							IPToStr32(e->SrcHost, sizeof(e->SrcHost), e->SrcIp);
+							IPToStr32(e->DestHost, sizeof(e->DestHost), e->DestIp);
+
+							if (nat->Sock != NULL)
+							{
+								e->SendSize = nat->Sock->SendSize;
+								e->RecvSize = nat->Sock->RecvSize;
+
+								if (nat->Sock->Type == SOCK_TCP)
+								{
+									StrCpy(e->DestHost, sizeof(e->DestHost), nat->Sock->RemoteHostname);
+								}
+							}
+
+							e->TcpStatus = nat->TcpStatus;
+						}
+					}
+					UnlockList(v->NatTable);
+				}
+			}
+			UnlockVirtual(v);
+		}
+	}
+	Unlock(n->lock);
+
+	return ret;
+}
+
+UINT NtEnumDhcpList(NAT *n, RPC_ENUM_DHCP *t)
+{
+	UINT ret = ERR_NO_ERROR;
+	VH *v = NULL;
+
+	Lock(n->lock);
+	{
+		v = n->Virtual;
+
+		if (n->Online == false || v == NULL)
+		{
+			ret = ERR_OFFLINE;
+		}
+		else
+		{
+			LockVirtual(v);
+			{
+				if (v->Active == false)
+				{
+					ret = ERR_OFFLINE;
+				}
+				else
+				{
+					FreeRpcEnumDhcp(t);
+					Zero(t, sizeof(RPC_ENUM_DHCP));
+
+					LockList(v->DhcpLeaseList);
+					{
+						UINT i;
+						t->NumItem = LIST_NUM(v->DhcpLeaseList);
+						t->Items = ZeroMalloc(sizeof(RPC_ENUM_DHCP_ITEM) * t->NumItem);
+
+						for (i = 0;i < t->NumItem;i++)
+						{
+							DHCP_LEASE *dhcp = LIST_DATA(v->DhcpLeaseList, i);
+							RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+							e->Id = dhcp->Id;
+							e->LeasedTime = TickToTime(dhcp->LeasedTime);
+							e->ExpireTime = TickToTime(dhcp->ExpireTime);
+							Copy(e->MacAddress, dhcp->MacAddress, 6);
+							e->IpAddress = dhcp->IpAddress;
+							e->Mask = dhcp->Mask;
+							StrCpy(e->Hostname, sizeof(e->Hostname), dhcp->Hostname);
+						}
+					}
+					UnlockList(v->DhcpLeaseList);
+				}
+			}
+			UnlockVirtual(v);
+		}
+	}
+	Unlock(n->lock);
+
+	return ret;
+}
+
+// VH_OPTION
+void InVhOption(VH_OPTION *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(VH_OPTION));
+	PackGetData2(p, "MacAddress", t->MacAddress, 6);
+	PackGetIp(p, "Ip", &t->Ip);
+	PackGetIp(p, "Mask", &t->Mask);
+	t->UseNat = PackGetBool(p, "UseNat");
+	t->Mtu = PackGetInt(p, "Mtu");
+	t->NatTcpTimeout = PackGetInt(p, "NatTcpTimeout");
+	t->NatUdpTimeout = PackGetInt(p, "NatUdpTimeout");
+	t->UseDhcp = PackGetBool(p, "UseDhcp");
+	PackGetIp(p, "DhcpLeaseIPStart", &t->DhcpLeaseIPStart);
+	PackGetIp(p, "DhcpLeaseIPEnd", &t->DhcpLeaseIPEnd);
+	PackGetIp(p, "DhcpSubnetMask", &t->DhcpSubnetMask);
+	t->DhcpExpireTimeSpan = PackGetInt(p, "DhcpExpireTimeSpan");
+	PackGetIp(p, "DhcpGatewayAddress", &t->DhcpGatewayAddress);
+	PackGetIp(p, "DhcpDnsServerAddress", &t->DhcpDnsServerAddress);
+	PackGetStr(p, "DhcpDomainName", t->DhcpDomainName, sizeof(t->DhcpDomainName));
+	t->SaveLog = PackGetBool(p, "SaveLog");
+	PackGetStr(p, "RpcHubName", t->HubName, sizeof(t->HubName));
+}
+void OutVhOption(PACK *p, VH_OPTION *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddData(p, "MacAddress", t->MacAddress, 6);
+	PackAddIp(p, "Ip", &t->Ip);
+	PackAddIp(p, "Mask", &t->Mask);
+	PackAddBool(p, "UseNat", t->UseNat);
+	PackAddInt(p, "Mtu", t->Mtu);
+	PackAddInt(p, "NatTcpTimeout", t->NatTcpTimeout);
+	PackAddInt(p, "NatUdpTimeout", t->NatUdpTimeout);
+	PackAddBool(p, "UseDhcp", t->UseDhcp);
+	PackAddIp(p, "DhcpLeaseIPStart", &t->DhcpLeaseIPStart);
+	PackAddIp(p, "DhcpLeaseIPEnd", &t->DhcpLeaseIPEnd);
+	PackAddIp(p, "DhcpSubnetMask", &t->DhcpSubnetMask);
+	PackAddInt(p, "DhcpExpireTimeSpan", t->DhcpExpireTimeSpan);
+	PackAddIp(p, "DhcpGatewayAddress", &t->DhcpGatewayAddress);
+	PackAddIp(p, "DhcpDnsServerAddress", &t->DhcpDnsServerAddress);
+	PackAddStr(p, "DhcpDomainName", t->DhcpDomainName);
+	PackAddBool(p, "SaveLog", t->SaveLog);
+	PackAddStr(p, "RpcHubName", t->HubName);
+}
+
+// RPC_ENUM_DHCP
+void InRpcEnumDhcp(RPC_ENUM_DHCP *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_DHCP));
+	t->NumItem = PackGetInt(p, "NumItem");
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_DHCP_ITEM) * t->NumItem);
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+		e->Id = PackGetIntEx(p, "Id", i);
+		e->LeasedTime = PackGetInt64Ex(p, "LeasedTime", i);
+		e->ExpireTime = PackGetInt64Ex(p, "ExpireTime", i);
+		PackGetDataEx2(p, "MacAddress", e->MacAddress, 6, i);
+		e->IpAddress = PackGetIp32Ex(p, "IpAddress", i);
+		e->Mask = PackGetIntEx(p, "Mask", i);
+		PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+	}
+}
+void OutRpcEnumDhcp(PACK *p, RPC_ENUM_DHCP *t)
+{
+	UINT i;
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+	PackAddStr(p, "HubName", t->HubName);
+
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+		PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+		PackAddInt64Ex(p, "LeasedTime", e->LeasedTime, i, t->NumItem);
+		PackAddInt64Ex(p, "ExpireTime", e->ExpireTime, i, t->NumItem);
+		PackAddDataEx(p, "MacAddress", e->MacAddress, 6, i, t->NumItem);
+		PackAddIp32Ex(p, "IpAddress", e->IpAddress, i, t->NumItem);
+		PackAddIntEx(p, "Mask", e->Mask, i, t->NumItem);
+		PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumItem);
+	}
+}
+void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_ENUM_NAT
+void InRpcEnumNat(RPC_ENUM_NAT *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_ENUM_NAT));
+	t->NumItem = PackGetInt(p, "NumItem");
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+	t->Items = ZeroMalloc(sizeof(RPC_ENUM_NAT_ITEM) * t->NumItem);
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+		e->Id = PackGetIntEx(p, "Id", i);
+		e->Protocol = PackGetIntEx(p, "Protocol", i);
+		e->SrcIp = PackGetIntEx(p, "SrcIp", i);
+		PackGetStrEx(p, "SrcHost", e->SrcHost, sizeof(e->SrcHost), i);
+		e->SrcPort = PackGetIntEx(p, "SrcPort", i);
+		e->DestIp = PackGetIntEx(p, "DestIp", i);
+		PackGetStrEx(p, "DestHost", e->DestHost, sizeof(e->DestHost), i);
+		e->DestPort = PackGetIntEx(p, "DestPort", i);
+		e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+		e->LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);
+		e->SendSize = PackGetInt64Ex(p, "SendSize", i);
+		e->RecvSize = PackGetInt64Ex(p, "RecvSize", i);
+		e->TcpStatus = PackGetIntEx(p, "TcpStatus", i);
+	}
+}
+void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "NumItem", t->NumItem);
+	PackAddStr(p, "HubName", t->HubName);
+	for (i = 0;i < t->NumItem;i++)
+	{
+		RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+		PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+		PackAddIntEx(p, "Protocol", e->Protocol, i, t->NumItem);
+		PackAddIp32Ex(p, "SrcIp", e->SrcIp, i, t->NumItem);
+		PackAddStrEx(p, "SrcHost", e->SrcHost, i, t->NumItem);
+		PackAddIntEx(p, "SrcPort", e->SrcPort, i, t->NumItem);
+		PackAddIp32Ex(p, "DestIp", e->DestIp, i, t->NumItem);
+		PackAddStrEx(p, "DestHost", e->DestHost, i, t->NumItem);
+		PackAddIntEx(p, "DestPort", e->DestPort, i, t->NumItem);
+		PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumItem);
+		PackAddInt64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumItem);
+		PackAddInt64Ex(p, "SendSize", e->SendSize, i, t->NumItem);
+		PackAddInt64Ex(p, "RecvSize", e->RecvSize, i, t->NumItem);
+		PackAddIntEx(p, "TcpStatus", e->TcpStatus, i, t->NumItem);
+	}
+}
+void FreeRpcEnumNat(RPC_ENUM_NAT *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Free(t->Items);
+}
+
+// RPC_NAT_INFO
+void InRpcNatInfo(RPC_NAT_INFO *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_NAT_INFO));
+	PackGetStr(p, "NatProductName", t->NatProductName, sizeof(t->NatProductName));
+	PackGetStr(p, "NatVersionString", t->NatVersionString, sizeof(t->NatVersionString));
+	PackGetStr(p, "NatBuildInfoString", t->NatBuildInfoString, sizeof(t->NatBuildInfoString));
+	t->NatVerInt = PackGetInt(p, "NatVerInt");
+	t->NatBuildInt = PackGetInt(p, "NatBuildInt");
+	PackGetStr(p, "NatHostName", t->NatHostName, sizeof(t->NatHostName));
+	InRpcOsInfo(&t->OsInfo, p);
+	InRpcMemInfo(&t->MemInfo, p);
+}
+void OutRpcNatInfo(PACK *p, RPC_NAT_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "NatProductName", t->NatProductName);
+	PackAddStr(p, "NatVersionString", t->NatVersionString);
+	PackAddStr(p, "NatBuildInfoString", t->NatBuildInfoString);
+	PackAddInt(p, "NatVerInt", t->NatVerInt);
+	PackAddInt(p, "NatBuildInt", t->NatBuildInt);
+	PackAddStr(p, "NatHostName", t->NatHostName);
+	OutRpcOsInfo(p, &t->OsInfo);
+	OutRpcMemInfo(p, &t->MemInfo);
+}
+void FreeRpcNatInfo(RPC_NAT_INFO *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	FreeRpcOsInfo(&t->OsInfo);
+}
+
+// RPC_NAT_STATUS
+void InRpcNatStatus(RPC_NAT_STATUS *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_NAT_STATUS));
+	t->NumTcpSessions = PackGetInt(p, "NumTcpSessions");
+	t->NumUdpSessions = PackGetInt(p, "NumUdpSessions");
+	t->NumDhcpClients = PackGetInt(p, "NumDhcpClients");
+	PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t)
+{
+	// 引数チェック
+	if (p == NULL || t == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "HubName", t->HubName);
+	PackAddInt(p, "NumTcpSessions", t->NumTcpSessions);
+	PackAddInt(p, "NumUdpSessions", t->NumUdpSessions);
+	PackAddInt(p, "NumDhcpClients", t->NumDhcpClients);
+}
+void FreeRpcNatStatus(RPC_NAT_STATUS *t)
+{
+}
+
+// RPC_DUMMY
+void InRpcDummy(RPC_DUMMY *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(RPC_DUMMY));
+	t->DummyValue = PackGetInt(p, "DummyValue");
+}
+void OutRpcDummy(PACK *p, RPC_DUMMY *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "DummyValue", t->DummyValue);
+}
+
+// 管理用メインプロシージャ
+void NiAdminMain(NAT *n, SOCK *s)
+{
+	RPC *r;
+	PACK *p;
+	// 引数チェック
+	if (n == NULL || s == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	HttpServerSend(s, p);
+	FreePack(p);
+
+	r = StartRpcServer(s, NiRpcServer, n);
+
+	RpcServer(r);
+
+	RpcFree(r);
+}
+
+// 管理スレッド
+void NiAdminThread(THREAD *thread, void *param)
+{
+	NAT_ADMIN *a = (NAT_ADMIN *)param;
+	NAT *n;
+	SOCK *s;
+	UCHAR random[SHA1_SIZE];
+	UINT err;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// 乱数生成
+	Rand(random, sizeof(random));
+
+	a->Thread = thread;
+	AddRef(a->Thread->ref);
+	s = a->Sock;
+	AddRef(s->ref);
+
+	n = a->Nat;
+
+	LockList(n->AdminList);
+	{
+		Add(n->AdminList, a);
+	}
+	UnlockList(n->AdminList);
+
+	NoticeThreadInit(thread);
+
+	err = ERR_AUTH_FAILED;
+
+	if (StartSSL(s, n->AdminX, n->AdminK))
+	{
+		PACK *p;
+
+		// 乱数を送信する
+		p = NewPack();
+		PackAddData(p, "auth_random", random, sizeof(random));
+
+		if (HttpServerSend(s, p))
+		{
+			PACK *p;
+			// パスワードを受け取る
+			p = HttpServerRecv(s);
+			if (p != NULL)
+			{
+				UCHAR secure_password[SHA1_SIZE];
+				UCHAR secure_check[SHA1_SIZE];
+
+				if (PackGetData2(p, "secure_password", secure_password, sizeof(secure_password)))
+				{
+					SecurePassword(secure_check, n->HashedPassword, random);
+
+					if (Cmp(secure_check, secure_password, SHA1_SIZE) == 0)
+					{
+						UCHAR test[SHA1_SIZE];
+						// パスワード一致
+						Hash(test, "", 0, true);
+						SecurePassword(test, test, random);
+
+#if	0
+						if (Cmp(test, secure_check, SHA1_SIZE) == 0 && s->RemoteIP.addr[0] != 127)
+						{
+							// 空白パスワードは外部から接続できない
+							err = ERR_NULL_PASSWORD_LOCAL_ONLY;
+						}
+						else
+#endif
+
+						{
+							// 接続成功
+							err = ERR_NO_ERROR;
+							NiAdminMain(n, s);
+						}
+					}
+				}
+
+				FreePack(p);
+			}
+		}
+
+		FreePack(p);
+
+		if (err != ERR_NO_ERROR)
+		{
+			p = PackError(err);
+			HttpServerSend(s, p);
+			FreePack(p);
+		}
+	}
+
+	Disconnect(s);
+	ReleaseSock(s);
+}
+
+// 管理ポート Listen スレッド
+void NiListenThread(THREAD *thread, void *param)
+{
+	NAT *n = (NAT *)param;
+	SOCK *a;
+	UINT i;
+	bool b = false;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// 管理リストの初期化
+	n->AdminList = NewList(NULL);
+
+	while (true)
+	{
+		a = Listen(DEFAULT_NAT_ADMIN_PORT);
+		if (b == false)
+		{
+			b = true;
+			NoticeThreadInit(thread);
+		}
+		if (a != NULL)
+		{
+			break;
+		}
+
+		Wait(n->HaltEvent, NAT_ADMIN_PORT_LISTEN_INTERVAL);
+		if (n->Halt)
+		{
+			return;
+		}
+	}
+
+	n->AdminListenSock = a;
+	AddRef(a->ref);
+
+	// 待ち受け
+	while (true)
+	{
+		SOCK *s = Accept(a);
+		THREAD *t;
+		NAT_ADMIN *admin;
+		if (s == NULL)
+		{
+			break;
+		}
+		if (n->Halt)
+		{
+			ReleaseSock(s);
+			break;
+		}
+
+		admin = ZeroMalloc(sizeof(NAT_ADMIN));
+		admin->Nat = n;
+		admin->Sock = s;
+		t = NewThread(NiAdminThread, admin);
+		WaitThreadInit(t);
+		ReleaseThread(t);
+	}
+
+	// すべての管理コネクションを切断
+	LockList(n->AdminList);
+	{
+		for (i = 0;i < LIST_NUM(n->AdminList);i++)
+		{
+			NAT_ADMIN *a = LIST_DATA(n->AdminList, i);
+			Disconnect(a->Sock);
+			WaitThread(a->Thread, INFINITE);
+			ReleaseThread(a->Thread);
+			ReleaseSock(a->Sock);
+			Free(a);
+		}
+	}
+	UnlockList(n->AdminList);
+
+	ReleaseList(n->AdminList);
+
+	ReleaseSock(a);
+}
+
+// 管理コマンド受付初期化
+void NiInitAdminAccept(NAT *n)
+{
+	THREAD *t;
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	t = NewThread(NiListenThread, n);
+	WaitThreadInit(t);
+	n->AdminAcceptThread = t;
+}
+
+// 管理コマンド受付終了
+void NiFreeAdminAccept(NAT *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	n->Halt = true;
+	Disconnect(n->AdminListenSock);
+	Set(n->HaltEvent);
+
+	while (true)
+	{
+		if (WaitThread(n->AdminAcceptThread, 1000) == false)
+		{
+			Disconnect(n->AdminListenSock);
+		}
+		else
+		{
+			break;
+		}
+	}
+	ReleaseThread(n->AdminAcceptThread);
+
+	ReleaseSock(n->AdminListenSock);
+}
+
+// ダイナミック仮想 HUB でサポートされていない DHCP オプションをクリアする
+void NiClearUnsupportedVhOptionForDynamicHub(VH_OPTION *o, bool initial)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	o->UseNat = false;
+
+	if (initial)
+	{
+		Zero(&o->DhcpGatewayAddress, sizeof(IP));
+		Zero(&o->DhcpDnsServerAddress, sizeof(IP));
+		StrCpy(o->DhcpDomainName, sizeof(o->DhcpDomainName), "");
+	}
+}
+
+// 仮想ホストのオプションを初期化する
+void NiSetDefaultVhOption(NAT *n, VH_OPTION *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	Zero(o, sizeof(VH_OPTION));
+	GenMacAddress(o->MacAddress);
+
+	// 仮想 IP を 192.168.30.1/24 にする
+	SetIP(&o->Ip, 192, 168, 30, 1);
+	SetIP(&o->Mask, 255, 255, 255, 0);
+	o->UseNat = true;
+	o->Mtu = 1500;
+	o->NatTcpTimeout = 7200;
+	o->NatUdpTimeout = 60;
+	o->UseDhcp = true;
+	SetIP(&o->DhcpLeaseIPStart, 192, 168, 30, 10);
+	SetIP(&o->DhcpLeaseIPEnd, 192, 168, 30, 200);
+	SetIP(&o->DhcpSubnetMask, 255, 255, 255, 0);
+	o->DhcpExpireTimeSpan = 7200;
+	o->SaveLog = true;
+
+	SetIP(&o->DhcpGatewayAddress, 192, 168, 30, 1);
+	SetIP(&o->DhcpDnsServerAddress, 192, 168, 30, 1);
+
+	GetDomainName(o->DhcpDomainName, sizeof(o->DhcpDomainName));
+}
+
+// NAT の設定を初期状態にする
+void NiInitDefaultConfig(NAT *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	// 仮想ホストオプション初期化
+	NiSetDefaultVhOption(n, &n->Option);
+
+	// 管理用ポート初期化
+	n->AdminPort = DEFAULT_NAT_ADMIN_PORT;
+
+	// オフライン
+	n->Online = false;
+
+	// ログを保存
+	n->Option.SaveLog = true;
+}
+
+// NAT の設定の初期化
+void NiInitConfig(NAT *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	// 初期状態
+	NiInitDefaultConfig(n);
+}
+
+// 仮想ホストオプションの読み込み (拡張)
+void NiLoadVhOptionEx(VH_OPTION *o, FOLDER *root)
+{
+	FOLDER *host, *nat, *dhcp;
+	char mac_address[MAX_SIZE];
+	// 引数チェック
+	if (o == NULL || root == NULL)
+	{
+		return;
+	}
+
+	host = CfgGetFolder(root, "VirtualHost");
+	nat = CfgGetFolder(root, "VirtualRouter");
+	dhcp = CfgGetFolder(root, "VirtualDhcpServer");
+
+	Zero(o, sizeof(VH_OPTION));
+
+	GenMacAddress(o->MacAddress);
+	if (CfgGetStr(host, "VirtualHostMacAddress", mac_address, sizeof(mac_address)))
+	{
+		BUF *b = StrToBin(mac_address);
+		if (b != NULL)
+		{
+			if (b->Size == 6)
+			{
+				Copy(o->MacAddress, b->Buf, 6);
+			}
+		}
+		FreeBuf(b);
+	}
+	CfgGetIp(host, "VirtualHostIp", &o->Ip);
+	CfgGetIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+	o->UseNat = CfgGetBool(nat, "NatEnabled");
+	o->Mtu = CfgGetInt(nat, "NatMtu");
+	o->NatTcpTimeout = CfgGetInt(nat, "NatTcpTimeout");
+	o->NatUdpTimeout = CfgGetInt(nat, "NatUdpTimeout");
+
+	o->UseDhcp = CfgGetBool(dhcp, "DhcpEnabled");
+	CfgGetIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+	CfgGetIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+	CfgGetIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+	o->DhcpExpireTimeSpan = CfgGetInt(dhcp, "DhcpExpireTimeSpan");
+	CfgGetIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+	CfgGetIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+	CfgGetStr(dhcp, "DhcpDomainName", o->DhcpDomainName, sizeof(o->DhcpDomainName));
+
+	Trim(o->DhcpDomainName);
+	if (StrLen(o->DhcpDomainName) == 0)
+	{
+		//GetDomainName(o->DhcpDomainName, sizeof(o->DhcpDomainName));
+	}
+
+	o->SaveLog = CfgGetBool(root, "SaveLog");
+}
+
+// 仮想ホストオプションの読み込み
+void NiLoadVhOption(NAT *n, FOLDER *root)
+{
+	VH_OPTION *o;
+	FOLDER *host, *nat, *dhcp;
+	char mac_address[MAX_SIZE];
+	// 引数チェック
+	if (n == NULL || root == NULL)
+	{
+		return;
+	}
+
+	host = CfgGetFolder(root, "VirtualHost");
+	nat = CfgGetFolder(root, "VirtualRouter");
+	dhcp = CfgGetFolder(root, "VirtualDhcpServer");
+
+	o = &n->Option;
+	Zero(o, sizeof(VH_OPTION));
+
+	GenMacAddress(o->MacAddress);
+	if (CfgGetStr(host, "VirtualHostMacAddress", mac_address, sizeof(mac_address)))
+	{
+		BUF *b = StrToBin(mac_address);
+		if (b != NULL)
+		{
+			if (b->Size == 6)
+			{
+				Copy(o->MacAddress, b->Buf, 6);
+			}
+		}
+		FreeBuf(b);
+	}
+	CfgGetIp(host, "VirtualHostIp", &o->Ip);
+	CfgGetIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+	o->UseNat = CfgGetBool(nat, "NatEnabled");
+	o->Mtu = CfgGetInt(nat, "NatMtu");
+	o->NatTcpTimeout = CfgGetInt(nat, "NatTcpTimeout");
+	o->NatUdpTimeout = CfgGetInt(nat, "NatUdpTimeout");
+
+	o->UseDhcp = CfgGetBool(dhcp, "DhcpEnabled");
+	CfgGetIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+	CfgGetIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+	CfgGetIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+	o->DhcpExpireTimeSpan = CfgGetInt(dhcp, "DhcpExpireTimeSpan");
+	CfgGetIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+	CfgGetIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+	CfgGetStr(dhcp, "DhcpDomainName", o->DhcpDomainName, sizeof(o->DhcpDomainName));
+
+	o->SaveLog = CfgGetBool(root, "SaveLog");
+}
+
+// VPN サーバーからの接続オプションの読み込み
+void NiLoadClientData(NAT *n, FOLDER *root)
+{
+	FOLDER *co, *ca;
+	// 引数チェック
+	if (n == NULL || root == NULL)
+	{
+		return;
+	}
+
+	co = CfgGetFolder(root, "VpnClientOption");
+	ca = CfgGetFolder(root, "VpnClientAuth");
+	if (co == NULL || ca == NULL)
+	{
+		return;
+	}
+
+	n->ClientOption = CiLoadClientOption(co);
+	n->ClientAuth = CiLoadClientAuth(ca);
+}
+
+// VPN サーバーへの接続オプションの書き込み
+void NiWriteClientData(NAT *n, FOLDER *root)
+{
+	// 引数チェック
+	if (n == NULL || root == NULL || n->ClientOption == NULL || n->ClientAuth == NULL)
+	{
+		return;
+	}
+
+	CiWriteClientOption(CfgCreateFolder(root, "VpnClientOption"), n->ClientOption);
+	CiWriteClientAuth(CfgCreateFolder(root, "VpnClientAuth"), n->ClientAuth);
+}
+
+// 仮想ホストオプションの書き込み (拡張)
+void NiWriteVhOptionEx(VH_OPTION *o, FOLDER *root)
+{
+	FOLDER *host, *nat, *dhcp;
+	char mac_address[MAX_SIZE];
+	// 引数チェック
+	if (o == NULL || root == NULL)
+	{
+		return;
+	}
+
+	host = CfgCreateFolder(root, "VirtualHost");
+	nat = CfgCreateFolder(root, "VirtualRouter");
+	dhcp = CfgCreateFolder(root, "VirtualDhcpServer");
+
+	MacToStr(mac_address, sizeof(mac_address), o->MacAddress);
+	CfgAddStr(host, "VirtualHostMacAddress", mac_address);
+	CfgAddIp(host, "VirtualHostIp", &o->Ip);
+	CfgAddIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+	CfgAddBool(nat, "NatEnabled", o->UseNat);
+	CfgAddInt(nat, "NatMtu", o->Mtu);
+	CfgAddInt(nat, "NatTcpTimeout", o->NatTcpTimeout);
+	CfgAddInt(nat, "NatUdpTimeout", o->NatUdpTimeout);
+
+	CfgAddBool(dhcp, "DhcpEnabled", o->UseDhcp);
+	CfgAddIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+	CfgAddIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+	CfgAddIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+	CfgAddInt(dhcp, "DhcpExpireTimeSpan", o->DhcpExpireTimeSpan);
+	CfgAddIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+	CfgAddIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+	CfgAddStr(dhcp, "DhcpDomainName", o->DhcpDomainName);
+
+	CfgAddBool(root, "SaveLog", o->SaveLog);
+}
+
+// 仮想ホストオプションの書き込み
+void NiWriteVhOption(NAT *n, FOLDER *root)
+{
+	VH_OPTION *o;
+	FOLDER *host, *nat, *dhcp;
+	char mac_address[MAX_SIZE];
+	// 引数チェック
+	if (n == NULL || root == NULL)
+	{
+		return;
+	}
+
+	host = CfgCreateFolder(root, "VirtualHost");
+	nat = CfgCreateFolder(root, "VirtualRouter");
+	dhcp = CfgCreateFolder(root, "VirtualDhcpServer");
+
+	o = &n->Option;
+
+	MacToStr(mac_address, sizeof(mac_address), o->MacAddress);
+	CfgAddStr(host, "VirtualHostMacAddress", mac_address);
+	CfgAddIp(host, "VirtualHostIp", &o->Ip);
+	CfgAddIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+	CfgAddBool(nat, "NatEnabled", o->UseNat);
+	CfgAddInt(nat, "NatMtu", o->Mtu);
+	CfgAddInt(nat, "NatTcpTimeout", o->NatTcpTimeout);
+	CfgAddInt(nat, "NatUdpTimeout", o->NatUdpTimeout);
+
+	CfgAddBool(dhcp, "DhcpEnabled", o->UseDhcp);
+	CfgAddIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+	CfgAddIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+	CfgAddIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+	CfgAddInt(dhcp, "DhcpExpireTimeSpan", o->DhcpExpireTimeSpan);
+	CfgAddIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+	CfgAddIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+	CfgAddStr(dhcp, "DhcpDomainName", o->DhcpDomainName);
+
+	CfgAddBool(root, "SaveLog", o->SaveLog);
+}
+
+// 設定ファイルを読み込む
+bool NiLoadConfig(NAT *n, FOLDER *root)
+{
+	FOLDER *host;
+	BUF *b;
+	// 引数チェック
+	if (n == NULL || root == NULL)
+	{
+		return false;
+	}
+
+	host = CfgGetFolder(root, "VirtualHost");
+	if (host == NULL)
+	{
+		return false;
+	}
+
+	CfgGetByte(root, "HashedPassword", n->HashedPassword, sizeof(n->HashedPassword));
+	n->AdminPort = CfgGetInt(root, "AdminPort");
+	n->Online = CfgGetBool(root, "Online");
+
+	b = CfgGetBuf(root, "AdminCert");
+	if (b != NULL)
+	{
+		n->AdminX = BufToX(b, false);
+		FreeBuf(b);
+	}
+
+	b = CfgGetBuf(root, "AdminKey");
+	if (b != NULL)
+	{
+		n->AdminK = BufToK(b, true, false, NULL);
+		FreeBuf(b);
+	}
+
+	NiLoadVhOption(n, root);
+
+	NiLoadClientData(n, root);
+
+	return true;
+}
+
+// 設定をファイルに書き込む
+void NiWriteConfig(NAT *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	Lock(n->lock);
+	{
+		FOLDER *root = CfgCreateFolder(NULL, TAG_ROOT);
+		BUF *b;
+
+		// 証明書
+		b = XToBuf(n->AdminX, false);
+		CfgAddBuf(root, "AdminCert", b);
+		FreeBuf(b);
+
+		// 秘密鍵
+		b = KToBuf(n->AdminK, false, NULL);
+		CfgAddBuf(root, "AdminKey", b);
+		FreeBuf(b);
+
+		// パスワード
+		CfgAddByte(root, "HashedPassword", n->HashedPassword, sizeof(n->HashedPassword));
+		CfgAddInt(root, "AdminPort", n->AdminPort);
+		CfgAddBool(root, "Online", n->Online);
+
+		// 仮想ホストオプション
+		NiWriteVhOption(n, root);
+
+		// 接続オプション
+		if (n->ClientOption != NULL && n->ClientAuth != NULL)
+		{
+			NiWriteClientData(n, root);
+		}
+
+		SaveCfgRw(n->CfgRw, root);
+		CfgDeleteFolder(root);
+	}
+	Unlock(n->lock);
+}
+
+// NAT の設定の解放
+void NiFreeConfig(NAT *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	// 最新の設定の書き込み
+	NiWriteConfig(n);
+
+	// 設定 R/W の解放
+	FreeCfgRw(n->CfgRw);
+	n->CfgRw = NULL;
+
+	Free(n->ClientOption);
+	CiFreeClientAuth(n->ClientAuth);
+
+	FreeX(n->AdminX);
+	FreeK(n->AdminK);
+}
+
+// NAT の作成
+NAT *NiNewNatEx(SNAT *snat, VH_OPTION *o)
+{
+	NAT *n = ZeroMalloc(sizeof(NAT));
+
+	n->lock = NewLock();
+	Hash(n->HashedPassword, "", 0, true);
+	n->HaltEvent = NewEvent();
+
+	//n->Cedar = NewCedar(NULL, NULL);
+
+	n->SecureNAT = snat;
+
+	// 優先順位を上げる
+	//OSSetHighPriority();
+
+	// 設定の初期化
+	NiInitConfig(n);
+
+#if	0
+	// 仮想ホストの動作を開始
+	if (n->Online && n->ClientOption != NULL)
+	{
+		n->Virtual = NewVirtualHostEx(n->Cedar, n->ClientOption, n->ClientAuth, &n->Option, n);
+	}
+	else
+	{
+		n->Online = false;
+		n->Virtual = NULL;
+	}
+#else
+	n->Virtual = NewVirtualHostEx(n->Cedar, NULL, NULL, o, n);
+	n->Online = true;
+#endif
+
+	// 管理コマンド開始
+	//NiInitAdminAccept(n);
+
+	return n;
+}
+NAT *NiNewNat()
+{
+	return NiNewNatEx(NULL, NULL);
+}
+
+// NAT の解放
+void NiFreeNat(NAT *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	// 管理コマンド終了
+	//NiFreeAdminAccept(n);
+
+	// 仮想ホストが動作中の場合は停止
+	Lock(n->lock);
+	{
+		if (n->Virtual != NULL)
+		{
+			StopVirtualHost(n->Virtual);
+			ReleaseVirtual(n->Virtual);
+			n->Virtual = NULL;
+		}
+	}
+	Unlock(n->lock);
+
+	// 設定の解放
+	NiFreeConfig(n);
+
+	// オブジェクトの削除
+	ReleaseCedar(n->Cedar);
+	ReleaseEvent(n->HaltEvent);
+	DeleteLock(n->lock);
+
+	Free(n);
+}
+
+// NAT の停止
+void NtStopNat()
+{
+	Lock(nat_lock);
+	{
+		if (nat != NULL)
+		{
+			NiFreeNat(nat);
+			nat = NULL;
+		}
+	}
+	Unlock(nat_lock);
+}
+
+// NAT の開始
+void NtStartNat()
+{
+	Lock(nat_lock);
+	{
+		if (nat == NULL)
+		{
+			nat = NiNewNat();
+		}
+	}
+	Unlock(nat_lock);
+}
+
+// NtXxx 関数の初期化
+void NtInit()
+{
+	if (nat_lock != NULL)
+	{
+		return;
+	}
+
+	nat_lock = NewLock();
+}
+
+// NtXxx 関数の解放
+void NtFree()
+{
+	if (nat_lock == NULL)
+	{
+		return;
+	}
+
+	DeleteLock(nat_lock);
+	nat_lock = NULL;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Nat.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Nat.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Nat.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,281 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Nat.h
+// Nat.c のヘッダ
+
+#ifndef	NAT_H
+#define	NAT_H
+
+// 定数
+#define	NAT_CONFIG_FILE_NAME			"@vpn_router.config"	// NAT 設定ファイル
+#define	DEFAULT_NAT_ADMIN_PORT			2828		// デフォルトの管理用ポート番号
+#define	NAT_ADMIN_PORT_LISTEN_INTERVAL	1000		// 管理用ポートを開こうとする間隔
+#define	NAT_FILE_SAVE_INTERVAL			(30 * 1000)	// 保存間隔
+
+
+// NAT オブジェクト
+struct NAT
+{
+	LOCK *lock;							// ロック
+	UCHAR HashedPassword[SHA1_SIZE];	// 管理用パスワード
+	VH_OPTION Option;					// オプション
+	CEDAR *Cedar;						// Cedar
+	UINT AdminPort;						// 管理用ポート番号
+	bool Online;						// オンライン フラグ
+	VH *Virtual;						// 仮想ホストオブジェクト
+	CLIENT_OPTION *ClientOption;		// クライアントオプション
+	CLIENT_AUTH *ClientAuth;			// クライアント認証データ
+	CFG_RW *CfgRw;						// Config ファイル R/W
+	THREAD *AdminAcceptThread;			// 管理用コネクション受付スレッド
+	SOCK *AdminListenSock;				// 管理ポートソケット
+	EVENT *HaltEvent;					// 停止イベント
+	volatile bool Halt;					// 停止フラグ
+	LIST *AdminList;					// 管理スレッドリスト
+	X *AdminX;							// 管理用サーバー証明書
+	K *AdminK;							// 管理用サーバー秘密鍵
+	SNAT *SecureNAT;					// SecureNAT オブジェクト
+};
+
+// NAT 管理コネクション
+struct NAT_ADMIN
+{
+	NAT *Nat;							// NAT
+	SOCK *Sock;							// ソケット
+	THREAD *Thread;						// スレッド
+};
+
+// RPC_DUMMY
+struct RPC_DUMMY
+{
+	UINT DummyValue;
+};
+
+// RPC_NAT_STATUS
+struct RPC_NAT_STATUS
+{
+	char HubName[MAX_HUBNAME_LEN + 1];			// HUB 名
+	UINT NumTcpSessions;						// TCP セッション数
+	UINT NumUdpSessions;						// UDP セッション数
+	UINT NumDhcpClients;						// DHCP クライアント数
+};
+
+// RPC_NAT_INFO *
+struct RPC_NAT_INFO
+{
+	char NatProductName[128];					// サーバー製品名
+	char NatVersionString[128];					// サーバーバージョン文字列
+	char NatBuildInfoString[128];				// サーバービルド情報文字列
+	UINT NatVerInt;								// サーバーバージョン整数値
+	UINT NatBuildInt;							// サーバービルド番号整数値
+	char NatHostName[MAX_HOST_NAME_LEN + 1];	// サーバーホスト名
+	OS_INFO OsInfo;								// OS 情報
+	MEMINFO MemInfo;							// メモリ情報
+};
+
+// RPC_ENUM_NAT_ITEM
+struct RPC_ENUM_NAT_ITEM
+{
+	UINT Id;									// ID
+	UINT Protocol;								// プロトコル
+	UINT SrcIp;									// 接続元 IP アドレス
+	char SrcHost[MAX_HOST_NAME_LEN + 1];		// 接続元ホスト名
+	UINT SrcPort;								// 接続元ポート番号
+	UINT DestIp;								// 接続先 IP アドレス
+	char DestHost[MAX_HOST_NAME_LEN + 1];		// 接続先ホスト名
+	UINT DestPort;								// 接続先ポート番号
+	UINT64 CreatedTime;							// 接続時刻
+	UINT64 LastCommTime;						// 最終通信時刻
+	UINT64 SendSize;							// 送信サイズ
+	UINT64 RecvSize;							// 受信サイズ
+	UINT TcpStatus;								// TCP 状態
+};
+
+// RPC_ENUM_NAT *
+struct RPC_ENUM_NAT
+{
+	char HubName[MAX_HUBNAME_LEN + 1];			// HUB 名
+	UINT NumItem;								// アイテム数
+	RPC_ENUM_NAT_ITEM *Items;					// アイテム
+};
+
+// RPC_ENUM_DHCP_ITEM
+struct RPC_ENUM_DHCP_ITEM
+{
+	UINT Id;									// ID
+	UINT64 LeasedTime;							// リース時刻
+	UINT64 ExpireTime;							// 有効期限
+	UCHAR MacAddress[6];						// MAC アドレス
+	UCHAR Padding[2];							// パディング
+	UINT IpAddress;								// IP アドレス
+	UINT Mask;									// サブネットマスク
+	char Hostname[MAX_HOST_NAME_LEN + 1];		// ホスト名
+};
+
+// RPC_ENUM_DHCP *
+struct RPC_ENUM_DHCP
+{
+	char HubName[MAX_HUBNAME_LEN + 1];			// HUB 名
+	UINT NumItem;								// アイテム数
+	RPC_ENUM_DHCP_ITEM *Items;					// アイテム
+};
+
+
+// 関数プロトタイプ
+NAT *NiNewNat();
+NAT *NiNewNatEx(SNAT *snat, VH_OPTION *o);
+void NiFreeNat(NAT *n);
+void NiInitConfig(NAT *n);
+void NiFreeConfig(NAT *n);
+void NiInitDefaultConfig(NAT *n);
+void NiSetDefaultVhOption(NAT *n, VH_OPTION *o);
+void NiClearUnsupportedVhOptionForDynamicHub(VH_OPTION *o, bool initial);
+void NiWriteConfig(NAT *n);
+void NiWriteVhOption(NAT *n, FOLDER *root);
+void NiWriteVhOptionEx(VH_OPTION *o, FOLDER *root);
+void NiWriteClientData(NAT *n, FOLDER *root);
+void NiLoadVhOption(NAT *n, FOLDER *root);
+void NiLoadVhOptionEx(VH_OPTION *o, FOLDER *root);
+bool NiLoadConfig(NAT *n, FOLDER *root);
+void NiLoadClientData(NAT *n, FOLDER *root);
+void NiInitAdminAccept(NAT *n);
+void NiFreeAdminAccept(NAT *n);
+void NiListenThread(THREAD *thread, void *param);
+void NiAdminThread(THREAD *thread, void *param);
+void NiAdminMain(NAT *n, SOCK *s);
+PACK *NiRpcServer(RPC *r, char *name, PACK *p);
+
+RPC *NatAdminConnect(CEDAR *cedar, char *hostname, UINT port, void *hashed_password, UINT *err);
+void NatAdminDisconnect(RPC *r);
+
+void NtStartNat();
+void NtStopNat();
+void NtInit();
+void NtFree();
+
+
+UINT NtOnline(NAT *n, RPC_DUMMY *t);
+UINT NtOffline(NAT *n, RPC_DUMMY *t);
+UINT NtSetHostOption(NAT *n, VH_OPTION *t);
+UINT NtGetHostOption(NAT *n, VH_OPTION *t);
+UINT NtSetClientConfig(NAT *n, RPC_CREATE_LINK *t);
+UINT NtGetClientConfig(NAT *n, RPC_CREATE_LINK *t);
+UINT NtGetStatus(NAT *n, RPC_NAT_STATUS *t);
+UINT NtGetInfo(NAT *n, RPC_NAT_INFO *t);
+UINT NtEnumNatList(NAT *n, RPC_ENUM_NAT *t);
+UINT NtEnumDhcpList(NAT *n, RPC_ENUM_DHCP *t);
+UINT NtSetPassword(NAT *n, RPC_SET_PASSWORD *t);
+
+
+UINT NcOnline(RPC *r, RPC_DUMMY *t);
+UINT NcOffline(RPC *r, RPC_DUMMY *t);
+UINT NcSetHostOption(RPC *r, VH_OPTION *t);
+UINT NcGetHostOption(RPC *r, VH_OPTION *t);
+UINT NcSetClientConfig(RPC *r, RPC_CREATE_LINK *t);
+UINT NcGetClientConfig(RPC *r, RPC_CREATE_LINK *t);
+UINT NcGetStatus(RPC *r, RPC_NAT_STATUS *t);
+UINT NcGetInfo(RPC *r, RPC_NAT_INFO *t);
+UINT NcEnumNatList(RPC *r, RPC_ENUM_NAT *t);
+UINT NcEnumDhcpList(RPC *r, RPC_ENUM_DHCP *t);
+UINT NcSetPassword(RPC *r, RPC_SET_PASSWORD *t);
+
+
+
+
+void InRpcEnumDhcp(RPC_ENUM_DHCP *t, PACK *p);
+void OutRpcEnumDhcp(PACK *p, RPC_ENUM_DHCP *t);
+void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t);
+void InRpcEnumNat(RPC_ENUM_NAT *t, PACK *p);
+void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t);
+void FreeRpcEnumNat(RPC_ENUM_NAT *t);
+void InRpcNatInfo(RPC_NAT_INFO *t, PACK *p);
+void OutRpcNatInfo(PACK *p, RPC_NAT_INFO *t);
+void FreeRpcNatInfo(RPC_NAT_INFO *t);
+void InRpcNatStatus(RPC_NAT_STATUS *t, PACK *p);
+void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t);
+void FreeRpcNatStatus(RPC_NAT_STATUS *t);
+void InVhOption(VH_OPTION *t, PACK *p);
+void OutVhOption(PACK *p, VH_OPTION *t);
+void InRpcDummy(RPC_DUMMY *t, PACK *p);
+void OutRpcDummy(PACK *p, RPC_DUMMY *t);
+
+
+
+
+#endif	// NAT_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NullLan.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NullLan.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NullLan.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,249 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// NullLan.c
+// テスト用仮想 LAN カードデバイスドライバ
+
+#include "CedarPch.h"
+
+static UCHAR null_lan_broadcast_address[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+// パケットアダプタの取得
+PACKET_ADAPTER *NullGetPacketAdapter()
+{
+	PACKET_ADAPTER *pa = NewPacketAdapter(NullPaInit, NullPaGetCancel, NullPaGetNextPacket,
+		NullPaPutPacket, NullPaFree);
+
+	return pa;
+}
+
+// パケット生成スレッド
+void NullPacketGenerateThread(THREAD *t, void *param)
+{
+	NULL_LAN *n = (NULL_LAN *)param;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		Wait(n->Event, Rand32() % NULL_PACKET_GENERATE_INTERVAL);
+		if (n->Halt)
+		{
+			break;
+		}
+
+		LockQueue(n->PacketQueue);
+		{
+			UCHAR *data;
+			BLOCK *b;
+			UINT size = Rand32() % 1500 + 14;
+			data = Malloc(size);
+			Copy(data, null_lan_broadcast_address, 6);
+			Copy(data + 6, n->MacAddr, 6);
+			b = NewBlock(data, size, 0);
+			InsertQueue(n->PacketQueue, b);
+		}
+		UnlockQueue(n->PacketQueue);
+		Cancel(n->Cancel);
+	}
+}
+
+// パケットアダプタの初期化
+bool NullPaInit(SESSION *s)
+{
+	NULL_LAN *n;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	n = ZeroMalloc(sizeof(NULL_LAN));
+	s->PacketAdapter->Param = (void *)n;
+
+	n->Cancel = NewCancel();
+	n->PacketQueue = NewQueue();
+	n->Event = NewEvent();
+
+	GenMacAddress(n->MacAddr);
+
+	n->PacketGeneratorThread = NewThread(NullPacketGenerateThread, n);
+
+	return true;
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *NullPaGetCancel(SESSION *s)
+{
+	// 引数チェック
+	NULL_LAN *n;
+	if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+	{
+		return NULL;
+	}
+
+	AddRef(n->Cancel->ref);
+
+	return n->Cancel;
+}
+
+// 次のパケットを取得
+UINT NullPaGetNextPacket(SESSION *s, void **data)
+{
+	UINT size = 0;
+	// 引数チェック
+	NULL_LAN *n;
+	if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+	{
+		return INFINITE;
+	}
+
+	LockQueue(n->PacketQueue);
+	{
+		BLOCK *b = GetNext(n->PacketQueue);
+
+		if (b != NULL)
+		{
+			*data = b->Buf;
+			size = b->Size;
+			Free(b);
+		}
+	}
+	UnlockQueue(n->PacketQueue);
+
+	return size;
+}
+
+// パケットを書き込み
+bool NullPaPutPacket(SESSION *s, void *data, UINT size)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+	if (data == NULL)
+	{
+		return true;
+	}
+
+	// パケット無視
+	Free(data);
+
+	return true;
+}
+
+// 解放
+void NullPaFree(SESSION *s)
+{
+	// 引数チェック
+	NULL_LAN *n;
+	BLOCK *b;
+	if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+	{
+		return;
+	}
+
+	n->Halt = true;
+	Set(n->Event);
+
+	WaitThread(n->PacketGeneratorThread, INFINITE);
+	ReleaseThread(n->PacketGeneratorThread);
+
+	LockQueue(n->PacketQueue);
+	{
+		while (b = GetNext(n->PacketQueue))
+		{
+			FreeBlock(b);
+		}
+	}
+	UnlockQueue(n->PacketQueue);
+
+	ReleaseQueue(n->PacketQueue);
+
+	ReleaseCancel(n->Cancel);
+
+	ReleaseEvent(n->Event);
+
+	s->PacketAdapter->Param = NULL;
+	Free(n);
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NullLan.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NullLan.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/NullLan.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,110 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// NullLan.h
+// NullLan.c のヘッダ
+
+#ifndef	NULLLAN_H
+#define	NULLLAN_H
+
+
+#define	NULL_PACKET_GENERATE_INTERVAL		100000000		// パケット発生間隔
+
+// NULL デバイス構造体
+struct NULL_LAN
+{
+	THREAD *PacketGeneratorThread;
+	CANCEL *Cancel;
+	QUEUE *PacketQueue;
+	volatile bool Halt;
+	EVENT *Event;
+	UCHAR MacAddr[6];
+	UCHAR Padding[2];
+};
+
+PACKET_ADAPTER *NullGetPacketAdapter();
+bool NullPaInit(SESSION *s);
+CANCEL *NullPaGetCancel(SESSION *s);
+UINT NullPaGetNextPacket(SESSION *s, void **data);
+bool NullPaPutPacket(SESSION *s, void *data, UINT size);
+void NullPaFree(SESSION *s);
+void NullPacketGenerateThread(THREAD *t, void *param);
+
+#endif	// NULLAN_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Protocol.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Protocol.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Protocol.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,7005 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Protocol.c
+// SoftEther プロトコル関係のルーチン
+
+#include "CedarPch.h"
+
+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";
+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";
+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";
+
+// マシンごとにユニークな ID を生成する
+void GenerateMachineUniqueHash(void *data)
+{
+	BUF *b;
+	char name[64];
+	char ip_str[64];
+	IP ip;
+	OS_INFO *osinfo;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return;
+	}
+
+	b = NewBuf();
+	GetMachineName(name, sizeof(name));
+	GetMachineIp(&ip);
+	IPToStr(ip_str, sizeof(ip_str), &ip);
+
+	osinfo = GetOsInfo();
+
+	WriteBuf(b, name, StrLen(name));
+	WriteBuf(b, ip_str, StrLen(ip_str));
+
+	WriteBuf(b, &osinfo->OsType, sizeof(osinfo->OsType));
+	WriteBuf(b, osinfo->KernelName, StrLen(osinfo->KernelName));
+	WriteBuf(b, osinfo->KernelVersion, StrLen(osinfo->KernelVersion));
+	WriteBuf(b, osinfo->OsProductName, StrLen(osinfo->OsProductName));
+	WriteBuf(b, &osinfo->OsServicePack, sizeof(osinfo->OsServicePack));
+	WriteBuf(b, osinfo->OsSystemName, StrLen(osinfo->OsSystemName));
+	WriteBuf(b, osinfo->OsVendorName, StrLen(osinfo->OsVendorName));
+	WriteBuf(b, osinfo->OsVersion, StrLen(osinfo->OsVersion));
+
+	Hash(data, b->Buf, b->Size, true);
+
+	FreeBuf(b);
+}
+
+// ノード情報を文字列に変換する
+void NodeInfoToStr(wchar_t *str, UINT size, NODE_INFO *info)
+{
+	char client_ip[128], server_ip[128], proxy_ip[128], unique_id[128];
+	// 引数チェック
+	if (str == NULL || info == NULL)
+	{
+		return;
+	}
+
+	IPToStr4or6(client_ip, sizeof(client_ip), info->ClientIpAddress, info->ClientIpAddress6);
+	IPToStr4or6(server_ip, sizeof(server_ip), info->ServerIpAddress, info->ServerIpAddress6);
+	IPToStr4or6(proxy_ip, sizeof(proxy_ip), info->ProxyIpAddress, info->ProxyIpAddress6);
+	BinToStr(unique_id, sizeof(unique_id), info->UniqueId, sizeof(info->UniqueId));
+
+	UniFormat(str, size, _UU("LS_NODE_INFO_TAG"), info->ClientProductName,
+		Endian32(info->ClientProductVer), Endian32(info->ClientProductBuild),
+		info->ServerProductName, Endian32(info->ServerProductVer), Endian32(info->ServerProductBuild),
+		info->ClientOsName, info->ClientOsVer, info->ClientOsProductId,
+		info->ClientHostname, client_ip, Endian32(info->ClientPort),
+		info->ServerHostname, server_ip, Endian32(info->ServerPort),
+		info->ProxyHostname, proxy_ip, Endian32(info->ProxyPort),
+		info->HubName, unique_id);
+}
+
+// ノード情報の比較
+bool CompareNodeInfo(NODE_INFO *a, NODE_INFO *b)
+{
+	// 引数チェック
+	if (a == NULL || b == NULL)
+	{
+		return false;
+	}
+
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	if (StrCmp(a->ClientProductName, b->ClientProductName) != 0)
+	{
+		return false;
+	}
+	if (a->ClientProductVer != b->ClientProductVer)
+	{
+		return false;
+	}
+	if (a->ClientProductBuild != b->ClientProductBuild)
+	{
+		return false;
+	}
+	if (StrCmp(a->ServerProductName, b->ServerProductName) != 0)
+	{
+		return false;
+	}
+	if (a->ServerProductVer != b->ServerProductVer)
+	{
+		return false;
+	}
+	if (a->ServerProductBuild != b->ServerProductBuild)
+	{
+		return false;
+	}
+	if (StrCmp(a->ClientOsName, b->ClientOsName) != 0)
+	{
+		return false;
+	}
+	if (StrCmp(a->ClientOsVer, b->ClientOsVer) != 0)
+	{
+		return false;
+	}
+	if (StrCmp(a->ClientOsProductId, b->ClientOsProductId) != 0)
+	{
+		return false;
+	}
+	if (StrCmp(a->ClientHostname, b->ClientHostname) != 0)
+	{
+		return false;
+	}
+	if (a->ClientIpAddress != b->ClientIpAddress)
+	{
+		return false;
+	}
+	if (StrCmp(a->ServerHostname, b->ServerHostname) != 0)
+	{
+		return false;
+	}
+	if (a->ServerIpAddress != b->ServerIpAddress)
+	{
+		return false;
+	}
+	if (a->ServerPort != b->ServerPort)
+	{
+		return false;
+	}
+	if (StrCmp(a->ProxyHostname, b->ProxyHostname) != 0)
+	{
+		return false;
+	}
+	if (a->ProxyIpAddress != b->ProxyIpAddress)
+	{
+		return false;
+	}
+	if (a->ProxyPort != b->ProxyPort)
+	{
+		return false;
+	}
+	if (StrCmp(a->HubName, b->HubName) != 0)
+	{
+		return false;
+	}
+	if (Cmp(a->UniqueId, b->UniqueId, 16) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// パスワード変更受付
+UINT ChangePasswordAccept(CONNECTION *c, PACK *p)
+{
+	CEDAR *cedar;
+	UCHAR random[SHA1_SIZE];
+	char hubname[MAX_HUBNAME_LEN + 1];
+	char username[MAX_USERNAME_LEN + 1];
+	UCHAR secure_old_password[SHA1_SIZE];
+	UCHAR new_password[SHA1_SIZE];
+	UCHAR check_secure_old_password[SHA1_SIZE];
+	UINT ret = ERR_NO_ERROR;
+	HUB *hub;
+	bool save = false;
+	// 引数チェック
+	if (c == NULL || p == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	Copy(random, c->Random, SHA1_SIZE);
+	if (PackGetStr(p, "hubname", hubname, sizeof(hubname)) == false ||
+		PackGetStr(p, "username", username, sizeof(username)) == false ||
+		PackGetData2(p, "secure_old_password", secure_old_password, sizeof(secure_old_password)) == false ||
+		PackGetData2(p, "new_password", new_password, sizeof(new_password)) == false)
+	{
+		return ERR_PROTOCOL_ERROR;
+	}
+
+	cedar = c->Cedar;
+
+	LockHubList(cedar);
+	{
+		hub = GetHub(cedar, hubname);
+	}
+	UnlockHubList(cedar);
+
+	if (hub == NULL)
+	{
+		ret = ERR_HUB_NOT_FOUND;
+	}
+	else
+	{
+		char tmp[MAX_SIZE];
+
+		if (GetHubAdminOption(hub, "deny_change_user_password") != 0)
+		{
+			ReleaseHub(hub);
+			return ERR_NOT_ENOUGH_RIGHT;
+		}
+
+		IPToStr(tmp, sizeof(tmp), &c->FirstSock->RemoteIP);
+		HLog(hub, "LH_CHANGE_PASSWORD_1", c->Name, tmp);
+
+		AcLock(hub);
+		{
+			USER *u = AcGetUser(hub, username);
+			if (u == NULL)
+			{
+				HLog(hub, "LH_CHANGE_PASSWORD_2", c->Name, username);
+				ret = ERR_OLD_PASSWORD_WRONG;
+			}
+			else
+			{
+				Lock(u->lock);
+				{
+					if (u->AuthType	!= AUTHTYPE_PASSWORD)
+					{
+						// パスワード認証ではない
+						HLog(hub, "LH_CHANGE_PASSWORD_3", c->Name, username);
+						ret = ERR_USER_AUTHTYPE_NOT_PASSWORD;
+					}
+					else
+					{
+						bool fix_password = false;
+						if (u->Policy != NULL)
+						{
+							fix_password = u->Policy->FixPassword;
+						}
+						else
+						{
+							if (u->Group != NULL)
+							{
+								if (u->Group->Policy != NULL)
+								{
+									fix_password = u->Group->Policy->FixPassword;
+								}
+							}
+						}
+						if (fix_password == false)
+						{
+							// 古いパスワードの確認
+							AUTHPASSWORD *pw = (AUTHPASSWORD *)u->AuthData;
+
+							SecurePassword(check_secure_old_password, pw->HashedKey, random);
+							if (Cmp(check_secure_old_password, secure_old_password, SHA1_SIZE) != 0)
+							{
+								// 古いパスワードが間違っている
+								ret = ERR_OLD_PASSWORD_WRONG;
+								HLog(hub, "LH_CHANGE_PASSWORD_4", c->Name, username);
+							}
+							else
+							{
+								// 新しいパスワードの書き込み
+								Copy(pw->HashedKey, new_password, SHA1_SIZE);
+								HLog(hub, "LH_CHANGE_PASSWORD_5", c->Name, username);
+								save = true;
+							}
+						}
+						else
+						{
+							// パスワード変更は禁止
+							ret = ERR_NOT_ENOUGH_RIGHT;
+						}
+					}
+				}
+				Unlock(u->lock);
+
+				ReleaseUser(u);
+			}
+		}
+		AcUnlock(hub);
+		ReleaseHub(hub);
+	}
+
+	return ret;
+}
+
+// パスワードを変更する
+UINT ChangePassword(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, char *username, char *old_pass, char *new_pass)
+{
+	UINT ret = ERR_NO_ERROR;
+	UCHAR old_password[SHA1_SIZE];
+	UCHAR secure_old_password[SHA1_SIZE];
+	UCHAR new_password[SHA1_SIZE];
+	SOCK *sock;
+	SESSION *s;
+	// 引数チェック
+	if (cedar == NULL || o == NULL || hubname == NULL || username == NULL || old_pass == NULL || new_pass == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+
+	// セッション作成
+	s = NewRpcSessionEx(cedar, o, &ret, NULL);
+
+	if (s != NULL)
+	{
+		PACK *p = NewPack();
+
+		sock = s->Connection->FirstSock;
+
+		HashPassword(old_password, username, old_pass);
+		SecurePassword(secure_old_password, old_password, s->Connection->Random);
+		HashPassword(new_password, username, new_pass);
+
+		PackAddClientVersion(p, s->Connection);
+
+		PackAddStr(p, "method", "password");
+		PackAddStr(p, "hubname", hubname);
+		PackAddStr(p, "username", username);
+		PackAddData(p, "secure_old_password", secure_old_password, SHA1_SIZE);
+		PackAddData(p, "new_password", new_password, SHA1_SIZE);
+
+		if (HttpClientSend(sock, p))
+		{
+			PACK *p = HttpClientRecv(sock);
+			if (p == NULL)
+			{
+				ret = ERR_DISCONNECTED;
+			}
+			else
+			{
+				ret = GetErrorFromPack(p);
+			}
+			FreePack(p);
+		}
+		else
+		{
+			ret = ERR_DISCONNECTED;
+		}
+		FreePack(p);
+
+		ReleaseSession(s);
+	}
+
+	return ret;
+}
+
+// HUB を列挙する
+TOKEN_LIST *EnumHub(SESSION *s)
+{
+	SOCK *sock;
+	TOKEN_LIST *ret;
+	PACK *p;
+	UINT num;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || s->Connection == NULL)
+	{
+		return NULL;
+	}
+
+	sock = s->Connection->FirstSock;
+	if (sock == NULL)
+	{
+		return NULL;
+	}
+
+	// タイムアウトの設定
+	SetTimeout(sock, 10000);
+
+	p = NewPack();
+	PackAddStr(p, "method", "enum_hub");
+
+	PackAddClientVersion(p, s->Connection);
+
+	if (HttpClientSend(sock, p) == false)
+	{
+		FreePack(p);
+		return NULL;
+	}
+	FreePack(p);
+
+	p = HttpClientRecv(sock);
+	if (p == NULL)
+	{
+		return NULL;
+	}
+
+	num = PackGetInt(p, "NumHub");
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->NumTokens = num;
+	ret->Token = ZeroMalloc(sizeof(char *) * num);
+	for (i = 0;i < num;i++)
+	{
+		char tmp[MAX_SIZE];
+		if (PackGetStrEx(p, "HubName", tmp, sizeof(tmp), i))
+		{
+			ret->Token[i] = CopyStr(tmp);
+		}
+	}
+	FreePack(p);
+
+	return ret;
+}
+
+// サーバーがクライアントからの接続を受け付ける
+bool ServerAccept(CONNECTION *c)
+{
+	bool ret = false;
+	UINT err;
+	PACK *p;
+	char username_real[MAX_SIZE];
+	char method[MAX_SIZE];
+	char hubname[MAX_SIZE];
+	char username[MAX_SIZE];
+	char groupname[MAX_SIZE];
+	UCHAR session_key[SHA1_SIZE];
+	UCHAR ticket[SHA1_SIZE];
+	RC4_KEY_PAIR key_pair;
+	UINT authtype;
+	POLICY *policy;
+	HUB *hub;
+	SESSION *s;
+	UINT64 user_expires = 0;
+	bool use_encrypt;
+	bool use_compress;
+	bool half_connection;
+	bool use_fast_rc4;
+	bool admin_mode = false;
+	UINT direction;
+	UINT max_connection;
+	UINT timeout;
+	bool farm_controller = false;
+	bool farm_member = false;
+	bool farm_mode = false;
+	bool require_bridge_routing_mode;
+	bool require_monitor_mode;
+	bool use_client_license = false, use_bridge_license = false;
+	bool local_host_session = false;
+	char sessionname[MAX_SESSION_NAME_LEN + 1];
+	bool is_server_or_bridge = false;
+	bool qos = false;
+	bool cluster_dynamic_secure_nat = false;
+	bool no_save_password = false;
+	NODE_INFO node;
+	wchar_t *msg = NULL;
+	USER *loggedin_user_object = NULL;
+	FARM_MEMBER *f = NULL;
+	SERVER *server = NULL;
+	POLICY ticketed_policy;
+	UINT64 timestamp;
+	UCHAR unique[SHA1_SIZE], unique2[SHA1_SIZE];
+	LICENSE_STATUS license;
+	CEDAR *cedar;
+	RPC_WINVER winver;
+	UINT client_id;
+	bool no_more_users_in_server = false;
+
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	Zero(&winver, sizeof(winver));
+
+	StrCpy(groupname, sizeof(groupname), "");
+	StrCpy(sessionname, sizeof(sessionname), "");
+
+	cedar = c->Cedar;
+
+	// ライセンス状況の取得
+	Zero(&license, sizeof(license));
+	if (c->Cedar->Server != NULL)
+	{
+		LiParseCurrentLicenseStatus(c->Cedar->Server->LicenseSystem, &license);
+	}
+
+	no_more_users_in_server = SiTooManyUserObjectsInServer(cedar->Server, true);
+
+	c->Status = CONNECTION_STATUS_NEGOTIATION;
+
+	if (c->Cedar->Server != NULL)
+	{
+		SERVER *s = c->Cedar->Server;
+		server = s;
+
+		if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+		{
+			farm_member = true;
+			farm_mode = true;
+		}
+
+		if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			farm_controller = true;
+			farm_mode = true;
+		}
+	}
+
+	// シグネチャを受信
+	Debug("Downloading Signature...\n");
+	if (ServerDownloadSignature(c) == false)
+	{
+		goto CLEANUP;
+	}
+
+	// Hello パケットを送信
+	Debug("Uploading Hello...\n");
+	if (ServerUploadHello(c) == false)
+	{
+		goto CLEANUP;
+	}
+
+	// 認証データを受信
+	Debug("Auth...\n");
+
+	p = HttpServerRecv(c->FirstSock);
+	if (p == NULL)
+	{
+		// 通信切断
+		c->Err = ERR_DISCONNECTED;
+		goto CLEANUP;
+	}
+
+	if (err = GetErrorFromPack(p))
+	{
+		// エラー発生
+		FreePack(p);
+		c->Err = err;
+		goto CLEANUP;
+	}
+
+	// メソッド取得
+	if (GetMethodFromPack(p, method, sizeof(method)) == false)
+	{
+		// プロトコルエラー
+		FreePack(p);
+		c->Err = ERR_PROTOCOL_ERROR;
+		goto CLEANUP;
+	}
+
+	// 時刻検査
+	timestamp = PackGetInt64(p, "timestamp");
+	if (timestamp != 0)
+	{
+		UINT64 now = SystemTime64();
+		UINT64 abs;
+		if (now >= timestamp)
+		{
+			abs = now - timestamp;
+		}
+		else
+		{
+			abs = timestamp - now;
+		}
+
+		if (abs > ALLOW_TIMESTAMP_DIFF)
+		{
+			// 時差が大きすぎる
+			FreePack(p);
+			c->Err = ERR_BAD_CLOCK;
+			goto CLEANUP;
+		}
+	}
+
+	// クライアントバージョン取得
+	PackGetStr(p, "client_str", c->ClientStr, sizeof(c->ClientStr));
+	c->ClientVer = PackGetInt(p, "client_ver");
+	c->ClientBuild = PackGetInt(p, "client_build");
+
+	if (SearchStrEx(c->ClientStr, "server", 0, false) != INFINITE ||
+		SearchStrEx(c->ClientStr, "bridge", 0, false) != INFINITE)
+	{
+		is_server_or_bridge = true;
+	}
+
+	// クライアント Windows バージョンの取得
+	InRpcWinVer(&winver, p);
+
+	DecrementNoSsl(c->Cedar, &c->FirstSock->RemoteIP, 2);
+
+	if (StrCmpi(method, "login") == 0)
+	{
+		bool auth_ret = false;
+
+		Debug("Login...\n");
+		c->Status = CONNECTION_STATUS_USERAUTH;
+
+		c->Type = CONNECTION_TYPE_LOGIN;
+
+		if (no_more_users_in_server)
+		{
+			// VPN Server に許可されているよりも多くのユーザーが存在する
+			FreePack(p);
+			c->Err = ERR_TOO_MANY_USER;
+			goto CLEANUP;
+		}
+
+		// クライアント名など
+		if (PackGetStr(p, "hello", c->ClientStr, sizeof(c->ClientStr)) == false)
+		{
+			StrCpy(c->ClientStr, sizeof(c->ClientStr), "Unknown");
+		}
+		c->ServerVer = CEDAR_VER;
+		c->ServerBuild = CEDAR_BUILD;
+
+		// NODE_INFO を取得する
+		Zero(&node, sizeof(node));
+		InRpcNodeInfo(&node, p);
+
+		// プロトコル
+		c->Protocol = GetProtocolFromPack(p);
+		if (c->Protocol == CONNECTION_UDP)
+		{
+			// TCP 関係の構造体を解放する
+			if (c->Tcp)
+			{
+				ReleaseList(c->Tcp->TcpSockList);
+				Free(c->Tcp);
+			}
+		}
+
+		if (GetServerCapsBool(c->Cedar->Server, "b_vpn_client_connect") == false)
+		{
+			// VPN クライアントが接続不可能である
+			FreePack(p);
+			c->Err = ERR_NOT_SUPPORTED;
+			goto CLEANUP;
+		}
+
+		// ログイン
+		if (GetHubnameAndUsernameFromPack(p, username, sizeof(username), hubname, sizeof(hubname)) == false)
+		{
+			// プロトコルエラー
+			FreePack(p);
+			c->Err = ERR_PROTOCOL_ERROR;
+			goto CLEANUP;
+		}
+
+		if (farm_member)
+		{
+			bool ok = false;
+			UINT authtype;
+
+			authtype = GetAuthTypeFromPack(p);
+			if (StrCmpi(username, ADMINISTRATOR_USERNAME) == 0 &&
+				authtype == AUTHTYPE_PASSWORD)
+			{
+				ok = true;
+			}
+
+			if (authtype == AUTHTYPE_TICKET)
+			{
+				ok = true;
+			}
+
+			if (ok == false)
+			{
+				// サーバーファームメンバへの Administrators 以外の直接ログオンは
+				// 禁止されている
+				FreePack(p);
+				SLog(c->Cedar, "LS_FARMMEMBER_NOT_ADMIN", c->Name, hubname, ADMINISTRATOR_USERNAME, username);
+				c->Err = ERR_ACCESS_DENIED;
+				goto CLEANUP;
+			}
+		}
+
+		Debug("Username = %s, HubName = %s\n", username, hubname);
+		LockHubList(c->Cedar);
+		{
+			hub = GetHub(c->Cedar, hubname);
+		}
+		UnlockHubList(c->Cedar);
+		if (hub == NULL)
+		{
+			// HUB が存在しない
+			FreePack(p);
+			c->Err = ERR_HUB_NOT_FOUND;
+			SLog(c->Cedar, "LS_HUB_NOT_FOUND", c->Name, hubname);
+			goto CLEANUP;
+		}
+
+		Lock(hub->lock);
+		{
+			USER *user;
+			USERGROUP *group;
+			if (hub->Halt || hub->Offline)
+			{
+				// HUB は停止中
+				FreePack(p);
+				Unlock(hub->lock);
+				ReleaseHub(hub);
+				c->Err = ERR_HUB_STOPPING;
+				goto CLEANUP;
+			}
+
+			// 各種フラグの取得
+			use_encrypt = PackGetInt(p, "use_encrypt") == 0 ? false : true;
+			use_compress = PackGetInt(p, "use_compress") == 0 ? false : true;
+			max_connection = PackGetInt(p, "max_connection");
+			half_connection = PackGetInt(p, "half_connection") == 0 ? false : true;
+			use_fast_rc4 = PackGetInt(p, "use_fast_rc4") == 0 ? false : true;
+			qos = PackGetInt(p, "qos") ? true : false;
+			client_id = PackGetInt(p, "client_id");
+
+			// 要求モード
+			require_bridge_routing_mode = PackGetBool(p, "require_bridge_routing_mode");
+			require_monitor_mode = PackGetBool(p, "require_monitor_mode");
+			if (require_monitor_mode)
+			{
+				qos = false;
+			}
+
+			if (is_server_or_bridge)
+			{
+				require_bridge_routing_mode = true;
+			}
+
+			// クライアントユニーク ID
+			Zero(unique, sizeof(unique));
+			if (PackGetDataSize(p, "unique_id") == SHA1_SIZE)
+			{
+				PackGetData(p, "unique_id", unique);
+			}
+
+			// 認証方法の取得
+			authtype = GetAuthTypeFromPack(p);
+
+			if (1)
+			{
+				// ログ
+				char ip1[64], ip2[64], verstr[64];
+				wchar_t *authtype_str = _UU("LH_AUTH_UNKNOWN");
+				switch (authtype)
+				{
+				case CLIENT_AUTHTYPE_ANONYMOUS:
+					authtype_str = _UU("LH_AUTH_ANONYMOUS");
+					break;
+				case CLIENT_AUTHTYPE_PASSWORD:
+					authtype_str = _UU("LH_AUTH_PASSWORD");
+					break;
+				case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+					authtype_str = _UU("LH_AUTH_PLAIN_PASSWORD");
+					break;
+				case CLIENT_AUTHTYPE_CERT:
+					authtype_str = _UU("LH_AUTH_CERT");
+					break;
+				case AUTHTYPE_TICKET:
+					authtype_str = _UU("LH_AUTH_TICKET");
+					break;
+				}
+				IPToStr(ip1, sizeof(ip1), &c->FirstSock->RemoteIP);
+				IPToStr(ip2, sizeof(ip2), &c->FirstSock->LocalIP);
+
+				Format(verstr, sizeof(verstr), "%u.%02u", c->ClientVer / 100, c->ClientVer % 100);
+
+				HLog(hub, "LH_CONNECT_CLIENT", c->Name, ip1, c->FirstSock->RemoteHostname, c->FirstSock->RemotePort,
+					c->ClientStr, verstr, c->ClientBuild, authtype_str, username);
+			}
+
+			// まず匿名認証を試行する
+			auth_ret = SamAuthUserByAnonymous(hub, username);
+
+			if (auth_ret)
+			{
+				// ユーザー認証成功
+				HLog(hub, "LH_AUTH_OK", c->Name, username);
+			}
+
+			if (auth_ret == false)
+			{
+				// 匿名認証に失敗した場合は他の認証方法を試行する
+				switch (authtype)
+				{
+				case CLIENT_AUTHTYPE_ANONYMOUS:
+					// 匿名認証 (すでに試行している)
+					break;
+
+				case AUTHTYPE_TICKET:
+					// チケット認証
+					if (PackGetDataSize(p, "ticket") == SHA1_SIZE)
+					{
+						PackGetData(p, "ticket", ticket);
+
+						auth_ret = SiCheckTicket(hub, ticket, username, sizeof(username), username_real, sizeof(username_real),
+							&ticketed_policy, sessionname, sizeof(sessionname), groupname, sizeof(groupname));
+					}
+					break;
+
+				case CLIENT_AUTHTYPE_PASSWORD:
+					// パスワード認証
+					if (PackGetDataSize(p, "secure_password") == SHA1_SIZE)
+					{
+						POLICY *pol = NULL;
+						UCHAR secure_password[SHA1_SIZE];
+						Zero(secure_password, sizeof(secure_password));
+						if (PackGetDataSize(p, "secure_password") == SHA1_SIZE)
+						{
+							PackGetData(p, "secure_password", secure_password);
+						}
+						auth_ret = SamAuthUserByPassword(hub, username, c->Random, secure_password);
+
+						pol = SamGetUserPolicy(hub, username);
+						if (pol != NULL)
+						{
+							no_save_password = pol->NoSavePassword;
+							Free(pol);
+						}
+					}
+					break;
+
+				case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+					// 外部サーバーによる認証はサポートされていない
+					HLog(hub, "LH_AUTH_RADIUS_NOT_SUPPORT", c->Name, username);
+					Unlock(hub->lock);
+					ReleaseHub(hub);
+					FreePack(p);
+					c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;
+					goto CLEANUP;
+
+				case CLIENT_AUTHTYPE_CERT:
+					// 証明書認証はサポートされていない
+					HLog(hub, "LH_AUTH_CERT_NOT_SUPPORT", c->Name, username);
+					Unlock(hub->lock);
+					ReleaseHub(hub);
+					FreePack(p);
+					c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;
+					goto CLEANUP;
+
+				default:
+					// 不明な認証方法
+					Unlock(hub->lock);
+					ReleaseHub(hub);
+					FreePack(p);
+					c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;
+					goto CLEANUP;
+				}
+
+				if (auth_ret == false)
+				{
+					// 認証失敗
+					HLog(hub, "LH_AUTH_NG", c->Name, username);
+				}
+				else
+				{
+					// 認証成功
+					HLog(hub, "LH_AUTH_OK", c->Name, username);
+				}
+			}
+
+			if (auth_ret == false)
+			{
+				// 認証失敗
+				Unlock(hub->lock);
+				ReleaseHub(hub);
+				FreePack(p);
+				c->Err = ERR_AUTH_FAILED;
+				goto CLEANUP;
+			}
+			else
+			{
+				if (authtype == CLIENT_AUTHTYPE_PASSWORD)
+				{
+					UCHAR test[SHA1_SIZE];
+					HashPassword(test, username, "");
+					if (Cmp(test, hub->SecurePassword, SHA1_SIZE) == 0)
+					{
+						SOCK *s = c->FirstSock;
+						if (s != NULL)
+						{
+							if (GetHubAdminOption(hub, "deny_empty_password") != 0 ||
+								(StrCmpi(username, ADMINISTRATOR_USERNAME) == 0 && s->RemoteIP.addr[0] != 127))
+							{
+								// パスワードが空のとき、リモートから接続してはいけない
+								HLog(hub, "LH_LOCAL_ONLY", c->Name, username);
+
+								Unlock(hub->lock);
+								ReleaseHub(hub);
+								FreePack(p);
+								c->Err = ERR_NULL_PASSWORD_LOCAL_ONLY;
+								goto CLEANUP;
+							}
+						}
+					}
+				}
+			}
+
+			policy = NULL;
+
+			// 認証成功
+			FreePack(p);
+
+			if (StrCmpi(username, ADMINISTRATOR_USERNAME) != 0)
+			{
+				// ポリシーを取得
+				if (farm_member == false)
+				{
+					// ファームメンバ以外の場合
+					user = AcGetUser(hub, username);
+					if (user == NULL)
+					{
+						user = AcGetUser(hub, "*");
+						if (user == NULL)
+						{
+							// ユーザー取得失敗
+							Unlock(hub->lock);
+							ReleaseHub(hub);
+							c->Err = ERR_ACCESS_DENIED;
+							goto CLEANUP;
+						}
+					}
+
+					policy = NULL;
+
+					Lock(user->lock);
+					{
+						// 有効期限を取得
+						user_expires = user->ExpireTime;
+
+						StrCpy(username_real, sizeof(username_real), user->Name);
+						group = user->Group;
+						if (group != NULL)
+						{
+							AddRef(group->ref);
+
+							Lock(group->lock);
+							{
+								// グループ名を取得
+								StrCpy(groupname, sizeof(groupname), group->Name);
+							}
+							Unlock(group->lock);
+						}
+
+						if (user->Policy != NULL)
+						{
+							policy = ClonePolicy(user->Policy);
+						}
+						else
+						{
+							if (group)
+							{
+								Lock(group->lock);
+								{
+									if (group->Policy != NULL)
+									{
+										policy = ClonePolicy(group->Policy);
+									}
+								}
+								Unlock(group->lock);
+							}
+						}
+
+						if (group != NULL)
+						{
+							ReleaseGroup(group);
+						}
+					}
+					Unlock(user->lock);
+					loggedin_user_object = user;
+				}
+				else
+				{
+					// ファームメンバの場合
+					policy = ClonePolicy(&ticketed_policy);
+				}
+			}
+			else
+			{
+				// 管理者モード
+				admin_mode = true;
+				StrCpy(username_real, sizeof(username_real), ADMINISTRATOR_USERNAME);
+
+				policy = ClonePolicy(GetDefaultPolicy());
+				policy->NoBroadcastLimiter = true;
+				policy->MonitorPort = true;
+			}
+
+			if (policy == NULL)
+			{
+				// デフォルトのポリシーを使用する
+				policy = ClonePolicy(GetDefaultPolicy());
+			}
+
+			if (policy->MaxConnection == 0)
+			{
+				policy->MaxConnection = MAX_TCP_CONNECTION;
+			}
+
+			if (policy->TimeOut == 0)
+			{
+				policy->TimeOut = 20;
+			}
+
+			if (qos)
+			{
+				// VoIP / QoS
+				if (policy->NoQoS)
+				{
+					// ポリシーが許可していない
+					qos = false;
+				}
+				if (GetServerCapsBool(c->Cedar->Server, "b_support_qos") == false)
+				{
+					// サーバーがサポートしていない
+					qos = false;
+					policy->NoQoS = true;
+				}
+				if (GetHubAdminOption(hub, "deny_qos") != 0)
+				{
+					// 管理オプションで禁止されている
+					qos = false;
+					policy->NoQoS = true;
+				}
+			}
+
+			if (GetHubAdminOption(hub, "max_bitrates_download") != 0)
+			{
+				if (policy->MaxDownload == 0)
+				{
+					policy->MaxDownload = GetHubAdminOption(hub, "max_bitrates_download");
+				}
+				else
+				{
+					policy->MaxDownload = MIN(policy->MaxDownload, GetHubAdminOption(hub, "max_bitrates_download"));
+				}
+			}
+
+			if (GetHubAdminOption(hub, "max_bitrates_upload") != 0)
+			{
+				if (policy->MaxUpload == 0)
+				{
+					policy->MaxUpload = GetHubAdminOption(hub, "max_bitrates_upload");
+				}
+				else
+				{
+					policy->MaxUpload = MIN(policy->MaxUpload, GetHubAdminOption(hub, "max_bitrates_upload"));
+				}
+			}
+
+			if (GetHubAdminOption(hub, "deny_bridge") != 0)
+			{
+				policy->NoBridge = true;
+			}
+
+			if (GetHubAdminOption(hub, "deny_routing") != 0)
+			{
+				policy->NoRouting = true;
+			}
+
+			if (hub->Option->ClientMinimumRequiredBuild > c->ClientBuild &&
+				 InStrEx(c->ClientStr, "client", false))
+			{
+				// クライアントのビルド番号が小さすぎる
+				HLog(hub, "LH_CLIENT_VERSION_OLD", c->Name, c->ClientBuild, hub->Option->ClientMinimumRequiredBuild);
+
+				Unlock(hub->lock);
+				ReleaseHub(hub);
+				c->Err = ERR_VERSION_INVALID;
+				Free(policy);
+				goto CLEANUP;
+			}
+
+			if (hub->Option->RequiredClientId != 0 &&
+				hub->Option->RequiredClientId != client_id && 
+				InStrEx(c->ClientStr, "client", false))
+			{
+				// クライアントのビルド番号が小さすぎる
+				HLog(hub, "LH_CLIENT_ID_REQUIRED", c->Name, client_id, hub->Option->RequiredClientId);
+
+				Unlock(hub->lock);
+				ReleaseHub(hub);
+				c->Err = ERR_CLIENT_ID_REQUIRED;
+				Free(policy);
+				goto CLEANUP;
+			}
+
+			if ((policy->NoSavePassword) || (policy->AutoDisconnect != 0))
+			{
+				if (c->ClientBuild < 6560 && InStrEx(c->ClientStr, "client", false))
+				{
+					// NoSavePassword ポリシーが指定されている場合は対応クライアント
+					// でなければ接続できない
+					HLog(hub, "LH_CLIENT_VERSION_OLD", c->Name, c->ClientBuild, 6560);
+
+					Unlock(hub->lock);
+					ReleaseHub(hub);
+					c->Err = ERR_VERSION_INVALID;
+					Free(policy);
+					goto CLEANUP;
+				}
+			}
+
+			if (user_expires != 0 && user_expires <= SystemTime64())
+			{
+				// 有効期限が切れている
+				// アクセスが拒否されている
+				HLog(hub, "LH_USER_EXPIRES", c->Name, username);
+
+				Unlock(hub->lock);
+				ReleaseHub(hub);
+				c->Err = ERR_ACCESS_DENIED;
+				Free(policy);
+				goto CLEANUP;
+			}
+
+			if (policy->Access == false)
+			{
+				// アクセスが拒否されている
+				HLog(hub, "LH_POLICY_ACCESS_NG", c->Name, username);
+
+				Unlock(hub->lock);
+				ReleaseHub(hub);
+				c->Err = ERR_ACCESS_DENIED;
+				Free(policy);
+				goto CLEANUP;
+			}
+
+			// ポリシーの内容をクライアントが要求したオプションと比較して
+			// 決定するか接続を拒否する
+			// 最初にモニタポートモードで接続できるかどうか確認する
+			if (require_monitor_mode && policy->MonitorPort == false)
+			{
+				// モニタポートモードで接続できない
+				HLog(hub, "LH_POLICY_MONITOR_MODE", c->Name);
+
+				Unlock(hub->lock);
+				ReleaseHub(hub);
+				c->Err = ERR_MONITOR_MODE_DENIED;
+				Free(policy);
+				goto CLEANUP;
+			}
+
+			if (policy->MonitorPort)
+			{
+				if (require_monitor_mode == false)
+				{
+					policy->MonitorPort = false;
+				}
+			}
+
+			if (policy->MonitorPort)
+			{
+				qos = false;
+			}
+
+			// 次にブリッジ / ルーティングモードで接続できるか確認する
+			if (require_bridge_routing_mode &&
+				(policy->NoBridge && policy->NoRouting))
+			{
+				// ブリッジ / ルーティングモードで接続できない
+				HLog(hub, "LH_POLICY_BRIDGE_MODE", c->Name);
+
+				Unlock(hub->lock);
+				ReleaseHub(hub);
+				c->Err = ERR_BRIDGE_MODE_DENIED;
+				Free(policy);
+				goto CLEANUP;
+			}
+
+			if (require_bridge_routing_mode == false)
+			{
+				policy->NoBridge = true;
+				policy->NoRouting = true;
+			}
+
+			// ライセンスが必要かどうかチェック
+			GenerateMachineUniqueHash(unique2);
+
+			if (Cmp(unique, unique2, SHA1_SIZE) == 0)
+			{
+				// ローカルホストセッションである
+				local_host_session = true;
+			}
+			else
+			{
+				if (license.NumUserLicense != INFINITE)
+				{
+					// ユーザー作成数が制限されているエディションでは多重ログイン禁止
+					policy->MultiLogins = 1;
+				}
+
+				if (policy->NoBridge == false || policy->NoRouting == false)
+				{
+					// ブリッジライセンスを消費
+					use_bridge_license = true;
+				}
+				else
+				{
+					// クライアントライセンスを消費
+					use_client_license = true;
+				}
+			}
+
+			if (server != NULL && server->ServerType != SERVER_TYPE_FARM_MEMBER &&
+				(use_bridge_license || use_client_license))
+			{
+				// クラスタコントローラまたはスタンドアロンサーバーの場合で
+				// クライアントにライセンスが必要になった場合、ここでライセンス数が
+				// 足りているかどうかを計算する
+
+				if (use_client_license)
+				{
+					if (server->CurrentAssignedClientLicense >= license.NumClientLicense)
+					{
+						// クライアント接続ライセンスが足りない
+						Unlock(hub->lock);
+
+						// 詳細エラーログを吐く
+						HLog(hub, "LH_NOT_ENOUGH_CLIENT_LICENSE", c->Name,
+							license.NumClientLicense,
+							server->CurrentAssignedClientLicense + 1);
+
+						ReleaseHub(hub);
+						c->Err = ERR_CLIENT_LICENSE_NOT_ENOUGH;
+						Free(policy);
+						goto CLEANUP;
+					}
+				}
+				if (use_bridge_license)
+				{
+					if (server->CurrentAssignedBridgeLicense >= license.NumBridgeLicense)
+					{
+						// ブリッジ接続ライセンス数が足りない
+						Unlock(hub->lock);
+
+						// 詳細エラーログを吐く
+						HLog(hub, "LH_NOT_ENOUGH_BRIDGE_LICENSE", c->Name,
+							license.NumBridgeLicense,
+							server->CurrentAssignedBridgeLicense + 1);
+
+						ReleaseHub(hub);
+						c->Err = ERR_BRIDGE_LICENSE_NOT_ENOUGH;
+						Free(policy);
+						goto CLEANUP;
+					}
+				}
+			}
+
+			if (server != NULL && server->ServerType != SERVER_TYPE_FARM_MEMBER &&
+				policy != NULL)
+			{
+				if (GetServerCapsBool(hub->Cedar->Server, "b_support_limit_multilogin"))
+				{
+					// ポリシーで多重ログイン制限数が指定されている場合は確認する
+					RPC_ENUM_SESSION t;
+					UINT i, num;
+					UINT max_logins = policy->MultiLogins;
+					UINT ao = GetHubAdminOption(hub, "max_multilogins_per_user");
+
+					if (ao != 0)
+					{
+						if (max_logins != 0)
+						{
+							max_logins = MIN(max_logins, ao);
+						}
+						else
+						{
+							max_logins = ao;
+						}
+					}
+
+					if (max_logins != 0)
+					{
+						Zero(&t, sizeof(t));
+						StrCpy(t.HubName, sizeof(t.HubName), hub->Name);
+
+						Unlock(hub->lock);
+
+						SiEnumSessionMain(server, &t);
+
+						Lock(hub->lock);
+
+						num = 0;
+
+						for (i = 0;i < t.NumSession;i++)
+						{
+							RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];
+
+							if (e->BridgeMode == false && e->Layer3Mode == false && e->LinkMode == false && e->CurrentNumTcp != 0)
+							{
+								if (StrCmpi(e->Username, username) == 0 &&
+									(IsZero(e->UniqueId, 16) || Cmp(e->UniqueId, node.UniqueId, 16) != 0))
+								{
+									num++;
+								}
+							}
+						}
+
+						FreeRpcEnumSession(&t);
+
+						if (num >= max_logins)
+						{
+							// これ以上接続できない
+							Unlock(hub->lock);
+
+							// 詳細エラーログを吐く
+							HLog(hub, license.NumUserLicense == INFINITE ? "LH_TOO_MANY_MULTILOGINS" : "LH_TOO_MANY_MULTILOGINS2",
+								c->Name,
+								username, max_logins, num);
+
+							ReleaseHub(hub);
+							c->Err = ERR_TOO_MANY_USER_SESSION;
+							Free(policy);
+							goto CLEANUP;
+						}
+					}
+				}
+			}
+
+			if (loggedin_user_object != NULL)
+			{
+				// ユーザー情報の更新
+				Lock(loggedin_user_object->lock);
+				{
+					loggedin_user_object->NumLogin++;
+					loggedin_user_object->LastLoginTime = SystemTime64();
+				}
+				Unlock(loggedin_user_object->lock);
+			}
+
+			// ログイン回数を更新する
+			hub->NumLogin++;
+			hub->LastCommTime = hub->LastLoginTime = SystemTime64();
+
+			if (farm_controller)
+			{
+				wchar_t *msg = GetHubMsg(hub);
+
+				Unlock(hub->lock);
+
+				Lock(cedar->CedarSuperLock);
+
+				// ファームコントローラの場合、この HUB をホスティングする
+				// ファームメンバを選定する
+				LockList(server->FarmMemberList);
+				{
+					HLog(hub, "LH_FARM_SELECT_1", c->Name);
+					f = SiGetHubHostingMember(server, hub, admin_mode);
+
+					if (f == NULL)
+					{
+						// 選定に失敗した
+						HLog(hub, "LH_FARM_SELECT_2", c->Name);
+						UnlockList(server->FarmMemberList);
+						Unlock(cedar->CedarSuperLock);
+						ReleaseHub(hub);
+						c->Err = ERR_COULD_NOT_HOST_HUB_ON_FARM;
+						Free(policy);
+						Free(msg);
+						goto CLEANUP;
+					}
+					else
+					{
+						if (f->Me == false)
+						{
+							UCHAR ticket[SHA1_SIZE];
+							PACK *p;
+							BUF *b;
+							UINT i;
+
+							SLog(c->Cedar, "LH_FARM_SELECT_4", c->Name, f->hostname);
+
+							// 選定したサーバーファームメンバにセッションを作成する
+							Rand(ticket, sizeof(ticket));
+							SiCallCreateTicket(server, f, hub->Name,
+								username, username_real, policy, ticket, Inc(hub->SessionCounter), groupname);
+
+							p = NewPack();
+							PackAddInt(p, "Redirect", 1);
+							PackAddIp32(p, "Ip", f->Ip);
+							for (i = 0;i < f->NumPort;i++)
+							{
+								PackAddIntEx(p, "Port", f->Ports[i], i, f->NumPort);
+							}
+							PackAddData(p, "Ticket", ticket, sizeof(ticket));
+
+							if (true)
+							{
+								char *utf = CopyUniToUtf(msg);
+
+								PackAddData(p, "Msg", utf, StrLen(utf));
+
+								Free(utf);
+							}
+
+							b = XToBuf(f->ServerCert, false);
+							PackAddBuf(p, "Cert", b);
+							FreeBuf(b);
+
+							UnlockList(server->FarmMemberList);
+							Unlock(cedar->CedarSuperLock);
+							ReleaseHub(hub);
+
+							HttpServerSend(c->FirstSock, p);
+							FreePack(p);
+
+							c->Err = 0;
+							Free(policy);
+
+							FreePack(HttpServerRecv(c->FirstSock));
+							Free(msg);
+							goto CLEANUP;
+						}
+						else
+						{
+							HLog(hub, "LH_FARM_SELECT_3", c->Name);
+							// 自分自身が選定されたのでこのまま続ける
+							UnlockList(server->FarmMemberList);
+							Unlock(cedar->CedarSuperLock);
+							f->Point = SiGetPoint(server);
+							Lock(hub->lock);
+							Free(msg);
+						}
+					}
+				}
+			}
+
+			if (admin_mode == false)
+			{
+				// HUB の最大接続数をチェック
+				if (hub->Option->MaxSession != 0 &&
+					hub->Option->MaxSession <= Count(hub->NumSessions))
+				{
+					// これ以上接続できない
+					Unlock(hub->lock);
+
+					HLog(hub, "LH_MAX_SESSION", c->Name, hub->Option->MaxSession);
+
+					ReleaseHub(hub);
+					c->Err = ERR_HUB_IS_BUSY;
+					Free(policy);
+					goto CLEANUP;
+				}
+			}
+
+			if (use_client_license || use_bridge_license)
+			{
+				// 仮想 HUB 管理オプションで規定された同時接続セッション数
+				// の制限に抵触しないかどうか調べる
+				if (
+					(GetHubAdminOption(hub, "max_sessions") != 0 &&
+					(Count(hub->NumSessionsClient) + Count(hub->NumSessionsBridge)) >= GetHubAdminOption(hub, "max_sessions"))
+					||
+					(hub->Option->MaxSession != 0 &&
+					(Count(hub->NumSessionsClient) + Count(hub->NumSessionsBridge)) >= hub->Option->MaxSession))
+				{
+					// これ以上接続できない
+					Unlock(hub->lock);
+
+					HLog(hub, "LH_MAX_SESSION", c->Name, GetHubAdminOption(hub, "max_sessions"));
+
+					ReleaseHub(hub);
+					c->Err = ERR_HUB_IS_BUSY;
+					Free(policy);
+					goto CLEANUP;
+				}
+			}
+
+			if (use_client_license)
+			{
+				// 仮想 HUB 管理オプションで規定された同時接続セッション数 (クライアント)
+				// の制限に抵触しないかどうか調べる
+				if (((GetHubAdminOption(hub, "max_sessions_client_bridge_apply") != 0 || license.CarrierEdition) &&
+					Count(hub->NumSessionsClient) >= GetHubAdminOption(hub, "max_sessions_client") && hub->Cedar->Server != NULL && hub->Cedar->Server->ServerType != SERVER_TYPE_FARM_MEMBER)
+					||
+					(hub->FarmMember_MaxSessionClientBridgeApply &&
+					Count(hub->NumSessionsClient) >= hub->FarmMember_MaxSessionClient))
+				{
+					// これ以上接続できない
+					Unlock(hub->lock);
+
+					HLog(hub, "LH_MAX_SESSION_CLIENT", c->Name, GetHubAdminOption(hub, "max_sessions_client"));
+
+					ReleaseHub(hub);
+					c->Err = ERR_HUB_IS_BUSY;
+					Free(policy);
+					goto CLEANUP;
+				}
+			}
+
+			if (use_bridge_license)
+			{
+				// 仮想 HUB 管理オプションで規定された同時接続セッション数 (ブリッジ)
+				// の制限に抵触しないかどうか調べる
+				if (((GetHubAdminOption(hub, "max_sessions_client_bridge_apply") != 0 || license.CarrierEdition) &&
+					Count(hub->NumSessionsBridge) >= GetHubAdminOption(hub, "max_sessions_bridge") && hub->Cedar->Server != NULL && hub->Cedar->Server->ServerType != SERVER_TYPE_FARM_MEMBER)
+					||
+					(hub->FarmMember_MaxSessionClientBridgeApply &&
+					Count(hub->NumSessionsBridge) >= hub->FarmMember_MaxSessionBridge))
+				{
+					// これ以上接続できない
+					Unlock(hub->lock);
+
+					HLog(hub, "LH_MAX_SESSION_BRIDGE", c->Name, GetHubAdminOption(hub, "max_sessions_bridge"));
+
+					ReleaseHub(hub);
+					c->Err = ERR_HUB_IS_BUSY;
+					Free(policy);
+					goto CLEANUP;
+				}
+			}
+
+			if (Count(hub->Cedar->CurrentSessions) >= GetServerCapsInt(hub->Cedar->Server, "i_max_sessions"))
+			{
+				// これ以上接続できない
+				Unlock(hub->lock);
+
+				HLog(hub, "LH_MAX_SESSION_2", c->Name, GetServerCapsInt(hub->Cedar->Server, "i_max_sessions"));
+
+				ReleaseHub(hub);
+				c->Err = ERR_HUB_IS_BUSY;
+				Free(policy);
+				goto CLEANUP;
+			}
+
+			// 現在の接続数をインクリメント
+			Inc(hub->NumSessions);
+			if (use_bridge_license)
+			{
+				Inc(hub->NumSessionsBridge);
+			}
+
+			if (use_client_license)
+			{
+				Inc(hub->NumSessionsClient);
+			}
+			Inc(hub->Cedar->CurrentSessions);
+
+			// タイムアウト時間を計算
+			timeout = policy->TimeOut * 1000;	// ミリ秒 → 秒 に変換
+			if (timeout == 0)
+			{
+				timeout = TIMEOUT_DEFAULT;
+			}
+			timeout = MIN(timeout, TIMEOUT_MAX);
+			timeout = MAX(timeout, TIMEOUT_MIN);
+
+			// ポリシーに応じて max_connection を更新
+			max_connection = MIN(max_connection, policy->MaxConnection);
+			max_connection = MIN(max_connection, MAX_TCP_CONNECTION);
+			max_connection = MAX(max_connection, 1);
+			if (half_connection)
+			{
+				// Half Connection 時にはコネクション数は 2 以上とする
+				max_connection = MAX(max_connection, 2);
+			}
+
+			if (qos)
+			{
+				// VoIP / QoS 使用時にはコネクション数は 2 以上とする
+				max_connection = MAX(max_connection, 2);
+				if (half_connection)
+				{
+					max_connection = MAX(max_connection, 4);
+				}
+			}
+
+			c->Status = CONNECTION_STATUS_ESTABLISHED;
+
+			// コネクションを Cedar から削除
+			DelConnection(c->Cedar, c);
+
+			// セッションの作成
+			StrLower(username);
+			s = NewServerSession(c->Cedar, c, hub, username, policy);
+
+			if (server != NULL)
+			{
+				s->NoSendSignature = server->NoSendSignature;
+			}
+
+			s->UseClientLicense = use_client_license;
+			s->UseBridgeLicense = use_bridge_license;
+
+			s->IsBridgeMode = (policy->NoBridge == false) || (policy->NoRouting == false);
+			s->IsMonitorMode = policy->MonitorPort;
+
+			// IPv6 セッションかどうかの判定
+			s->IPv6Session = false;
+
+			if (node.ClientIpAddress == 0)
+			{
+				s->IPv6Session = true;
+			}
+
+			if (use_bridge_license)
+			{
+				Inc(s->Cedar->AssignedBridgeLicense);
+			}
+
+			if (use_client_license)
+			{
+				Inc(s->Cedar->AssignedClientLicense);
+			}
+
+			if (server != NULL)
+			{
+				// Server 構造体の合計割り当て済みライセンス数の更新
+				if (server->ServerType == SERVER_TYPE_STANDALONE)
+				{
+					// スタンドアロンモードのみ更新
+					// (クラスタコントローラモードでは定期的にポーリングしている)
+					server->CurrentAssignedClientLicense = Count(s->Cedar->AssignedClientLicense);
+					server->CurrentAssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);
+				}
+			}
+
+			if (StrLen(sessionname) != 0)
+			{
+				// セッション名の指定
+				Free(s->Name);
+				s->Name = CopyStr(sessionname);
+			}
+
+			{
+				char ip[128];
+				IPToStr(ip, sizeof(ip), &c->FirstSock->RemoteIP);
+				HLog(hub, "LH_NEW_SESSION", c->Name, s->Name, ip, c->FirstSock->RemotePort);
+			}
+
+			c->Session = s;
+			s->AdministratorMode = admin_mode;
+			StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username_real);
+			StrCpy(s->GroupName, sizeof(s->GroupName), groupname);
+
+			// セッションキーの取得
+			Copy(session_key, s->SessionKey, SHA1_SIZE);
+
+			// パラメータをセット
+			s->MaxConnection = max_connection;
+			s->UseEncrypt = use_encrypt;
+			if (s->UseEncrypt && use_fast_rc4)
+			{
+				s->UseFastRC4 = use_fast_rc4;
+			}
+			s->UseCompress = use_compress;
+			s->HalfConnection = half_connection;
+			s->Timeout = timeout;
+			s->QoS = qos;
+
+			if (policy != NULL)
+			{
+				s->VLanId = policy->VLanId;
+			}
+
+			// ユーザー名
+			s->Username = CopyStr(username);
+
+			HLog(hub, "LH_SET_SESSION", s->Name, s->MaxConnection,
+				s->UseEncrypt ? _UU("L_YES") : _UU("L_NO"),
+				s->UseCompress ? _UU("L_YES") : _UU("L_NO"),
+				s->HalfConnection ? _UU("L_YES") : _UU("L_NO"),
+				s->Timeout / 1000);
+
+			msg = GetHubMsg(hub);
+		}
+		Unlock(hub->lock);
+
+		// クライアントに Welcome パケットを送信
+		p = PackWelcome(s);
+
+		if (true)
+		{
+			// VPN Client に表示するメッセージ
+			char *utf;
+			wchar_t winver_msg_client[3800];
+			wchar_t winver_msg_server[3800];
+			wchar_t *utvpn_msg;
+			UINT tmpsize;
+			wchar_t *tmp;
+			RPC_WINVER server_winver;
+
+			GetWinVer(&server_winver);
+
+			Zero(winver_msg_client, sizeof(winver_msg_client));
+			Zero(winver_msg_server, sizeof(winver_msg_server));
+
+			utvpn_msg = _UU("UTVPN_MSG");
+
+			if (IsSupportedWinVer(&winver) == false)
+			{
+				SYSTEMTIME st;
+
+				LocalTime(&st);
+
+				UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+					_UU("WINVER_ERROR_PC_LOCAL"),
+					winver.Title,
+					_UU("WINVER_ERROR_VPNSERVER"),
+					SUPPORTED_WINDOWS_LIST,
+					_UU("WINVER_ERROR_PC_LOCAL"),
+					_UU("WINVER_ERROR_VPNSERVER"),
+					_UU("WINVER_ERROR_VPNSERVER"),
+					_UU("WINVER_ERROR_VPNSERVER"),
+					st.wYear, st.wMonth);
+			}
+
+			if (IsSupportedWinVer(&server_winver) == false)
+			{
+				SYSTEMTIME st;
+
+				LocalTime(&st);
+
+				UniFormat(winver_msg_server, sizeof(winver_msg_server), _UU("WINVER_ERROR_FORMAT"),
+					_UU("WINVER_ERROR_PC_REMOTE"),
+					server_winver.Title,
+					_UU("WINVER_ERROR_VPNSERVER"),
+					SUPPORTED_WINDOWS_LIST,
+					_UU("WINVER_ERROR_PC_REMOTE"),
+					_UU("WINVER_ERROR_VPNSERVER"),
+					_UU("WINVER_ERROR_VPNSERVER"),
+					_UU("WINVER_ERROR_VPNSERVER"),
+					st.wYear, st.wMonth);
+			}
+
+			tmpsize = UniStrSize(winver_msg_client) + UniStrSize(winver_msg_server) + UniStrSize(utvpn_msg) + UniStrSize(msg) * 100;
+
+			tmp = ZeroMalloc(tmpsize);
+
+			if (IsURLMsg(msg, NULL, 0) == false)
+			{
+				UniStrCat(tmp, tmpsize, utvpn_msg);
+				UniStrCat(tmp, tmpsize, winver_msg_client);
+				UniStrCat(tmp, tmpsize, winver_msg_server);
+			}
+			UniStrCat(tmp, tmpsize, msg);
+			
+			utf = CopyUniToUtf(tmp);
+
+			PackAddData(p, "Msg", utf, StrLen(utf));
+
+			Free(tmp);
+			Free(utf);
+		}
+
+		Free(msg);
+
+		if (s->UseFastRC4)
+		{
+			// RC4 キーペアを生成
+			GenerateRC4KeyPair(&key_pair);
+
+			// Welcome パケットに追加
+			PackAddData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey, sizeof(key_pair.ClientToServerKey));
+			PackAddData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey, sizeof(key_pair.ServerToClientKey));
+			{
+				char key1[64], key2[64];
+				BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+				BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+				Debug(
+					"Client to Server Key: %s\n"
+					"Server to Client Key: %s\n",
+					key1, key2);
+			}
+		}
+		HttpServerSend(c->FirstSock, p);
+		FreePack(p);
+
+		Copy(&c->Session->NodeInfo, &node, sizeof(NODE_INFO));
+		{
+			wchar_t tmp[MAX_SIZE * 2];
+			NodeInfoToStr(tmp, sizeof(tmp), &s->NodeInfo);
+
+			HLog(hub, "LH_NODE_INFO", s->Name, tmp);
+		}
+
+		// コネクションをトンネリングモードに移行
+		StartTunnelingMode(c);
+
+		// ハーフコネクションモード時の処理
+		if (s->HalfConnection)
+		{
+			// 1 つ目のソケットはクライアント→サーバー 方向 とする
+			TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+			ts->Direction = TCP_CLIENT_TO_SERVER;
+		}
+
+		if (s->UseFastRC4)
+		{
+			// 1 つ目の TCP コネクションに RC4 キー情報をセットする
+			TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+			Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+			InitTcpSockRc4Key(ts, true);
+		}
+
+		if (s->UseEncrypt && s->UseFastRC4 == false)
+		{
+			s->UseSSLDataEncryption = true;
+		}
+		else
+		{
+			s->UseSSLDataEncryption = false;
+		}
+
+		if (s->Hub->Type == HUB_TYPE_FARM_DYNAMIC && s->Cedar->Server != NULL && s->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			if (s->Hub->BeingOffline == false)
+			{
+				// ダイナミック仮想 HUB で SecureNAT を開始
+				EnableSecureNATEx(s->Hub, false, true);
+
+				cluster_dynamic_secure_nat = true;
+			}
+		}
+
+		// セッションのメインルーチン
+		SessionMain(s);
+
+		// 現在の接続数をデクリメント
+		Lock(s->Hub->lock);
+		{
+			if (use_bridge_license)
+			{
+				Dec(hub->NumSessionsBridge);
+			}
+
+			if (use_client_license)
+			{
+				Dec(hub->NumSessionsClient);
+			}
+
+			Dec(s->Hub->NumSessions);
+			Dec(s->Hub->Cedar->CurrentSessions);
+
+			// ライセンス数のデクリメント
+			if (use_bridge_license)
+			{
+				Dec(s->Cedar->AssignedBridgeLicense);
+			}
+
+			if (use_client_license)
+			{
+				Dec(s->Cedar->AssignedClientLicense);
+			}
+
+			if (server != NULL)
+			{
+				// Server 構造体の合計割り当て済みライセンス数の更新
+				if (server->ServerType == SERVER_TYPE_STANDALONE)
+				{
+					// スタンドアロンモードのみ更新
+					// (クラスタコントローラモードでは定期的にポーリングしている)
+					server->CurrentAssignedClientLicense = Count(s->Cedar->AssignedClientLicense);
+					server->CurrentAssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);
+				}
+			}
+		}
+		Unlock(s->Hub->lock);
+
+		PrintSessionTotalDataSize(s);
+
+		HLog(s->Hub, "LH_END_SESSION", s->Name, s->TotalSendSizeReal, s->TotalRecvSizeReal);
+
+		if (cluster_dynamic_secure_nat && s->Hub->BeingOffline == false)
+		{
+			// ダイナミック仮想 HUB で SecureNAT を停止
+			EnableSecureNATEx(s->Hub, false, true);
+		}
+
+		ReleaseSession(s);
+
+		ret = true;
+		c->Err = ERR_SESSION_REMOVED;
+
+		ReleaseHub(hub);
+
+		goto CLEANUP;
+	}
+	else if (StrCmpi(method, "additional_connect") == 0)
+	{
+		SOCK *sock;
+		TCPSOCK *ts;
+		UINT dummy;
+
+		c->Type = CONNECTION_TYPE_ADDITIONAL;
+
+		// 追加接続
+		// セッションキーを読み出し
+		if (GetSessionKeyFromPack(p, session_key, &dummy) == false)
+		{
+			FreePack(p);
+			c->Err = ERR_PROTOCOL_ERROR;
+			goto CLEANUP;
+		}
+
+		FreePack(p);
+
+		// セッションキーからセッションを取得
+		s = GetSessionFromKey(c->Cedar, session_key);
+		if (s == NULL || s->Halt)
+		{
+			// セッションが発見できない
+			Debug("Session Not Found.\n");
+			c->Err = ERR_SESSION_TIMEOUT;
+			goto CLEANUP;
+		}
+
+		// セッションが見つかった
+		Debug("Session Found: %s\n", s->Name);
+		// セッションのプロトコルを確認
+		c->Err = 0;
+		Lock(s->lock);
+		{
+			if (s->Connection->Protocol != CONNECTION_TCP)
+			{
+				c->Err = ERR_INVALID_PROTOCOL;
+			}
+		}
+		Unlock(s->lock);
+		// セッションの現在のコネクション数を調べる
+		Lock(s->Connection->lock);
+		if (c->Err == 0)
+		{
+			if (Count(s->Connection->CurrentNumConnection) > s->MaxConnection)
+			{
+				c->Err = ERR_TOO_MANY_CONNECTION;
+			}
+		}
+		if (c->Err != 0)
+		{
+			Unlock(s->Connection->lock);
+			if (c->Err == ERR_TOO_MANY_CONNECTION)
+			{
+				Debug("Session TOO MANY CONNECTIONS !!: %u\n",
+					Count(s->Connection->CurrentNumConnection));
+			}
+			else
+			{
+				Debug("Session Invalid Protocol.\n");
+			}
+			ReleaseSession(s);
+			goto CLEANUP;
+		}
+
+		// RC4 高速暗号化鍵の生成
+		if (s->UseFastRC4)
+		{
+			GenerateRC4KeyPair(&key_pair);
+		}
+
+		// セッションのコネクションリスト (TCP) にこのコネクションのソケットを追加する
+		sock = c->FirstSock;
+		ts = NewTcpSock(sock);
+		SetTimeout(sock, CONNECTING_TIMEOUT);
+		direction = TCP_BOTH;
+		LockList(s->Connection->Tcp->TcpSockList);
+		{
+			if (s->HalfConnection)
+			{
+				// ハーフコネクション時、現在のすべての TCP コネクションの方向を
+				// 調べて自動的に調整する
+				UINT i, c2s, s2c;
+				c2s = s2c = 0;
+				for (i = 0;i < LIST_NUM(s->Connection->Tcp->TcpSockList);i++)
+				{
+					TCPSOCK *ts = (TCPSOCK *)LIST_DATA(s->Connection->Tcp->TcpSockList, i);
+					if (ts->Direction == TCP_SERVER_TO_CLIENT)
+					{
+						s2c++;
+					}
+					else
+					{
+						c2s++;
+					}
+				}
+				if (s2c > c2s)
+				{
+					direction = TCP_CLIENT_TO_SERVER;
+				}
+				else
+				{
+					direction = TCP_SERVER_TO_CLIENT;
+				}
+				Debug("%u/%u\n", s2c, c2s);
+				ts->Direction = direction;
+			}
+		}
+		UnlockList(s->Connection->Tcp->TcpSockList);
+
+		if (s->UseFastRC4)
+		{
+			// RC4 鍵情報の設定
+			Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+			InitTcpSockRc4Key(ts, true);
+		}
+
+		// 成功結果を返す
+		p = PackError(ERR_NO_ERROR);
+		PackAddInt(p, "direction", direction);
+
+		if (s->UseFastRC4)
+		{
+			// RC4 鍵情報の追加
+			PackAddData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey, sizeof(key_pair.ClientToServerKey));
+			PackAddData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey, sizeof(key_pair.ServerToClientKey));
+			{
+				char key1[64], key2[64];
+				BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+				BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+				Debug(
+					"Client to Server Key: %s\n"
+					"Server to Client Key: %s\n",
+					key1, key2);
+			}
+		}
+
+		HttpServerSend(c->FirstSock, p);
+		FreePack(p);
+
+		SetTimeout(sock, INFINITE);
+
+		LockList(s->Connection->Tcp->TcpSockList);
+		{
+			Add(s->Connection->Tcp->TcpSockList, ts);
+		}
+		UnlockList(s->Connection->Tcp->TcpSockList);
+
+		// コネクション数をインクリメントする
+		Inc(s->Connection->CurrentNumConnection);
+		Debug("TCP Connection Incremented: %u\n", Count(s->Connection->CurrentNumConnection));
+
+		// セッションの Cancel を発行する
+		Cancel(s->Cancel1);
+
+		Unlock(s->Connection->lock);
+
+		c->flag1 = true;
+
+		ReleaseSession(s);
+
+		return true;
+	}
+	else if (StrCmpi(method, "enum_hub") == 0)
+	{
+		// 仮想 HUB の列挙
+		UINT i, num;
+		LIST *o;
+		o = NewListFast(NULL);
+
+		c->Type = CONNECTION_TYPE_ENUM_HUB;
+
+		FreePack(p);
+		p = NewPack();
+		LockList(c->Cedar->HubList);
+		{
+			num = LIST_NUM(c->Cedar->HubList);
+			for (i = 0;i < num;i++)
+			{
+				HUB *h = LIST_DATA(c->Cedar->HubList, i);
+				if (h->Option != NULL && h->Option->NoEnum == false)
+				{
+					Insert(o, CopyStr(h->Name));
+				}
+			}
+		}
+		UnlockList(c->Cedar->HubList);
+
+		num = LIST_NUM(o);
+		for (i = 0;i < num;i++)
+		{
+			char *name = LIST_DATA(o, i);
+			PackAddStrEx(p, "HubName", name, i, num);
+			Free(name);
+		}
+		ReleaseList(o);
+		PackAddInt(p, "NumHub", num);
+
+		HttpServerSend(c->FirstSock, p);
+		FreePack(p);
+		FreePack(HttpServerRecv(c->FirstSock));
+		c->Err = 0;
+
+		SLog(c->Cedar, "LS_ENUM_HUB", c->Name, num);
+
+		goto CLEANUP;
+	}
+	else if (StrCmpi(method, "farm_connect") == 0)
+	{
+		// サーバーファーム接続要求
+		CEDAR *cedar = c->Cedar;
+		c->Type = CONNECTION_TYPE_FARM_RPC;
+		c->Err = 0;
+		if (c->Cedar->Server == NULL)
+		{
+			// サポートされていない
+			c->Err = ERR_NOT_FARM_CONTROLLER;
+		}
+		else
+		{
+			SERVER *s = c->Cedar->Server;
+			if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER || s->FarmControllerInited == false)
+			{
+				// ファームコントローラではない
+				SLog(c->Cedar, "LS_FARM_ACCEPT_1", c->Name);
+				c->Err = ERR_NOT_FARM_CONTROLLER;
+			}
+			else
+			{
+				UCHAR check_secure_password[SHA1_SIZE];
+				UCHAR secure_password[SHA1_SIZE];
+				// ユーザー認証
+				SecurePassword(check_secure_password, s->HashedPassword, c->Random);
+				if (PackGetDataSize(p, "SecurePassword") == sizeof(secure_password))
+				{
+					PackGetData(p, "SecurePassword", secure_password);
+				}
+				else
+				{
+					Zero(secure_password, sizeof(secure_password));
+				}
+
+				if (Cmp(secure_password, check_secure_password, SHA1_SIZE) != 0)
+				{
+					// パスワードが違う
+					SLog(c->Cedar, "LS_FARM_ACCEPT_2", c->Name);
+					c->Err = ERR_ACCESS_DENIED;
+				}
+				else
+				{
+					// 証明書を取得する
+					BUF *b;
+					X *server_x;
+
+					SLog(c->Cedar, "LS_FARM_ACCEPT_3", c->Name);
+					b = PackGetBuf(p, "ServerCert");
+					if (b == NULL)
+					{
+						c->Err = ERR_PROTOCOL_ERROR;
+					}
+					else
+					{
+						server_x = BufToX(b, false);
+						FreeBuf(b);
+						if (server_x == NULL)
+						{
+							c->Err = ERR_PROTOCOL_ERROR;
+						}
+						else
+						{
+							UINT ip;
+							UINT point;
+							char hostname[MAX_SIZE];
+
+#ifdef	OS_WIN32
+							MsSetThreadPriorityRealtime();
+#endif	// OS_WIN32
+
+							SetTimeout(c->FirstSock, SERVER_CONTROL_TCP_TIMEOUT);
+
+							ip = PackGetIp32(p, "PublicIp");
+							point = PackGetInt(p, "Point");
+							if (PackGetStr(p, "HostName", hostname, sizeof(hostname)))
+							{
+								UINT num_port = PackGetIndexCount(p, "PublicPort");
+								if (num_port >= 1 && num_port <= MAX_PUBLIC_PORT_NUM)
+								{
+									UINT *ports = ZeroMalloc(sizeof(UINT) * num_port);
+									UINT i;
+
+									for (i = 0;i < num_port;i++)
+									{
+										ports[i] = PackGetIntEx(p, "PublicPort", i);
+									}
+
+									SiFarmServ(s, c->FirstSock, server_x, ip, num_port, ports, hostname, point,
+										PackGetInt(p, "Weight"), PackGetInt(p, "MaxSessions"));
+
+									Free(ports);
+								}
+							}
+
+							FreeX(server_x);
+						}
+					}
+				}
+			}
+		}
+		FreePack(p);
+		goto CLEANUP;
+	}
+	else if (StrCmpi(method, "admin") == 0 && c->Cedar->Server != NULL)
+	{
+		UINT err;
+		// 管理用 RPC 接続要求
+		c->Type = CONNECTION_TYPE_ADMIN_RPC;
+		err = AdminAccept(c, p);
+		FreePack(p);
+		if (err != ERR_NO_ERROR)
+		{
+			PACK *p = PackError(err);
+			HttpServerSend(c->FirstSock, p);
+			FreePack(p);
+		}
+		goto CLEANUP;
+	}
+	else if (StrCmpi(method, "password") == 0)
+	{
+		UINT err;
+		// パスワード変更要求
+		c->Type = CONNECTION_TYPE_PASSWORD;
+		err = ChangePasswordAccept(c, p);
+		FreePack(p);
+
+		p = PackError(err);
+		HttpServerSend(c->FirstSock, p);
+		FreePack(p);
+		goto CLEANUP;
+	}
+	else
+	{
+		// 不明なメソッド
+		FreePack(p);
+		c->Err = ERR_PROTOCOL_ERROR;
+		goto CLEANUP;
+	}
+
+CLEANUP:
+	// ユーザーオブジェクトの解放
+	if (loggedin_user_object != NULL)
+	{
+		ReleaseUser(loggedin_user_object);
+	}
+
+	// エラーパケット送信
+	p = PackError(c->Err);
+	PackAddBool(p, "no_save_password", no_save_password);
+	HttpServerSend(c->FirstSock, p);
+	FreePack(p);
+
+	SLog(c->Cedar, "LS_CONNECTION_ERROR", c->Name, GetUniErrorStr(c->Err), c->Err);
+
+	return ret;
+}
+// シグネチャの送信 (TCP パケット) 用スレッド
+void SendSignatureByTcpThread(THREAD *thread, void *param)
+{
+	BUF *buf;
+	SEND_SIGNATURE_PARAM *p;
+	SOCK *s;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	p = (SEND_SIGNATURE_PARAM *)param;
+
+	AddWaitThread(thread);
+	NoticeThreadInit(thread);
+
+	buf = p->Buffer;
+
+	s = Connect(p->Hostname, p->Port);
+
+	if (s != NULL)
+	{
+		SendAll(s, buf->Buf, buf->Size, false);
+
+		Disconnect(s);
+		ReleaseSock(s);
+	}
+
+	DelWaitThread(thread);
+
+	FreeBuf(buf);
+	Free(p);
+}
+
+// シグネチャの送信 (TCP パケット)
+void SendSignatureByTcp(CONNECTION *c, IP *ip)
+{
+	NODE_INFO info;
+	BUF *b;
+	SEND_SIGNATURE_PARAM *param;
+	THREAD *t;
+	// 引数チェック
+	if (c == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	if (c->Session == NULL || c->Session->ClientOption == NULL)
+	{
+		return;
+	}
+
+	CreateNodeInfo(&info, c);
+
+	b = NewBuf();
+	WriteBuf(b, CEDAR_SIGNATURE_STR, StrLen(CEDAR_SIGNATURE_STR));
+	SeekBuf(b, 0, 0);
+
+	param = ZeroMalloc(sizeof(SEND_SIGNATURE_PARAM));
+	param->Buffer = b;
+
+	if (c->Session != NULL && c->Session->ClientOption != NULL)
+	{
+		CLIENT_OPTION *o = c->Session->ClientOption;
+
+		if (o->ProxyType == PROXY_DIRECT)
+		{
+			IPToStr(param->Hostname, sizeof(param->Hostname), ip);
+			param->Port = o->Port;
+		}
+		else
+		{
+			StrCpy(param->Hostname, sizeof(param->Hostname), o->ProxyName);
+			param->Port = o->ProxyPort;
+		}
+	}
+
+	t = NewThread(SendSignatureByTcpThread, param);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+}
+
+// ノード情報の作成
+void CreateNodeInfo(NODE_INFO *info, CONNECTION *c)
+{
+	SESSION *s;
+	OS_INFO *os;
+	char *product_id;
+	IP ip;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	s = c->Session;
+	os = GetOsInfo();
+
+	Zero(info, sizeof(NODE_INFO));
+
+	// クライアント製品名
+	StrCpy(info->ClientProductName, sizeof(info->ClientProductName), c->ClientStr);
+	// クライアントバージョン
+	info->ClientProductVer = Endian32(c->ClientVer);
+	// クライアントビルド番号
+	info->ClientProductBuild = Endian32(c->ClientBuild);
+
+	// サーバー製品名
+	StrCpy(info->ServerProductName, sizeof(info->ServerProductName), c->ServerStr);
+	// サーバーバージョン
+	info->ServerProductVer = Endian32(c->ServerVer);
+	// サーバービルド番号
+	info->ServerProductBuild = Endian32(c->ServerBuild);
+
+	// クライアント OS 名
+	StrCpy(info->ClientOsName, sizeof(info->ClientOsName), os->OsProductName);
+	// クライアント OS バージョン
+	StrCpy(info->ClientOsVer, sizeof(info->ClientOsVer), os->OsVersion);
+	// クライアント OS プロダクト ID
+	product_id = OSGetProductId();
+	StrCpy(info->ClientOsProductId, sizeof(info->ClientOsProductId), product_id);
+	Free(product_id);
+
+	// クライアントホスト名
+	GetMachineName(info->ClientHostname, sizeof(info->ClientHostname));
+	// クライアント IP アドレス
+	if (IsIP6(&c->FirstSock->LocalIP) == false)
+	{
+		info->ClientIpAddress = IPToUINT(&c->FirstSock->LocalIP);
+	}
+	else
+	{
+		Copy(info->ClientIpAddress6, c->FirstSock->LocalIP.ipv6_addr, sizeof(info->ClientIpAddress6));
+	}
+	// クライアントポート番号
+	info->ClientPort = Endian32(c->FirstSock->LocalPort);
+
+	// サーバーホスト名
+	StrCpy(info->ServerHostname, sizeof(info->ServerHostname), c->ServerName);
+	// サーバー IP アドレス
+	if (GetIP(&ip, info->ServerHostname))
+	{
+		if (IsIP6(&ip) == false)
+		{
+			info->ServerIpAddress = IPToUINT(&ip);
+		}
+		else
+		{
+			Copy(info->ServerIpAddress6, ip.ipv6_addr, sizeof(info->ServerIpAddress6));
+		}
+	}
+	// サーバーポート番号
+	info->ServerPort = Endian32(c->ServerPort);
+
+	if (s->ClientOption->ProxyType == PROXY_SOCKS || s->ClientOption->ProxyType == PROXY_HTTP)
+	{
+		// プロキシホスト名
+		StrCpy(info->ProxyHostname, sizeof(info->ProxyHostname), s->ClientOption->ProxyName);
+
+		// プロキシ IP アドレス
+		if (IsIP6(&c->FirstSock->RemoteIP) == false)
+		{
+			info->ProxyIpAddress = IPToUINT(&c->FirstSock->RemoteIP);
+		}
+		else
+		{
+			Copy(&info->ProxyIpAddress6, c->FirstSock->RemoteIP.ipv6_addr, sizeof(info->ProxyIpAddress6));
+		}
+
+		info->ProxyPort = Endian32(c->FirstSock->RemotePort);
+	}
+
+	// HUB 名
+	StrCpy(info->HubName, sizeof(info->HubName), s->ClientOption->HubName);
+
+	// ユニーク ID
+	Copy(info->UniqueId, c->Cedar->UniqueId, sizeof(info->UniqueId));
+}
+
+// ソケットを追加接続する
+SOCK *ClientAdditionalConnectToServer(CONNECTION *c)
+{
+	SOCK *s;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	// ソケット接続
+	s = ClientConnectGetSocket(c, true);
+	if (s == NULL)
+	{
+		// 接続失敗
+		return NULL;
+	}
+
+	// ソケットをリストに追加する
+	LockList(c->ConnectingSocks);
+	{
+		Add(c->ConnectingSocks, s);
+		AddRef(s->ref);
+	}
+	UnlockList(c->ConnectingSocks);
+
+	if (c->Session->Halt)
+	{
+		// 停止
+		Disconnect(s);
+		LockList(c->ConnectingSocks);
+		{
+			if (Delete(c->ConnectingSocks, s))
+			{
+				ReleaseSock(s);
+			}
+		}
+		UnlockList(c->ConnectingSocks);
+		ReleaseSock(s);
+		return NULL;
+	}
+
+	// タイムアウト
+	SetTimeout(s, CONNECTING_TIMEOUT);
+
+	// SSL 通信開始
+	if (StartSSLEx(s, NULL, NULL, (c->DontUseTls1 ? false : true)) == false)
+	{
+		// SSL 通信失敗
+		Disconnect(s);
+		LockList(c->ConnectingSocks);
+		{
+			if (Delete(c->ConnectingSocks, s))
+			{
+				ReleaseSock(s);
+			}
+		}
+		UnlockList(c->ConnectingSocks);
+		ReleaseSock(s);
+		return NULL;
+	}
+
+	// 証明書のチェック
+	if (CompareX(s->RemoteX, c->ServerX) == false)
+	{
+		// 証明書が不正
+		Disconnect(s);
+		c->Session->SessionTimeOuted = true;
+	}
+
+	return s;
+}
+
+// セキュアデバイス内の証明書と鍵を削除する
+UINT SecureDelete(UINT device_id, char *pin, char *cert_name, char *key_name)
+{
+	SECURE *sec;
+	// 引数チェック
+	if (pin == NULL || device_id == 0)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	// デバイスを開く
+	sec = OpenSec(device_id);
+	if (sec == NULL)
+	{
+		return ERR_SECURE_DEVICE_OPEN_FAILED;
+	}
+
+	// セッションを開く
+	if (OpenSecSession(sec, 0) == false)
+	{
+		CloseSec(sec);
+		return ERR_SECURE_DEVICE_OPEN_FAILED;
+	}
+
+	// ログイン
+	if (LoginSec(sec, pin) == false)
+	{
+		CloseSecSession(sec);
+		CloseSec(sec);
+		return ERR_SECURE_PIN_LOGIN_FAILED;
+	}
+
+	// 証明書削除
+	if (cert_name != NULL)
+	{
+		DeleteSecCert(sec, cert_name);
+	}
+
+	// 秘密鍵削除
+	if (key_name != NULL)
+	{
+		DeleteSecKey(sec, key_name);
+	}
+
+	// ログアウト
+	LogoutSec(sec);
+
+	// セッションを閉じる
+	CloseSecSession(sec);
+
+	// デバイスを閉じる
+	CloseSec(sec);
+
+	return ERR_NO_ERROR;
+}
+
+// セキュアデバイス内の証明書と鍵を列挙する
+UINT SecureEnum(UINT device_id, char *pin, TOKEN_LIST **cert_list, TOKEN_LIST **key_list)
+{
+	SECURE *sec;
+	LIST *o;
+	LIST *cert_name_list, *key_name_list;
+	// 引数チェック
+	if (pin == NULL || device_id == 0 || cert_list == NULL || key_list == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	// デバイスを開く
+	sec = OpenSec(device_id);
+	if (sec == NULL)
+	{
+		return ERR_SECURE_DEVICE_OPEN_FAILED;
+	}
+
+	// セッションを開く
+	if (OpenSecSession(sec, 0) == false)
+	{
+		CloseSec(sec);
+		return ERR_SECURE_DEVICE_OPEN_FAILED;
+	}
+
+	// ログイン
+	if (LoginSec(sec, pin) == false)
+	{
+		CloseSecSession(sec);
+		CloseSec(sec);
+		return ERR_SECURE_PIN_LOGIN_FAILED;
+	}
+
+	// オブジェクトの列挙
+	if ((o = EnumSecObject(sec)) != NULL)
+	{
+		UINT i;
+
+		cert_name_list = NewList(CompareStr);
+		key_name_list = NewList(CompareStr);
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			SEC_OBJ *obj = LIST_DATA(o, i);
+
+			if (obj->Type == SEC_X)
+			{
+				Add(cert_name_list, CopyStr(obj->Name));
+			}
+			else if (obj->Type == SEC_K)
+			{
+				Add(key_name_list, CopyStr(obj->Name));
+			}
+		}
+
+		Sort(cert_name_list);
+		Sort(key_name_list);
+
+		*cert_list = ListToTokenList(cert_name_list);
+		*key_list = ListToTokenList(key_name_list);
+
+		// メモリ解放
+		FreeStrList(cert_name_list);
+		FreeStrList(key_name_list);
+		FreeEnumSecObject(o);
+	}
+	else
+	{
+		*cert_list = NullToken();
+		*key_list = NullToken();
+	}
+
+	// ログアウト
+	LogoutSec(sec);
+
+	// セッションを閉じる
+	CloseSecSession(sec);
+
+	// デバイスを閉じる
+	CloseSec(sec);
+
+	return ERR_NO_ERROR;
+}
+
+// セキュアデバイスに証明書と鍵を記録する
+UINT SecureWrite(UINT device_id, char *cert_name, X *x, char *key_name, K *k, char *pin)
+{
+	SECURE *sec;
+	bool failed;
+	// 引数チェック
+	if (pin == NULL || device_id == 0 || cert_name == NULL || x == NULL || key_name == NULL || k == NULL)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	// デバイスを開く
+	sec = OpenSec(device_id);
+	if (sec == NULL)
+	{
+		return ERR_SECURE_DEVICE_OPEN_FAILED;
+	}
+
+	// セッションを開く
+	if (OpenSecSession(sec, 0) == false)
+	{
+		CloseSec(sec);
+		return ERR_SECURE_DEVICE_OPEN_FAILED;
+	}
+
+	// ログイン
+	if (LoginSec(sec, pin) == false)
+	{
+		CloseSecSession(sec);
+		CloseSec(sec);
+		return ERR_SECURE_PIN_LOGIN_FAILED;
+	}
+
+	// 登録
+	failed = false;
+
+	// 証明書の登録
+	if (WriteSecCert(sec, true, cert_name, x) == false)
+	{
+		failed = true;
+	}
+
+	// 秘密鍵の登録
+	if (WriteSecKey(sec, true, key_name, k) == false)
+	{
+		failed = true;
+	}
+
+	// ログアウト
+	LogoutSec(sec);
+
+	// セッションを閉じる
+	CloseSecSession(sec);
+
+	// デバイスを閉じる
+	CloseSec(sec);
+
+	if (failed == false)
+	{
+		// 成功
+		return ERR_NO_ERROR;
+	}
+	else
+	{
+		// 失敗
+		return ERR_SECURE_CANT_WRITE;
+	}
+}
+
+// セキュアデバイスによる署名を試行する
+UINT SecureSign(SECURE_SIGN *sign, UINT device_id, char *pin)
+{
+	SECURE *sec;
+	X *x;
+	// 引数チェック
+	if (sign == false || pin == NULL || device_id == 0)
+	{
+		return ERR_INTERNAL_ERROR;
+	}
+
+	// デバイスを開く
+	sec = OpenSec(device_id);
+	if (sec == NULL)
+	{
+		return ERR_SECURE_DEVICE_OPEN_FAILED;
+	}
+
+	// セッションを開く
+	if (OpenSecSession(sec, 0) == false)
+	{
+		CloseSec(sec);
+		return ERR_SECURE_DEVICE_OPEN_FAILED;
+	}
+
+	// ログイン
+	if (LoginSec(sec, pin) == false)
+	{
+		CloseSecSession(sec);
+		CloseSec(sec);
+		return ERR_SECURE_PIN_LOGIN_FAILED;
+	}
+
+	// 証明書の読み込み
+	x = ReadSecCert(sec, sign->SecurePublicCertName);
+	if (x == NULL)
+	{
+		LogoutSec(sec);
+		CloseSecSession(sec);
+		CloseSec(sec);
+		return ERR_SECURE_NO_CERT;
+	}
+
+	// 秘密鍵による署名
+	if (SignSec(sec, sign->SecurePrivateKeyName, sign->Signature, sign->Random, SHA1_SIZE) == false)
+	{
+		// 署名失敗
+		FreeX(x);
+		LogoutSec(sec);
+		CloseSecSession(sec);
+		CloseSec(sec);
+		return ERR_SECURE_NO_PRIVATE_KEY;
+	}
+
+	// 証明書をバッファに変換
+	sign->ClientCert = x;
+
+	// ログアウト
+	LogoutSec(sec);
+
+	// セッションを閉じる
+	CloseSecSession(sec);
+
+	// デバイスを閉じる
+	CloseSec(sec);
+
+	// 成功
+	return ERR_NO_ERROR;
+}
+
+// クライアントがサーバーに追加接続する
+bool ClientAdditionalConnect(CONNECTION *c, THREAD *t)
+{
+	SOCK *s;
+	PACK *p;
+	TCPSOCK *ts;
+	UINT err;
+	UINT direction;
+	RC4_KEY_PAIR key_pair;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	// サーバーにソケット接続
+	s = ClientAdditionalConnectToServer(c);
+	if (s == NULL)
+	{
+		// ソケット接続に失敗
+		return false;
+	}
+
+	if (c->Halt)
+	{
+		goto CLEANUP;
+	}
+
+	// シグネチャを送信
+	Debug("Uploading Signature...\n");
+	if (ClientUploadSignature(s) == false)
+	{
+		goto CLEANUP;
+	}
+
+	if (c->Halt)
+	{
+		// 停止
+		goto CLEANUP;
+	}
+
+	// Hello パケットを受信
+	Debug("Downloading Hello...\n");
+	if (ClientDownloadHello(c, s) == false)
+	{
+		goto CLEANUP;
+	}
+
+	if (c->Halt)
+	{
+		// 停止
+		goto CLEANUP;
+	}
+
+	// 追加接続用の認証データを送信
+	if (ClientUploadAuth2(c, s) == false)
+	{
+		// 切断された
+		goto CLEANUP;
+	}
+
+	// 応答を受信
+	p = HttpClientRecv(s);
+	if (p == NULL)
+	{
+		// 切断された
+		goto CLEANUP;
+	}
+
+	err = GetErrorFromPack(p);
+	direction = PackGetInt(p, "direction");
+
+	if (c->Session->UseFastRC4)
+	{
+		// RC4 鍵情報の取得
+		if (PackGetDataSize(p, "rc4_key_client_to_server") == 16)
+		{
+			PackGetData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey);
+		}
+		if (PackGetDataSize(p, "rc4_key_server_to_client") == 16)
+		{
+			PackGetData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey);
+		}
+		{
+			char key1[64], key2[64];
+			BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+			BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+			Debug(
+				"Client to Server Key: %s\n"
+				"Server to Client Key: %s\n",
+				key1, key2);
+		}
+	}
+
+	FreePack(p);
+	p = NULL;
+
+	if (err != 0)
+	{
+		// エラーが発生した
+		Debug("Additional Connect Error: %u\n", err);
+		if (err == ERR_SESSION_TIMEOUT || err == ERR_INVALID_PROTOCOL)
+		{
+			// 致命的なエラーなので再接続しなおすことにする
+			c->Session->SessionTimeOuted = true;
+		}
+		goto CLEANUP;
+	}
+
+	Debug("Additional Connect Succeed!\n");
+
+	// 追加接続成功
+	// コネクションの TcpSockList に追加する
+	ts = NewTcpSock(s);
+
+	if (c->ServerMode == false)
+	{
+		if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)
+		{
+			ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;
+		}
+	}
+
+	LockList(c->Tcp->TcpSockList);
+	{
+		ts->Direction = direction;
+		Add(c->Tcp->TcpSockList, ts);
+	}
+	UnlockList(c->Tcp->TcpSockList);
+	Debug("TCP Connection Incremented: %u\n", Count(c->CurrentNumConnection));
+
+	if (c->Session->HalfConnection)
+	{
+		Debug("New Half Connection: %s\n",
+			direction == TCP_SERVER_TO_CLIENT ? "TCP_SERVER_TO_CLIENT" : "TCP_CLIENT_TO_SERVER"
+			);
+	}
+
+	if (c->Session->UseFastRC4)
+	{
+		// RC4 暗号化鍵のセット
+		Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+		InitTcpSockRc4Key(ts, false);
+	}
+
+	// セッションに Cancel を発行する
+	Cancel(c->Session->Cancel1);
+
+	// 接続中のソケット一覧からこのソケットを削除
+	LockList(c->ConnectingSocks);
+	{
+		if (Delete(c->ConnectingSocks, s))
+		{
+			ReleaseSock(s);
+		}
+	}
+	UnlockList(c->ConnectingSocks);
+	ReleaseSock(s);
+	return true;
+
+CLEANUP:
+	// 切断処理
+	Disconnect(s);
+	LockList(c->ConnectingSocks);
+	{
+		if (Delete(c->ConnectingSocks, s))
+		{
+			ReleaseSock(s);
+
+		}
+	}
+	UnlockList(c->ConnectingSocks);
+	ReleaseSock(s);
+	return false;
+}
+
+// セキュアデバイス署名スレッド
+void ClientSecureSignThread(THREAD *thread, void *param)
+{
+	SECURE_SIGN_THREAD_PROC *p = (SECURE_SIGN_THREAD_PROC *)param;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	NoticeThreadInit(thread);
+
+	p->Ok = p->SecureSignProc(p->Connection->Session, p->Connection, p->SecureSign);
+	p->UserFinished = true;
+}
+
+// セキュアデバイスを使用した署名
+bool ClientSecureSign(CONNECTION *c, UCHAR *sign, UCHAR *random, X **x)
+{
+	SECURE_SIGN_THREAD_PROC *p;
+	SECURE_SIGN *ss;
+	SESSION *s;
+	CLIENT_OPTION *o;
+	CLIENT_AUTH *a;
+	THREAD *thread;
+	UINT64 start;
+	bool ret;
+	// 引数チェック
+	if (c == NULL || sign == NULL || random == NULL || x == NULL)
+	{
+		return false;
+	}
+
+	s = c->Session;
+	o = s->ClientOption;
+	a = s->ClientAuth;
+
+	p = ZeroMalloc(sizeof(SECURE_SIGN_THREAD_PROC));
+	p->Connection = c;
+	ss = p->SecureSign = ZeroMallocEx(sizeof(SECURE_SIGN), true);
+	StrCpy(ss->SecurePrivateKeyName, sizeof(ss->SecurePrivateKeyName),
+		a->SecurePrivateKeyName);
+	StrCpy(ss->SecurePublicCertName, sizeof(ss->SecurePublicCertName),
+		a->SecurePublicCertName);
+	ss->UseSecureDeviceId = c->Cedar->Client->UseSecureDeviceId;
+	Copy(ss->Random, random, SHA1_SIZE);
+
+#ifdef	OS_WIN32
+	ss->BitmapId = CmGetSecureBitmapId(c->ServerName);
+#endif	// OS_WIN32
+
+	p->SecureSignProc = a->SecureSignProc;
+
+	// スレッド作成
+	thread = NewThread(ClientSecureSignThread, p);
+	WaitThreadInit(thread);
+
+	// 署名が完了するかキャンセルするまで 0.5 秒ごとにポーリングする
+	start = Tick64();
+	while (true)
+	{
+		if ((Tick64() - start) > CONNECTING_POOLING_SPAN)
+		{
+			// 切断防止のため一定期間ごとに NOOP を送信する
+			start = Tick64();
+			ClientUploadNoop(c);
+		}
+		if (p->UserFinished)
+		{
+			// ユーザーが選択した
+			break;
+		}
+		WaitThread(thread, 500);
+	}
+	ReleaseThread(thread);
+
+	ret = p->Ok;
+
+	if (ret)
+	{
+		Copy(sign, ss->Signature, 128);
+		*x = ss->ClientCert;
+	}
+
+	Free(p->SecureSign);
+	Free(p);
+
+	return ret;
+}
+
+// サーバー証明書確認用スレッド
+void ClientCheckServerCertThread(THREAD *thread, void *param)
+{
+	CHECK_CERT_THREAD_PROC *p = (CHECK_CERT_THREAD_PROC *)param;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// 初期化完了を通知する
+	NoticeThreadInit(thread);
+
+	// ユーザーに選択を問い合わせる
+	p->Ok = p->CheckCertProc(p->Connection->Session, p->Connection, p->ServerX, &p->Exipred);
+	p->UserSelected = true;
+}
+
+// クライアントがサーバーの証明書を確認する
+bool ClientCheckServerCert(CONNECTION *c, bool *expired)
+{
+	CLIENT_AUTH *auth;
+	X *x;
+	CHECK_CERT_THREAD_PROC *p;
+	THREAD *thread;
+	CEDAR *cedar;
+	bool ret;
+	UINT64 start;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	if (expired != NULL)
+	{
+		*expired = false;
+	}
+
+	auth = c->Session->ClientAuth;
+	cedar = c->Cedar;
+
+	if (auth->CheckCertProc == NULL && c->Session->LinkModeClient == false)
+	{
+		// チェック関数無し
+		return true;
+	}
+
+	if (c->Session->LinkModeClient && c->Session->Link->CheckServerCert == false)
+	{
+		// カスケード接続モードだがサーバー証明書はチェックしない
+		return true;
+	}
+
+	if (c->UseTicket)
+	{
+		// リダイレクト先 VPN サーバーの証明書を確認する
+		if (CompareX(c->FirstSock->RemoteX, c->ServerX) == false)
+		{
+			return false;
+		}
+		else
+		{
+			return true;
+		}
+	}
+
+	x = CloneX(c->FirstSock->RemoteX);
+	if (x == NULL)
+	{
+		// 変なエラーが発生した
+		return false;
+	}
+
+	if (CheckXDateNow(x))
+	{
+		// 信頼するルート証明書によって署名されているかどうか確認する
+		if (c->Session->LinkModeClient == false)
+		{
+			// 通常の VPN Client モード
+			if (CheckSignatureByCa(cedar, x))
+			{
+				// 署名されているのでこの証明書は信頼できる
+				FreeX(x);
+				return true;
+			}
+		}
+		else
+		{
+			// カスケード接続モード
+			if (CheckSignatureByCaLinkMode(c->Session, x))
+			{
+				// 署名されているのでこの証明書は信頼できる
+				FreeX(x);
+				return true;
+			}
+		}
+	}
+
+	if (c->Session->LinkModeClient)
+	{
+		if (CheckXDateNow(x))
+		{
+			Lock(c->Session->Link->lock);
+			{
+				if (c->Session->Link->ServerCert != NULL)
+				{
+					if (CompareX(c->Session->Link->ServerCert, x))
+					{
+						Unlock(c->Session->Link->lock);
+						// カスケード接続設定に登録されている証明書と完全一致
+						FreeX(x);
+						return true;
+					}
+				}
+			}
+			Unlock(c->Session->Link->lock);
+		}
+		else
+		{
+			if (expired != NULL)
+			{
+				*expired = true;
+			}
+		}
+
+		// カスケード接続モードの場合はこの時点で検証失敗
+		FreeX(x);
+		return false;
+	}
+
+	p = ZeroMalloc(sizeof(CHECK_CERT_THREAD_PROC));
+	p->ServerX = x;
+	p->CheckCertProc = auth->CheckCertProc;
+	p->Connection = c;
+
+	// スレッドを作成する
+	thread = NewThread(ClientCheckServerCertThread, p);
+	WaitThreadInit(thread);
+
+	// ユーザーが接続の可否を選択するまで 0.5 秒間隔でポーリングする
+	start = Tick64();
+	while (true)
+	{
+		if ((Tick64() - start) > CONNECTING_POOLING_SPAN)
+		{
+			// 切断防止のため一定期間ごとに NOOP を送信する
+			start = Tick64();
+			ClientUploadNoop(c);
+		}
+		if (p->UserSelected)
+		{
+			// ユーザーが選択した
+			break;
+		}
+		WaitThread(thread, 500);
+	}
+
+	if (expired != NULL)
+	{
+		*expired = p->Exipred;
+	}
+
+	ret = p->Ok;
+	FreeX(p->ServerX);
+	Free(p);
+	ReleaseThread(thread);
+
+	return ret;
+}
+
+// クライアントがサーバーに接続する
+bool ClientConnect(CONNECTION *c)
+{
+	bool ret = false;
+	bool ok = false;
+	UINT err;
+	SOCK *s;
+	PACK *p = NULL;
+	UINT session_key_32;
+	SESSION *sess;
+	char session_name[MAX_SESSION_NAME_LEN + 1];
+	char connection_name[MAX_CONNECTION_NAME_LEN + 1];
+	UCHAR session_key[SHA1_SIZE];
+	RC4_KEY_PAIR key_pair;
+	POLICY *policy;
+	bool expired = false;
+	IP server_ip;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	sess = c->Session;
+
+	PrintStatus(sess, L"init");
+	PrintStatus(sess, _UU("STATUS_1"));
+
+REDIRECTED:
+
+	// [接続中]
+	c->Status = CONNECTION_STATUS_CONNECTING;
+	c->Session->ClientStatus = CLIENT_STATUS_CONNECTING;
+
+	s = ClientConnectToServer(c);
+	if (s == NULL)
+	{
+		PrintStatus(sess, L"free");
+		return false;
+	}
+
+	Copy(&server_ip, &s->RemoteIP, sizeof(IP));
+
+	if (c->Halt)
+	{
+		// 停止
+		c->Err = ERR_USER_CANCEL;
+		goto CLEANUP;
+	}
+
+	// [ネゴシエーション中]
+	c->Session->ClientStatus = CLIENT_STATUS_NEGOTIATION;
+
+	// シグネチャを送信
+	Debug("Uploading Signature...\n");
+	if (ClientUploadSignature(s) == false)
+	{
+		c->Err = ERR_DISCONNECTED;
+		goto CLEANUP;
+	}
+
+	if (c->Halt)
+	{
+		// 停止
+		c->Err = ERR_USER_CANCEL;
+		goto CLEANUP;
+	}
+
+	PrintStatus(sess, _UU("STATUS_5"));
+
+	// Hello パケットを受信
+	Debug("Downloading Hello...\n");
+	if (ClientDownloadHello(c, s) == false)
+	{
+		goto CLEANUP;
+	}
+
+	if (c->Session->ClientOption != NULL && c->Session->ClientOption->FromAdminPack)
+	{
+		if (IsAdminPackSupportedServerProduct(c->ServerStr) == false)
+		{
+			c->Err = ERR_NOT_ADMINPACK_SERVER;
+			goto CLEANUP;
+		}
+	}
+
+	if (c->Halt)
+	{
+		// 停止
+		c->Err = ERR_USER_CANCEL;
+		goto CLEANUP;
+	}
+
+	Debug("Server Version : %u\n"
+		"Server String  : %s\n"
+		"Server Build   : %u\n"
+		"Client Version : %u\n"
+		"Client String  : %s\n"
+		"Client Build   : %u\n",
+		c->ServerVer, c->ServerStr, c->ServerBuild,
+		c->ClientVer, c->ClientStr, c->ClientBuild);
+
+	// ユーザー認証中
+	c->Session->ClientStatus = CLIENT_STATUS_AUTH;
+
+	// クライアントによるサーバー証明書の確認
+	if (ClientCheckServerCert(c, &expired) == false)
+	{
+		if (expired == false)
+		{
+			c->Err = ERR_CERT_NOT_TRUSTED;
+		}
+		else
+		{
+			c->Err = ERR_SERVER_CERT_EXPIRES;
+		}
+
+		if (c->Session->LinkModeClient == false && c->Err == ERR_CERT_NOT_TRUSTED)
+		{
+			c->Session->ForceStopFlag = true;
+		}
+
+		goto CLEANUP;
+	}
+
+	PrintStatus(sess, _UU("STATUS_6"));
+
+	// 認証データを送信
+	if (ClientUploadAuth(c) == false)
+	{
+		goto CLEANUP;
+	}
+
+	if (c->Halt)
+	{
+		// 停止
+		c->Err = ERR_USER_CANCEL;
+		goto CLEANUP;
+	}
+
+	// Welcome パケットを受信
+	p = HttpClientRecv(s);
+	if (p == NULL)
+	{
+		c->Err = ERR_DISCONNECTED;
+		goto CLEANUP;
+	}
+
+	// エラーチェック
+	err = GetErrorFromPack(p);
+	if (err != 0)
+	{
+		// エラー発生
+		c->Err = err;
+		c->ClientConnectError_NoSavePassword = PackGetBool(p, "no_save_password");
+		goto CLEANUP;
+	}
+
+	// 接続制限のためのブランド化文字列チェック
+	{
+		char tmp[20];
+		char *branded_cfroms = _SS("BRANDED_C_FROM_S");
+		PackGetStr(p, "branded_cfroms", tmp, sizeof(tmp));
+
+		if(StrLen(branded_cfroms) > 0 && StrCmpi(branded_cfroms, tmp) != 0)
+		{
+			c->Err = ERR_BRANDED_C_FROM_S;
+			goto CLEANUP;
+		}
+	}
+
+	if (true)
+	{
+		// メッセージ取得
+		UINT utf_size;
+		char *utf;
+		wchar_t *msg;
+
+		utf_size = PackGetDataSize(p, "Msg");
+		utf = ZeroMalloc(utf_size + 8);
+		PackGetData(p, "Msg", utf);
+
+		msg = CopyUtfToUni(utf);
+
+		if (IsEmptyUniStr(msg) == false)
+		{
+			if (c->Session->Client_Message != NULL)
+			{
+				Free(c->Session->Client_Message);
+			}
+
+			c->Session->Client_Message = msg;
+		}
+		else
+		{
+			Free(msg);
+		}
+
+		Free(utf);
+	}
+
+	if (PackGetInt(p, "Redirect") != 0)
+	{
+		UINT i;
+		UINT ip;
+		UINT num_port;
+		UINT *ports;
+		UINT use_port = 0;
+		UINT current_port = c->ServerPort;
+		UCHAR ticket[SHA1_SIZE];
+		X *server_cert;
+		BUF *b;
+
+		// リダイレクトモード
+		PrintStatus(sess, _UU("STATUS_8"));
+
+		ip = PackGetIp32(p, "Ip");
+		num_port = MAX(MIN(PackGetIndexCount(p, "Port"), MAX_PUBLIC_PORT_NUM), 1);
+		ports = ZeroMalloc(sizeof(UINT) * num_port);
+		for (i = 0;i < num_port;i++)
+		{
+			ports[i] = PackGetIntEx(p, "Port", i);
+		}
+
+		// ポート番号を選定する
+		for (i = 0;i < num_port;i++)
+		{
+			if (ports[i] == current_port)
+			{
+				use_port = current_port;
+			}
+		}
+		if (use_port == 0)
+		{
+			use_port = ports[0];
+		}
+
+		Free(ports);
+
+		if (PackGetDataSize(p, "Ticket") == SHA1_SIZE)
+		{
+			PackGetData(p, "Ticket", ticket);
+		}
+
+		b = PackGetBuf(p, "Cert");
+		if (b != NULL)
+		{
+			server_cert = BufToX(b, false);
+			FreeBuf(b);
+		}
+
+		if (c->ServerX != NULL)
+		{
+			FreeX(c->ServerX);
+		}
+		c->ServerX = server_cert;
+
+		IPToStr32(c->ServerName, sizeof(c->ServerName), ip);
+		c->ServerPort = use_port;
+
+		c->UseTicket = true;
+		Copy(c->Ticket, ticket, SHA1_SIZE);
+
+		FreePack(p);
+
+		p = NewPack();
+		HttpClientSend(s, p);
+		FreePack(p);
+
+		p = NULL;
+
+		c->FirstSock = NULL;
+		Disconnect(s);
+		ReleaseSock(s);
+		s = NULL;
+
+		goto REDIRECTED;
+	}
+
+	PrintStatus(sess, _UU("STATUS_7"));
+
+	// Welcome パケットをパース
+	if (ParseWelcomeFromPack(p, session_name, sizeof(session_name),
+		connection_name, sizeof(connection_name), &policy) == false)
+	{
+		// パース失敗
+		c->Err = ERR_PROTOCOL_ERROR;
+		goto CLEANUP;
+	}
+
+	// セッションキーを取得
+	if (GetSessionKeyFromPack(p, session_key, &session_key_32) == false)
+	{
+		// 取得失敗
+		Free(policy);
+		policy = NULL;
+		c->Err = ERR_PROTOCOL_ERROR;
+		goto CLEANUP;
+	}
+
+	Copy(c->Session->SessionKey, session_key, SHA1_SIZE);
+	c->Session->SessionKey32 = session_key_32;
+
+	// Welcome パケットの内容を保存
+	Debug("session_name: %s, connection_name: %s\n",
+		session_name, connection_name);
+
+	Lock(c->Session->lock);
+	{
+		// 接続パラメータの展開と更新
+		c->Session->MaxConnection = PackGetInt(p, "max_connection");
+		c->Session->MaxConnection = MIN(c->Session->MaxConnection, c->Session->ClientOption->MaxConnection);
+		c->Session->MaxConnection = MIN(c->Session->MaxConnection, MAX_TCP_CONNECTION);
+		c->Session->MaxConnection = MAX(c->Session->MaxConnection, 1);
+		c->Session->UseCompress = PackGetInt(p, "use_compress") == 0 ? false : true;
+		c->Session->UseEncrypt = PackGetInt(p, "use_encrypt") == 0 ? false : true;
+		c->Session->NoSendSignature = PackGetBool(p, "no_send_signature");
+		if (c->Session->UseEncrypt)
+		{
+			c->Session->UseFastRC4 = PackGetInt(p, "use_fast_rc4") == 0 ? false : true;
+		}
+		c->Session->HalfConnection = PackGetInt(p, "half_connection") == 0 ? false : true;
+		c->Session->Timeout = PackGetInt(p, "timeout");
+		c->Session->QoS = PackGetInt(p, "qos") == 0 ? false : true;
+		if (c->Session->QoS)
+		{
+			c->Session->MaxConnection = MAX(c->Session->MaxConnection, (UINT)(c->Session->HalfConnection ? 4 : 2));
+		}
+		c->Session->VLanId = PackGetInt(p, "vlan_id");
+
+		if (c->Protocol == CONNECTION_UDP)
+		{
+			// UDP プロトコルの場合、サーバーから鍵を受け取る
+			if (PackGetDataSize(p, "udp_send_key") == sizeof(c->Session->UdpSendKey))
+			{
+				PackGetData(p, "udp_send_key", c->Session->UdpSendKey);
+			}
+
+			if (PackGetDataSize(p, "udp_recv_key") == sizeof(c->Session->UdpRecvKey))
+			{
+				PackGetData(p, "udp_recv_key", c->Session->UdpRecvKey);
+			}
+		}
+
+		if (c->Session->UseFastRC4)
+		{
+			// RC4 鍵情報の取得
+			if (PackGetDataSize(p, "rc4_key_client_to_server") == 16)
+			{
+				PackGetData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey);
+			}
+			if (PackGetDataSize(p, "rc4_key_server_to_client") == 16)
+			{
+				PackGetData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey);
+			}
+			{
+				char key1[64], key2[64];
+				BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+				BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+				Debug(
+					"Client to Server Key: %s\n"
+					"Server to Client Key: %s\n",
+					key1, key2);
+			}
+		}
+	}
+	Unlock(c->Session->lock);
+
+	Lock(c->lock);
+	{
+		if (c->Name != NULL)
+		{
+			Free(c->Name);
+		}
+		c->Name = CopyStr(connection_name);
+
+		// 暗号化アルゴリズム名の保存
+		if (c->CipherName != NULL)
+		{
+			Free(c->CipherName);
+		}
+
+		c->CipherName = CopyStr(c->FirstSock->CipherName);
+	}
+	Unlock(c->lock);
+
+	Lock(c->Session->lock);
+	{
+		if (c->Session->Name != NULL)
+		{
+			Free(c->Session->Name);
+		}
+		c->Session->Name = CopyStr(session_name);
+
+		c->Session->Policy = policy;
+	}
+	Unlock(c->Session->lock);
+
+	// Welcome パケットを破棄
+	FreePack(p);
+	p = NULL;
+
+	// server_ip に対して TCP でシグネチャを送信
+	if (c->Session->NoSendSignature == false)
+	{
+		SendSignatureByTcp(c, &server_ip);
+	}
+
+	// コネクション確立
+	c->Session->ClientStatus = CLIENT_STATUS_ESTABLISHED;
+
+	// サーバー証明書の保存
+	if (c->ServerX == NULL)
+	{
+		c->ServerX = CloneX(c->FirstSock->RemoteX);
+	}
+
+	PrintStatus(sess, _UU("STATUS_9"));
+
+	// コネクションをトンネリングモードに移行
+	StartTunnelingMode(c);
+	s = NULL;
+
+	if (c->Session->HalfConnection)
+	{
+		// ハーフコネクション時の処理
+		TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+		ts->Direction = TCP_CLIENT_TO_SERVER;
+	}
+
+	if (c->Session->UseFastRC4)
+	{
+		// RC4 高速暗号化鍵のセット
+		TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+		Copy(&ts->Rc4KeyPair, &key_pair, sizeof(key_pair));
+
+		InitTcpSockRc4Key(ts, false);
+	}
+
+	// SSL 暗号化フラグ
+	if (c->Session->UseEncrypt && c->Session->UseFastRC4 == false)
+	{
+		c->Session->UseSSLDataEncryption = true;
+	}
+	else
+	{
+		c->Session->UseSSLDataEncryption = false;
+	}
+
+	PrintStatus(sess, L"free");
+
+	CLog(c->Cedar->Client, "LC_CONNECT_2", c->Session->ClientOption->AccountName,
+		session_name);
+
+	if (c->Session->LinkModeClient && c->Session->Link != NULL)
+	{
+		HLog(c->Session->Link->Hub, "LH_CONNECT_2", c->Session->ClientOption->AccountName, session_name);
+	}
+
+	// セッションのメインルーチン
+	SessionMain(c->Session);
+
+	ok = true;
+
+	if (c->Err == ERR_USER_CANCEL)
+	{
+		ret = true;
+	}
+
+CLEANUP:
+	c->FirstSock = NULL;
+
+	if (p != NULL)
+	{
+		FreePack(p);
+	}
+
+	Disconnect(s);
+	ReleaseSock(s);
+
+	Debug("Error: %u\n", c->Err);
+
+	if (ok == false)
+	{
+		PrintStatus(sess, L"free");
+	}
+
+	return ret;
+}
+
+// Welcome パケットのパース
+bool ParseWelcomeFromPack(PACK *p, char *session_name, UINT session_name_size,
+						  char *connection_name, UINT connection_name_size,
+						  POLICY **policy)
+{
+	// 引数チェック
+	if (p == NULL || session_name == NULL || connection_name == NULL || policy == NULL)
+	{
+		return false;
+	}
+
+	// セッション名
+	if (PackGetStr(p, "session_name", session_name, session_name_size) == false)
+	{
+		return false;
+	}
+
+	// コネクション名
+	if (PackGetStr(p, "connection_name", connection_name, connection_name_size) == false)
+	{
+		return false;
+	}
+
+	// ポリシー
+	*policy = PackGetPolicy(p);
+	if (*policy == NULL)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// Welcome パケットの生成
+PACK *PackWelcome(SESSION *s)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+
+	// セッション名
+	PackAddStr(p, "session_name", s->Name);
+
+	// コネクション名
+	PackAddStr(p, "connection_name", s->Connection->Name);
+
+	// パラメータ
+	PackAddInt(p, "max_connection", s->MaxConnection);
+	PackAddInt(p, "use_encrypt", s->UseEncrypt == false ? 0 : 1);
+	PackAddInt(p, "use_fast_rc4", s->UseFastRC4 == false ? 0 : 1);
+	PackAddInt(p, "use_compress", s->UseCompress == false ? 0 : 1);
+	PackAddInt(p, "half_connection", s->HalfConnection == false ? 0 : 1);
+	PackAddInt(p, "timeout", s->Timeout);
+	PackAddInt(p, "qos", s->QoS ? 1 : 0);
+
+	// セッションキー
+	PackAddData(p, "session_key", s->SessionKey, SHA1_SIZE);
+	PackAddInt(p, "session_key_32", s->SessionKey32);
+
+	// ポリシー
+	PackAddPolicy(p, s->Policy);
+
+	// VLAN ID
+	PackAddInt(p, "vlan_id", s->VLanId);
+
+	if (s->Connection->Protocol == CONNECTION_UDP)
+	{
+		// UDP プロトコルの場合、2 組のキーを生成する
+		Rand(s->UdpSendKey, sizeof(s->UdpSendKey));
+		Rand(s->UdpRecvKey, sizeof(s->UdpRecvKey));
+
+		// クライアントには鍵を反転して送る
+		PackAddData(p, "udp_send_key", s->UdpRecvKey, sizeof(s->UdpRecvKey));
+		PackAddData(p, "udp_recv_key", s->UdpSendKey, sizeof(s->UdpSendKey));
+	}
+
+	// no_send_signature
+	if (s->NoSendSignature)
+	{
+		PackAddBool(p, "no_send_signature", true);
+	}
+
+	return p;
+}
+
+#define	PACK_ADD_POLICY_BOOL(name, value)	\
+	PackAddInt(p, "policy:" name, y->value == false ? 0 : 1)
+#define	PACK_ADD_POLICY_UINT(name, value)	\
+	PackAddInt(p, "policy:" name, y->value)
+#define	PACK_GET_POLICY_BOOL(name, value)	\
+	y->value = (PackGetInt(p, "policy:" name) == 0 ? false : true)
+#define	PACK_GET_POLICY_UINT(name, value)	\
+	y->value = PackGetInt(p, "policy:" name)
+
+// セッションキーを PACK から取得
+bool GetSessionKeyFromPack(PACK *p, UCHAR *session_key, UINT *session_key_32)
+{
+	// 引数チェック
+	if (p == NULL || session_key == NULL || session_key_32 == NULL)
+	{
+		return false;
+	}
+
+	if (PackGetDataSize(p, "session_key") != SHA1_SIZE)
+	{
+		return false;
+	}
+	if (PackGetData(p, "session_key", session_key) == false)
+	{
+		return false;
+	}
+	*session_key_32 = PackGetInt(p, "session_key_32");
+
+	return true;
+}
+
+// ポリシーを PACK から取得
+POLICY *PackGetPolicy(PACK *p)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	POLICY *y;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return NULL;
+	}
+
+	y = ZeroMalloc(sizeof(POLICY));
+
+	// bool 値
+	// Ver 2
+	PACK_GET_POLICY_BOOL("Access", Access);
+	PACK_GET_POLICY_BOOL("DHCPFilter", DHCPFilter);
+	PACK_GET_POLICY_BOOL("DHCPNoServer", DHCPNoServer);
+	PACK_GET_POLICY_BOOL("DHCPForce", DHCPForce);
+	PACK_GET_POLICY_BOOL("NoBridge", NoBridge);
+	PACK_GET_POLICY_BOOL("NoRouting", NoRouting);
+	PACK_GET_POLICY_BOOL("PrivacyFilter", PrivacyFilter);
+	PACK_GET_POLICY_BOOL("NoServer", NoServer);
+	PACK_GET_POLICY_BOOL("CheckMac", CheckMac);
+	PACK_GET_POLICY_BOOL("CheckIP", CheckIP);
+	PACK_GET_POLICY_BOOL("ArpDhcpOnly", ArpDhcpOnly);
+	PACK_GET_POLICY_BOOL("MonitorPort", MonitorPort);
+	PACK_GET_POLICY_BOOL("NoBroadcastLimiter", NoBroadcastLimiter);
+	PACK_GET_POLICY_BOOL("FixPassword", FixPassword);
+	PACK_GET_POLICY_BOOL("NoQoS", NoQoS);
+	// Ver 3
+	PACK_GET_POLICY_BOOL("RSandRAFilter", RSandRAFilter);
+	PACK_GET_POLICY_BOOL("RAFilter", RAFilter);
+	PACK_GET_POLICY_BOOL("DHCPv6Filter", DHCPv6Filter);
+	PACK_GET_POLICY_BOOL("DHCPv6NoServer", DHCPv6NoServer);
+	PACK_GET_POLICY_BOOL("NoRoutingV6", NoRoutingV6);
+	PACK_GET_POLICY_BOOL("CheckIPv6", CheckIPv6);
+	PACK_GET_POLICY_BOOL("NoServerV6", NoServerV6);
+	PACK_GET_POLICY_BOOL("NoSavePassword", NoSavePassword);
+	PACK_GET_POLICY_BOOL("FilterIPv4", FilterIPv4);
+	PACK_GET_POLICY_BOOL("FilterIPv6", FilterIPv6);
+	PACK_GET_POLICY_BOOL("FilterNonIP", FilterNonIP);
+	PACK_GET_POLICY_BOOL("NoIPv6DefaultRouterInRA", NoIPv6DefaultRouterInRA);
+	PACK_GET_POLICY_BOOL("NoIPv6DefaultRouterInRAWhenIPv6", NoIPv6DefaultRouterInRAWhenIPv6);
+
+	// UINT 値
+	// Ver 2
+	PACK_GET_POLICY_UINT("MaxConnection", MaxConnection);
+	PACK_GET_POLICY_UINT("TimeOut", TimeOut);
+	PACK_GET_POLICY_UINT("MaxMac", MaxMac);
+	PACK_GET_POLICY_UINT("MaxIP", MaxIP);
+	PACK_GET_POLICY_UINT("MaxUpload", MaxUpload);
+	PACK_GET_POLICY_UINT("MaxDownload", MaxDownload);
+	PACK_GET_POLICY_UINT("MultiLogins", MultiLogins);
+	// Ver 3
+	PACK_GET_POLICY_UINT("MaxIPv6", MaxIPv6);
+	PACK_GET_POLICY_UINT("AutoDisconnect", AutoDisconnect);
+	PACK_GET_POLICY_UINT("VLanId", VLanId);
+
+	// Ver 3 フラグ
+	PACK_GET_POLICY_BOOL("Ver3", Ver3);
+
+	return y;
+}
+
+// ポリシーを PACK に挿入
+void PackAddPolicy(PACK *p, POLICY *y)
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	// 引数チェック
+	if (p == NULL || y == NULL)
+	{
+		return;
+	}
+
+	// bool 値
+	// Ver 2
+	PACK_ADD_POLICY_BOOL("Access", Access);
+	PACK_ADD_POLICY_BOOL("DHCPFilter", DHCPFilter);
+	PACK_ADD_POLICY_BOOL("DHCPNoServer", DHCPNoServer);
+	PACK_ADD_POLICY_BOOL("DHCPForce", DHCPForce);
+	PACK_ADD_POLICY_BOOL("NoBridge", NoBridge);
+	PACK_ADD_POLICY_BOOL("NoRouting", NoRouting);
+	PACK_ADD_POLICY_BOOL("PrivacyFilter", PrivacyFilter);
+	PACK_ADD_POLICY_BOOL("NoServer", NoServer);
+	PACK_ADD_POLICY_BOOL("CheckMac", CheckMac);
+	PACK_ADD_POLICY_BOOL("CheckIP", CheckIP);
+	PACK_ADD_POLICY_BOOL("ArpDhcpOnly", ArpDhcpOnly);
+	PACK_ADD_POLICY_BOOL("MonitorPort", MonitorPort);
+	PACK_ADD_POLICY_BOOL("NoBroadcastLimiter", NoBroadcastLimiter);
+	PACK_ADD_POLICY_BOOL("FixPassword", FixPassword);
+	PACK_ADD_POLICY_BOOL("NoQoS", NoQoS);
+	// Ver 3
+	PACK_ADD_POLICY_BOOL("RSandRAFilter", RSandRAFilter);
+	PACK_ADD_POLICY_BOOL("RAFilter", RAFilter);
+	PACK_ADD_POLICY_BOOL("DHCPv6Filter", DHCPv6Filter);
+	PACK_ADD_POLICY_BOOL("DHCPv6NoServer", DHCPv6NoServer);
+	PACK_ADD_POLICY_BOOL("NoRoutingV6", NoRoutingV6);
+	PACK_ADD_POLICY_BOOL("CheckIPv6", CheckIPv6);
+	PACK_ADD_POLICY_BOOL("NoServerV6", NoServerV6);
+	PACK_ADD_POLICY_BOOL("NoSavePassword", NoSavePassword);
+	PACK_ADD_POLICY_BOOL("FilterIPv4", FilterIPv4);
+	PACK_ADD_POLICY_BOOL("FilterIPv6", FilterIPv6);
+	PACK_ADD_POLICY_BOOL("FilterNonIP", FilterNonIP);
+	PACK_ADD_POLICY_BOOL("NoIPv6DefaultRouterInRA", NoIPv6DefaultRouterInRA);
+	PACK_ADD_POLICY_BOOL("NoIPv6DefaultRouterInRAWhenIPv6", NoIPv6DefaultRouterInRAWhenIPv6);
+
+	// UINT 値
+	// Ver 2
+	PACK_ADD_POLICY_UINT("MaxConnection", MaxConnection);
+	PACK_ADD_POLICY_UINT("TimeOut", TimeOut);
+	PACK_ADD_POLICY_UINT("MaxMac", MaxMac);
+	PACK_ADD_POLICY_UINT("MaxIP", MaxIP);
+	PACK_ADD_POLICY_UINT("MaxUpload", MaxUpload);
+	PACK_ADD_POLICY_UINT("MaxDownload", MaxDownload);
+	PACK_ADD_POLICY_UINT("MultiLogins", MultiLogins);
+	// Ver 3
+	PACK_ADD_POLICY_UINT("MaxIPv6", MaxIPv6);
+	PACK_ADD_POLICY_UINT("AutoDisconnect", AutoDisconnect);
+	PACK_ADD_POLICY_UINT("VLanId", VLanId);
+
+	// Ver 3 フラグ
+	PackAddBool(p, "policy:Ver3", true);
+}
+
+// 追加接続用の認証データをアップロードする
+bool ClientUploadAuth2(CONNECTION *c, SOCK *s)
+{
+	PACK *p = NULL;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	p = PackAdditionalConnect(c->Session->SessionKey);
+
+	PackAddClientVersion(p, c);
+
+	if (HttpClientSend(s, p) == false)
+	{
+		FreePack(p);
+		return false;
+	}
+	FreePack(p);
+
+	return true;
+}
+
+// NOOP を送信する
+void ClientUploadNoop(CONNECTION *c)
+{
+	PACK *p;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	p = PackError(0);
+	PackAddInt(p, "noop", 1);
+	HttpClientSend(c->FirstSock, p);
+	FreePack(p);
+
+	p = HttpClientRecv(c->FirstSock);
+	if (p != NULL)
+	{
+		FreePack(p);
+	}
+}
+
+// クライアントのバージョン情報を PACK に追加する
+void PackAddClientVersion(PACK *p, CONNECTION *c)
+{
+	// 引数チェック
+	if (p == NULL || c == NULL)
+	{
+		return;
+	}
+
+	PackAddStr(p, "client_str", c->ClientStr);
+	PackAddInt(p, "client_ver", c->ClientVer);
+	PackAddInt(p, "client_build", c->ClientBuild);
+}
+
+// 新規接続用の認証データをアップロードする
+bool ClientUploadAuth(CONNECTION *c)
+{
+	PACK *p = NULL;
+	CLIENT_AUTH *a;
+	CLIENT_OPTION *o;
+	X *x;
+	bool ret;
+	NODE_INFO info;
+	UCHAR secure_password[SHA1_SIZE];
+	UCHAR sign[4096 / 8];
+	UCHAR unique[SHA1_SIZE];
+	RPC_WINVER v;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	Zero(sign, sizeof(sign));
+
+	a = c->Session->ClientAuth;
+	o = c->Session->ClientOption;
+
+	if (c->UseTicket == false)
+	{
+		switch (a->AuthType)
+		{
+		case CLIENT_AUTHTYPE_ANONYMOUS:
+			// 匿名認証
+			p = PackLoginWithAnonymous(o->HubName, a->Username);
+			break;
+
+		case CLIENT_AUTHTYPE_PASSWORD:
+			// パスワード認証
+			SecurePassword(secure_password, a->HashedPassword, c->Random);
+			p = PackLoginWithPassword(o->HubName, a->Username, secure_password);
+			break;
+
+		case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+			// 平文パスワード認証
+			p = PackLoginWithPlainPassword(o->HubName, a->Username, a->PlainPassword);
+			break;
+
+		case CLIENT_AUTHTYPE_CERT:
+			// 証明書認証
+			if (a->ClientX != NULL && a->ClientX->is_compatible_bit &&
+				a->ClientX->bits != 0 && (a->ClientX->bits / 8) <= sizeof(sign))
+			{
+				if (RsaSignEx(sign, c->Random, SHA1_SIZE, a->ClientK, a->ClientX->bits))
+				{
+					p = PackLoginWithCert(o->HubName, a->Username, a->ClientX, sign, a->ClientX->bits / 8);
+					c->ClientX = CloneX(a->ClientX);
+				}
+			}
+			break;
+
+		case CLIENT_AUTHTYPE_SECURE:
+			// セキュアデバイスによる認証
+			if (ClientSecureSign(c, sign, c->Random, &x))
+			{
+				p = PackLoginWithCert(o->HubName, a->Username, x, sign, 128);
+				c->ClientX = CloneX(x);
+				FreeX(x);
+			}
+			else
+			{
+				c->Err = ERR_SECURE_DEVICE_OPEN_FAILED;
+				c->Session->ForceStopFlag = true;
+			}
+			break;
+		}
+	}
+	else
+	{
+		// チケット
+		p = NewPack();
+		PackAddStr(p, "method", "login");
+		PackAddStr(p, "hubname", o->HubName);
+		PackAddStr(p, "username", a->Username);
+		PackAddInt(p, "authtype", AUTHTYPE_TICKET);
+		PackAddData(p, "ticket", c->Ticket, SHA1_SIZE);
+	}
+
+	// 現在時刻
+	PackAddInt64(p, "timestamp", SystemTime64());
+
+	if (p == NULL)
+	{
+		// エラー
+		if (c->Err != ERR_SECURE_DEVICE_OPEN_FAILED)
+		{
+			c->Err = ERR_PROTOCOL_ERROR;
+		}
+		return false;
+	}
+
+	PackAddClientVersion(p, c);
+
+	// プロトコル
+	PackAddInt(p, "protocol", c->Protocol);
+
+	// バージョン等
+	PackAddStr(p, "hello", c->ClientStr);
+	PackAddInt(p, "version", c->ClientVer);
+	PackAddInt(p, "build", c->ClientBuild);
+	PackAddInt(p, "client_id", c->Cedar->ClientId);
+
+	// 最大コネクション数
+	PackAddInt(p, "max_connection", o->MaxConnection);
+	// 暗号化使用フラグ
+	PackAddInt(p, "use_encrypt", o->UseEncrypt == false ? 0 : 1);
+	// 高速暗号化使用フラグ
+	//	PackAddInt(p, "use_fast_rc4", o->UseFastRC4 == false ? 0 : 1);
+	// データ圧縮使用フラグ
+	PackAddInt(p, "use_compress", o->UseCompress == false ? 0 : 1);
+	// ハーフコネクションフラグ
+	PackAddInt(p, "half_connection", o->HalfConnection == false ? 0 : 1);
+
+	// ブリッジ / ルーティングモードフラグ
+	PackAddBool(p, "require_bridge_routing_mode", o->RequireBridgeRoutingMode);
+
+	// モニタモードフラグ
+	PackAddBool(p, "require_monitor_mode", o->RequireMonitorMode);
+
+	// VoIP / QoS フラグ
+	PackAddBool(p, "qos", o->DisableQoS ? false : true);
+
+	// ユニーク ID
+	GenerateMachineUniqueHash(unique);
+	PackAddData(p, "unique_id", unique, SHA1_SIZE);
+
+	// ノード情報
+	CreateNodeInfo(&info, c);
+	OutRpcNodeInfo(p, &info);
+
+	// OS 情報
+	GetWinVer(&v);
+	OutRpcWinVer(p, &v);
+
+	ret = HttpClientSend(c->FirstSock, p);
+	if (ret == false)
+	{
+		c->Err = ERR_DISCONNECTED;
+	}
+
+	FreePack(p);
+
+	return ret;
+}
+
+// Hello パケットをアップロードする
+bool ServerUploadHello(CONNECTION *c)
+{
+	PACK *p;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	// 乱数生成
+	Rand(c->Random, SHA1_SIZE);
+
+	p = PackHello(c->Random, c->ServerVer, c->ServerBuild, c->ServerStr);
+	if (HttpServerSend(c->FirstSock, p) == false)
+	{
+		FreePack(p);
+		c->Err = ERR_DISCONNECTED;
+		return false;
+	}
+
+	FreePack(p);
+
+	return true;
+}
+
+// Hello パケットをダウンロードする
+bool ClientDownloadHello(CONNECTION *c, SOCK *s)
+{
+	PACK *p;
+	UINT err;
+	UCHAR random[SHA1_SIZE];
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	// データ受信
+	p = HttpClientRecv(s);
+	if (p == NULL)
+	{
+		c->Err = ERR_SERVER_IS_NOT_VPN;
+		return false;
+	}
+
+	if (err = GetErrorFromPack(p))
+	{
+		// エラー発生
+		c->Err = err;
+		FreePack(p);
+		return false;
+	}
+
+	// パケット解釈
+	if (GetHello(p, random, &c->ServerVer, &c->ServerBuild, c->ServerStr, sizeof(c->ServerStr)) == false)
+	{
+		c->Err = ERR_SERVER_IS_NOT_VPN;
+		FreePack(p);
+		return false;
+	}
+
+	if (c->FirstSock == s)
+	{
+		Copy(c->Random, random, SHA1_SIZE);
+	}
+
+	FreePack(p);
+
+	return true;
+}
+
+// シグネチャをダウンロードする
+bool ServerDownloadSignature(CONNECTION *c)
+{
+	HTTP_HEADER *h;
+	UCHAR *data;
+	UINT data_size;
+	SOCK *s;
+	UINT num = 0, max = 19;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	s = c->FirstSock;
+
+	while (true)
+	{
+		num++;
+		if (num > max)
+		{
+			// 切断
+			Disconnect(s);
+			c->Err = ERR_CLIENT_IS_NOT_VPN;
+			return false;
+		}
+		// ヘッダを受信する
+		h = RecvHttpHeader(s);
+		if (h == NULL)
+		{
+			c->Err = ERR_CLIENT_IS_NOT_VPN;
+			return false;
+		}
+
+		// 解釈する
+		if (StrCmpi(h->Method, "POST") == 0)
+		{
+			// POST なのでデータを受信する
+			data_size = GetContentLength(h);
+			if ((data_size > 3411 || data_size < 1411) && (data_size != StrLen(HTTP_VPN_TARGET_POSTDATA)))
+			{
+				// データが大きすぎる
+				HttpSendForbidden(s, h->Target, NULL);
+				FreeHttpHeader(h);
+				c->Err = ERR_CLIENT_IS_NOT_VPN;
+				return false;
+			}
+			data = Malloc(data_size);
+			if (RecvAll(s, data, data_size, s->SecureMode) == false)
+			{
+				// データ受信失敗
+				Free(data);
+				FreeHttpHeader(h);
+				c->Err = ERR_DISCONNECTED;
+				return false;
+			}
+			// Target を確認する
+			if (StrCmpi(h->Target, HTTP_VPN_TARGET2) != 0)
+			{
+				// ターゲットが不正
+				HttpSendNotFound(s, h->Target);
+				Free(data);
+				FreeHttpHeader(h);
+			}
+			else
+			{
+				if (((data_size == StrLen(HTTP_VPN_TARGET_POSTDATA)) && (Cmp(data, HTTP_VPN_TARGET_POSTDATA, data_size) == 0)) || (data_size >= 1411))
+				{
+					// VPN Client が接続してきた
+					Free(data);
+					FreeHttpHeader(h);
+					return true;
+				}
+				else
+				{
+					// VPN Client 以外のソフトウェアが接続してきた
+					HttpSendForbidden(s, h->Target, NULL);
+					FreeHttpHeader(h);
+				}
+			}
+		}
+		else
+		{
+			// これ以上解釈しても VPN クライアントで無い可能性が高いが
+			// 一応する
+			if (StrCmpi(h->Method, "GET") != 0)
+			{
+				// サポートされていないメソッド呼び出し
+				HttpSendNotImplemented(s, h->Method, h->Target, h->Version);
+			}
+			else
+			{
+				if (StrCmpi(h->Target, "/") == 0)
+				{
+					// ルートディレクトリ
+					HttpSendForbidden(c->FirstSock, h->Target, "");
+				}
+				else
+				{
+					// Not Found
+					HttpSendNotFound(s, h->Target);
+				}
+			}
+			FreeHttpHeader(h);
+		}
+	}
+}
+
+// シグネチャをアップロードする
+bool ClientUploadSignature(SOCK *s)
+{
+	HTTP_HEADER *h;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	h = NewHttpHeader("POST", HTTP_VPN_TARGET2, "HTTP/1.1");
+	AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE3));
+	AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+
+	if (PostHttp(s, h, HTTP_VPN_TARGET_POSTDATA, StrLen(HTTP_VPN_TARGET_POSTDATA)) == false)
+	{
+		FreeHttpHeader(h);
+		return false;
+	}
+
+	FreeHttpHeader(h);
+
+	return true;
+}
+
+// サーバーへの接続を確立する
+SOCK *ClientConnectToServer(CONNECTION *c)
+{
+	SOCK *s = NULL;
+	X *x = NULL;
+	K *k = NULL;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	if (c->Halt)
+	{
+		c->Err = ERR_USER_CANCEL;
+		return NULL;
+	}
+
+	// 接続してソケットを取得
+	s = ClientConnectGetSocket(c, false);
+	if (s == NULL)
+	{
+		// 接続失敗
+		return NULL;
+	}
+
+	c->FirstSock = s;
+
+	if (c->Halt)
+	{
+		c->Err = ERR_USER_CANCEL;
+		ReleaseSock(s);
+		c->FirstSock = NULL;
+		return NULL;
+	}
+
+	// タイムアウト
+	SetTimeout(s, CONNECTING_TIMEOUT);
+
+	// SSL 通信の開始
+	if (StartSSLEx(s, x, k, (c->DontUseTls1 ? false : true)) == false)
+	{
+		// SSL 通信開始失敗
+		Disconnect(s);
+		ReleaseSock(s);
+		c->FirstSock = NULL;
+		c->Err = ERR_SERVER_IS_NOT_VPN;
+		return NULL;
+	}
+
+	if (s->RemoteX == NULL)
+	{
+		// SSL 通信開始失敗
+		Disconnect(s);
+		ReleaseSock(s);
+		c->FirstSock = NULL;
+		c->Err = ERR_SERVER_IS_NOT_VPN;
+		return NULL;
+	}
+
+	return s;
+}
+
+// サーバーに接続しソケットを返す
+SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect)
+{
+	SOCK *s = NULL;
+	CLIENT_OPTION *o;
+	char *host_for_direct_connection;
+	UINT port_for_direct_connection;
+	wchar_t tmp[MAX_SIZE];
+	SESSION *sess;
+	volatile bool *cancel_flag = NULL;
+	void *hWnd;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return NULL;
+	}
+
+	sess = c->Session;
+
+	if (sess != NULL)
+	{
+		cancel_flag = &sess->CancelConnect;
+	}
+
+	hWnd = c->hWndForUI;
+
+	o = c->Session->ClientOption;
+
+	if (c->RestoreServerNameAndPort && additional_connect)
+	{
+		// サーバー名とポート番号を元に戻す
+		c->RestoreServerNameAndPort = false;
+
+		StrCpy(c->ServerName, sizeof(c->ServerName), o->Hostname);
+		c->ServerPort = o->Port;
+	}
+
+	host_for_direct_connection = c->ServerName;
+	port_for_direct_connection = c->ServerPort;
+
+	if (o->PortUDP != 0)
+	{
+		// UDP Connection
+		goto UDP_CONNECTION;
+	}
+
+	switch (o->ProxyType)
+	{
+	case PROXY_DIRECT:	// TCP/IP
+UDP_CONNECTION:
+		UniFormat(tmp, sizeof(tmp), _UU("STATUS_4"), c->ServerName);
+		PrintStatus(sess, tmp);
+		// 本番
+		s = TcpIpConnectEx(host_for_direct_connection, port_for_direct_connection,
+			(bool *)cancel_flag, hWnd);
+		if (s == NULL)
+		{
+			// 接続失敗
+			c->Err = ERR_CONNECT_FAILED;
+			return NULL;
+		}
+		break;
+
+	case PROXY_HTTP:	// HTTP Proxy
+		host_for_direct_connection = o->ProxyName;
+		port_for_direct_connection = o->ProxyPort;
+
+		UniFormat(tmp, sizeof(tmp), _UU("STATUS_2"), c->ServerName, o->ProxyName);
+		PrintStatus(sess, tmp);
+		// プロキシ接続
+		s = ProxyConnectEx(c, host_for_direct_connection, port_for_direct_connection,
+			c->ServerName, c->ServerPort, o->ProxyUsername, o->ProxyPassword,
+			additional_connect, (bool *)cancel_flag, hWnd);
+		if (s == NULL)
+		{
+			// 接続失敗
+			return NULL;
+		}
+		break;
+
+	case PROXY_SOCKS:	// SOCKS Proxy
+		host_for_direct_connection = o->ProxyName;
+
+		port_for_direct_connection = o->ProxyPort;
+
+		UniFormat(tmp, sizeof(tmp), _UU("STATUS_2"), c->ServerName, o->ProxyName);
+		PrintStatus(sess, tmp);
+		// SOCKS 接続
+		s = SocksConnectEx(c, host_for_direct_connection, port_for_direct_connection,
+			c->ServerName, c->ServerPort, o->ProxyUsername,
+			additional_connect, (bool *)cancel_flag, hWnd);
+		if (s == NULL)
+		{
+			// 接続失敗
+			return NULL;
+		}
+		break;
+	}
+
+	if (s == NULL)
+	{
+		// 接続失敗
+		c->Err = ERR_CONNECT_FAILED;
+	}
+	else
+	{
+		// 接続成功
+		// IP アドレスを控えておく
+		if (GetIP(&c->Session->ServerIP, host_for_direct_connection) == false)
+		{
+			Copy(&c->Session->ServerIP, &s->RemoteIP, sizeof(IP));
+		}
+	}
+
+	return s;
+}
+
+// SOCKS 経由で接続する
+SOCK *SocksConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+				   char *server_host_name, UINT server_port,
+				   char *username, bool additional_connect)
+{
+	return SocksConnectEx(c, proxy_host_name, proxy_port,
+		server_host_name, server_port, username, additional_connect, NULL, NULL);
+}
+SOCK *SocksConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+				   char *server_host_name, UINT server_port,
+				   char *username, bool additional_connect,
+				   bool *cancel_flag, void *hWnd)
+{
+	SOCK *s = NULL;
+	IP ip;
+	// 引数チェック
+	if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL
+		|| server_port == 0)
+	{
+		c->Err = ERR_PROXY_CONNECT_FAILED;
+		return NULL;
+	}
+
+	// 接続先サーバーの IP アドレスを取得す
+	if (GetIP(&ip, server_host_name) == false)
+	{
+		// 失敗
+		c->Err = ERR_CONNECT_FAILED;
+		return NULL;
+	}
+
+	if (c->Halt)
+	{
+		// 停止
+		c->Err = ERR_USER_CANCEL;
+		return NULL;
+	}
+
+	// 接続
+	s = TcpConnectEx2(proxy_host_name, proxy_port, 0, cancel_flag, hWnd);
+	if (s == NULL)
+	{
+		// 失敗
+		c->Err = ERR_PROXY_CONNECT_FAILED;
+		return NULL;
+	}
+
+	// タイムアウト設定
+	SetTimeout(s, CONNECTING_TIMEOUT_PROXY);
+
+	if (additional_connect == false)
+	{
+		c->FirstSock = s;
+	}
+
+	// リクエストパケット送信
+	if (SocksSendRequestPacket(c, s, server_port, &ip, username) == false)
+	{
+		// 失敗
+		if (additional_connect == false)
+		{
+			c->FirstSock = NULL;
+		}
+		Disconnect(s);
+		ReleaseSock(s);
+		return NULL;
+	}
+
+	// 応答パケット受信
+	if (SocksRecvResponsePacket(c, s) == false)
+	{
+		// 失敗
+		if (additional_connect == false)
+		{
+			c->FirstSock = NULL;
+		}
+		Disconnect(s);
+		ReleaseSock(s);
+		return NULL;
+	}
+
+	SetTimeout(s, INFINITE);
+
+	return s;
+}
+
+// SOCKS 応答パケットを受信する
+bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s)
+{
+	BUF *b;
+	UINT size = 8;
+	UCHAR tmp[8];
+	UCHAR vn, cd;
+	// 引数チェック
+	if (c == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	if (RecvAll(s, tmp, sizeof(tmp), false) == false)
+	{
+		c->Err = ERR_DISCONNECTED;
+		return false;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, tmp, sizeof(tmp));
+	SeekBuf(b, 0, 0);
+
+	ReadBuf(b, &vn, 1);
+	ReadBuf(b, &cd, 1);
+
+	FreeBuf(b);
+
+	if (vn != 0)
+	{
+		c->Err = ERR_PROXY_ERROR;
+		return false;
+	}
+
+	switch (cd)
+	{
+	case 90:
+		// 成功
+		return true;
+
+	case 93:
+		// 認証失敗
+		c->Err = ERR_PROXY_AUTH_FAILED;
+		return false;
+
+	default:
+		// サーバーへの接続失敗
+		c->Err = ERR_CONNECT_FAILED;
+		return false;
+	}
+}
+
+// SOCKS リクエストパケットを送信する
+bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid)
+{
+	BUF *b;
+	UCHAR vn, cd;
+	USHORT port;
+	UINT ip;
+	bool ret;
+	// 引数チェック
+	if (s == NULL || dest_port == 0 || dest_ip == NULL || c == NULL)
+	{
+		return false;
+	}
+	if (userid == NULL)
+	{
+		userid = "";
+	}
+
+	b = NewBuf();
+	vn = 4;
+	cd = 1;
+	WriteBuf(b, &vn, 1);
+	WriteBuf(b, &cd, 1);
+	port = Endian16((USHORT)dest_port);
+	ip = IPToUINT(dest_ip);
+	WriteBuf(b, &port, 2);
+	WriteBuf(b, &ip, 4);
+	WriteBuf(b, userid, StrLen(userid) + 1);
+
+	ret = SendAll(s, b->Buf, b->Size, false);
+	if (ret == false)
+	{
+		c->Err = ERR_DISCONNECTED;
+	}
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// プロキシ経由で接続する
+SOCK *ProxyConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+				   char *server_host_name, UINT server_port,
+				   char *username, char *password, bool additional_connect)
+{
+	return ProxyConnectEx(c, proxy_host_name, proxy_port,
+		server_host_name, server_port, username, password, additional_connect, NULL, NULL);
+}
+SOCK *ProxyConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+				   char *server_host_name, UINT server_port,
+				   char *username, char *password, bool additional_connect,
+				   bool *cancel_flag, void *hWnd)
+{
+	SOCK *s = NULL;
+	bool use_auth = false;
+	char tmp[MAX_SIZE];
+	char auth_tmp_str[MAX_SIZE], auth_b64_str[MAX_SIZE * 2];
+	char basic_str[MAX_SIZE * 2];
+	UINT http_error_code;
+	HTTP_HEADER *h;
+	// 引数チェック
+	if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL ||
+		server_port == 0)
+	{
+		c->Err = ERR_PROXY_CONNECT_FAILED;
+		return NULL;
+	}
+	if (username != NULL && password != NULL &&
+		(StrLen(username) != 0 || StrLen(password) != 0))
+	{
+		use_auth = true;
+	}
+
+	if (c->Halt)
+	{
+		// 停止
+		c->Err = ERR_USER_CANCEL;
+		return NULL;
+	}
+
+	// 接続
+	s = TcpConnectEx2(proxy_host_name, proxy_port, 0, cancel_flag, hWnd);
+	if (s == NULL)
+	{
+		// 失敗
+		c->Err = ERR_PROXY_CONNECT_FAILED;
+		return NULL;
+	}
+
+	// タイムアウト設定
+	SetTimeout(s, CONNECTING_TIMEOUT_PROXY);
+
+	if (additional_connect == false)
+	{
+		c->FirstSock = s;
+	}
+
+	// HTTP ヘッダ生成
+	if (IsStrIPv6Address(server_host_name))
+	{
+		IP ip;
+		char iptmp[MAX_PATH];
+
+		StrToIP(&ip, server_host_name);
+		IPToStr(iptmp, sizeof(iptmp), &ip);
+
+		Format(tmp, sizeof(tmp), "[%s]:%u", iptmp, server_port);
+	}
+	else
+	{
+		Format(tmp, sizeof(tmp), "%s:%u", server_host_name, server_port);
+	}
+
+	h = NewHttpHeader("CONNECT", tmp, "HTTP/1.0");
+	AddHttpValue(h, NewHttpValue("User-Agent", c->Cedar->HttpUserAgent));
+	Debug("proxy user agent = %s\n", c->Cedar->HttpUserAgent);
+	AddHttpValue(h, NewHttpValue("Host", server_host_name));
+	AddHttpValue(h, NewHttpValue("Content-Length", "0"));
+	AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive"));
+	AddHttpValue(h, NewHttpValue("Pragma", "no-cache"));
+
+	if (use_auth)
+	{
+		wchar_t tmp[MAX_SIZE];
+		UniFormat(tmp, sizeof(tmp), _UU("STATUS_3"), server_host_name);
+		// 認証文字列の生成
+		Format(auth_tmp_str, sizeof(auth_tmp_str), "%s:%s",
+			username, password);
+
+		// Base64 エンコード
+		Zero(auth_b64_str, sizeof(auth_b64_str));
+		Encode64(auth_b64_str, auth_tmp_str);
+		Format(basic_str, sizeof(basic_str), "Basic %s", auth_b64_str);
+
+		AddHttpValue(h, NewHttpValue("Proxy-Authorization", basic_str));
+	}
+
+	// 送信
+	if (SendHttpHeader(s, h) == false)
+	{
+		// 失敗
+		if (additional_connect == false)
+		{
+			c->FirstSock = NULL;
+		}
+		FreeHttpHeader(h);
+		Disconnect(s);
+		ReleaseSock(s);
+		c->Err = ERR_PROXY_ERROR;
+		return NULL;
+	}
+
+	FreeHttpHeader(h);
+
+	if (c->Halt)
+	{
+		// 停止
+		if (additional_connect == false)
+		{
+			c->FirstSock = NULL;
+		}
+		Disconnect(s);
+		ReleaseSock(s);
+		c->Err = ERR_USER_CANCEL;
+		return NULL;
+	}
+
+	// 結果を受信
+	h = RecvHttpHeader(s);
+	if (h == NULL)
+	{
+		// 失敗
+		if (additional_connect == false)
+		{
+			c->FirstSock = NULL;
+		}
+		FreeHttpHeader(h);
+		Disconnect(s);
+		ReleaseSock(s);
+		c->Err = ERR_PROXY_ERROR;
+		return NULL;
+	}
+
+	http_error_code = 0;
+	if (StrLen(h->Method) == 8)
+	{
+		if (Cmp(h->Method, "HTTP/1.", 7) == 0)
+		{
+			http_error_code = ToInt(h->Target);
+		}
+	}
+	FreeHttpHeader(h);
+
+	// コードを確認
+	switch (http_error_code)
+	{
+	case 401:
+	case 403:
+	case 407:
+		// 認証失敗
+		if (additional_connect == false)
+		{
+			c->FirstSock = NULL;
+		}
+		Disconnect(s);
+		ReleaseSock(s);
+		c->Err = ERR_PROXY_AUTH_FAILED;
+		return NULL;
+
+	default:
+		if ((http_error_code / 100) == 2)
+		{
+			// 成功
+			SetTimeout(s, INFINITE);
+			return s;
+		}
+		else
+		{
+			// 不明な結果を受信
+			if (additional_connect == false)
+			{
+				c->FirstSock = NULL;
+			}
+			Disconnect(s);
+			ReleaseSock(s);
+			c->Err = ERR_PROXY_ERROR;
+			return NULL;
+		}
+	}
+}
+
+// TCP 接続関数
+SOCK *TcpConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd)
+{
+#ifdef	OS_WIN32
+	if (hWnd == NULL)
+	{
+		return ConnectEx2(hostname, port, timeout, cancel_flag);
+	}
+	else
+	{
+		return WinConnectEx2((HWND)hWnd, hostname, port, timeout, 0, NULL, NULL);
+	}
+#else	// OS_WIN32
+	return ConnectEx2(hostname, port, timeout, cancel_flag);
+#endif	// OS_WIN32
+}
+
+// TCP/IP で接続する
+SOCK *TcpIpConnect(char *hostname, UINT port)
+{
+	return TcpIpConnectEx(hostname, port, NULL, NULL);
+}
+SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd)
+{
+	SOCK *s = NULL;
+	// 引数チェック
+	if (hostname == NULL || port == 0)
+	{
+		return NULL;
+	}
+
+	s = TcpConnectEx2(hostname, port, 0, cancel_flag, hWnd);
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	return s;
+}
+
+// PACK にダミーのエントリを作成する
+// Q. なぜランダムなサイズのランダムデータをここで挿入するのか?
+// A. ネットワーク経路中の盗聴者によってこの SSL 通信が VPN 通信であること
+//    を検出しにくいようにするためである。
+void CreateDummyValue(PACK *p)
+{
+	UINT size;
+	UCHAR *buf;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	size = Rand32() % HTTP_PACK_RAND_SIZE_MAX;
+	buf = Malloc(size);
+	Rand(buf, size);
+
+	PackAddData(p, "pencore", buf, size);
+
+	Free(buf);
+}
+
+// サーバーがクライアントから PACK を受信する
+PACK *HttpServerRecv(SOCK *s)
+{
+	BUF *b;
+	PACK *p;
+	HTTP_HEADER *h;
+	UINT size;
+	UCHAR *tmp;
+	HTTP_VALUE *v;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+START:
+
+	h = RecvHttpHeader(s);
+	if (h == NULL)
+	{
+		goto BAD_REQUEST;
+	}
+
+	if (StrCmpi(h->Method, "POST") != 0 ||
+		StrCmpi(h->Target, HTTP_VPN_TARGET) != 0 ||
+		StrCmpi(h->Version, "HTTP/1.1") != 0)
+	{
+		FreeHttpHeader(h);
+		goto BAD_REQUEST;
+	}
+
+	v = GetHttpValue(h, "Content-Type");
+	if (v == NULL || StrCmpi(v->Data, HTTP_CONTENT_TYPE2) != 0)
+	{
+		FreeHttpHeader(h);
+		goto BAD_REQUEST;
+	}
+
+	size = GetContentLength(h);
+	if (size == 0 || size > MAX_PACK_SIZE)
+	{
+		FreeHttpHeader(h);
+		goto BAD_REQUEST;
+	}
+
+	tmp = MallocEx(size, true);
+	if (RecvAll(s, tmp, size, s->SecureMode) == false)
+	{
+		Free(tmp);
+		FreeHttpHeader(h);
+		return NULL;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, tmp, size);
+	Free(tmp);
+	FreeHttpHeader(h);
+
+	SeekBuf(b, 0, 0);
+	p = BufToPack(b);
+	FreeBuf(b);
+
+	// NOOP かどうか判断
+	if (PackGetInt(p, "noop") != 0)
+	{
+		Debug("recv: noop\n");
+		FreePack(p);
+
+		p = PackError(0);
+		PackAddInt(p, "noop", 1);
+		if (HttpServerSend(s, p) == false)
+		{
+			FreePack(p);
+			return NULL;
+		}
+
+		FreePack(p);
+
+		goto START;
+	}
+
+	return p;
+
+BAD_REQUEST:
+	// エラーを返す
+
+
+	return NULL;
+}
+
+// クライアントがサーバーから PACK を受信する
+PACK *HttpClientRecv(SOCK *s)
+{
+	BUF *b;
+	PACK *p;
+	HTTP_HEADER *h;
+	UINT size;
+	UCHAR *tmp;
+	HTTP_VALUE *v;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	h = RecvHttpHeader(s);
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	if (StrCmpi(h->Method, "HTTP/1.1") != 0 ||
+		StrCmpi(h->Target, "200") != 0)
+	{
+		FreeHttpHeader(h);
+		return NULL;
+	}
+
+	v = GetHttpValue(h, "Content-Type");
+	if (v == NULL || StrCmpi(v->Data, HTTP_CONTENT_TYPE2) != 0)
+	{
+		FreeHttpHeader(h);
+		return NULL;
+	}
+
+	size = GetContentLength(h);
+	if (size == 0 || size > MAX_PACK_SIZE)
+	{
+		FreeHttpHeader(h);
+		return NULL;
+	}
+
+	tmp = MallocEx(size, true);
+	if (RecvAll(s, tmp, size, s->SecureMode) == false)
+	{
+		Free(tmp);
+		FreeHttpHeader(h);
+		return NULL;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, tmp, size);
+	Free(tmp);
+	FreeHttpHeader(h);
+
+	SeekBuf(b, 0, 0);
+	p = BufToPack(b);
+	FreeBuf(b);
+
+	return p;
+}
+
+// クライアントからサーバーに PACK を送信する
+bool HttpClientSend(SOCK *s, PACK *p)
+{
+	BUF *b;
+	bool ret;
+	HTTP_HEADER *h;
+	char date_str[MAX_SIZE];
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	CreateDummyValue(p);
+
+	b = PackToBuf(p);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	h = NewHttpHeader("POST", HTTP_VPN_TARGET, "HTTP/1.1");
+
+	GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
+	AddHttpValue(h, NewHttpValue("Date", date_str));
+	AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+	AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+	AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE2));
+
+	ret = PostHttp(s, h, b->Buf, b->Size);
+
+	FreeHttpHeader(h);
+	FreeBuf(b);
+
+	return ret;
+}
+
+// サーバーからクライアントに PACK を送信する
+bool HttpServerSend(SOCK *s, PACK *p)
+{
+	BUF *b;
+	bool ret;
+	HTTP_HEADER *h;
+	char date_str[MAX_SIZE];
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	CreateDummyValue(p);
+
+	b = PackToBuf(p);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	h = NewHttpHeader("HTTP/1.1", "200", "OK");
+
+	GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
+	AddHttpValue(h, NewHttpValue("Date", date_str));
+	AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+	AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+	AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE2));
+
+	ret = PostHttp(s, h, b->Buf, b->Size);
+
+	FreeHttpHeader(h);
+	FreeBuf(b);
+
+	return ret;
+}
+
+// 501 Not Implemented エラーの送信
+bool HttpSendNotImplemented(SOCK *s, char *method, char *target, char *version)
+{
+	HTTP_HEADER *h;
+	char date_str[MAX_SIZE];
+	char *str;
+	UINT str_size;
+	char port_str[MAX_SIZE];
+	bool ret;
+	char host[MAX_SIZE];
+	UINT port;
+	// 引数チェック
+	if (s == NULL || target == NULL)
+	{
+		return false;
+	}
+
+	// ホスト名の取得
+	GetMachineName(host, MAX_SIZE);
+	// ポート番号の取得
+	port = s->LocalPort;
+
+	// ヘッダの作成
+	GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
+
+	h = NewHttpHeader("HTTP/1.1", "501", "Method Not Implemented");
+
+	AddHttpValue(h, NewHttpValue("Date", date_str));
+	AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+	AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+	AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE));
+
+	// データの作成
+	str_size = sizeof(http_501_str) * 2 + StrLen(target) + StrLen(host) + StrLen(method) + StrLen(version);
+	str = Malloc(str_size);
+	StrCpy(str, str_size, http_501_str);
+
+	// TARGET
+	ReplaceStri(str, str_size, str, "$TARGET$", target);
+
+	// HOST
+	ReplaceStri(str, str_size, str, "$HOST$", host);
+
+	// PORT
+	ToStr(port_str, port);
+	ReplaceStri(str, str_size, str, "$PORT$", port_str);
+
+	// METHOD
+	ReplaceStri(str, str_size, str, "$METHOD$", method);
+
+	// VERSION
+	ReplaceStri(str, str_size, str, "$VERSION$", version);
+
+	// 送信
+	ret = PostHttp(s, h, str, StrLen(str));
+
+	FreeHttpHeader(h);
+	Free(str);
+
+	return ret;
+}
+
+// 404 Not Found エラーの送信
+bool HttpSendNotFound(SOCK *s, char *target)
+{
+	HTTP_HEADER *h;
+	char date_str[MAX_SIZE];
+	char *str;
+	UINT str_size;
+	char port_str[MAX_SIZE];
+	bool ret;
+	char host[MAX_SIZE];
+	UINT port;
+	// 引数チェック
+	if (s == NULL || target == NULL)
+	{
+		return false;
+	}
+
+	// ホスト名の取得
+	GetMachineName(host, MAX_SIZE);
+	// ポート番号の取得
+	port = s->LocalPort;
+
+	// ヘッダの作成
+	GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
+
+	h = NewHttpHeader("HTTP/1.1", "404", "Not Found");
+
+	AddHttpValue(h, NewHttpValue("Date", date_str));
+	AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+	AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+	AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE));
+
+	// データの作成
+	str_size = sizeof(http_404_str) * 2 + StrLen(target) + StrLen(host);
+	str = Malloc(str_size);
+	StrCpy(str, str_size, http_404_str);
+
+	// TARGET
+	ReplaceStri(str, str_size, str, "$TARGET$", target);
+
+	// HOST
+	ReplaceStri(str, str_size, str, "$HOST$", host);
+
+	// PORT
+	ToStr(port_str, port);
+	ReplaceStri(str, str_size, str, "$PORT$", port_str);
+
+	// 送信
+	ret = PostHttp(s, h, str, StrLen(str));
+
+	FreeHttpHeader(h);
+	Free(str);
+
+	return ret;
+}
+
+// 403 Forbidden エラーの送信
+bool HttpSendForbidden(SOCK *s, char *target, char *server_id)
+{
+	HTTP_HEADER *h;
+	char date_str[MAX_SIZE];
+	char *str;
+	UINT str_size;
+	char port_str[MAX_SIZE];
+	bool ret;
+	char host[MAX_SIZE];
+	UINT port;
+	// 引数チェック
+	if (s == NULL || target == NULL)
+	{
+		return false;
+	}
+
+	// ホスト名の取得
+	GetMachineName(host, MAX_SIZE);
+	// ポート番号の取得
+	port = s->LocalPort;
+
+	// ヘッダの作成
+	GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
+
+	h = NewHttpHeader("HTTP/1.1", "403", "Forbidden");
+
+	AddHttpValue(h, NewHttpValue("Date", date_str));
+	AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+	AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+	AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE));
+
+	// データの作成
+	str_size = sizeof(http_403_str) * 2 + StrLen(target) + StrLen(host);
+	str = Malloc(str_size);
+	StrCpy(str, str_size, http_403_str);
+
+	// TARGET
+	ReplaceStri(str, str_size, str, "$TARGET$", target);
+
+	// HOST
+	ReplaceStri(str, str_size, str, "$HOST$", host);
+
+	// PORT
+	ToStr(port_str, port);
+	ReplaceStri(str, str_size, str, "$PORT$", port_str);
+
+	// 送信
+	ret = PostHttp(s, h, str, StrLen(str));
+
+	FreeHttpHeader(h);
+	Free(str);
+
+	return ret;
+}
+
+// HTTP ヘッダ用の日時文字列を取得
+void GetHttpDateStr(char *str, UINT size, UINT64 t)
+{
+	SYSTEMTIME s;
+	static char *wday[] =
+	{
+		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+	};
+	static char *month[] =
+	{
+		"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
+		"Nov", "Dec",
+	};
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	UINT64ToSystem(&s, t);
+
+	Format(str, size, "%s, %02u %s %04u %02u:%02u:%02u GMT",
+		wday[s.wDayOfWeek], s.wDay, month[s.wMonth - 1], s.wYear,
+		s.wHour, s.wMinute, s.wSecond);
+}
+
+// HTTP ヘッダからコンテンツ長を取得する
+UINT GetContentLength(HTTP_HEADER *header)
+{
+	UINT ret;
+	HTTP_VALUE *v;
+	// 引数チェック
+	if (header == NULL)
+	{
+		return 0;
+	}
+
+	v = GetHttpValue(header, "Content-Length");
+	if (v == NULL)
+	{
+		return 0;
+	}
+
+	ret = ToInt(v->Data);
+
+	return ret;
+}
+
+// HTTP でデータを送信する
+bool PostHttp(SOCK *s, HTTP_HEADER *header, void *post_data, UINT post_size)
+{
+	char *header_str;
+	BUF *b;
+	bool ret;
+	// 引数チェック
+	if (s == NULL || header == NULL || post_data == NULL)
+	{
+		return false;
+	}
+
+	// Content-Lentgh が存在するかどうかチェック
+	if (GetHttpValue(header, "Content-Length") == NULL)
+	{
+		char tmp[MAX_SIZE];
+		// 存在しないので付加する
+		ToStr(tmp, post_size);
+		AddHttpValue(header, NewHttpValue("Content-Length", tmp));
+	}
+
+	// ヘッダを文字列にする
+	header_str = HttpHeaderToStr(header);
+	if (header_str == NULL)
+	{
+		return false;
+	}
+	b = NewBuf();
+	WriteBuf(b, header_str, StrLen(header_str));
+	Free(header_str);
+
+	// データを追記する
+	WriteBuf(b, post_data, post_size);
+
+	// 送信する
+	ret = SendAll(s, b->Buf, b->Size, s->SecureMode);
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// HTTP ヘッダを文字列に変換
+char *HttpHeaderToStr(HTTP_HEADER *header)
+{
+	BUF *b;
+	char *tmp;
+	UINT i;
+	char *s;
+	// 引数チェック
+	if (header == NULL)
+	{
+		return NULL;
+	}
+
+	tmp = Malloc(HTTP_HEADER_LINE_MAX_SIZE);
+	b = NewBuf();
+
+	// ヘッダ
+	Format(tmp, HTTP_HEADER_LINE_MAX_SIZE,
+		"%s %s %s\r\n", header->Method, header->Target, header->Version);
+	WriteBuf(b, tmp, StrLen(tmp));
+
+	// 値
+	for (i = 0;i < LIST_NUM(header->ValueList);i++)
+	{
+		HTTP_VALUE *v = (HTTP_VALUE *)LIST_DATA(header->ValueList, i);
+		Format(tmp, HTTP_HEADER_LINE_MAX_SIZE,
+			"%s: %s\r\n", v->Name, v->Data);
+		WriteBuf(b, tmp, StrLen(tmp));
+	}
+
+	// 最後の改行
+	WriteBuf(b, "\r\n", 2);
+	s = Malloc(b->Size + 1);
+	Copy(s, b->Buf, b->Size);
+	s[b->Size] = 0;
+
+	FreeBuf(b);
+	Free(tmp);
+
+	return s;
+}
+
+// HTTP ヘッダを送信
+bool SendHttpHeader(SOCK *s, HTTP_HEADER *header)
+{
+	char *str;
+	bool ret;
+	// 引数チェック
+	if (s == NULL || header == NULL)
+	{
+		return false;
+	}
+
+	// 文字列に変換
+	str = HttpHeaderToStr(header);
+
+	// 送信
+	ret = SendAll(s, str, StrLen(str), s->SecureMode);
+
+	Free(str);
+
+	return ret;
+}
+
+// HTTP ヘッダを受信
+HTTP_HEADER *RecvHttpHeader(SOCK *s)
+{
+	TOKEN_LIST *token = NULL;
+	char *str = NULL;
+	HTTP_HEADER *header = NULL;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	// 1 行目を取得する
+	str = RecvLine(s, HTTP_HEADER_LINE_MAX_SIZE);
+	if (str == NULL)
+	{
+		goto ERROR;
+	}
+
+	// トークンに分割する
+	token = ParseToken(str, " ");
+	if (token->NumTokens < 3)
+	{
+		goto ERROR;
+	}
+
+	Free(str);
+	str = NULL;
+
+	// ヘッダの作成
+	header = NewHttpHeader(token->Token[0], token->Token[1], token->Token[2]);
+
+	if (!StrCmpi(header->Version, "HTTP/1.0") || !StrCmpi(header->Version, "HTTP/0.9"))
+	{
+		// この行で終わり
+		return header;
+	}
+
+	// 2 行目以降を取得する
+	while (true)
+	{
+		UINT pos;
+		HTTP_VALUE *v;
+		char *value_name, *value_data;
+		str = RecvLine(s, HTTP_HEADER_LINE_MAX_SIZE);
+		if (str == NULL)
+		{
+			goto ERROR;
+		}
+		Trim(str);
+
+		if (StrLen(str) == 0)
+		{
+			// ヘッダの終了
+			Free(str);
+			str = NULL;
+			break;
+		}
+
+		// コロンの位置を取得する
+		pos = SearchStr(str, ":", 0);
+		if (pos == INFINITE)
+		{
+			// コロンが存在しない
+			goto ERROR;
+		}
+		if ((pos + 1) >= StrLen(str))
+		{
+			// データが存在しない
+			goto ERROR;
+		}
+
+		// 名前とデータの 2 つに分ける
+		value_name = Malloc(pos + 1);
+		Copy(value_name, str, pos);
+		value_name[pos] = 0;
+		value_data = &str[pos + 1];
+
+		v = NewHttpValue(value_name, value_data);
+		if (v == NULL)
+		{
+			Free(value_name);
+			goto ERROR;
+		}
+
+		Free(value_name);
+
+		AddHttpValue(header, v);
+		Free(str);
+	}
+
+	FreeToken(token);
+
+	return header;
+
+ERROR:
+	// メモリ解放
+	if (token)
+	{
+		FreeToken(token);
+	}
+	if (str)
+	{
+		Free(str);
+	}
+	if (header)
+	{
+		FreeHttpHeader(header);
+	}
+	return NULL;
+}
+
+// 1 行を受信する
+char *RecvLine(SOCK *s, UINT max_size)
+{
+	BUF *b;
+	char c;
+	char *str;
+	// 引数チェック
+	if (s == NULL || max_size == 0)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+	while (true)
+	{
+		UCHAR *buf;
+		if (RecvAll(s, &c, sizeof(c), s->SecureMode) == false)
+		{
+			FreeBuf(b);
+			return NULL;
+		}
+		WriteBuf(b, &c, sizeof(c));
+		buf = (UCHAR *)b->Buf;
+		if (b->Size > max_size)
+		{
+			FreeBuf(b);
+			return NULL;
+		}
+		if (b->Size >= 1)
+		{
+			if (buf[b->Size - 1] == '\n')
+			{
+				b->Size--;
+				if (b->Size >= 1)
+				{
+					if (buf[b->Size - 1] == '\r')
+					{
+						b->Size--;
+					}
+				}
+				str = Malloc(b->Size + 1);
+				Copy(str, b->Buf, b->Size);
+				str[b->Size] = 0;
+				FreeBuf(b);
+
+				return str;
+			}
+		}
+	}
+}
+
+// 新しい HTTP 値の作成
+HTTP_VALUE *NewHttpValue(char *name, char *data)
+{
+	HTTP_VALUE *v;
+	// 引数チェック
+	if (name == NULL || data == NULL)
+	{
+		return NULL;
+	}
+
+	v = ZeroMalloc(sizeof(HTTP_VALUE));
+
+	v->Name = CopyStr(name);
+	v->Data = CopyStr(data);
+
+	Trim(v->Name);
+	Trim(v->Data);
+
+	return v;
+}
+
+// プロトコルルーチンの初期化
+void InitProtocol()
+{
+}
+
+// プロトコルルーチンの解放
+void FreeProtocol()
+{
+}
+
+// HTTP ヘッダから HTTP 値を探す
+HTTP_VALUE *GetHttpValue(HTTP_HEADER *header, char *name)
+{
+	HTTP_VALUE *v, t;
+	// 引数チェック
+	if (header == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	t.Name = name;
+	v = Search(header->ValueList, &t);
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	return v;
+}
+
+// HTTP ヘッダに HTTP 値を追加
+void AddHttpValue(HTTP_HEADER *header, HTTP_VALUE *value)
+{
+	// 引数チェック
+	if (header == NULL || value == NULL)
+	{
+		return;
+	}
+
+	Insert(header->ValueList, value);
+}
+
+// HTTP ヘッダを作成
+HTTP_HEADER *NewHttpHeader(char *method, char *target, char *version)
+{
+	HTTP_HEADER *header;
+	// 引数チェック
+	if (method == NULL || target == NULL || version == NULL)
+	{
+		return NULL;
+	}
+
+	header = ZeroMalloc(sizeof(HTTP_HEADER));
+
+	header->Method = CopyStr(method);
+	header->Target = CopyStr(target);
+	header->Version = CopyStr(version);
+	header->ValueList = NewListFast(CompareHttpValue);
+
+	return header;
+}
+
+// HTTP 値の比較関数
+int CompareHttpValue(void *p1, void *p2)
+{
+	HTTP_VALUE *v1, *v2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	v1 = *(HTTP_VALUE **)p1;
+	v2 = *(HTTP_VALUE **)p2;
+	if (v1 == NULL || v2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(v1->Name, v2->Name);
+}
+
+// HTTP 値を解放
+void FreeHttpValue(HTTP_VALUE *value)
+{
+	// 引数チェック
+	if (value == NULL)
+	{
+		return;
+	}
+
+	Free(value->Data);
+	Free(value->Name);
+
+	Free(value);
+}
+
+// HTTP ヘッダを解放
+void FreeHttpHeader(HTTP_HEADER *header)
+{
+	UINT i;
+	HTTP_VALUE **values;
+	// 引数チェック
+	if (header == NULL)
+	{
+		return;
+	}
+
+	Free(header->Method);
+	Free(header->Target);
+	Free(header->Version);
+
+	values = ToArray(header->ValueList);
+	for (i = 0;i < LIST_NUM(header->ValueList);i++)
+	{
+		FreeHttpValue(values[i]);
+	}
+	Free(values);
+
+	ReleaseList(header->ValueList);
+
+	Free(header);
+}
+
+// パケットを受信
+PACK *RecvPack(SOCK *s)
+{
+	PACK *p;
+	BUF *b;
+	void *data;
+	UINT sz;
+	// 引数チェック
+	if (s == NULL || s->Type != SOCK_TCP)
+	{
+		return false;
+	}
+
+	if (RecvAll(s, &sz, sizeof(UINT), s->SecureMode) == false)
+	{
+		return false;
+	}
+	sz = Endian32(sz);
+	if (sz > MAX_PACK_SIZE)
+	{
+		return false;
+	}
+	data = MallocEx(sz, true);
+	if (RecvAll(s, data, sz, s->SecureMode) == false)
+	{
+		Free(data);
+		return false;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, data, sz);
+	SeekBuf(b, 0, 0);
+	p = BufToPack(b);
+	FreeBuf(b);
+	Free(data);
+
+	return p;
+}
+
+// パケットを送信
+bool SendPack(SOCK *s, PACK *p)
+{
+	BUF *b;
+	UINT sz;
+	// 引数チェック
+	if (s == NULL || p == NULL || s->Type != SOCK_TCP)
+	{
+		return false;
+	}
+
+	b = PackToBuf(p);
+	sz = Endian32(b->Size);
+
+	SendAdd(s, &sz, sizeof(UINT));
+	SendAdd(s, b->Buf, b->Size);
+	FreeBuf(b);
+
+	return SendNow(s, s->SecureMode);
+}
+
+// Hello パケットを作成
+PACK *PackHello(void *random, UINT ver, UINT build, char *server_str)
+{
+	PACK *p;
+	// 引数チェック
+	if (random == NULL || server_str == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "hello", server_str);
+	PackAddInt(p, "version", ver);
+	PackAddInt(p, "build", build);
+	PackAddData(p, "random", random, SHA1_SIZE);
+
+	return p;
+}
+
+// Hello パケットを解釈
+bool GetHello(PACK *p, void *random, UINT *ver, UINT *build, char *server_str, UINT server_str_size)
+{
+	// 引数チェック
+	if (p == NULL || random == NULL || ver == NULL || server_str == NULL)
+	{
+		return false;
+	}
+
+	if (PackGetStr(p, "hello", server_str, server_str_size) == false)
+	{
+		return false;
+	}
+	*ver = PackGetInt(p, "version");
+	*build = PackGetInt(p, "build");
+	if (PackGetDataSize(p, "random") != SHA1_SIZE)
+	{
+		return false;
+	}
+	if (PackGetData(p, "random", random) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// エラー値を PACK に格納
+PACK *PackError(UINT error)
+{
+	PACK *p;
+
+	p = NewPack();
+	PackAddInt(p, "error", error);
+
+	return p;
+}
+
+// エラー値を PACK から取得
+UINT GetErrorFromPack(PACK *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return 0;
+	}
+
+	return PackGetInt(p, "error");
+}
+
+// 認証方法を PACK から取得
+UINT GetAuthTypeFromPack(PACK *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return 0;
+	}
+
+	return PackGetInt(p, "authtype");
+}
+
+// ユーザー名と HUB 名を PACK から取得
+bool GetHubnameAndUsernameFromPack(PACK *p, char *username, UINT username_size,
+								   char *hubname, UINT hubname_size)
+{
+	// 引数チェック
+	if (p == NULL || username == NULL || hubname == NULL)
+	{
+		return false;
+	}
+
+	if (PackGetStr(p, "username", username, username_size) == false)
+	{
+		return false;
+	}
+	if (PackGetStr(p, "hubname", hubname, hubname_size) == false)
+	{
+		return false;
+	}
+	return true;
+}
+
+// プロトコルを PACK から取得
+UINT GetProtocolFromPack(PACK *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return 0;
+	}
+
+#if	0
+	return PackGetInt(p, "protocol");
+#else
+	// 現バージョンでは TCP プロトコルに限定する
+	return CONNECTION_TCP;
+#endif
+}
+
+// メソッドを PACK から取得
+bool GetMethodFromPack(PACK *p, char *method, UINT size)
+{
+	// 引数チェック
+	if (p == NULL || method == NULL || size == 0)
+	{
+		return false;
+	}
+
+	return PackGetStr(p, "method", method, size);
+}
+
+// 証明書認証ログイン用のパケットを生成
+PACK *PackLoginWithCert(char *hubname, char *username, X *x, void *sign, UINT sign_size)
+{
+	PACK *p;
+	BUF *b;
+	// 引数チェック
+	if (hubname == NULL || username == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "method", "login");
+	PackAddStr(p, "hubname", hubname);
+	PackAddStr(p, "username", username);
+	PackAddInt(p, "authtype", CLIENT_AUTHTYPE_CERT);
+
+	// 証明書
+	b = XToBuf(x, false);
+	PackAddData(p, "cert", b->Buf, b->Size);
+	FreeBuf(b);
+
+	// 署名データ
+	PackAddData(p, "sign", sign, sign_size);
+
+	return p;
+}
+
+// 平文パスワード認証ログイン用のパケットを生成
+PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_password)
+{
+	PACK *p;
+	// 引数チェック
+	if (hubname == NULL || username == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "method", "login");
+	PackAddStr(p, "hubname", hubname);
+	PackAddStr(p, "username", username);
+	PackAddInt(p, "authtype", CLIENT_AUTHTYPE_PLAIN_PASSWORD);
+	PackAddStr(p, "plain_password", plain_password);
+
+	return p;
+}
+
+// パスワード認証ログイン用のパケットを作成
+PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password)
+{
+	PACK *p;
+	// 引数チェック
+	if (hubname == NULL || username == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "method", "login");
+	PackAddStr(p, "hubname", hubname);
+	PackAddStr(p, "username", username);
+	PackAddInt(p, "authtype", CLIENT_AUTHTYPE_PASSWORD);
+	PackAddData(p, "secure_password", secure_password, SHA1_SIZE);
+
+	return p;
+}
+
+// 匿名ログイン用のパケットを作成
+PACK *PackLoginWithAnonymous(char *hubname, char *username)
+{
+	PACK *p;
+	// 引数チェック
+	if (hubname == NULL || username == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "method", "login");
+	PackAddStr(p, "hubname", hubname);
+	PackAddStr(p, "username", username);
+	PackAddInt(p, "authtype", CLIENT_AUTHTYPE_ANONYMOUS);
+
+	return p;
+}
+
+// 追加接続用のパケットを作成
+PACK *PackAdditionalConnect(UCHAR *session_key)
+{
+	PACK *p;
+	// 引数チェック
+	if (session_key == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "method", "additional_connect");
+	PackAddData(p, "session_key", session_key, SHA1_SIZE);
+
+	return p;
+}
+
+// PACK から K を取得
+K *PackGetK(PACK *p, char *name)
+{
+	K *k;
+	BUF *b;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	b = PackGetBuf(p, name);
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	k = BufToK(b, true, false, NULL);
+	FreeBuf(b);
+
+	return k;
+}
+
+// PACK から X を取得
+X *PackGetX(PACK *p, char *name)
+{
+	X *x;
+	BUF *b;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	b = PackGetBuf(p, name);
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	x = BufToX(b, false);
+	FreeBuf(b);
+
+	return x;
+}
+
+// PACK に K を追加
+void PackAddK(PACK *p, char *name, K *k)
+{
+	BUF *b;
+	// 引数チェック
+	if (p == NULL || name == NULL || k == NULL)
+	{
+		return;
+	}
+
+	b = KToBuf(k, false, NULL);
+	if (b == NULL)
+	{
+		return;
+	}
+
+	PackAddBuf(p, name, b);
+	FreeBuf(b);
+}
+
+// PACK に X を追加
+void PackAddX(PACK *p, char *name, X *x)
+{
+	BUF *b;
+	// 引数チェック
+	if (p == NULL || name == NULL || x == NULL)
+	{
+		return;
+	}
+
+	b = XToBuf(x, false);
+	if (b == NULL)
+	{
+		return;
+	}
+
+	PackAddBuf(p, name, b);
+	FreeBuf(b);
+}
+
+// PACK からバッファを取得
+BUF *PackGetBuf(PACK *p, char *name)
+{
+	return PackGetBufEx(p, name, 0);
+}
+BUF *PackGetBufEx(PACK *p, char *name, UINT index)
+{
+	UINT size;
+	void *tmp;
+	BUF *b;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	size = PackGetDataSizeEx(p, name, index);
+	tmp = MallocEx(size, true);
+	if (PackGetDataEx(p, name, tmp, index) == false)
+	{
+		Free(tmp);
+		return NULL;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, tmp, size);
+	SeekBuf(b, 0, 0);
+
+	Free(tmp);
+
+	return b;
+}
+
+// PACK からデータを取得
+bool PackGetData(PACK *p, char *name, void *data)
+{
+	return PackGetDataEx(p, name, data, 0);
+}
+bool PackGetDataEx(PACK *p, char *name, void *data, UINT index)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	e = GetElement(p, name, VALUE_DATA);
+	if (e == NULL)
+	{
+		return false;
+	}
+	Copy(data, GetDataValue(e, index), GetDataValueSize(e, index));
+	return true;
+}
+bool PackGetData2(PACK *p, char *name, void *data, UINT size)
+{
+	return PackGetDataEx2(p, name, data, size, 0);
+}
+bool PackGetDataEx2(PACK *p, char *name, void *data, UINT size, UINT index)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	e = GetElement(p, name, VALUE_DATA);
+	if (e == NULL)
+	{
+		return false;
+	}
+	if (GetDataValueSize(e, index) != size)
+	{
+		return false;
+	}
+	Copy(data, GetDataValue(e, index), GetDataValueSize(e, index));
+	return true;
+}
+
+// PACK からデータサイズを取得
+UINT PackGetDataSize(PACK *p, char *name)
+{
+	return PackGetDataSizeEx(p, name, 0);
+}
+UINT PackGetDataSizeEx(PACK *p, char *name, UINT index)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	e = GetElement(p, name, VALUE_DATA);
+	if (e == NULL)
+	{
+		return 0;
+	}
+	return GetDataValueSize(e, index);
+}
+
+// PACK から整数を取得
+UINT64 PackGetInt64(PACK *p, char *name)
+{
+	return PackGetInt64Ex(p, name, 0);
+}
+UINT64 PackGetInt64Ex(PACK *p, char *name, UINT index)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	e = GetElement(p, name, VALUE_INT64);
+	if (e == NULL)
+	{
+		return 0;
+	}
+	return GetInt64Value(e, index);
+}
+
+// PACK からインデックス数を取得
+UINT PackGetIndexCount(PACK *p, char *name)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	e = GetElement(p, name, INFINITE);
+	if (e == NULL)
+	{
+		return 0;
+	}
+
+	return e->num_value;
+}
+
+// PACK から個数を取得
+UINT PackGetNum(PACK *p, char *name)
+{
+	return MIN(PackGetInt(p, name), 65536);
+}
+
+// PACK から bool 型を取得
+bool PackGetBool(PACK *p, char *name)
+{
+	return PackGetInt(p, name) == 0 ? false : true;
+}
+bool PackGetBoolEx(PACK *p, char *name, UINT index)
+{
+	return PackGetIntEx(p, name, index) == 0 ? false : true;
+}
+
+// PACK に bool 型を追加
+void PackAddBool(PACK *p, char *name, bool b)
+{
+	PackAddInt(p, name, b ? 1 : 0);
+}
+void PackAddBoolEx(PACK *p, char *name, bool b, UINT index, UINT total)
+{
+	PackAddIntEx(p, name, b ? 1 : 0, index, total);
+}
+
+// PACK に IPV6_ADDR を追加
+void PackAddIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index, UINT total)
+{
+	// 引数チェック
+	if (p == NULL || name == NULL || addr == NULL)
+	{
+		return;
+	}
+
+	PackAddDataEx(p, name, addr, sizeof(IPV6_ADDR), index, total);
+}
+void PackAddIp6Addr(PACK *p, char *name, IPV6_ADDR *addr)
+{
+	PackAddIp6AddrEx(p, name, addr, 0, 1);
+}
+
+// PACK から IPV6_ADDR を取得
+bool PackGetIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index)
+{
+	// 引数チェック
+	if (p == NULL || name == NULL || addr == NULL)
+	{
+		Zero(addr, sizeof(IPV6_ADDR));
+		return false;
+	}
+
+	return PackGetDataEx2(p, name, addr, sizeof(IPV6_ADDR), index);
+}
+bool PackGetIp6Addr(PACK *p, char *name, IPV6_ADDR *addr)
+{
+	return PackGetIp6AddrEx(p, name, addr, 0);
+}
+
+// PACK に IP を追加
+void PackAddIp32Ex(PACK *p, char *name, UINT ip32, UINT index, UINT total)
+{
+	IP ip;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return;
+	}
+
+	UINTToIP(&ip, ip32);
+
+	PackAddIpEx(p, name, &ip, index, total);
+}
+void PackAddIp32(PACK *p, char *name, UINT ip32)
+{
+	PackAddIp32Ex(p, name, ip32, 0, 1);
+}
+void PackAddIpEx(PACK *p, char *name, IP *ip, UINT index, UINT total)
+{
+	UINT i;
+	bool b = false;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (p == NULL || name == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	b = IsIP6(ip);
+
+	Format(tmp, sizeof(tmp), "%s@ipv6_bool", name);
+	PackAddBoolEx(p, tmp, b, index, total);
+
+	Format(tmp, sizeof(tmp), "%s@ipv6_array", name);
+	if (b)
+	{
+		PackAddDataEx(p, tmp, ip->ipv6_addr, sizeof(ip->ipv6_addr), index, total);
+	}
+	else
+	{
+		UCHAR dummy[16];
+
+		Zero(dummy, sizeof(dummy));
+
+		PackAddDataEx(p, tmp, dummy, sizeof(dummy), index, total);
+	}
+
+	Format(tmp, sizeof(tmp), "%s@ipv6_scope_id", name);
+	if (b)
+	{
+		PackAddIntEx(p, tmp, ip->ipv6_scope_id, index, total);
+	}
+	else
+	{
+		PackAddIntEx(p, tmp, 0, index, total);
+	}
+
+	i = IPToUINT(ip);
+
+	if (IsBigEndian())
+	{
+		i = Swap32(i);
+	}
+
+	PackAddIntEx(p, name, i, index, total);
+}
+void PackAddIp(PACK *p, char *name, IP *ip)
+{
+	PackAddIpEx(p, name, ip, 0, 1);
+}
+
+// PACK から IP を取得
+UINT PackGetIp32Ex(PACK *p, char *name, UINT index)
+{
+	IP ip;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	if (PackGetIpEx(p, name, &ip, index) == false)
+	{
+		return 0;
+	}
+
+	return IPToUINT(&ip);
+}
+UINT PackGetIp32(PACK *p, char *name)
+{
+	return PackGetIp32Ex(p, name, 0);
+}
+bool PackGetIpEx(PACK *p, char *name, IP *ip, UINT index)
+{
+	UINT i;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (p == NULL || ip == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	Format(tmp, sizeof(tmp), "%s@ipv6_bool", name);
+	if (PackGetBoolEx(p, tmp, index))
+	{
+		UCHAR data[16];
+		UINT scope_id;
+
+		Zero(data, sizeof(data));
+
+		Format(tmp, sizeof(tmp), "%s@ipv6_array", name);
+		PackGetDataEx2(p, tmp, data, sizeof(data), index);
+
+		Format(tmp, sizeof(tmp), "%s@ipv6_scope_id", name);
+		scope_id = PackGetIntEx(p, tmp, index);
+
+		SetIP6(ip, data);
+		ip->ipv6_scope_id = scope_id;
+	}
+	else
+	{
+		if (GetElement(p, name, VALUE_INT) == NULL)
+		{
+			Zero(ip, sizeof(IP));
+			return false;
+		}
+
+		i = PackGetIntEx(p, name, index);
+
+		if (IsBigEndian())
+		{
+			i = Swap32(i);
+		}
+
+		UINTToIP(ip, i);
+	}
+
+	return true;
+}
+bool PackGetIp(PACK *p, char *name, IP *ip)
+{
+	return PackGetIpEx(p, name, ip, 0);
+}
+
+// PACK から整数を取得
+UINT PackGetInt(PACK *p, char *name)
+{
+	return PackGetIntEx(p, name, 0);
+}
+UINT PackGetIntEx(PACK *p, char *name, UINT index)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	e = GetElement(p, name, VALUE_INT);
+	if (e == NULL)
+	{
+		return 0;
+	}
+	return GetIntValue(e, index);
+}
+
+// PACK から Unicode 文字列を取得
+bool PackGetUniStr(PACK *p, char *name, wchar_t *unistr, UINT size)
+{
+	return PackGetUniStrEx(p, name, unistr, size, 0);
+}
+bool PackGetUniStrEx(PACK *p, char *name, wchar_t *unistr, UINT size, UINT index)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL || unistr == NULL || size == 0)
+	{
+		return false;
+	}
+
+	unistr[0] = 0;
+
+	e = GetElement(p, name, VALUE_UNISTR);
+	if (e == NULL)
+	{
+		return false;
+	}
+	UniStrCpy(unistr, size, GetUniStrValue(e, index));
+	return true;
+}
+
+// PACK から文字列を取得
+bool PackGetStr(PACK *p, char *name, char *str, UINT size)
+{
+	return PackGetStrEx(p, name, str, size, 0);
+}
+bool PackGetStrEx(PACK *p, char *name, char *str, UINT size, UINT index)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL || str == NULL || size == 0)
+	{
+		return false;
+	}
+
+	str[0] = 0;
+
+	e = GetElement(p, name, VALUE_STR);
+	if (e == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(str, size, GetStrValue(e, index));
+	return true;
+}
+
+// バッファを PACK に追加 (配列)
+void PackAddBufEx(PACK *p, char *name, BUF *b, UINT index, UINT total)
+{
+	// 引数チェック
+	if (p == NULL || name == NULL || b == NULL || total == 0)
+	{
+		return;
+	}
+
+	PackAddDataEx(p, name, b->Buf, b->Size, index, total);
+}
+
+// データを PACK に追加 (配列)
+void PackAddDataEx(PACK *p, char *name, void *data, UINT size, UINT index, UINT total)
+{
+	VALUE *v;
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || data == NULL || name == NULL || total == 0)
+	{
+		return;
+	}
+
+	v = NewDataValue(data, size);
+	e = GetElement(p, name, VALUE_DATA);
+	if (e != NULL)
+	{
+		if (e->num_value <= total)
+		{
+			e->values[index] = v;
+		}
+		else
+		{
+			FreeValue(v, VALUE_DATA);
+		}
+	}
+	else
+	{
+		e = ZeroMallocEx(sizeof(ELEMENT), true);
+		StrCpy(e->name, sizeof(e->name), name);
+		e->num_value = total;
+		e->type = VALUE_DATA;
+		e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);
+		e->values[index] = v;
+		AddElement(p, e);
+	}
+}
+
+// バッファを PACK に追加
+void PackAddBuf(PACK *p, char *name, BUF *b)
+{
+	// 引数チェック
+	if (p == NULL || name == NULL || b == NULL)
+	{
+		return;
+	}
+
+	PackAddData(p, name, b->Buf, b->Size);
+}
+
+// データを PACK に追加
+void PackAddData(PACK *p, char *name, void *data, UINT size)
+{
+	VALUE *v;
+	// 引数チェック
+	if (p == NULL || data == NULL || name == NULL)
+	{
+		return;
+	}
+
+	v = NewDataValue(data, size);
+	AddElement(p, NewElement(name, VALUE_DATA, 1, &v));
+}
+
+// 64 bit 整数を PACK に追加 (配列)
+void PackAddInt64Ex(PACK *p, char *name, UINT64 i, UINT index, UINT total)
+{
+	VALUE *v;
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL || total == 0)
+	{
+		return;
+	}
+
+	v = NewInt64Value(i);
+	e = GetElement(p, name, VALUE_INT64);
+	if (e != NULL)
+	{
+		if (e->num_value <= total)
+		{
+			e->values[index] = v;
+		}
+		else
+		{
+			FreeValue(v, VALUE_INT64);
+		}
+	}
+	else
+	{
+		e = ZeroMallocEx(sizeof(ELEMENT), true);
+		StrCpy(e->name, sizeof(e->name), name);
+		e->num_value = total;
+		e->type = VALUE_INT64;
+		e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);
+		e->values[index] = v;
+		AddElement(p, e);
+	}
+}
+
+// 整数を PACK に追加 (配列)
+void PackAddIntEx(PACK *p, char *name, UINT i, UINT index, UINT total)
+{
+	VALUE *v;
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL || total == 0)
+	{
+		return;
+	}
+
+	v = NewIntValue(i);
+	e = GetElement(p, name, VALUE_INT);
+	if (e != NULL)
+	{
+		if (e->num_value <= total)
+		{
+			e->values[index] = v;
+		}
+		else
+		{
+			FreeValue(v, VALUE_INT);
+		}
+	}
+	else
+	{
+		e = ZeroMallocEx(sizeof(ELEMENT), true);
+		StrCpy(e->name, sizeof(e->name), name);
+		e->num_value = total;
+		e->type = VALUE_INT;
+		e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);
+		e->values[index] = v;
+		AddElement(p, e);
+	}
+}
+
+// 64 bit 整数を PACK に追加
+void PackAddInt64(PACK *p, char *name, UINT64 i)
+{
+	VALUE *v;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return;
+	}
+
+	v = NewInt64Value(i);
+	AddElement(p, NewElement(name, VALUE_INT64, 1, &v));
+}
+
+// 個数を PACK に追加
+void PackAddNum(PACK *p, char *name, UINT num)
+{
+	PackAddInt(p, name, num);
+}
+
+// 整数を PACK に追加
+void PackAddInt(PACK *p, char *name, UINT i)
+{
+	VALUE *v;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return;
+	}
+
+	v = NewIntValue(i);
+	AddElement(p, NewElement(name, VALUE_INT, 1, &v));
+}
+
+// Unicode 文字列を PACK に追加 (配列)
+void PackAddUniStrEx(PACK *p, char *name, wchar_t *unistr, UINT index, UINT total)
+{
+	VALUE *v;
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL || unistr == NULL || total == 0)
+	{
+		return;
+	}
+
+	v = NewUniStrValue(unistr);
+	e = GetElement(p, name, VALUE_UNISTR);
+	if (e != NULL)
+	{
+		if (e->num_value <= total)
+		{
+			e->values[index] = v;
+		}
+		else
+		{
+			FreeValue(v, VALUE_UNISTR);
+		}
+	}
+	else
+	{
+		e = ZeroMallocEx(sizeof(ELEMENT), true);
+		StrCpy(e->name, sizeof(e->name), name);
+		e->num_value = total;
+		e->type = VALUE_UNISTR;
+		e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);
+		e->values[index] = v;
+		AddElement(p, e);
+	}
+}
+
+// Unicode 文字列を PACK に追加
+void PackAddUniStr(PACK *p, char *name, wchar_t *unistr)
+{
+	VALUE *v;
+	// 引数チェック
+	if (p == NULL || name == NULL || unistr == NULL)
+	{
+		return;
+	}
+
+	v = NewUniStrValue(unistr);
+	AddElement(p, NewElement(name, VALUE_UNISTR, 1, &v));
+}
+
+// 文字列を PACK に追加 (配列)
+void PackAddStrEx(PACK *p, char *name, char *str, UINT index, UINT total)
+{
+	VALUE *v;
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL || str == NULL || total == 0)
+	{
+		return;
+	}
+
+	v = NewStrValue(str);
+	e = GetElement(p, name, VALUE_STR);
+	if (e != NULL)
+	{
+		if (e->num_value <= total)
+		{
+			e->values[index] = v;
+		}
+		else
+		{
+			FreeValue(v, VALUE_STR);
+		}
+	}
+	else
+	{
+		e = ZeroMallocEx(sizeof(ELEMENT), true);
+		StrCpy(e->name, sizeof(e->name), name);
+		e->num_value = total;
+		e->type = VALUE_STR;
+		e->values = ZeroMallocEx(sizeof(VALUE *) * total, true);
+		e->values[index] = v;
+		AddElement(p, e);
+	}
+}
+
+// 文字列を PACK に追加
+void PackAddStr(PACK *p, char *name, char *str)
+{
+	VALUE *v;
+	// 引数チェック
+	if (p == NULL || name == NULL || str == NULL)
+	{
+		return;
+	}
+
+	v = NewStrValue(str);
+	AddElement(p, NewElement(name, VALUE_STR, 1, &v));
+}
+
+// RC4 キーペアを生成
+void GenerateRC4KeyPair(RC4_KEY_PAIR *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	Rand(k->ClientToServerKey, sizeof(k->ClientToServerKey));
+	Rand(k->ServerToClientKey, sizeof(k->ServerToClientKey));
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Protocol.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Protocol.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Protocol.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,299 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Protocol.h
+// Protocol.c のヘッダ
+
+#ifndef	PROTOCOL_H
+#define	PROTOCOL_H
+
+// 証明書確認用スレッドに渡すパラメータ
+struct CHECK_CERT_THREAD_PROC
+{
+	CONNECTION *Connection;
+	X *ServerX;
+	CHECK_CERT_PROC *CheckCertProc;
+	bool UserSelected;
+	bool Exipred;
+	bool Ok;
+};
+
+// セキュアデバイス署名用スレッドに渡すパラメータ
+struct SECURE_SIGN_THREAD_PROC
+{
+	SECURE_SIGN_PROC *SecureSignProc;
+	CONNECTION *Connection;
+	SECURE_SIGN *SecureSign;
+	bool UserFinished;
+	bool Ok;
+};
+
+// ランダムサイズキャッシュ
+struct RAND_CACHE
+{
+	IP Ip;							// IP アドレス
+	UINT RandSize;					// ランダムサイズ
+	UINT64 LastTime;				// 最終使用日時
+};
+
+// HTTP 値
+struct HTTP_VALUE
+{
+	char *Name;						// 名前
+	char *Data;						// データ
+};
+
+// HTTP ヘッダ
+struct HTTP_HEADER
+{
+	char *Method;					// メソッド
+	char *Target;					// ターゲット
+	char *Version;					// バージョン
+	LIST *ValueList;				// 値リスト
+};
+
+// シグネチャ送信スレッド用パラメータ
+struct SEND_SIGNATURE_PARAM
+{
+	char Hostname[MAX_PATH];		// ホスト名
+	UINT Port;						// ポート番号
+	BUF *Buffer;					// パケット内容
+};
+
+
+// 関数プロトタイプ
+bool ServerAccept(CONNECTION *c);
+bool ClientConnect(CONNECTION *c);
+SOCK *ClientConnectToServer(CONNECTION *c);
+SOCK *TcpIpConnect(char *hostname, UINT port);
+SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd);
+bool ClientUploadSignature(SOCK *s);
+bool ClientDownloadHello(CONNECTION *c, SOCK *s);
+bool ServerDownloadSignature(CONNECTION *c);
+bool ServerUploadHello(CONNECTION *c);
+bool ClientUploadAuth(CONNECTION *c);
+SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect);
+SOCK *TcpConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd);
+
+void InitProtocol();
+void FreeProtocol();
+
+bool HttpServerSend(SOCK *s, PACK *p);
+PACK *HttpServerRecv(SOCK *s);
+PACK *HttpClientRecv(SOCK *s);
+bool HttpClientSend(SOCK *s, PACK *p);
+
+bool HttpSendForbidden(SOCK *s, char *target, char *server_id);
+bool HttpSendNotFound(SOCK *s, char *target);
+bool HttpSendNotImplemented(SOCK *s, char *method, char *target, char *version);
+
+char *RecvLine(SOCK *s, UINT max_size);
+HTTP_HEADER *RecvHttpHeader(SOCK *s);
+void FreeHttpHeader(HTTP_HEADER *header);
+void FreeHttpValue(HTTP_VALUE *value);
+HTTP_HEADER *NewHttpHeader(char *method, char *target, char *version);
+void AddHttpValue(HTTP_HEADER *header, HTTP_VALUE *value);
+int CompareHttpValue(void *p1, void *p2);
+HTTP_VALUE *GetHttpValue(HTTP_HEADER *header, char *name);
+HTTP_VALUE *NewHttpValue(char *name, char *data);
+char *HttpHeaderToStr(HTTP_HEADER *header);
+bool SendHttpHeader(SOCK *s, HTTP_HEADER *header);
+bool PostHttp(SOCK *s, HTTP_HEADER *header, void *post_data, UINT post_size);
+UINT GetContentLength(HTTP_HEADER *header);
+void GetHttpDateStr(char *str, UINT size, UINT64 t);
+void CreateDummyValue(PACK *p);
+
+X *PackGetX(PACK *p, char *name);
+K *PackGetK(PACK *p, char *name);
+void PackAddX(PACK *p, char *name, X *x);
+void PackAddK(PACK *p, char *name, K *k);
+void PackAddStr(PACK *p, char *name, char *str);
+void PackAddStrEx(PACK *p, char *name, char *str, UINT index, UINT total);
+void PackAddUniStr(PACK *p, char *name, wchar_t *unistr);
+void PackAddUniStrEx(PACK *p, char *name, wchar_t *unistr, UINT index, UINT total);
+void PackAddInt(PACK *p, char *name, UINT i);
+void PackAddNum(PACK *p, char *name, UINT num);
+void PackAddIntEx(PACK *p, char *name, UINT i, UINT index, UINT total);
+void PackAddInt64(PACK *p, char *name, UINT64 i);
+void PackAddInt64Ex(PACK *p, char *name, UINT64 i, UINT index, UINT total);
+void PackAddData(PACK *p, char *name, void *data, UINT size);
+void PackAddDataEx(PACK *p, char *name, void *data, UINT size, UINT index, UINT total);
+void PackAddBuf(PACK *p, char *name, BUF *b);
+void PackAddBufEx(PACK *p, char *name, BUF *b, UINT index, UINT total);
+bool PackGetStr(PACK *p, char *name, char *str, UINT size);
+bool PackGetStrEx(PACK *p, char *name, char *str, UINT size, UINT index);
+bool PackGetUniStr(PACK *p, char *name, wchar_t *unistr, UINT size);
+bool PackGetUniStrEx(PACK *p, char *name, wchar_t *unistr, UINT size, UINT index);
+UINT PackGetIndexCount(PACK *p, char *name);
+UINT PackGetInt(PACK *p, char *name);
+UINT PackGetNum(PACK *p, char *name);
+UINT PackGetIntEx(PACK *p, char *name, UINT index);
+UINT64 PackGetInt64(PACK *p, char *name);
+UINT64 PackGetInt64Ex(PACK *p, char *name, UINT index);
+UINT PackGetDataSizeEx(PACK *p, char *name, UINT index);
+UINT PackGetDataSize(PACK *p, char *name);
+bool PackGetData(PACK *p, char *name, void *data);
+bool PackGetDataEx(PACK *p, char *name, void *data, UINT index);
+BUF *PackGetBuf(PACK *p, char *name);
+BUF *PackGetBufEx(PACK *p, char *name, UINT index);
+POLICY *PackGetPolicy(PACK *p);
+void PackAddPolicy(PACK *p, POLICY *y);
+bool PackGetBool(PACK *p, char *name);
+void PackAddBool(PACK *p, char *name, bool b);
+void PackAddBoolEx(PACK *p, char *name, bool b, UINT index, UINT total);
+bool PackGetBoolEx(PACK *p, char *name, UINT index);
+void PackAddIp(PACK *p, char *name, IP *ip);
+void PackAddIpEx(PACK *p, char *name, IP *ip, UINT index, UINT total);
+bool PackGetIp(PACK *p, char *name, IP *ip);
+bool PackGetIpEx(PACK *p, char *name, IP *ip, UINT index);
+UINT PackGetIp32(PACK *p, char *name);
+UINT PackGetIp32Ex(PACK *p, char *name, UINT index);
+void PackAddIp32(PACK *p, char *name, UINT ip32);
+void PackAddIp32Ex(PACK *p, char *name, UINT ip32, UINT index, UINT total);
+void PackAddIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index, UINT total);
+bool PackGetIp6AddrEx(PACK *p, char *name, IPV6_ADDR *addr, UINT index);
+void PackAddIp6Addr(PACK *p, char *name, IPV6_ADDR *addr);
+bool PackGetIp6Addr(PACK *p, char *name, IPV6_ADDR *addr);
+
+PACK *PackWelcome(SESSION *s);
+PACK *PackHello(void *random, UINT ver, UINT build, char *server_str);
+bool GetHello(PACK *p, void *random, UINT *ver, UINT *build, char *server_str, UINT server_str_size);
+PACK *PackLoginWithAnonymous(char *hubname, char *username);
+PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password);
+PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_password);
+PACK *PackLoginWithCert(char *hubname, char *username, X *x, void *sign, UINT sign_size);
+bool GetMethodFromPack(PACK *p, char *method, UINT size);
+bool GetHubnameAndUsernameFromPack(PACK *p, char *username, UINT username_size,
+								   char *hubname, UINT hubname_size);
+PACK *PackAdditionalConnect(UCHAR *session_key);
+UINT GetAuthTypeFromPack(PACK *p);
+UINT GetErrorFromPack(PACK *p);
+PACK *PackError(UINT error);
+UINT GetProtocolFromPack(PACK *p);
+bool ParseWelcomeFromPack(PACK *p, char *session_name, UINT session_name_size,
+						  char *connection_name, UINT connection_name_size,
+						  POLICY **policy);
+
+bool SendPack(SOCK *s, PACK *p);
+PACK *RecvPack(SOCK *s);
+
+bool ClientAdditionalConnect(CONNECTION *c, THREAD *t);
+SOCK *ClientAdditionalConnectToServer(CONNECTION *c);
+bool ClientUploadAuth2(CONNECTION *c, SOCK *s);
+bool GetSessionKeyFromPack(PACK *p, UCHAR *session_key, UINT *session_key_32);
+void GenerateRC4KeyPair(RC4_KEY_PAIR *k);
+
+SOCK *ProxyConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+				   char *server_host_name, UINT server_port,
+				   char *username, char *password, bool additional_connect);
+SOCK *ProxyConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+					 char *server_host_name, UINT server_port,
+					 char *username, char *password, bool additional_connect,
+					 bool *cancel_flag, void *hWnd);
+SOCK *SocksConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+				   char *server_host_name, UINT server_port,
+				   char *username, bool additional_connect);
+SOCK *SocksConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+					 char *server_host_name, UINT server_port,
+					 char *username, bool additional_connect,
+					 bool *cancel_flag, void *hWnd);
+bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid);
+bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s);
+void CreateNodeInfo(NODE_INFO *info, CONNECTION *c);
+UINT SecureSign(SECURE_SIGN *sign, UINT device_id, char *pin);
+void ClientUploadNoop(CONNECTION *c);
+bool ClientCheckServerCert(CONNECTION *c, bool *expired);
+void ClientCheckServerCertThread(THREAD *thread, void *param);
+bool ClientSecureSign(CONNECTION *c, UCHAR *sign, UCHAR *random, X **x);
+void ClientSecureSignThread(THREAD *thread, void *param);
+UINT SecureWrite(UINT device_id, char *cert_name, X *x, char *key_name, K *k, char *pin);
+UINT SecureEnum(UINT device_id, char *pin, TOKEN_LIST **cert_list, TOKEN_LIST **key_list);
+UINT SecureDelete(UINT device_id, char *pin, char *cert_name, char *key_name);
+bool PackGetData2(PACK *p, char *name, void *data, UINT size);
+bool PackGetDataEx2(PACK *p, char *name, void *data, UINT size, UINT index);
+TOKEN_LIST *EnumHub(SESSION *s);
+UINT ChangePasswordAccept(CONNECTION *c, PACK *p);
+UINT ChangePassword(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, char *username, char *old_pass, char *new_pass);
+void PackAddClientVersion(PACK *p, CONNECTION *c);
+void NodeInfoToStr(wchar_t *str, UINT size, NODE_INFO *info);
+void GenerateMachineUniqueHash(void *data);
+void SendSignatureByUdp(CONNECTION *c, IP *ip);
+void SendSignatureByTcp(CONNECTION *c, IP *ip);
+void SendSignatureByTcpThread(THREAD *thread, void *param);
+
+
+#endif	// PROTOCOL_H
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Remote.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Remote.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Remote.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,441 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Remote.c
+// リモートプロシージャーコール
+
+#include "CedarPch.h"
+
+// RPC の終了
+void EndRpc(RPC *rpc)
+{
+	RpcFree(rpc);
+}
+
+// RPC の解放
+void RpcFree(RPC *rpc)
+{
+	// 引数チェック
+	if (rpc == NULL)
+	{
+		return;
+	}
+
+	Disconnect(rpc->Sock);
+	ReleaseSock(rpc->Sock);
+
+	DeleteLock(rpc->Lock);
+
+	Free(rpc);
+}
+
+// エラーの取得
+UINT RpcGetError(PACK *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return ERR_DISCONNECTED;
+	}
+
+	return PackGetInt(p, "error_code");
+}
+
+// エラーチェック
+bool RpcIsOk(PACK *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	if (PackGetInt(p, "error") == 0)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// エラーコード設定
+void RpcError(PACK *p, UINT err)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "error", 1);
+	PackAddInt(p, "error_code", err);
+}
+
+// RPC ディスパッチャを起動する
+PACK *CallRpcDispatcher(RPC *r, PACK *p)
+{
+	char func_name[MAX_SIZE];
+	// 引数チェック
+	if (r == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	if (PackGetStr(p, "function_name", func_name, sizeof(func_name)) == false)
+	{
+		return NULL;
+	}
+
+	return r->Dispatch(r, func_name, p);
+}
+
+// 次の RPC 呼び出しを待機する
+bool RpcRecvNextCall(RPC *r)
+{
+	UINT size;
+	void *tmp;
+	SOCK *s;
+	BUF *b;
+	PACK *p;
+	PACK *ret;
+	// 引数チェック
+	if (r == NULL)
+	{
+		return false;
+	}
+
+	s = r->Sock;
+
+	if (RecvAll(s, &size, sizeof(UINT), s->SecureMode) == false)
+	{
+		return false;
+	}
+
+	size = Endian32(size);
+
+	if (size > MAX_PACK_SIZE)
+	{
+		return false;
+	}
+
+	tmp = MallocEx(size, true);
+
+	if (RecvAll(s, tmp, size, s->SecureMode) == false)
+	{
+		Free(tmp);
+		return false;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, tmp, size);
+	SeekBuf(b, 0, 0);
+	Free(tmp);
+
+	p = BufToPack(b);
+	FreeBuf(b);
+
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	ret = CallRpcDispatcher(r, p);
+	FreePack(p);
+
+	if (ret == NULL)
+	{
+		ret = PackError(ERR_NOT_SUPPORTED);
+	}
+
+	b = PackToBuf(ret);
+	FreePack(ret);
+
+	size = Endian32(b->Size);
+	SendAdd(s, &size, sizeof(UINT));
+	SendAdd(s, b->Buf, b->Size);
+
+	if (SendNow(s, s->SecureMode) == false)
+	{
+		FreeBuf(b);
+		return false;
+	}
+
+	FreeBuf(b);
+
+	return true;
+}
+
+// RPC サーバー動作
+void RpcServer(RPC *r)
+{
+	SOCK *s;
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	s = r->Sock;
+
+	while (true)
+	{
+		// 次の RPC 呼び出しを待機する
+		if (RpcRecvNextCall(r) == false)
+		{
+			// 通信エラー
+			break;
+		}
+	}
+}
+
+// RPC 呼び出し
+PACK *RpcCall(RPC *r, char *function_name, PACK *p)
+{
+	PACK *ret;
+	UINT num_retry = 0;
+	UINT err = 0;
+	// 引数チェック
+	if (r == NULL || function_name == NULL)
+	{
+		return NULL;
+	}
+
+//	Debug("RpcCall: %s\n", function_name);
+
+	Lock(r->Lock);
+	{
+		if (p == NULL)
+		{
+			p = NewPack();
+		}
+
+		PackAddStr(p, "function_name", function_name);
+
+RETRY:
+		err = 0;
+		ret = RpcCallInternal(r, p);
+
+		if (ret == NULL)
+		{
+			if (r->IsVpnServer && r->Sock != NULL)
+			{
+				if (num_retry < 1)
+				{
+					num_retry++;
+
+					// VPN Server に RPC 再接続を試みる
+					err = AdminReconnect(r);
+
+					if (err == ERR_NO_ERROR)
+					{
+						goto RETRY;
+					}
+				}
+			}
+		}
+
+		FreePack(p);
+
+		if (ret == NULL)
+		{
+			if (err == 0)
+			{
+				err = ERR_DISCONNECTED;
+			}
+
+			ret = PackError(err);
+			PackAddInt(ret, "error_code", err);
+		}
+	}
+	Unlock(r->Lock);
+
+	return ret;
+}
+
+// RPC 内部呼び出し
+PACK *RpcCallInternal(RPC *r, PACK *p)
+{
+	BUF *b;
+	UINT size;
+	PACK *ret;
+	void *tmp;
+	// 引数チェック
+	if (r == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	if (r->Sock == NULL)
+	{
+		return NULL;
+	}
+
+	b = PackToBuf(p);
+
+	size = Endian32(b->Size);
+	SendAdd(r->Sock, &size, sizeof(UINT));
+	SendAdd(r->Sock, b->Buf, b->Size);
+	FreeBuf(b);
+
+	if (SendNow(r->Sock, r->Sock->SecureMode) == false)
+	{
+		return NULL;
+	}
+
+	if (RecvAll(r->Sock, &size, sizeof(UINT), r->Sock->SecureMode) == false)
+	{
+		return NULL;
+	}
+
+	size = Endian32(size);
+	if (size > MAX_PACK_SIZE)
+	{
+		return NULL;
+	}
+
+	tmp = MallocEx(size, true);
+	if (RecvAll(r->Sock, tmp, size, r->Sock->SecureMode) == false)
+	{
+		Free(tmp);
+		return NULL;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, tmp, size);
+	SeekBuf(b, 0, 0);
+	Free(tmp);
+
+	ret = BufToPack(b);
+	if (ret == NULL)
+	{
+		FreeBuf(b);
+		return NULL;
+	}
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// RPC サーバーの開始
+RPC *StartRpcServer(SOCK *s, RPC_DISPATCHER *dispatch, void *param)
+{
+	RPC *r;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	r = ZeroMallocEx(sizeof(RPC), true);
+	r->Sock = s;
+	r->Param = param;
+	r->Lock = NewLock();
+	AddRef(s->ref);
+
+	r->ServerMode = true;
+	r->Dispatch = dispatch;
+
+	// 名前の生成
+	Format(r->Name, sizeof(r->Name), "RPC-%u", s->socket);
+
+	return r;
+}
+
+// RPC クライアントの開始
+RPC *StartRpcClient(SOCK *s, void *param)
+{
+	RPC *r;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	r = ZeroMalloc(sizeof(RPC));
+	r->Sock = s;
+	r->Param = param;
+	r->Lock = NewLock();
+	AddRef(s->ref);
+
+	r->ServerMode = false;
+
+	return r;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Remote.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Remote.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Remote.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,120 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Remote.h
+// Remote.c のヘッダ
+
+#ifndef	REMOTE_H
+#define	REMOTE_H
+
+// RPC 実行関数
+typedef PACK *(RPC_DISPATCHER)(RPC *r, char *function_name, PACK *p);
+
+// RPC オブジェクト
+struct RPC
+{
+	SOCK *Sock;						// ソケット
+	bool ServerMode;				// サーバーモード
+	RPC_DISPATCHER *Dispatch;		// 実行ルーチン
+	void *Param;					// パラメータ
+	bool ServerAdminMode;			// サーバー管理モード
+	char HubName[MAX_HUBNAME_LEN + 1];	// 管理対象 HUB 名
+	char Name[MAX_SIZE];			// RPC セッション名
+	LOCK *Lock;						// ロック
+	bool IsVpnServer;				// VPN Server 管理 RPC かどうか
+	CLIENT_OPTION VpnServerClientOption;
+	char VpnServerHubName[MAX_HUBNAME_LEN + 1];
+	UCHAR VpnServerHashedPassword[SHA1_SIZE];
+	char VpnServerClientName[MAX_PATH];
+};
+
+// 関数プロトタイプ
+RPC *StartRpcClient(SOCK *s, void *param);
+RPC *StartRpcServer(SOCK *s, RPC_DISPATCHER *dispatch, void *param);
+PACK *RpcCallInternal(RPC *r, PACK *p);
+PACK *RpcCall(RPC *r, char *function_name, PACK *p);
+void RpcServer(RPC *r);
+bool RpcRecvNextCall(RPC *r);
+PACK *CallRpcDispatcher(RPC *r, PACK *p);
+void RpcError(PACK *p, UINT err);
+bool RpcIsOk(PACK *p);
+UINT RpcGetError(PACK *p);
+void EndRpc(RPC *rpc);
+void RpcFree(RPC *rpc);
+
+#endif	// REMOTE_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SM.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SM.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SM.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,17688 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// SM.c
+// Win32 用 SoftEther UT-VPN Server Manager
+
+
+#ifdef	WIN32
+
+#define	SM_C
+#define	CM_C
+#define	NM_C
+
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "../PenCore/resource.h"
+
+// グローバル変数
+static SM *sm = NULL;
+static bool link_create_now = false;
+
+// メッセージ設定
+void SmHubMsg(HWND hWnd, SM_EDIT_HUB *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_MSG, SmHubMsgDlg, s);
+}
+
+// メッセージダイアログプロシージャ
+UINT SmHubMsgDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_HUB *s = (SM_EDIT_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmHubMsgDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_TEXT:
+			SmHubMsgDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			SmHubMsgDlgOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case C_USEMSG:
+			SmHubMsgDlgUpdate(hWnd, s);
+
+			if (IsChecked(hWnd, C_USEMSG))
+			{
+				FocusEx(hWnd, E_TEXT);
+			}
+			break;
+		}
+
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// メッセージダイアログ初期化
+void SmHubMsgDlgInit(HWND hWnd, SM_EDIT_HUB *s)
+{
+	RPC_MSG t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (MsIsVista())
+	{
+		SetFont(hWnd, E_TEXT, GetMeiryoFont());
+	}
+	else
+	{
+		DlgFont(hWnd, E_TEXT, 11, false);
+	}
+
+	FormatText(hWnd, S_MSG_2, s->HubName);
+
+	LimitText(hWnd, E_TEXT, HUB_MAXMSG_LEN);
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+	if (CALL(hWnd, ScGetHubMsg(s->p->Rpc, &t)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	if (UniIsEmptyStr(t.Msg) == false)
+	{
+		SetText(hWnd, E_TEXT, t.Msg);
+
+		Check(hWnd, C_USEMSG, true);
+	}
+	else
+	{
+		Check(hWnd, C_USEMSG, false);
+	}
+
+	FreeRpcMsg(&t);
+
+	SmHubMsgDlgUpdate(hWnd, s);
+}
+
+// OK ボタン
+void SmHubMsgDlgOnOk(HWND hWnd, SM_EDIT_HUB *s)
+{
+	RPC_MSG t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+	if (IsChecked(hWnd, C_USEMSG) == false)
+	{
+		t.Msg = CopyUniStr(L"");
+	}
+	else
+	{
+		t.Msg = GetText(hWnd, E_TEXT);
+	}
+
+	if (CALL(hWnd, ScSetHubMsg(s->p->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	FreeRpcMsg(&t);
+
+	EndDialog(hWnd, 1);
+}
+
+// メッセージダイアログ更新
+void SmHubMsgDlgUpdate(HWND hWnd, SM_EDIT_HUB *s)
+{
+	bool b = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, E_TEXT, IsChecked(hWnd, C_USEMSG));
+
+	if (IsChecked(hWnd, C_USEMSG))
+	{
+		wchar_t *s = GetText(hWnd, E_TEXT);
+
+		b = !IsEmptyUniStr(s);
+
+		Free(s);
+	}
+
+	SetEnable(hWnd, IDOK, b);
+}
+
+// VLAN ユーティリティ
+void SmVLan(HWND hWnd, SM_SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_VLAN, SmVLanDlg, s);
+}
+
+// VLAN ダイアログ
+UINT SmVLanDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *s = (SM_SERVER *)param;
+	NMHDR *n;
+
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmVLanDlgInit(hWnd, s);
+
+		if (LvNum(hWnd, L_LIST) == 0)
+		{
+			Disable(hWnd, L_LIST);
+			SetTimer(hWnd, 1, 100, NULL);
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_VLAN_NOTHING"),
+				s->CurrentSetting->ClientOption.Hostname);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case B_ENABLE:
+		case B_DISABLE:
+			{
+				UINT i = LvGetSelected(hWnd, L_LIST);
+				if (i != INFINITE)
+				{
+					char *name = LvGetStrA(hWnd, L_LIST, i, 0);
+
+					if (IsEmptyStr(name) == false)
+					{
+						RPC_TEST t;
+
+						Zero(&t, sizeof(t));
+
+						StrCpy(t.StrValue, sizeof(t.StrValue), name);
+						t.IntValue = BOOL_TO_INT(wParam == B_ENABLE);
+
+						if (CALL(hWnd, ScSetEnableEthVLan(s->Rpc, &t)))
+						{
+							SmVLanDlgRefresh(hWnd, s);
+
+							if (wParam == B_ENABLE)
+							{
+								MsgBoxEx(hWnd, MB_ICONINFORMATION,
+									_UU("SM_VLAN_MSG_1"),
+									name, name, name);
+							}
+							else
+							{
+								MsgBoxEx(hWnd, MB_ICONINFORMATION,
+									_UU("SM_VLAN_MSG_2"),
+									name);
+							}
+						}
+					}
+
+					Free(name);
+				}
+				break;
+			}
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_LIST:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmVLanDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// VLAN ダイアログ初期化
+void SmVLanDlgInit(HWND hWnd, SM_SERVER *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_VLAN_COLUMN_0"), 245);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_VLAN_COLUMN_1"), 75);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_VLAN_COLUMN_2"), 100);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_VLAN_COLUMN_3"), 100);
+	LvInsertColumn(hWnd, L_LIST, 4, _UU("SM_VLAN_COLUMN_4"), 290);
+	LvInsertColumn(hWnd, L_LIST, 5, _UU("SM_VLAN_COLUMN_5"), 430);
+
+	SmVLanDlgRefresh(hWnd, s);
+}
+
+// VLAN ダイアログ内容更新
+void SmVLanDlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+	LVB *b;
+	RPC_ENUM_ETH_VLAN t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScEnumEthVLan(s->Rpc, &t)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	b = LvInsertStart();
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_ETH_VLAN_ITEM *e = &t.Items[i];
+
+		if (e->Support)
+		{
+			wchar_t tmp0[MAX_SIZE];
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_SIZE];
+			wchar_t *tmp3;
+			wchar_t tmp4[MAX_SIZE];
+			wchar_t tmp5[MAX_SIZE];
+
+			StrToUni(tmp0, sizeof(tmp0), e->DeviceName);
+			StrToUni(tmp1, sizeof(tmp1), e->DriverType);
+			StrToUni(tmp2, sizeof(tmp2), e->DriverName);
+			tmp3 = (e->Enabled ? _UU("SM_VLAN_YES") : _UU("SM_VLAN_NO"));
+			StrToUni(tmp4, sizeof(tmp4), e->Guid);
+			StrToUni(tmp5, sizeof(tmp5), e->DeviceInstanceId);
+
+			LvInsertAdd(b,
+				e->Enabled ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE, 0, 6,
+				tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+		}
+	}
+
+	LvInsertEnd(b, hWnd, L_LIST);
+
+	FreeRpcEnumEthVLan(&t);
+
+	SmVLanDlgUpdate(hWnd, s);
+}
+
+// VLAN ダイアログコントロール更新
+void SmVLanDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSingleSelected(hWnd, L_LIST) == false)
+	{
+		Disable(hWnd, B_ENABLE);
+		Disable(hWnd, B_DISABLE);
+	}
+	else
+	{
+		UINT i = LvGetSelected(hWnd, L_LIST);
+		if (i != INFINITE)
+		{
+			wchar_t *s = LvGetStr(hWnd, L_LIST, i, 3);
+
+			if (UniStrCmpi(s, _UU("SM_VLAN_YES")) != 0)
+			{
+				Enable(hWnd, B_ENABLE);
+				Disable(hWnd, B_DISABLE);
+			}
+			else
+			{
+				Enable(hWnd, B_DISABLE);
+				Disable(hWnd, B_ENABLE);
+			}
+
+			Free(s);
+		}
+	}
+}
+
+// 現在の VPN Server / VPN Bridge の状態が初期状態かどうか調べる
+bool SmSetupIsNew(SM_SERVER *s)
+{
+	RPC *rpc;
+	bool is_bridge;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	bool check_hub = false;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	if (s->ServerAdminMode == false)
+	{
+		return false;
+	}
+
+	rpc = s->Rpc;
+	is_bridge =s->Bridge;
+
+	// ローカルブリッジのサポート
+	if (true)
+	{
+		RPC_BRIDGE_SUPPORT t;
+
+		Zero(&t, sizeof(t));
+
+		if (ScGetBridgeSupport(rpc, &t) == ERR_NO_ERROR)
+		{
+			if (t.IsBridgeSupportedOs == false ||
+				t.IsWinPcapNeeded)
+			{
+				return false;
+			}
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	// サーバー種類
+	if (is_bridge == false)
+	{
+		bool b = false;
+		RPC_SERVER_INFO t;
+
+		Zero(&t, sizeof(t));
+		if (ScGetServerInfo(rpc, &t) == ERR_NO_ERROR)
+		{
+			if (t.ServerType != SERVER_TYPE_STANDALONE)
+			{
+				b = true;
+			}
+
+			FreeRpcServerInfo(&t);
+		}
+		else
+		{
+			return false;
+		}
+
+		if (b)
+		{
+			return false;
+		}
+	}
+
+	// ローカルブリッジ
+	if (true)
+	{
+		RPC_ENUM_LOCALBRIDGE t;
+		bool b = false;
+
+		Zero(&t, sizeof(t));
+		if (ScEnumLocalBridge(rpc, &t) == ERR_NO_ERROR)
+		{
+			if (t.NumItem != 0)
+			{
+				b = true;
+			}
+			FreeRpcEnumLocalBridge(&t);
+		}
+
+		if (b)
+		{
+			return false;
+		}
+	}
+
+	// 仮想 HUB
+
+	check_hub = false;
+
+	if (is_bridge == false)
+	{
+		RPC_ENUM_HUB t;
+		bool b = false;
+
+		Zero(&t, sizeof(t));
+		if (ScEnumHub(rpc, &t) == ERR_NO_ERROR)
+		{
+			if (t.NumHub >= 2)
+			{
+				b = true;
+			}
+			else if (t.NumHub == 1)
+			{
+				if (StrCmpi(t.Hubs[0].HubName, SERVER_DEFAULT_HUB_NAME) != 0)
+				{
+					b = true;
+				}
+				else
+				{
+					check_hub = true;
+				}
+			}
+
+			FreeRpcEnumHub(&t);
+		}
+
+		if (b)
+		{
+			return false;
+		}
+	}
+	else
+	{
+		check_hub = true;
+	}
+
+	// 仮想 HUB の状態
+	if (is_bridge == false)
+	{
+		StrCpy(hubname, sizeof(hubname), SERVER_DEFAULT_HUB_NAME);
+	}
+	else
+	{
+		StrCpy(hubname, sizeof(hubname), SERVER_DEFAULT_BRIDGE_NAME);
+	}
+
+	if (check_hub)
+	{
+		if (true)
+		{
+			// 仮想 HUB 内のオブジェクト数
+			RPC_HUB_STATUS t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+			if (ScGetHubStatus(rpc, &t) == ERR_NO_ERROR)
+			{
+				if (t.NumSessions != 0 || t.NumAccessLists != 0 ||
+					t.NumUsers != 0 || t.NumGroups != 0 ||
+					t.NumMacTables != 0 || t.NumIpTables != 0 ||
+					t.SecureNATEnabled)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		if (true)
+		{
+			// カスケード接続
+			RPC_ENUM_LINK t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+			if (ScEnumLink(rpc, &t) == ERR_NO_ERROR)
+			{
+				bool b = false;
+
+				if (t.NumLink != 0)
+				{
+					b = true;
+				}
+
+				FreeRpcEnumLink(&t);
+
+				if (b)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		if (is_bridge == false)
+		{
+			// 信頼する証明書一覧
+			RPC_HUB_ENUM_CA t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+			if (ScEnumCa(rpc, &t) == ERR_NO_ERROR)
+			{
+				bool b = false;
+
+				if (t.NumCa != 0)
+				{
+					b = true;
+				}
+
+				FreeRpcHubEnumCa(&t);
+
+				if (b)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		if (is_bridge == false)
+		{
+			// 無効な証明書一覧
+			RPC_ENUM_CRL t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+			if (ScEnumCrl(rpc, &t) == ERR_NO_ERROR)
+			{
+				bool b = false;
+
+				if (t.NumItem != 0)
+				{
+					b = true;
+				}
+
+				FreeRpcEnumCrl(&t);
+
+				if (b)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		if (is_bridge == false)
+		{
+			// 認証サーバーの設定
+			RPC_RADIUS t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+			if (ScGetHubRadius(rpc, &t) == ERR_NO_ERROR)
+			{
+				if (IsEmptyStr(t.RadiusServerName) == false)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		if (is_bridge == false)
+		{
+			// 仮想 HUB の設定
+			RPC_CREATE_HUB t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+			if (ScGetHub(rpc, &t) == ERR_NO_ERROR)
+			{
+				if (t.HubOption.NoEnum || t.HubOption.MaxSession != 0 ||
+					t.Online == false)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		if (is_bridge == false)
+		{
+			// IP アクセス制御リスト
+			RPC_AC_LIST t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+			if (ScGetAcList(rpc, &t) == ERR_NO_ERROR)
+			{
+				bool b = false;
+				if (LIST_NUM(t.o) != 0)
+				{
+					b = true;
+				}
+				FreeRpcAcList(&t);
+
+				if (b)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		if (is_bridge == false)
+		{
+			// AO
+			RPC_ADMIN_OPTION t;
+
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+			if (ScGetHubAdminOptions(rpc, &t) == ERR_NO_ERROR)
+			{
+				bool b = false;
+				UINT i;
+
+				for (i = 0;i < t.NumItem;i++)
+				{
+					if (t.Items[i].Value != 0)
+					{
+						b = true;
+					}
+				}
+
+				FreeRpcAdminOption(&t);
+
+				if (b)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				return false;
+			}
+		}
+	}
+
+	// 仮想レイヤ 3 スイッチ
+	if (is_bridge == false)
+	{
+		RPC_ENUM_L3SW t;
+		bool b = false;
+
+		Zero(&t, sizeof(t));
+		if (ScEnumL3Switch(rpc, &t) == ERR_NO_ERROR)
+		{
+			if (t.NumItem != 0)
+			{
+				b = true;
+			}
+
+			FreeRpcEnumL3Sw(&t);
+		}
+		else
+		{
+			return false;
+		}
+
+		if (b)
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// セットアップ手順ダイアログ初期化
+void SmSetupStepDlgInit(HWND hWnd, SM_SETUP *s)
+{
+	bool b;
+	RPC_ENUM_ETH t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_SETUP);
+
+	DlgFont(hWnd, S_1_1, 0, true);
+	DlgFont(hWnd, S_2_1, 0, true);
+	DlgFont(hWnd, S_3_1, 0, true);
+
+	b = false;
+	if (s->UseRemote)
+	{
+		b = true;
+	}
+	if (s->UseSite && s->UseSiteEdge == false)
+	{
+		b = true;
+	}
+
+	SetEnable(hWnd, S_1_1, b);
+	SetEnable(hWnd, S_1_2, b);
+	SetEnable(hWnd, B_USER, b);
+
+	b = false;
+	if (s->UseSiteEdge)
+	{
+		b = true;
+	}
+
+	SetEnable(hWnd, S_2_1, b);
+	SetEnable(hWnd, S_2_2, b);
+	SetEnable(hWnd, B_CASCADE, b);
+
+	CbReset(hWnd, C_DEVICE);
+	CbSetHeight(hWnd, C_DEVICE, 18);
+
+	Zero(&t, sizeof(t));
+
+	CbAddStr(hWnd, C_DEVICE, _UU("SM_SETUP_SELECT"), 0);
+
+	if (CALL(hWnd, ScEnumEthernet(s->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		wchar_t tmp[MAX_PATH];
+		RPC_ENUM_ETH_ITEM *e = &t.Items[i];
+
+		StrToUni(tmp, sizeof(tmp), e->DeviceName);
+
+		CbAddStr(hWnd, C_DEVICE, tmp, 1);
+	}
+
+	FreeRpcEnumEth(&t);
+
+	s->Flag1 = false;
+	s->Flag2 = false;
+}
+
+// 閉じる
+void SmSetupOnClose(HWND hWnd, SM_SETUP *s)
+{
+	wchar_t *tmp;
+	char name[MAX_PATH];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	tmp = CbGetStr(hWnd, C_DEVICE);
+
+	if (tmp != NULL)
+	{
+		UniToStr(name, sizeof(name), tmp);
+
+		if (CbGetSelect(hWnd, C_DEVICE) != 0)
+		{
+			RPC_LOCALBRIDGE t;
+
+			Zero(&t, sizeof(t));
+			t.Active = true;
+			StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+			StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+			t.Online = true;
+			t.TapMode = false;
+
+			if (CALL(hWnd, ScAddLocalBridge(s->Rpc, &t)) == false)
+			{
+				Free(tmp);
+				return;
+			}
+		}
+		Free(tmp);
+	}
+
+	EndDialog(hWnd, 0);
+}
+
+// セットアップ手順ダイアログプロシージャ
+UINT SmSetupStepDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SETUP *s = (SM_SETUP *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmSetupStepDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_USER:
+			// ユーザー作成
+			if (true)
+			{
+				SM_HUB h;
+
+				Zero(&h, sizeof(h));
+				h.HubName = s->HubName;
+				h.p = s->s;
+				h.Rpc = s->Rpc;
+
+				SmUserListDlgEx(hWnd, &h, NULL, s->Flag1 ? false : true);
+
+				s->Flag1 = true;
+			}
+			break;
+
+		case B_CASCADE:
+			// カスケード接続作成
+			if (true)
+			{
+				SM_HUB h;
+
+				Zero(&h, sizeof(h));
+				h.HubName = s->HubName;
+				h.p = s->s;
+				h.Rpc = s->Rpc;
+
+				SmLinkDlgEx(hWnd, &h, s->Flag2 ? false : true);
+				s->Flag2 = true;
+			}
+			break;
+
+		case IDCANCEL:
+			// 閉じるボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		// 終了
+		SmSetupOnClose(hWnd, s);
+		break;
+	}
+
+	return 0;
+}
+
+// セットアップ手順ダイアログ
+void SmSetupStep(HWND hWnd, SM_SETUP *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_SETUP_STEP, SmSetupStepDlg, s);
+}
+
+// セットアップによる初期化を行う
+bool SmSetupInit(HWND hWnd, SM_SETUP *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	if (s->IsBridge == false)
+	{
+		if (SmSetupDeleteAllLayer3(hWnd, s) == false)
+		{
+			return false;
+		}
+
+		if (SmSetupDeleteAllHub(hWnd, s) == false)
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if (SmSetupDeleteAllObjectInBridgeHub(hWnd, s) == false)
+		{
+			return false;
+		}
+	}
+
+	if (SmSetupDeleteAllLocalBridge(hWnd, s) == false)
+	{
+		return false;
+	}
+
+	if (s->IsBridge == false)
+	{
+		// 仮想 HUB の作成
+		RPC_CREATE_HUB t;
+		char *password = "";
+
+		Zero(&t, sizeof(t));
+		Hash(t.HashedPassword, password, StrLen(password), true);
+		HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, password);
+		StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+		t.HubType = HUB_TYPE_STANDALONE;
+		t.Online = true;
+
+		if (CALL(hWnd, ScCreateHub(s->Rpc, &t)) == false)
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// すべての VPN Bridge 用の仮想 HUB 内のオブジェクトを削除
+bool SmSetupDeleteAllObjectInBridgeHub(HWND hWnd, SM_SETUP *s)
+{
+	char *hubname = SERVER_DEFAULT_BRIDGE_NAME;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	if (true)
+	{
+		RPC_ENUM_LINK t;
+		UINT i;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+		if (CALL(hWnd, ScEnumLink(s->Rpc, &t)) == false)
+		{
+			return false;
+		}
+
+		for (i = 0;i < t.NumLink;i++)
+		{
+			RPC_ENUM_LINK_ITEM *e = &t.Links[i];
+			RPC_LINK a;
+
+			Zero(&a, sizeof(a));
+			StrCpy(a.HubName, sizeof(a.HubName), hubname);
+			UniStrCpy(a.AccountName, sizeof(a.AccountName), e->AccountName);
+
+			if (CALL(hWnd, ScDeleteLink(s->Rpc, &a)) == false)
+			{
+				FreeRpcEnumLink(&t);
+				return false;
+			}
+		}
+
+		FreeRpcEnumLink(&t);
+	}
+
+	if (true)
+	{
+		RPC_HUB t;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+		if (CALL(hWnd, ScDisableSecureNAT(s->Rpc, &t)) == false)
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// すべての仮想レイヤ 3 スイッチの削除
+bool SmSetupDeleteAllLayer3(HWND hWnd, SM_SETUP *s)
+{
+	RPC_ENUM_L3SW t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	if(CALL(hWnd, ScEnumL3Switch(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+		RPC_L3SW tt;
+
+		Zero(&tt, sizeof(tt));
+		StrCpy(tt.Name, sizeof(tt.Name), e->Name);
+
+		if (CALL(hWnd, ScDelL3Switch(s->Rpc, &tt)) == false)
+		{
+			FreeRpcEnumL3Sw(&t);
+			return false;
+		}
+	}
+
+	FreeRpcEnumL3Sw(&t);
+
+	return true;
+}
+
+// すべてのローカルブリッジの削除
+bool SmSetupDeleteAllLocalBridge(HWND hWnd, SM_SETUP *s)
+{
+	RPC_ENUM_LOCALBRIDGE t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScEnumLocalBridge(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_LOCALBRIDGE *e = &t.Items[i];
+
+		if (CALL(hWnd, ScDeleteLocalBridge(s->Rpc, e)) == false)
+		{
+			FreeRpcEnumLocalBridge(&t);
+			return false;
+		}
+	}
+
+	FreeRpcEnumLocalBridge(&t);
+
+	return true;
+}
+
+// すべての仮想 HUB の削除
+bool SmSetupDeleteAllHub(HWND hWnd, SM_SETUP *s)
+{
+	RPC_ENUM_HUB t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScEnumHub(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	for (i = 0;i < t.NumHub;i++)
+	{
+		RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+		RPC_DELETE_HUB tt;
+
+		Zero(&tt, sizeof(tt));
+		StrCpy(tt.HubName, sizeof(tt.HubName), e->HubName);
+
+		if (CALL(hWnd, ScDeleteHub(s->Rpc, &tt)) == false)
+		{
+			FreeRpcEnumHub(&t);
+			return false;
+		}
+	}
+
+	FreeRpcEnumHub(&t);
+
+	return true;
+}
+
+// 仮想 HUB のコントロール更新
+void SmSetupHubDlgUpdate(HWND hWnd, SM_SETUP *s)
+{
+	bool ok = true;
+	char tmp[MAX_HUBNAME_LEN + 1];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	GetTxtA(hWnd, E_HUBNAME, tmp, sizeof(tmp));
+
+	if (IsEmptyStr(tmp) || IsSafeStr(tmp) == false)
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// 仮想 HUB 作成ダイアログ
+UINT SmSetupHubDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SETUP *s = (SM_SETUP *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetTextA(hWnd, E_HUBNAME, "VPN");
+		FocusEx(hWnd, E_HUBNAME);
+		SmSetupHubDlgUpdate(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		SmSetupHubDlgUpdate(hWnd, s);
+
+		switch (wParam)
+		{
+		case IDOK:
+			GetTxtA(hWnd, E_HUBNAME, s->HubName, sizeof(s->HubName));
+			EndDialog(hWnd, true);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// セットアップダイアログの [次へ] ボタン
+void SmSetupDlgOnOk(HWND hWnd, SM_SETUP *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (MsgBox(hWnd, MB_YESNO | MB_ICONEXCLAMATION, _UU("SM_SETUP_WARNING")) == IDNO)
+	{
+		return;
+	}
+
+	s->UseRemote = IsChecked(hWnd, C_REMOTE);
+	s->UseSite = IsChecked(hWnd, C_SITE);
+	s->UseSiteEdge = IsChecked(hWnd, C_EDGE);
+
+	if (s->IsBridge)
+	{
+		StrCpy(s->HubName, sizeof(s->HubName), SERVER_DEFAULT_BRIDGE_NAME);
+	}
+	else
+	{
+		if (Dialog(hWnd, D_SM_SETUP_HUB, SmSetupHubDlg, s) == false)
+		{
+			return;
+		}
+	}
+
+	// 初期化 (既存オブジェクトの抹消)
+	if (SmSetupInit(hWnd, s) == false)
+	{
+		return;
+	}
+
+	// 手順の実行
+	SmSetupStep(hWnd, s);
+
+	// ダイアログを閉じる
+	EndDialog(hWnd, true);
+}
+
+// セットアップダイアログ初期化
+void SmSetupDlgInit(HWND hWnd, SM_SETUP *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_SETUP);
+	DlgFont(hWnd, S_TITLE, 14, true);
+	DlgFont(hWnd, C_REMOTE, 0, true);
+	DlgFont(hWnd, C_SITE, 0, true);
+	DlgFont(hWnd, C_OTHER, 0, true);
+
+	if (s->IsBridge)
+	{
+		SetText(hWnd, B_BOLD, _UU("SM_SETUP_BRIDGE_ONLY"));
+		SetText(hWnd, C_EDGE, _UU("SM_SETUP_BRIDGE_EDGE"));
+
+		Check(hWnd, C_SITE, true);
+		Check(hWnd, C_EDGE, true);
+		Focus(hWnd, C_SITE);
+	}
+
+	SmSetupDlgUpdate(hWnd, s);
+}
+
+// セットアップダイアログ更新
+void SmSetupDlgUpdate(HWND hWnd, SM_SETUP *s)
+{
+	bool enable_remote = true;
+	bool enable_site = true;
+	bool enable_site_center = true;
+	bool enable_detail = true;
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (s->IsBridge)
+	{
+		enable_remote = false;
+		enable_site_center = false;
+		enable_detail = false;
+	}
+
+	if (IsChecked(hWnd, C_OTHER))
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, C_REMOTE, enable_remote && IsChecked(hWnd, C_OTHER) == false);
+	SetEnable(hWnd, S_REMOTE_1, enable_remote && IsChecked(hWnd, C_OTHER) == false);
+
+	SetEnable(hWnd, C_SITE, enable_site && IsChecked(hWnd, C_OTHER) == false);
+	SetEnable(hWnd, S_SITE_1, enable_site && IsChecked(hWnd, C_OTHER) == false);
+	SetEnable(hWnd, S_SITE_2, enable_site && IsChecked(hWnd, C_SITE) && IsChecked(hWnd, C_OTHER) == false);
+	SetEnable(hWnd, C_CENTER, enable_site && enable_site_center && IsChecked(hWnd, C_SITE) && IsChecked(hWnd, C_OTHER) == false);
+	SetEnable(hWnd, C_EDGE, enable_site && IsChecked(hWnd, C_SITE) && IsChecked(hWnd, C_OTHER) == false);
+
+	SetEnable(hWnd, C_OTHER, enable_detail);
+	SetEnable(hWnd, S_OTHER, enable_detail);
+
+	if (IsChecked(hWnd, C_REMOTE) == false && IsChecked(hWnd, C_SITE) == false)
+	{
+		ok = false;
+	}
+
+	if (IsChecked(hWnd, C_SITE))
+	{
+		if (IsChecked(hWnd, C_CENTER) == false && IsChecked(hWnd, C_EDGE) == false)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+
+	SetText(hWnd, S_INFO,
+		IsChecked(hWnd, C_OTHER) ? _UU("SM_SETUP_INFO_2") : _UU("SM_SETUP_INFO_1"));
+}
+
+// セットアップダイアログ
+UINT SmSetupDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SETUP *s = (SM_SETUP *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmSetupDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		SmSetupDlgUpdate(hWnd, s);
+
+		switch (wParam)
+		{
+		case IDOK:
+			SmSetupDlgOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// セットアップ
+bool SmSetup(HWND hWnd, SM_SERVER *s)
+{
+	SM_SETUP ss;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&ss, sizeof(ss));
+	ss.s = s;
+	ss.IsBridge = ss.s->Bridge;
+	ss.Rpc = s->Rpc;
+
+	if (Dialog(hWnd, D_SM_SETUP, SmSetupDlg, &ss) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ライセンス登録処理
+void SmLicenseAddDlgOnOk(HWND hWnd, SM_SERVER *s)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SmLicenseAddDlgGetText(hWnd, tmp, sizeof(tmp));
+
+	if (true)
+	{
+		RPC_TEST t;
+
+		Disable(hWnd, IDOK);
+		Disable(hWnd, IDCANCEL);
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.StrValue, sizeof(t.StrValue), tmp);
+
+		if (CALL(hWnd, ScAddLicenseKey(s->Rpc, &t)) == false)
+		{
+			FocusEx(hWnd, B_KEY6);
+		}
+		else
+		{
+			EndDialog(hWnd, true);
+		}
+
+		Enable(hWnd, IDOK);
+		Enable(hWnd, IDCANCEL);
+	}
+}
+
+// テキスト入力のシフト処理
+void SmLicenseAddDlgShiftTextItem(HWND hWnd, UINT id1, UINT id2, UINT *next_focus)
+{
+	char *s;
+	// 引数チェック
+	if (hWnd == NULL || next_focus == NULL)
+	{
+		return;
+	}
+
+	s = GetTextA(hWnd, id1);
+	if (StrLen(s) >= 6)
+	{
+		char *s2 = CopyStr(s);
+		char tmp[MAX_SIZE];
+		s2[6] = 0;
+		SetTextA(hWnd, id1, s2);
+		Free(s2);
+
+		if (id2 != 0)
+		{
+			GetTxtA(hWnd, id2, tmp, sizeof(tmp));
+
+			StrCat(tmp, sizeof(tmp), s + 6);
+			ReplaceStrEx(tmp, sizeof(tmp), tmp, "-", "", false);
+
+			SetTextA(hWnd, id2, tmp);
+
+			*next_focus = id2;
+		}
+		else
+		{
+			*next_focus = IDOK;
+		}
+	}
+
+	Free(s);
+}
+
+// 入力データをテキスト化
+void SmLicenseAddDlgGetText(HWND hWnd, char *str, UINT size)
+{
+	char *k1, *k2, *k3, *k4, *k5, *k6;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return;
+	}
+
+	k1 = GetTextA(hWnd, B_KEY1);
+	k2 = GetTextA(hWnd, B_KEY2);
+	k3 = GetTextA(hWnd, B_KEY3);
+	k4 = GetTextA(hWnd, B_KEY4);
+	k5 = GetTextA(hWnd, B_KEY5);
+	k6 = GetTextA(hWnd, B_KEY6);
+
+	Format(str, size, "%s-%s-%s-%s-%s-%s", k1, k2, k3, k4, k5, k6);
+
+	Free(k1);
+	Free(k2);
+	Free(k3);
+	Free(k4);
+	Free(k5);
+	Free(k6);
+}
+
+// ライセンス追加ダイアログ更新
+void SmLicenseAddDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+	UINT next_focus = 0;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (s == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	SmLicenseAddDlgShiftTextItem(hWnd, B_KEY1, B_KEY2, &next_focus);
+	SmLicenseAddDlgShiftTextItem(hWnd, B_KEY2, B_KEY3, &next_focus);
+	SmLicenseAddDlgShiftTextItem(hWnd, B_KEY3, B_KEY4, &next_focus);
+	SmLicenseAddDlgShiftTextItem(hWnd, B_KEY4, B_KEY5, &next_focus);
+	SmLicenseAddDlgShiftTextItem(hWnd, B_KEY5, B_KEY6, &next_focus);
+	SmLicenseAddDlgShiftTextItem(hWnd, B_KEY6, 0, &next_focus);
+
+	if ((IsFocus(hWnd, B_KEY1) && GetTextLen(hWnd, B_KEY1, true) <= 5) ||
+		(IsFocus(hWnd, B_KEY2) && GetTextLen(hWnd, B_KEY2, true) <= 5) ||
+		(IsFocus(hWnd, B_KEY3) && GetTextLen(hWnd, B_KEY3, true) <= 5) ||
+		(IsFocus(hWnd, B_KEY4) && GetTextLen(hWnd, B_KEY4, true) <= 5) ||
+		(IsFocus(hWnd, B_KEY5) && GetTextLen(hWnd, B_KEY5, true) <= 5) ||
+		(IsFocus(hWnd, B_KEY6) && GetTextLen(hWnd, B_KEY6, true) <= 5))
+	{
+		next_focus = 0;
+	}
+
+	if (next_focus != 0)
+	{
+		Focus(hWnd, next_focus);
+	}
+
+	SmLicenseAddDlgGetText(hWnd, tmp, sizeof(tmp));
+
+	SetEnable(hWnd, IDOK, true);
+}
+
+// ライセンス追加ダイアログ初期化
+void SmLicenseAddDlgInit(HWND hWnd, SM_SERVER *s)
+{
+	HFONT h;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	h = GetFont("Arial", 10, true, false, false, false);
+	SetFont(hWnd, B_KEY1, h);
+	SetFont(hWnd, B_KEY2, h);
+	SetFont(hWnd, B_KEY3, h);
+	SetFont(hWnd, B_KEY4, h);
+	SetFont(hWnd, B_KEY5, h);
+	SetFont(hWnd, B_KEY6, h);
+
+	DlgFont(hWnd, S_INFO, 10, true);
+
+	SmLicenseAddDlgUpdate(hWnd, s);
+}
+
+// ライセンスの追加ダイアログ
+UINT SmLicenseAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *s = (SM_SERVER *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmLicenseAddDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case B_KEY1:
+		case B_KEY2:
+		case B_KEY3:
+		case B_KEY4:
+		case B_KEY5:
+		case B_KEY6:
+			switch (HIWORD(wParam))
+			{
+			case EN_CHANGE:
+				SmLicenseAddDlgUpdate(hWnd, s);
+
+				switch (LOWORD(wParam))
+				{
+				case B_KEY2:
+					if (GetTextLen(hWnd, B_KEY2, true) == 0)
+					{
+						FocusEx(hWnd, B_KEY1);
+					}
+					break;
+				case B_KEY3:
+					if (GetTextLen(hWnd, B_KEY3, true) == 0)
+					{
+						FocusEx(hWnd, B_KEY2);
+					}
+					break;
+				case B_KEY4:
+					if (GetTextLen(hWnd, B_KEY4, true) == 0)
+					{
+						FocusEx(hWnd, B_KEY3);
+					}
+					break;
+				case B_KEY5:
+					if (GetTextLen(hWnd, B_KEY5, true) == 0)
+					{
+						FocusEx(hWnd, B_KEY4);
+					}
+					break;
+				case B_KEY6:
+					if (GetTextLen(hWnd, B_KEY6, true) == 0)
+					{
+						FocusEx(hWnd, B_KEY5);
+					}
+					break;
+				}
+				break;
+			}
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			SmLicenseAddDlgOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// ライセンスの追加
+bool SmLicenseAdd(HWND hWnd, SM_SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	return Dialog(hWnd, D_SM_LICENSE_ADD, SmLicenseAddDlg, s);
+}
+
+// ライセンスダイアログ初期化
+void SmLicenseDlgInit(HWND hWnd, SM_SERVER *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_CERT);
+
+	DlgFont(hWnd, S_BOLD, 0, true);
+	DlgFont(hWnd, S_BOLD2, 0, true);
+
+	LvInit(hWnd, L_LIST);
+	LvSetStyle(hWnd, L_LIST, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_LICENSE_COLUMN_1"), 50);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_LICENSE_COLUMN_2"), 100);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_LICENSE_COLUMN_3"), 290);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_LICENSE_COLUMN_4"), 150);
+	LvInsertColumn(hWnd, L_LIST, 4, _UU("SM_LICENSE_COLUMN_5"), 120);
+	LvInsertColumn(hWnd, L_LIST, 5, _UU("SM_LICENSE_COLUMN_6"), 250);
+	LvInsertColumn(hWnd, L_LIST, 6, _UU("SM_LICENSE_COLUMN_7"), 100);
+	LvInsertColumn(hWnd, L_LIST, 7, _UU("SM_LICENSE_COLUMN_8"), 100);
+	LvInsertColumn(hWnd, L_LIST, 8, _UU("SM_LICENSE_COLUMN_9"), 100);
+
+	LvInitEx(hWnd, L_STATUS, true);
+	LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 100);
+	LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 100);
+
+	SmLicenseDlgRefresh(hWnd, s);
+}
+
+// ライセンスダイアログ更新
+void SmLicenseDlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+	RPC_ENUM_LICENSE_KEY t;
+	RPC_LICENSE_STATUS st;
+	UINT i;
+	wchar_t tmp[MAX_SIZE];
+	LVB *b;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+
+	if (CALL(hWnd, ScEnumLicenseKey(s->Rpc, &t)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	b = LvInsertStart();
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		wchar_t tmp1[32], tmp2[LICENSE_KEYSTR_LEN + 1], tmp3[LICENSE_MAX_PRODUCT_NAME_LEN + 1],
+			*tmp4, tmp5[128], tmp6[LICENSE_LICENSEID_STR_LEN + 1], tmp7[64],
+			tmp8[64], tmp9[64];
+		RPC_ENUM_LICENSE_KEY_ITEM *e = &t.Items[i];
+
+		UniToStru(tmp1, e->Id);
+		StrToUni(tmp2, sizeof(tmp2), e->LicenseKey);
+		StrToUni(tmp3, sizeof(tmp3), e->LicenseName);
+		tmp4 = LiGetLicenseStatusStr(e->Status);
+		if (e->Expires == 0)
+		{
+			UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_LICENSE_NO_EXPIRES"));
+		}
+		else
+		{
+			GetDateStrEx64(tmp5, sizeof(tmp5), e->Expires, NULL);
+		}
+		StrToUni(tmp6, sizeof(tmp6), e->LicenseId);
+		UniToStru(tmp7, e->ProductId);
+		UniFormat(tmp8, sizeof(tmp8), L"%I64u", e->SystemId);
+		UniToStru(tmp9, e->SerialId);
+
+		LvInsertAdd(b,
+			e->Status == LICENSE_STATUS_OK ? ICO_PASS : ICO_DISCARD,
+			(void *)e->Id, 9,
+			tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+	}
+
+	LvInsertEnd(b, hWnd, L_LIST);
+
+	FreeRpcEnumLicenseKey(&t);
+
+	Zero(&st, sizeof(st));
+
+	if (CALL(hWnd, ScGetLicenseStatus(s->Rpc, &st)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	b = LvInsertStart();
+
+	if (st.EditionId == LICENSE_EDITION_VPN3_NO_LICENSE)
+	{
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_NO_LICENSE_COLUMN"), _UU("SM_NO_LICENSE"));
+	}
+	else
+	{
+		// 製品エディション名
+		StrToUni(tmp, sizeof(tmp), st.EditionStr);
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_EDITION"), tmp);
+
+		// リリース日付
+		if (st.ReleaseDate != 0)
+		{
+			GetDateStrEx64(tmp, sizeof(tmp), st.ReleaseDate, NULL);
+			LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_RELEASE"), tmp);
+		}
+
+		// 現在のシステム ID
+		UniFormat(tmp, sizeof(tmp), L"%I64u", st.SystemId);
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SYSTEM_ID"), tmp);
+
+		// 現在の製品ライセンスの有効期限
+		if (st.SystemExpires == 0)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_NO_EXPIRES"));
+		}
+		else
+		{
+			GetDateStrEx64(tmp, sizeof(tmp), st.SystemExpires, NULL);
+		}
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_EXPIRES"), tmp);
+
+		// サブスクリプション (サポート) 契約
+		if (st.NeedSubscription == false)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONEED"));
+		}
+		else
+		{
+			if (st.SubscriptionExpires == 0)
+			{
+				UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONE"));
+			}
+			else
+			{
+				wchar_t dtstr[MAX_PATH];
+
+				GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+				UniFormat(tmp, sizeof(tmp),
+					st.IsSubscriptionExpired ? _UU("SM_LICENSE_STATUS_SUBSCRIPTION_EXPIRED") :  _UU("SM_LICENSE_STATUS_SUBSCRIPTION_VALID"),
+					dtstr);
+			}
+		}
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SUBSCRIPTION"), tmp);
+
+		if (st.NeedSubscription == false && st.SubscriptionExpires != 0)
+		{
+			wchar_t dtstr[MAX_PATH];
+
+			GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+			LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD_STR"), tmp);
+		}
+
+		if (st.NeedSubscription && st.SubscriptionExpires != 0)
+		{
+			wchar_t dtstr[MAX_PATH];
+
+			GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+			UniFormat(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD_STR"), dtstr);
+
+			LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD"), tmp);
+		}
+
+		if (GetCapsBool(s->CapsList, "b_vpn3"))
+		{
+			// ユーザー作成可能数
+			if (st.NumUserCreationLicense == INFINITE)
+			{
+				UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+			}
+			else
+			{
+				UniToStru(tmp, st.NumUserCreationLicense);
+			}
+			LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_NUM_USER"), tmp);
+		}
+
+		// クライアント同時接続可能数
+		if (st.NumClientConnectLicense == INFINITE)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+		}
+		else
+		{
+			UniToStru(tmp, st.NumClientConnectLicense);
+		}
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_NUM_CLIENT"), tmp);
+
+		// ブリッジ同時接続可能数
+		if (st.NumBridgeConnectLicense == INFINITE)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+		}
+		else
+		{
+			UniToStru(tmp, st.NumBridgeConnectLicense);
+		}
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_NUM_BRIDGE"), tmp);
+
+		// エンタープライズ機能の利用可否
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_ENTERPRISE"),
+			st.AllowEnterpriseFunction ? _UU("SM_LICENSE_STATUS_ENTERPRISE_YES") : _UU("SM_LICENSE_STATUS_ENTERPRISE_NO"));
+	}
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	if (LvNum(hWnd, L_STATUS) >= 1)
+	{
+		LvAutoSize(hWnd, L_STATUS);
+	}
+
+	SmLicenseDlgUpdate(hWnd, s);
+}
+
+// ライセンスダイアログコントロール更新
+void SmLicenseDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+	bool b = false;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	b = LvIsSingleSelected(hWnd, L_LIST);
+
+	SetEnable(hWnd, B_DEL, b);
+	SetEnable(hWnd, IDOK, b);
+}
+
+// ライセンスダイアログ
+UINT SmLicenseDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *s = (SM_SERVER *)param;
+	NMHDR *n;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmLicenseDlgInit(hWnd, s);
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->code)
+		{
+		case LVN_ITEMCHANGED:
+			switch (n->idFrom)
+			{
+			case L_LIST:
+			case L_STATUS:
+				SmLicenseDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (IsEnable(hWnd, IDOK))
+			{
+				UINT i = LvGetSelected(hWnd, L_LIST);
+
+				if (i != INFINITE)
+				{
+					char *s = LvGetStrA(hWnd, L_LIST, i, 1);
+					char tmp[MAX_SIZE];
+
+					Format(tmp, sizeof(tmp), _SS("LICENSE_SUPPORT_URL"), s);
+					ShellExecute(hWnd, "open", tmp, NULL, NULL, SW_SHOW);
+
+					Free(s);
+				}
+			}
+			break;
+
+		case B_OBTAIN:
+			ShellExecute(hWnd, "open", _SS("LICENSE_INFO_URL"), NULL, NULL, SW_SHOW);
+			break;
+
+		case B_ADD:
+			if (SmLicenseAdd(hWnd, s))
+			{
+				SmLicenseDlgRefresh(hWnd, s);
+			}
+			break;
+
+		case B_DEL:
+			if (IsEnable(hWnd, B_DEL))
+			{
+				UINT id = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+				if (id != 0)
+				{
+					if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_LICENSE_DELETE_MSG")) == IDYES)
+					{
+						RPC_TEST t;
+
+						Zero(&t, sizeof(t));
+						t.IntValue = id;
+
+						if (CALL(hWnd, ScDelLicenseKey(s->Rpc, &t)))
+						{
+							SmLicenseDlgRefresh(hWnd, s);
+						}
+					}
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+	return 0;
+}
+
+// ライセンスの追加と削除
+void SmLicense(HWND hWnd, SM_SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_LICENSE, SmLicenseDlg, s);
+
+	FreeCapsList(s->CapsList);
+	s->CapsList = ScGetCapsEx(s->Rpc);
+}
+
+// ログ保存プロシージャ
+UINT SmSaveLogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_READ_LOG_FILE *p = (SM_READ_LOG_FILE *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		FormatText(hWnd, S_INFO, p->filepath);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case B_SAVE:
+			if (p->Buffer != NULL)
+			{
+				char filename[MAX_PATH];
+
+				Format(filename, sizeof(filename), "%s_%s", p->server_name, p->filepath);
+				ConvertSafeFileName(filename, sizeof(filename), filename);
+
+				if (wParam == IDOK)
+				{
+					// エディタで開く
+					char fullpath[MAX_PATH];
+
+					Format(fullpath, sizeof(fullpath), "%s\\%s",
+						MsGetMyTempDir(), filename);
+
+					if (DumpBuf(p->Buffer, fullpath) == false)
+					{
+						MsgBoxEx(hWnd, MB_ICONSTOP, _UU("SM_READ_SAVE_TMP_FAILED"),
+							fullpath);
+					}
+					else
+					{
+						if (((UINT)ShellExecute(hWnd, "open", fullpath, NULL, NULL, SW_SHOWNORMAL)) > 32)
+						{
+							EndDialog(hWnd, true);
+						}
+						else
+						{
+							MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SM_READ_SAVE_OPEN_ERROR"), fullpath);
+						}
+					}
+				}
+				else
+				{
+					// ファイルに保存する
+					wchar_t def[MAX_PATH];
+					wchar_t *uni_path;
+
+					StrToUni(def, sizeof(def), filename);
+					
+					uni_path = SaveDlg(hWnd, _UU("SM_READ_SAVE_DLG_FILTER"), _UU("SM_READ_SAVE_DLG_TITLE"),
+						def, L".log");
+
+					if (uni_path != NULL)
+					{
+						char path[MAX_PATH];
+
+						UniToStr(path, sizeof(path), uni_path);
+						Free(uni_path);
+
+						if (DumpBuf(p->Buffer, path) == false)
+						{
+							MsgBox(hWnd, MB_ICONSTOP, _UU("SM_READ_SAVE_FAILED"));
+						}
+						else
+						{
+							EndDialog(hWnd, true);
+						}
+					}
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ダウンロードコールバックプロシージャ
+bool SmReadLogFileProc(DOWNLOAD_PROGRESS *g)
+{
+	wchar_t tmp[MAX_SIZE];
+	char size1[64], size2[64];
+	SM_READ_LOG_FILE *p;
+	HWND hWnd;
+	// 引数チェック
+	if (g == NULL)
+	{
+		return false;
+	}
+
+	p = (SM_READ_LOG_FILE *)g->Param;
+	hWnd = p->hWnd;
+
+	SetPos(hWnd, P_PROGRESS, g->ProgressPercent);
+
+	ToStrByte(size1, sizeof(size1), g->CurrentSize);
+	ToStrByte(size2, sizeof(size2), g->TotalSize);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_READ_LOG_FILE_INFO_2"), size2, size1);
+
+	SetText(hWnd, S_INFO, tmp);
+
+	DoEvents(hWnd);
+
+	return p->cancel_flag ? false : true;
+}
+
+// ログファイルダウンロードダイアログプロシージャ
+UINT SmReadLogFile(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_READ_LOG_FILE *p = (SM_READ_LOG_FILE *)param;
+	BUF *buf;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		p->hWnd = hWnd;
+		SetFont(hWnd, S_INFO, Font(11, true));
+		SetText(hWnd, S_INFO, _UU("SM_READ_LOG_FILE_INFO_1"));
+		DisableClose(hWnd);
+		FormatText(hWnd, S_INFO2, p->filepath);
+		SetRange(hWnd, P_PROGRESS, 0, 100);
+
+		SetTimer(hWnd, 1, 100, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			buf = DownloadFileFromServer(p->s->Rpc, p->server_name, p->filepath, p->totalsize, SmReadLogFileProc, p);
+			if (buf == NULL)
+			{
+				if (p->cancel_flag == false)
+				{
+					// ダウンロード失敗
+					MsgBox(hWnd, MB_ICONSTOP, _UU("SM_READ_LOG_FILE_ERROR"));
+				}
+				EndDialog(hWnd, false);
+			}
+			else
+			{
+				// ダウンロード成功
+				p->Buffer = buf;
+				Dialog(hWnd, D_SM_SAVE_LOG, SmSaveLogProc, p);
+				FreeBuf(buf);
+				EndDialog(hWnd, true);
+			}
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDCANCEL:
+			p->cancel_flag = true;
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// ログファイルのダウンロードを開始する
+void SmLogFileStartDownload(HWND hWnd, SM_SERVER *s, char *server_name, char *filepath, UINT totalsize)
+{
+	SM_READ_LOG_FILE p;
+	// 引数チェック
+	if (hWnd == NULL || server_name == NULL || filepath == NULL || totalsize == 0)
+	{
+		return;
+	}
+
+	Zero(&p, sizeof(p));
+	p.filepath = filepath;
+	p.s = s;
+	p.server_name = server_name;
+	p.totalsize = totalsize;
+
+	Dialog(hWnd, D_SM_READ_LOG_FILE, SmReadLogFile, &p);
+}
+
+// ダイアログ初期化
+void SmLogFileDlgInit(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_LOG2);
+
+	LvInit(hWnd, L_LIST);
+
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_LOG_FILE_COLUMN_1"), 250);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_LOG_FILE_COLUMN_2"), 100);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_LOG_FILE_COLUMN_3"), 130);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_LOG_FILE_COLUMN_4"), 110);
+
+	SmLogFileDlgRefresh(hWnd, p);
+}
+
+// ダイアログ内容更新
+void SmLogFileDlgRefresh(HWND hWnd, SM_SERVER *p)
+{
+	UINT i;
+	LVB *v;
+	RPC_ENUM_LOG_FILE t;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScEnumLogFile(p->Rpc, &t)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	v = LvInsertStart();
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_LOG_FILE_ITEM *e = &t.Items[i];
+		wchar_t tmp1[MAX_PATH], tmp2[128], tmp3[128], tmp4[MAX_HOST_NAME_LEN + 1];
+		char tmp[MAX_SIZE];
+
+		StrToUni(tmp1, sizeof(tmp1), e->FilePath);
+
+		ToStrByte(tmp, sizeof(tmp), e->FileSize);
+		StrToUni(tmp2, sizeof(tmp2), tmp);
+
+		GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->UpdatedTime));
+
+		StrToUni(tmp4, sizeof(tmp4), e->ServerName);
+
+		LvInsertAdd(v, ICO_LOG2, (void *)e->FileSize, 4, tmp1, tmp2, tmp3, tmp4);
+	}
+
+	LvInsertEndEx(v, hWnd, L_LIST, true);
+
+	if (t.NumItem != 0)
+	{
+		LvAutoSize(hWnd, L_LIST);
+	}
+
+	FreeRpcEnumLogFile(&t);
+
+	SmLogFileDlgUpdate(hWnd, p);
+}
+
+// ダイアログコントロール更新
+void SmLogFileDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, IDOK, LvIsSingleSelected(hWnd, L_LIST));
+}
+
+// ログファイルダイアログプロシージャ
+UINT SmLogFileDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	SM_SERVER *p = (SM_SERVER *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmLogFileDlgInit(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (IsEnable(hWnd, IDOK))
+			{
+				UINT i = LvGetSelected(hWnd, L_LIST);
+				if (i != INFINITE)
+				{
+					UINT size = (UINT)LvGetParam(hWnd, L_LIST, i);
+					char *server_name;
+					char *filepath;
+
+					server_name = LvGetStrA(hWnd, L_LIST, i, 3);
+					filepath = LvGetStrA(hWnd, L_LIST, i, 0);
+					SmLogFileStartDownload(hWnd, p, server_name, filepath, size);
+					Free(filepath);
+					Free(server_name);
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case B_REFRESH:
+			SmLogFileDlgRefresh(hWnd, p);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->code)
+		{
+		case LVN_ITEMCHANGED:
+			switch (n->idFrom)
+			{
+			case L_LIST:
+				SmLogFileDlgUpdate(hWnd, p);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+	return 0;
+}
+
+// ダイアログ初期化
+void SmHubEditAcDlgInit(HWND hWnd, SM_EDIT_AC *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, R_IPV6, GetCapsBool(p->e->s->p->CapsList, "b_support_ipv6_ac"));
+
+	if (p->id == 0)
+	{
+		UINT i, v;
+
+		Check(hWnd, R_SINGLE, true);
+		Check(hWnd, R_PASS, true);
+		Check(hWnd, R_IPV4, true);
+
+		v = 0;
+
+		for (i = 0;i < LIST_NUM(p->e->AcList);i++)
+		{
+			AC *ac = LIST_DATA(p->e->AcList, i);
+
+			v = MAX(v, ac->Priority);
+		}
+
+		v += 100;
+
+		SetInt(hWnd, E_PRIORITY, v);
+	}
+	else
+	{
+		AC *ac = GetAc(p->e->AcList, p->id);
+
+		if (ac == NULL)
+		{
+			EndDialog(hWnd, false);
+			return;
+		}
+
+		Check(hWnd, R_SINGLE, ac->Masked == false);
+		Check(hWnd, R_MASKED, ac->Masked);
+		Check(hWnd, R_IPV4, IsIP4(&ac->IpAddress));
+		Check(hWnd, R_IPV6, IsIP6(&ac->IpAddress));
+
+		if (IsIP4(&ac->IpAddress))
+		{
+			IpSet(hWnd, E_IP, IPToUINT(&ac->IpAddress));
+		}
+		else
+		{
+			char tmp[MAX_SIZE];
+
+			IPToStr(tmp, sizeof(tmp), &ac->IpAddress);
+			SetTextA(hWnd, E_IPV6, tmp);
+		}
+
+		if (ac->Masked)
+		{
+			if (IsIP4(&ac->IpAddress))
+			{
+				IpSet(hWnd, E_MASK, IPToUINT(&ac->SubnetMask));
+			}
+			else
+			{
+				char tmp[MAX_SIZE];
+
+				MaskToStrEx(tmp, sizeof(tmp), &ac->SubnetMask, false);
+
+				if (IsNum(tmp))
+				{
+					StrCatLeft(tmp, sizeof(tmp), "/");
+				}
+
+				SetTextA(hWnd, E_MASKV6, tmp);
+			}
+		}
+
+		Check(hWnd, R_PASS, ac->Deny == false);
+		Check(hWnd, R_DENY, ac->Deny);
+		SetInt(hWnd, E_PRIORITY, ac->Priority);
+
+		Free(ac);
+	}
+
+	Focus(hWnd, E_IP);
+
+	SmHubEditAcDlgUpdate(hWnd, p);
+}
+
+// ダイアログ更新
+void SmHubEditAcDlgUpdate(HWND hWnd, SM_EDIT_AC *p)
+{
+	bool b = true;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (IsChecked(hWnd, R_SINGLE))
+	{
+		if (IsChecked(hWnd, R_IPV6) == false)
+		{
+			Show(hWnd, E_IP);
+			Hide(hWnd, E_IPV6);
+
+			if (IpIsFilled(hWnd, E_IP) == false)
+			{
+				b = false;
+			}
+
+			if (IpGet(hWnd, E_IP) == 0 || IpGet(hWnd, E_IP) == 0xffffffff)
+			{
+				b = false;
+			}
+		}
+		else
+		{
+			Show(hWnd, E_IPV6);
+			Hide(hWnd, E_IP);
+
+			GetTxtA(hWnd, E_IPV6, tmp, sizeof(tmp));
+
+			if (IsStrIPv6Address(tmp) == false)
+			{
+				b = false;
+			}
+		}
+
+		Hide(hWnd, S_MASK);
+		Hide(hWnd, E_MASK);
+		Hide(hWnd, E_MASKV6);
+	}
+	else
+	{
+		if (IsChecked(hWnd, R_IPV6) == false)
+		{
+			Show(hWnd, E_IP);
+			Hide(hWnd, E_IPV6);
+
+			if (IpIsFilled(hWnd, E_IP) == false || IpIsFilled(hWnd, E_MASK) == false)
+			{
+				b = false;
+			}
+
+			if (IpGet(hWnd, E_IP) == 0xffffffff)
+			{
+				b = false;
+			}
+		}
+		else
+		{
+			char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+
+			Show(hWnd, E_IPV6);
+			Hide(hWnd, E_IP);
+
+			GetTxtA(hWnd, E_IPV6, tmp1, sizeof(tmp1));
+			GetTxtA(hWnd, E_MASKV6, tmp2, sizeof(tmp2));
+
+			if (!(IsIpStr6(tmp1) && IsIpMask6(tmp2)))
+			{
+				b = false;
+			}
+		}
+
+		Show(hWnd, S_MASK);
+		SetShow(hWnd, E_MASK, !IsChecked(hWnd, R_IPV6));
+		SetShow(hWnd, E_MASKV6, IsChecked(hWnd, R_IPV6));
+	}
+
+	if (GetInt(hWnd, E_PRIORITY) == 0)
+	{
+		b = false;
+	}
+
+	SetIcon(hWnd, S_ICON, IsChecked(hWnd, R_PASS) ? ICO_INTERNET : ICO_INTERNET_X);
+
+	SetEnable(hWnd, IDOK, b);
+}
+
+// ダイアログで OK ボタンがクリックされた
+void SmHubEditAcDlgOnOk(HWND hWnd, SM_EDIT_AC *p)
+{
+	AC ac;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(&ac, sizeof(ac));
+	ac.Deny = IsChecked(hWnd, R_DENY);
+	ac.Priority = GetInt(hWnd, E_PRIORITY);
+
+	if (IsChecked(hWnd, R_IPV6) == false)
+	{
+		UINTToIP(&ac.IpAddress, IpGet(hWnd, E_IP));
+	}
+	else
+	{
+		GetTxtA(hWnd, E_IPV6, tmp, sizeof(tmp));
+
+		StrToIP6(&ac.IpAddress, tmp);
+	}
+
+	ac.Masked = IsChecked(hWnd, R_MASKED);
+
+	if (ac.Masked)
+	{
+		if (IsChecked(hWnd, R_IPV6) == false)
+		{
+			UINTToIP(&ac.SubnetMask, IpGet(hWnd, E_MASK));
+		}
+		else
+		{
+			GetTxtA(hWnd, E_MASKV6, tmp, sizeof(tmp));
+
+			StrToMask6(&ac.SubnetMask, tmp);
+		}
+	}
+
+	if (p->id != 0)
+	{
+		SetAc(p->e->AcList, p->id, &ac);
+	}
+	else
+	{
+		AddAc(p->e->AcList, &ac);
+	}
+
+	EndDialog(hWnd, true);
+}
+
+// AC 編集ダイアログ
+UINT SmHubEditAcDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_AC *p = (SM_EDIT_AC *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmHubEditAcDlgInit(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_SINGLE:
+		case R_MASKED:
+		case E_IP:
+		case E_MASK:
+		case R_PASS:
+		case R_DENY:
+		case E_PRIORITY:
+		case R_IPV4:
+		case R_IPV6:
+		case E_IPV6:
+		case E_MASKV6:
+			SmHubEditAcDlgUpdate(hWnd, p);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case R_IPV4:
+		case R_IPV6:
+		case R_SINGLE:
+		case R_MASKED:
+			if (IsChecked(hWnd, R_IPV6) == false)
+			{
+				if (IpIsFilled(hWnd, E_IP))
+				{
+					Focus(hWnd, E_MASK);
+				}
+				else
+				{
+					Focus(hWnd, E_IP);
+				}
+			}
+			else
+			{
+				char tmp[MAX_SIZE];
+
+				GetTxtA(hWnd, E_IPV6, tmp, sizeof(tmp));
+
+				if (IsStrIPv6Address(tmp))
+				{
+					FocusEx(hWnd, E_MASKV6);
+				}
+				else
+				{
+					FocusEx(hWnd, E_IPV6);
+				}
+			}
+			break;
+
+		case IDOK:
+			SmHubEditAcDlgOnOk(hWnd, p);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ダイアログ初期化
+void SmHubAcDlgInit(HWND hWnd, SM_EDIT_AC_LIST *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_INTERNET);
+
+	FormatText(hWnd, S_TITLE, p->s->HubName);
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_AC_COLUMN_1"), 40);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_AC_COLUMN_2"), 80);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_AC_COLUMN_3"), 90);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_AC_COLUMN_4"), 170);
+
+	SmHubAcDlgRefresh(hWnd, p);
+}
+
+// ダイアログコントロール更新
+void SmHubAcDlgUpdate(HWND hWnd, SM_EDIT_AC_LIST *p)
+{
+	bool b;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	b = LvIsSingleSelected(hWnd, L_LIST);
+
+	SetEnable(hWnd, IDOK, b);
+	SetEnable(hWnd, B_DELETE, b);
+}
+
+// ダイアログ内容更新
+void SmHubAcDlgRefresh(HWND hWnd, SM_EDIT_AC_LIST *p)
+{
+	UINT i;
+	LVB *v;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	v = LvInsertStart();
+
+	for (i = 0;i < LIST_NUM(p->AcList);i++)
+	{
+		wchar_t tmp1[32], *tmp2, tmp3[MAX_SIZE], tmp4[32];
+		char *tmp_str;
+		AC *ac = LIST_DATA(p->AcList, i);
+
+		UniToStru(tmp1, ac->Id);
+		tmp2 = ac->Deny ? _UU("SM_AC_DENY") : _UU("SM_AC_PASS");
+		tmp_str = GenerateAcStr(ac);
+		StrToUni(tmp3, sizeof(tmp3), tmp_str);
+
+		Free(tmp_str);
+
+		UniToStru(tmp4, ac->Priority);
+
+		LvInsertAdd(v, ac->Deny ? ICO_INTERNET_X : ICO_INTERNET,
+			(void *)ac->Id, 4, tmp1, tmp4, tmp2, tmp3);
+	}
+
+	LvInsertEnd(v, hWnd, L_LIST);
+	LvSortEx(hWnd, L_LIST, 0, false, true);
+
+
+	SmHubAcDlgUpdate(hWnd, p);
+}
+
+// アクセス制御リスト編集ダイアログ
+UINT SmHubAcDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	SM_EDIT_AC_LIST *p = (SM_EDIT_AC_LIST *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmHubAcDlgInit(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (IsEnable(hWnd, IDOK))
+			{
+				SM_EDIT_AC s;
+				Zero(&s, sizeof(s));
+
+				s.e = p;
+				s.id = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+				if (Dialog(hWnd, D_SM_AC, SmHubEditAcDlgProc, &s))
+				{
+					SmHubAcDlgRefresh(hWnd, p);
+				}
+			}
+			break;
+
+		case B_ADD:
+			if (IsEnable(hWnd, B_ADD))
+			{
+				SM_EDIT_AC s;
+				Zero(&s, sizeof(s));
+
+				s.e = p;
+
+				if (Dialog(hWnd, D_SM_AC, SmHubEditAcDlgProc, &s))
+				{
+					SmHubAcDlgRefresh(hWnd, p);
+				}
+			}
+			break;
+
+		case B_DELETE:
+			if (IsEnable(hWnd, B_DELETE))
+			{
+				UINT id = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+				if (DelAc(p->AcList, id))
+				{
+					SmHubAcDlgRefresh(hWnd, p);
+				}
+			}
+			break;
+
+		case B_SAVE:
+			if (IsEnable(hWnd, B_SAVE))
+			{
+				RPC_AC_LIST t;
+
+				Zero(&t, sizeof(t));
+				StrCpy(t.HubName, sizeof(t.HubName), p->s->HubName);
+				t.o = CloneAcList(p->AcList);
+
+				if (CALL(hWnd, ScSetAcList(p->s->p->Rpc, &t)))
+				{
+					EndDialog(hWnd, true);
+				}
+
+				FreeRpcAcList(&t);
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->code)
+		{
+		case LVN_ITEMCHANGED:
+			switch (n->idFrom)
+			{
+			case L_LIST:
+				SmHubAcDlgUpdate(hWnd, p);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+	return 0;
+}
+
+// アクセス制御リスト編集
+void SmHubAc(HWND hWnd, SM_EDIT_HUB *s)
+{
+	SM_EDIT_AC_LIST p;
+	RPC_AC_LIST t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+	if (CALL(hWnd, ScGetAcList(s->p->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	Zero(&p, sizeof(p));
+	p.s = s;
+	p.AcList = CloneAcList(t.o);
+
+	FreeRpcAcList(&t);
+
+	Dialog(hWnd, D_SM_AC_LIST, SmHubAcDlgProc, &p);
+
+	FreeAcList(p.AcList);
+}
+
+// ダイアログ初期化
+void SmEditCrlDlgInit(HWND hWnd, SM_EDIT_CRL *c)
+{
+	// 引数チェック
+	if (hWnd == NULL || c == NULL)
+	{
+		return;
+	}
+
+	if (c->NewCrl == false)
+	{
+		RPC_CRL t;
+		CRL *crl;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.HubName, sizeof(t.HubName), c->s->HubName);
+		t.Key = c->Key;
+
+		if (CALL(hWnd, ScGetCrl(c->s->Rpc, &t)) == false)
+		{
+			EndDialog(hWnd, false);
+			return;
+		}
+
+		crl = t.Crl;
+
+		SmEditCrlDlgSetName(hWnd, crl->Name);
+		SmEditCrlDlgSetSerial(hWnd, crl->Serial);
+		SmEditCrlDlgSetHash(hWnd, crl->DigestMD5, crl->DigestSHA1);
+
+		FreeRpcCrl(&t);
+	}
+
+	SmEditCrlDlgUpdate(hWnd, c);
+}
+
+// コントロール更新
+void SmEditCrlDlgUpdate(HWND hWnd, SM_EDIT_CRL *c)
+{
+	bool b = true;
+	// 引数チェック
+	if (hWnd == NULL || c == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, E_CN, IsChecked(hWnd, R_CN));
+	SetEnable(hWnd, E_O, IsChecked(hWnd, R_O));
+	SetEnable(hWnd, E_OU, IsChecked(hWnd, R_OU));
+	SetEnable(hWnd, E_C, IsChecked(hWnd, R_C));
+	SetEnable(hWnd, E_ST, IsChecked(hWnd, R_ST));
+	SetEnable(hWnd, E_L, IsChecked(hWnd, R_L));
+	SetEnable(hWnd, E_SERI, IsChecked(hWnd, R_SERI));
+	SetEnable(hWnd, E_MD5_HASH, IsChecked(hWnd, R_MD5_HASH));
+	SetEnable(hWnd, E_SHA1_HASH, IsChecked(hWnd, R_SHA1_HASH));
+
+	if (IsChecked(hWnd, R_CN))
+	{
+		if (IsEmpty(hWnd, E_CN))
+		{
+			b = false;
+		}
+	}
+
+	if (IsChecked(hWnd, R_O))
+	{
+		if (IsEmpty(hWnd, E_O))
+		{
+			b = false;
+		}
+	}
+
+	if (IsChecked(hWnd, R_OU))
+	{
+		if (IsEmpty(hWnd, E_OU))
+		{
+			b = false;
+		}
+	}
+
+	if (IsChecked(hWnd, R_C))
+	{
+		if (IsEmpty(hWnd, E_C))
+		{
+			b = false;
+		}
+	}
+
+	if (IsChecked(hWnd, R_ST))
+	{
+		if (IsEmpty(hWnd, E_ST))
+		{
+			b = false;
+		}
+	}
+
+	if (IsChecked(hWnd, R_L))
+	{
+		if (IsEmpty(hWnd, E_L))
+		{
+			b = false;
+		}
+	}
+
+	if (IsChecked(hWnd, R_SERI))
+	{
+		char tmp[MAX_SIZE];
+		BUF *buf;
+
+		GetTxtA(hWnd, E_SERI, tmp, sizeof(tmp));
+		buf = StrToBin(tmp);
+
+		if (buf->Size == 0)
+		{
+			b = false;
+		}
+
+		FreeBuf(buf);
+	}
+
+	if (IsChecked(hWnd, R_MD5_HASH))
+	{
+		char tmp[MAX_SIZE];
+		BUF *buf;
+
+		GetTxtA(hWnd, E_MD5_HASH, tmp, sizeof(tmp));
+		buf = StrToBin(tmp);
+
+		if (buf->Size != MD5_SIZE)
+		{
+			b = false;
+		}
+
+		FreeBuf(buf);
+	}
+
+	if (IsChecked(hWnd, R_SHA1_HASH))
+	{
+		char tmp[MAX_SIZE];
+		BUF *buf;
+
+		GetTxtA(hWnd, E_SHA1_HASH, tmp, sizeof(tmp));
+		buf = StrToBin(tmp);
+
+		if (buf->Size != SHA1_SIZE)
+		{
+			b = false;
+		}
+
+		FreeBuf(buf);
+	}
+
+	SetEnable(hWnd, IDOK, b);
+}
+
+// OK ボタンクリック
+void SmEditCrlDlgOnOk(HWND hWnd, SM_EDIT_CRL *c)
+{
+	CRL *crl;
+	NAME *n;
+	RPC_CRL t;
+	bool empty = true;
+	// 引数チェック
+	if (hWnd == NULL || c == NULL)
+	{
+		return;
+	}
+
+	crl = ZeroMalloc(sizeof(CRL));
+	crl->Name = ZeroMalloc(sizeof(NAME));
+	n = crl->Name;
+
+	if (IsChecked(hWnd, R_CN))
+	{
+		n->CommonName = GetText(hWnd, E_CN);
+		empty = false;
+	}
+
+	if (IsChecked(hWnd, R_O))
+	{
+		n->Organization = GetText(hWnd, E_O);
+		empty = false;
+	}
+
+	if (IsChecked(hWnd, R_OU))
+	{
+		n->Unit = GetText(hWnd, E_OU);
+		empty = false;
+	}
+
+	if (IsChecked(hWnd, R_C))
+	{
+		n->Country = GetText(hWnd, E_C);
+		empty = false;
+	}
+
+	if (IsChecked(hWnd, R_ST))
+	{
+		n->State = GetText(hWnd, E_ST);
+		empty = false;
+	}
+
+	if (IsChecked(hWnd, R_L))
+	{
+		n->Local = GetText(hWnd, E_L);
+		empty = false;
+	}
+
+	if (IsChecked(hWnd, R_SERI))
+	{
+		char tmp[MAX_SIZE];
+		BUF *b;
+
+		GetTxtA(hWnd, E_SERI, tmp, sizeof(tmp));
+		b = StrToBin(tmp);
+
+		if (b != NULL && b->Size >= 1)
+		{
+			crl->Serial = NewXSerial(b->Buf, b->Size);
+		}
+
+		FreeBuf(b);
+
+		empty = false;
+	}
+
+	if (IsChecked(hWnd, R_MD5_HASH))
+	{
+		char tmp[MAX_SIZE];
+		BUF *b;
+
+		GetTxtA(hWnd, E_MD5_HASH, tmp, sizeof(tmp));
+		b = StrToBin(tmp);
+
+		if (b != NULL && b->Size == MD5_SIZE)
+		{
+			Copy(crl->DigestMD5, b->Buf, MD5_SIZE);
+		}
+
+		FreeBuf(b);
+
+		empty = false;
+	}
+
+	if (IsChecked(hWnd, R_SHA1_HASH))
+	{
+		char tmp[MAX_SIZE];
+		BUF *b;
+
+		GetTxtA(hWnd, E_SHA1_HASH, tmp, sizeof(tmp));
+		b = StrToBin(tmp);
+
+		if (b != NULL && b->Size == SHA1_SIZE)
+		{
+			Copy(crl->DigestSHA1, b->Buf, SHA1_SIZE);
+		}
+
+		FreeBuf(b);
+
+		empty = false;
+	}
+
+	if (empty)
+	{
+		if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_CRL_EMPTY_MSG")) == IDNO)
+		{
+			return;
+		}
+	}
+
+	if (c->NewCrl)
+	{
+		Zero(&t, sizeof(t));
+		StrCpy(t.HubName, sizeof(t.HubName), c->s->HubName);
+		t.Crl = crl;
+
+		if (CALL(hWnd, ScAddCrl(c->s->Rpc, &t)))
+		{
+			EndDialog(hWnd, true);
+		}
+
+		FreeRpcCrl(&t);
+	}
+	else
+	{
+		Zero(&t, sizeof(t));
+		StrCpy(t.HubName, sizeof(t.HubName), c->s->HubName);
+		t.Crl = crl;
+		t.Key = c->Key;
+
+		if (CALL(hWnd, ScSetCrl(c->s->Rpc, &t)))
+		{
+			EndDialog(hWnd, true);
+		}
+
+		FreeRpcCrl(&t);
+	}
+}
+
+// 証明書の読み込み
+void SmEditCrlDlgOnLoad(HWND hWnd, SM_EDIT_CRL *c)
+{
+	X *x;
+	// 引数チェック
+	if (hWnd == NULL || c == NULL)
+	{
+		return;
+	}
+
+	if (CmLoadXFromFileOrSecureCard(hWnd, &x))
+	{
+		UCHAR md5[MD5_SIZE], sha1[SHA1_SIZE];
+
+		SmEditCrlDlgSetName(hWnd, x->subject_name);
+		SmEditCrlDlgSetSerial(hWnd, x->serial);
+		GetXDigest(x, md5, false);
+		GetXDigest(x, sha1, true);
+		SmEditCrlDlgSetHash(hWnd, md5, sha1);
+
+		FreeX(x);
+
+		SmEditCrlDlgUpdate(hWnd, c);
+	}
+}
+
+// ダイアログにハッシュ情報を設定する
+void SmEditCrlDlgSetHash(HWND hWnd, UCHAR *hash_md5, UCHAR *hash_sha1)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (hash_md5 != NULL && IsZero(hash_md5, MD5_SIZE) == false)
+	{
+		Check(hWnd, R_MD5_HASH, true);
+		BinToStrEx(tmp, sizeof(tmp), hash_md5, MD5_SIZE);
+		SetTextA(hWnd, E_MD5_HASH, tmp);
+	}
+	else
+	{
+		Check(hWnd, R_MD5_HASH, false);
+	}
+
+	if (hash_sha1 != NULL && IsZero(hash_sha1, SHA1_SIZE) == false)
+	{
+		Check(hWnd, R_SHA1_HASH, true);
+		BinToStrEx(tmp, sizeof(tmp), hash_sha1, SHA1_SIZE);
+		SetTextA(hWnd, E_SHA1_HASH, tmp);
+	}
+	else
+	{
+		Check(hWnd, R_SHA1_HASH, false);
+	}
+}
+
+// ダイアログにシリアル番号を設定する
+void SmEditCrlDlgSetSerial(HWND hWnd, X_SERIAL *serial)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || serial == NULL)
+	{
+		return;
+	}
+
+	BinToStrEx(tmp, sizeof(tmp), serial->data, serial->size);
+
+	Check(hWnd, R_SERI, true);
+
+	SetTextA(hWnd, E_SERI, tmp);
+}
+
+// ダイアログに名前状況を設定する
+void SmEditCrlDlgSetName(HWND hWnd, NAME *name)
+{
+	// 引数チェック
+	if (hWnd == NULL || name == NULL)
+	{
+		return;
+	}
+
+	// CN
+	if (UniIsEmptyStr(name->CommonName))
+	{
+		Check(hWnd, R_CN, false);
+	}
+	else
+	{
+		Check(hWnd, R_CN, true);
+		SetText(hWnd, E_CN, name->CommonName);
+	}
+
+	// O
+	if (UniIsEmptyStr(name->Organization))
+	{
+		Check(hWnd, R_O, false);
+	}
+	else
+	{
+		Check(hWnd, R_O, true);
+		SetText(hWnd, E_O, name->Organization);
+	}
+
+	// OU
+	if (UniIsEmptyStr(name->Unit))
+	{
+		Check(hWnd, R_OU, false);
+	}
+	else
+	{
+		Check(hWnd, R_OU, true);
+		SetText(hWnd, E_OU, name->Unit);
+	}
+
+	// C
+	if (UniIsEmptyStr(name->Country))
+	{
+		Check(hWnd, R_C, false);
+	}
+	else
+	{
+		Check(hWnd, R_C, true);
+		SetText(hWnd, E_C, name->Country);
+	}
+
+	// ST
+	if (UniIsEmptyStr(name->State))
+	{
+		Check(hWnd, R_ST, false);
+	}
+	else
+	{
+		Check(hWnd, R_ST, true);
+		SetText(hWnd, E_ST, name->State);
+	}
+
+	// L
+	if (UniIsEmptyStr(name->Local))
+	{
+		Check(hWnd, R_L, false);
+	}
+	else
+	{
+		Check(hWnd, R_L, true);
+		SetText(hWnd, E_L, name->Local);
+	}
+}
+
+// CRL 編集ダイアログプロシージャ
+UINT SmEditCrlDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_CRL *c = (SM_EDIT_CRL *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmEditCrlDlgInit(hWnd, c);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_CN:
+		case E_CN:
+		case R_O:
+		case E_O:
+		case R_OU:
+		case E_OU:
+		case R_C:
+		case E_C:
+		case R_ST:
+		case E_ST:
+		case R_L:
+		case E_L:
+		case R_SERI:
+		case E_SERI:
+		case R_MD5_HASH:
+		case E_MD5_HASH:
+		case R_SHA1_HASH:
+		case E_SHA1_HASH:
+			SmEditCrlDlgUpdate(hWnd, c);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case B_LOAD:
+			SmEditCrlDlgOnLoad(hWnd, c);
+			break;
+
+		case IDOK:
+			SmEditCrlDlgOnOk(hWnd, c);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case R_CN:
+			FocusEx(hWnd, E_CN);
+			break;
+
+		case R_O:
+			FocusEx(hWnd, E_O);
+			break;
+
+		case R_OU:
+			FocusEx(hWnd, E_OU);
+			break;
+
+		case R_C:
+			FocusEx(hWnd, E_C);
+			break;
+
+		case R_ST:
+			FocusEx(hWnd, E_ST);
+			break;
+
+		case R_L:
+			FocusEx(hWnd, E_L);
+			break;
+
+		case R_SERI:
+			FocusEx(hWnd, E_SERI);
+			break;
+
+		case R_MD5_HASH:
+			FocusEx(hWnd, E_MD5_HASH);
+			break;
+
+		case R_SHA1_HASH:
+			FocusEx(hWnd, E_SHA1_HASH);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ダイアログ初期化
+void SmCrlDlgInit(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_CERT_X);
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_CRL_COLUMN_1"), 555);
+
+	SmCrlDlgRefresh(hWnd, s);
+}
+
+// コントロール更新
+void SmCrlDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, IDOK, LvIsSingleSelected(hWnd, L_LIST));
+	SetEnable(hWnd, B_DELETE, LvIsSingleSelected(hWnd, L_LIST));
+}
+
+// 内容更新
+void SmCrlDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+	UINT i;
+	RPC_ENUM_CRL t;
+	LVB *v;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+	if (CALL(hWnd, ScEnumCrl(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	v = LvInsertStart();
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_CRL_ITEM *e = &t.Items[i];
+		LvInsertAdd(v, ICO_CERT_X, (void *)e->Key, 1, e->CrlInfo);
+	}
+
+	LvInsertEndEx(v, hWnd, L_LIST, true);
+
+	if (t.NumItem >= 1)
+	{
+		LvAutoSize(hWnd, L_LIST);
+	}
+
+	FreeRpcEnumCrl(&t);
+
+	SmCrlDlgUpdate(hWnd, s);
+}
+
+// 無効な証明書一覧ダイアログプロシージャ
+UINT SmCrlDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_CRL c;
+	SM_HUB *s = (SM_HUB *)param;
+	NMHDR *n;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmCrlDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_ADD:
+			Zero(&c, sizeof(c));
+			c.NewCrl = true;
+			c.s = s;
+
+			if (Dialog(hWnd, D_SM_EDIT_CRL, SmEditCrlDlgProc, &c))
+			{
+				SmCrlDlgRefresh(hWnd, s);
+			}
+			break;
+
+		case B_DELETE:
+			if (IsEnable(hWnd, B_DELETE))
+			{
+				if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_CRL_DELETE_MSG")) == IDYES)
+				{
+					RPC_CRL t;
+
+					Zero(&t, sizeof(t));
+					StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+					t.Key = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+					if (CALL(hWnd, ScDelCrl(s->Rpc, &t)))
+					{
+						SmCrlDlgRefresh(hWnd, s);
+					}
+
+					FreeRpcCrl(&t);
+				}
+			}
+			break;
+
+		case IDOK:
+			if (IsEnable(hWnd, IDOK))
+			{
+				SM_EDIT_CRL c;
+
+				Zero(&c, sizeof(c));
+				c.NewCrl = false;
+				c.s = s;
+				c.Key = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+				if (Dialog(hWnd, D_SM_EDIT_CRL, SmEditCrlDlgProc, &c))
+				{
+					SmCrlDlgRefresh(hWnd, s);
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->code)
+		{
+		case LVN_ITEMCHANGED:
+			switch (n->idFrom)
+			{
+			case L_LIST:
+				SmCrlDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+	return 0;
+}
+
+// スマートカードマネージャ
+void SmSecureManager(HWND hWnd)
+{
+	UINT id = SmGetCurrentSecureIdFromReg();
+
+	if (id == 0)
+	{
+		id = SmSelectSecureId(hWnd);
+	}
+
+	if (id == 0)
+	{
+		return;
+	}
+
+	CmSecureManager(hWnd, id);
+}
+
+// ダイアログ初期化
+void SmSelectKeyPairDlgInit(HWND hWnd, SM_SECURE_KEYPAIR *k)
+{
+	SECURE_DEVICE *dev;
+	// 引数チェック
+	if (hWnd == NULL || k == NULL)
+	{
+		return;
+	}
+
+	dev = GetSecureDevice(k->Id);
+	if (dev != NULL)
+	{
+		FormatText(hWnd, S_INFO, dev->DeviceName);
+	}
+
+	LvInit(hWnd, L_CERT);
+	LvInsertColumn(hWnd, L_CERT, 0, _UU("SEC_MGR_COLUMN1"), 200);
+	LvInsertColumn(hWnd, L_CERT, 1, _UU("SEC_MGR_COLUMN2"), 110);
+
+	LvInit(hWnd, L_KEY);
+	LvInsertColumn(hWnd, L_KEY, 0, _UU("SEC_MGR_COLUMN1"), 200);
+	LvInsertColumn(hWnd, L_KEY, 1, _UU("SEC_MGR_COLUMN2"), 110);
+
+	SetEnable(hWnd, L_CERT, k->UseCert);
+	SetEnable(hWnd, B_BOLD1, k->UseCert);
+	SetEnable(hWnd, L_KEY, k->UseKey);
+	SetEnable(hWnd, B_BOLD2, k->UseKey);
+
+	SetFont(hWnd, B_BOLD1, Font(0, true));
+	SetFont(hWnd, B_BOLD2, Font(0, true));
+
+	SmSelectKeyPairDlgUpdate(hWnd, k);
+}
+
+// ダイアログコントロール更新
+void SmSelectKeyPairDlgUpdate(HWND hWnd, SM_SECURE_KEYPAIR *k)
+{
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || k == NULL)
+	{
+		return;
+	}
+
+	if (k->UseCert)
+	{
+		if (LvIsSingleSelected(hWnd, L_CERT) == false)
+		{
+			ok = false;
+		}
+		else
+		{
+			char *name = LvGetSelectedStrA(hWnd, L_CERT, 0);
+			if (name != NULL)
+			{
+				if (LvIsSingleSelected(hWnd, L_KEY) == false)
+				{
+					if ((k->Flag++) == 0)
+					{
+						LvSelect(hWnd, L_KEY, LvSearchStrA(hWnd, L_KEY, 0, name));
+					}
+				}
+				Free(name);
+			}
+		}
+	}
+
+	if (k->UseKey)
+	{
+		if (LvIsSingleSelected(hWnd, L_KEY) == false)
+		{
+			ok = false;
+		}
+		else
+		{
+			char *name = LvGetSelectedStrA(hWnd, L_KEY, 0);
+			if (name != NULL)
+			{
+				if (LvIsSingleSelected(hWnd, L_CERT) == false)
+				{
+					if ((k->Flag++) == 0)
+					{
+						LvSelect(hWnd, L_CERT, LvSearchStrA(hWnd, L_CERT, 0, name));
+					}
+				}
+				Free(name);
+			}
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// コンテンツ更新
+void SmSelectKeyPairDlgRefresh(HWND hWnd, SM_SECURE_KEYPAIR *k)
+{
+	bool ret;
+	LIST *o;
+	WINUI_SECURE_BATCH batch[] =
+	{
+		{WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+	};
+	// 引数チェック
+	if (hWnd == NULL || k == NULL)
+	{
+		return;
+	}
+
+	ret = SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), k->Id, k->BitmapId);
+
+	if (ret == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	o = batch[0].EnumList;
+	if (o != NULL)
+	{
+		if (k->UseCert)
+		{
+			CmSecureManagerDlgPrintListEx(hWnd, L_CERT, o, SEC_X);
+		}
+
+		if (k->UseKey)
+		{
+			CmSecureManagerDlgPrintListEx(hWnd, L_KEY, o, SEC_K);
+		}
+
+		FreeEnumSecObject(o);
+	}
+
+	// コントロール更新
+	SmSelectKeyPairDlgUpdate(hWnd, k);
+}
+
+// キーペア読み込みダイアログプロシージャ
+UINT SmSelectKeyPairDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	SM_SECURE_KEYPAIR *k = (SM_SECURE_KEYPAIR *)param;
+	char *s1, *s2;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmSelectKeyPairDlgInit(hWnd, k);
+
+		SetTimer(hWnd, 1, 1, NULL);
+		SetTimer(hWnd, 2, 100, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			SmSelectKeyPairDlgRefresh(hWnd, k);
+			break;
+
+		case 2:
+			SmSelectKeyPairDlgUpdate(hWnd, k);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			s1 = LvGetSelectedStrA(hWnd, L_CERT, 0);
+			s2 = LvGetSelectedStrA(hWnd, L_KEY, 0);
+			if (k->UseCert)
+			{
+				StrCpy(k->CertName, sizeof(k->CertName), s1);
+			}
+			if (k->UseKey)
+			{
+				StrCpy(k->KeyName, sizeof(k->KeyName), s2);
+			}
+			Free(s1);
+			Free(s2);
+			EndDialog(hWnd, true);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_CERT:
+		case L_KEY:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmSelectKeyPairDlgUpdate(hWnd, k);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// キーペアをスマートカードから読み込む
+bool SmSelectKeyPair(HWND hWnd, char *cert_name, UINT cert_name_size, char *key_name, UINT key_name_size)
+{
+	return SmSelectKeyPairEx(hWnd, cert_name, cert_name_size, key_name, key_name_size, 0);
+}
+bool SmSelectKeyPairEx(HWND hWnd, char *cert_name, UINT cert_name_size, char *key_name, UINT key_name_size, UINT bitmap_id)
+{
+	SM_SECURE_KEYPAIR p;
+	// 引数チェック
+	if (hWnd == NULL || (cert_name == NULL && key_name == NULL))
+	{
+		return false;
+	}
+
+	Zero(&p, sizeof(p));
+	p.Id = SmGetCurrentSecureId(hWnd);
+	if (p.Id == 0)
+	{
+		return false;
+	}
+
+	p.UseCert = (cert_name == NULL) ? false : true;
+	p.UseKey = (key_name == NULL) ? false : true;
+	p.BitmapId = bitmap_id;
+
+	if (Dialog(hWnd, D_SM_SELECT_KEYPAIR, SmSelectKeyPairDlg, &p) == false)
+	{
+		return false;
+	}
+
+	if (p.UseCert)
+	{
+		StrCpy(cert_name, cert_name_size, p.CertName);
+	}
+	if (p.UseKey)
+	{
+		StrCpy(key_name, key_name_size, p.KeyName);
+	}
+
+	return true;
+}
+
+// スマートカード番号をユーザーに選択させる
+UINT SmSelectSecureId(HWND hWnd)
+{
+	UINT id = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DeviceId");
+	UINT ret;
+
+	if (id != 0 && CheckSecureDeviceId(id) == false)
+	{
+		id = 0;
+	}
+
+	ret = CmSelectSecure(hWnd, id);
+	if (ret == 0)
+	{
+		return 0;
+	}
+
+	SmWriteSelectSecureIdReg(ret);
+
+	return ret;
+}
+
+// 現在のスマートカード番号をレジストリに書き込む
+void SmWriteSelectSecureIdReg(UINT id)
+{
+	MsRegWriteInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DeviceId", id);
+}
+
+// 現在のスマートカード番号を取得する
+UINT SmGetCurrentSecureId(HWND hWnd)
+{
+	// 現在の設定をロード
+	UINT id = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DeviceId");
+
+	// 正常かどうかチェック
+	if (id == 0 || CheckSecureDeviceId(id) == false)
+	{
+		// 不正な場合はスマートカードデバイス番号を選択させる
+		id = SmSelectSecureId(hWnd);
+	}
+
+	return id;
+}
+
+// レジストリから現在のスマートカード番号を取得する
+UINT SmGetCurrentSecureIdFromReg()
+{
+	// 現在の設定をロード
+	UINT id = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DeviceId");
+
+	// 正常かどうかチェック
+	if (id == 0 || CheckSecureDeviceId(id) == false)
+	{
+		id = 0;
+	}
+
+	return id;
+}
+
+// 指定した名前の L3 スイッチが開始されているかどうか取得する
+bool SmL3IsSwActive(SM_SERVER *s, char *name)
+{
+	bool ret = false;
+	UINT i;
+	RPC_ENUM_L3SW t;
+	// 引数チェック
+	if (s == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	if (ScEnumL3Switch(s->Rpc, &t) == ERR_NO_ERROR)
+	{
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+			if (StrCmpi(e->Name, name) == 0)
+			{
+				if (e->Active)
+				{
+					ret = true;
+					break;
+				}
+			}
+		}
+		FreeRpcEnumL3Sw(&t);
+	}
+
+	return ret;
+}
+
+// ダイアログ初期化
+void SmL3SwTableDlgInit(HWND hWnd, SM_L3SW *w)
+{
+	// 引数チェック
+	if (hWnd == NULL || w == NULL)
+	{
+		return;
+	}
+
+	SmL3SwTableDlgUpdate(hWnd, w);
+}
+
+// コントロール更新
+void SmL3SwTableDlgUpdate(HWND hWnd, SM_L3SW *w)
+{
+	bool b = true;
+	UINT ip;
+	// 引数チェック
+	if (hWnd == NULL || w == NULL)
+	{
+		return;
+	}
+
+	if (IpIsFilled(hWnd, E_NETWORK) == false ||
+		IpIsFilled(hWnd, E_MASK) == false ||
+		IpIsFilled(hWnd, E_GATEWAY) == false)
+	{
+		b = false;
+	}
+
+	ip = IpGet(hWnd, E_GATEWAY);
+	if (ip == 0 || ip == 0xffffffff)
+	{
+		b = false;
+	}
+
+	if (GetInt(hWnd, E_METRIC) == 0)
+	{
+		b = false;
+	}
+
+	if (IsNetworkAddress32(IpGet(hWnd, E_NETWORK), IpGet(hWnd, E_MASK)) == false)
+	{
+		b = false;
+	}
+
+	SetEnable(hWnd, IDOK, b);
+}
+
+UINT SmL3SwTableDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_L3SW *w = (SM_L3SW *)param;
+	RPC_L3TABLE t;
+
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmL3SwTableDlgInit(hWnd, w);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_NETWORK:
+		case E_MASK:
+		case E_GATEWAY:
+		case E_METRIC:
+			SmL3SwTableDlgUpdate(hWnd, w);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			Zero(&t, sizeof(t));
+			StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+			t.NetworkAddress = IpGet(hWnd, E_NETWORK);
+			t.SubnetMask = IpGet(hWnd, E_MASK);
+			t.GatewayAddress = IpGet(hWnd, E_GATEWAY);
+			t.Metric = GetInt(hWnd, E_METRIC);
+
+			if (CALL(hWnd, ScAddL3Table(w->s->Rpc, &t)))
+			{
+				EndDialog(hWnd, 1);
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// ダイアログ初期化
+void SmL3SwIfDlgInit(HWND hWnd, SM_L3SW *w)
+{
+	RPC_ENUM_HUB t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || w == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+
+	if (CALL(hWnd, ScEnumHub(w->s->Rpc, &t)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	CbReset(hWnd, E_HUBNAME);
+	CbSetHeight(hWnd, E_HUBNAME, 18);
+
+	for (i = 0;i < t.NumHub;i++)
+	{
+		RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+
+		if (e->HubType != HUB_TYPE_FARM_DYNAMIC)
+		{
+			CbAddStrA(hWnd, E_HUBNAME, e->HubName, 0);
+		}
+	}
+
+	FreeRpcEnumHub(&t);
+
+	SetTextA(hWnd, E_HUBNAME, "");
+
+	SmL3SwIfDlgUpdate(hWnd, w);
+}
+
+// コントロール更新
+void SmL3SwIfDlgUpdate(HWND hWnd, SM_L3SW *w)
+{
+	bool b = true;
+	// 引数チェック
+	if (hWnd == NULL || w == NULL)
+	{
+		return;
+	}
+
+	if (IsEmpty(hWnd, E_HUBNAME))
+	{
+		b = false;
+	}
+
+	if (IpIsFilled(hWnd, E_IP) == false || IpIsFilled(hWnd, E_MASK) == false)
+	{
+		b = false;
+	}
+
+	if (IpGet(hWnd, E_IP) == 0 || IpGet(hWnd, E_IP) == 0xffffffff)
+	{
+		b = false;
+	}
+
+	if (IsSubnetMask32(IpGet(hWnd, E_MASK)) == false)
+	{
+		b = false;
+	}
+
+	SetEnable(hWnd, IDOK, b);
+}
+
+// 仮想インターフェイスの追加ダイアログ
+UINT SmL3SwIfDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_L3SW *w = (SM_L3SW *)param;
+	char *hubname;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmL3SwIfDlgInit(hWnd, w);
+
+		SetTimer(hWnd, 1, 250, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			SmL3SwIfDlgUpdate(hWnd, w);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_HUBNAME:
+		case E_IP:
+		case E_MASK:
+			SmL3SwIfDlgUpdate(hWnd, w);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			hubname = GetTextA(hWnd, E_HUBNAME);
+			if (hubname != NULL)
+			{
+				RPC_L3IF t;
+				Zero(&t, sizeof(t));
+				StrCpy(t.HubName, sizeof(t.HubName), hubname);
+				t.IpAddress = IpGet(hWnd, E_IP);
+				t.SubnetMask = IpGet(hWnd, E_MASK);
+				StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+				if (CALL(hWnd, ScAddL3If(w->s->Rpc, &t)))
+				{
+					EndDialog(hWnd, 1);
+				}
+
+				Free(hubname);
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// 初期化
+void SmL3SwDlgInit(HWND hWnd, SM_L3SW *w)
+{
+	// 引数チェック
+	if (hWnd == NULL || w == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_SWITCH_OFFLINE);
+
+	FormatText(hWnd, 0, w->SwitchName);
+
+	SetFont(hWnd, S_BOLD1, Font(0, true));
+	SetFont(hWnd, S_BOLD2, Font(0, true));
+
+	LvInit(hWnd, L_IF);
+	LvInsertColumn(hWnd, L_IF, 0, _UU("SM_L3_SW_IF_COLUMN1"), 150);
+	LvInsertColumn(hWnd, L_IF, 1, _UU("SM_L3_SW_IF_COLUMN2"), 150);
+	LvInsertColumn(hWnd, L_IF, 2, _UU("SM_L3_SW_IF_COLUMN3"), 180);
+
+	LvInit(hWnd, L_TABLE);
+	LvInsertColumn(hWnd, L_TABLE, 0, _UU("SM_L3_SW_TABLE_COLUMN1"), 130);
+	LvInsertColumn(hWnd, L_TABLE, 1, _UU("SM_L3_SW_TABLE_COLUMN2"), 130);
+	LvInsertColumn(hWnd, L_TABLE, 2, _UU("SM_L3_SW_TABLE_COLUMN3"), 130);
+	LvInsertColumn(hWnd, L_TABLE, 3, _UU("SM_L3_SW_TABLE_COLUMN4"), 100);
+
+	w->Enable = SmL3IsSwActive(w->s, w->SwitchName) ? false : true;
+
+	SmL3SwDlgRefresh(hWnd, w);
+}
+
+// コントロール更新
+void SmL3SwDlgUpdate(HWND hWnd, SM_L3SW *w)
+{
+	// 引数チェック
+	if (hWnd == NULL || w == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, B_ADD_IF, w->s->ServerAdminMode && w->Enable);
+	SetEnable(hWnd, B_ADD_TABLE, w->s->ServerAdminMode && w->Enable);
+	SetEnable(hWnd, B_DEL_IF, LvIsSingleSelected(hWnd, L_IF) && w->s->ServerAdminMode && w->Enable);
+	SetEnable(hWnd, B_DEL_TABLE, LvIsSingleSelected(hWnd, L_TABLE) && w->s->ServerAdminMode && w->Enable);
+	SetEnable(hWnd, B_START, w->s->ServerAdminMode && w->Enable);
+	SetEnable(hWnd, B_STOP, w->s->ServerAdminMode && (w->Enable == false));
+}
+
+// 内容更新
+void SmL3SwDlgRefresh(HWND hWnd, SM_L3SW *w)
+{
+	UINT i;
+	wchar_t tmp1[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	wchar_t tmp3[MAX_SIZE];
+	wchar_t tmp4[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || w == NULL)
+	{
+		return;
+	}
+
+	// 仮想インターフェイス一覧
+	{
+		RPC_ENUM_L3IF t;
+		LVB *v;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+		if (CALL(hWnd, ScEnumL3If(w->s->Rpc, &t)) == false)
+		{
+			Close(hWnd);
+			return;
+		}
+
+		v = LvInsertStart();
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_L3IF *e = &t.Items[i];
+
+			IPToUniStr32(tmp1, sizeof(tmp1), e->IpAddress);
+			IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+			StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+			LvInsertAdd(v, ICO_NIC_ONLINE, NULL, 3, tmp1, tmp2, tmp3);
+		}
+
+		LvReset(hWnd, L_IF);
+
+		LvInsertEnd(v, hWnd, L_IF);
+
+		FreeRpcEnumL3If(&t);
+	}
+
+	// ルーティングテーブル一覧
+	{
+		RPC_ENUM_L3TABLE t;
+		LVB *v;
+
+		Zero(&t, sizeof(t));
+		StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+		if (CALL(hWnd, ScEnumL3Table(w->s->Rpc, &t)) == false)
+		{
+			Close(hWnd);
+			return;
+		}
+
+		v = LvInsertStart();
+
+		for (i = 0;i < t.NumItem;i++)
+		{
+			RPC_L3TABLE *e = &t.Items[i];
+
+			IPToUniStr32(tmp1, sizeof(tmp1), e->NetworkAddress);
+			IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+			IPToUniStr32(tmp3, sizeof(tmp3), e->GatewayAddress);
+			UniToStru(tmp4, e->Metric);
+
+			LvInsertAdd(v, ICO_PROTOCOL, NULL, 4, tmp1, tmp2, tmp3, tmp4);
+		}
+
+		LvReset(hWnd, L_TABLE);
+
+		LvInsertEnd(v, hWnd, L_TABLE);
+
+		FreeRpcEnumL3Table(&t);
+	}
+
+	SmL3SwDlgUpdate(hWnd, w);
+}
+
+// L3 スイッチの編集ダイアログ
+UINT SmL3SwDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_L3SW *w = (SM_L3SW *)param;
+	NMHDR *n;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmL3SwDlgInit(hWnd, w);
+
+		SetTimer(hWnd, 1, 1000, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			w->Enable = SmL3IsSwActive(w->s, w->SwitchName) ? false : true;
+			SmL3SwDlgUpdate(hWnd, w);
+			SetTimer(hWnd, 1, 1000, NULL);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_START:
+			if (IsEnable(hWnd, B_START))
+			{
+				RPC_L3SW t;
+
+				Zero(&t, sizeof(t));
+				StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+				if (CALL(hWnd, ScStartL3Switch(w->s->Rpc, &t)))
+				{
+					SmL3SwDlgUpdate(hWnd, w);
+				}
+			}
+			break;
+
+		case B_STOP:
+			if (IsEnable(hWnd, B_STOP))
+			{
+				RPC_L3SW t;
+
+				Zero(&t, sizeof(t));
+				StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+				if (CALL(hWnd, ScStopL3Switch(w->s->Rpc, &t)))
+				{
+					SmL3SwDlgUpdate(hWnd, w);
+				}
+			}
+			break;
+
+		case B_ADD_IF:
+			if (Dialog(hWnd, D_SM_L3_SW_IF, SmL3SwIfDlg, w))
+			{
+				SmL3SwDlgRefresh(hWnd, w);
+			}
+			break;
+
+		case B_DEL_IF:
+			if (LvIsSingleSelected(hWnd, L_IF))
+			{
+				RPC_L3IF t;
+				char *tmp1, *tmp2, *tmp3;
+
+				tmp1 = LvGetSelectedStrA(hWnd, L_IF, 0);
+				tmp2 = LvGetSelectedStrA(hWnd, L_IF, 1);
+				tmp3 = LvGetSelectedStrA(hWnd, L_IF, 2);
+
+				Zero(&t, sizeof(t));
+				StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+				t.IpAddress = StrToIP32(tmp1);
+				t.SubnetMask = StrToIP32(tmp2);
+				StrCpy(t.HubName, sizeof(t.HubName), tmp3);
+
+				if (CALL(hWnd, ScDelL3If(w->s->Rpc, &t)))
+				{
+					SmL3SwDlgRefresh(hWnd, w);
+				}
+
+				Free(tmp1);
+				Free(tmp2);
+				Free(tmp3);
+			}
+			break;
+
+		case B_ADD_TABLE:
+			if (Dialog(hWnd, D_SM_L3_SW_TABLE, SmL3SwTableDlg, w))
+			{
+				SmL3SwDlgRefresh(hWnd, w);
+			}
+			break;
+
+		case B_DEL_TABLE:
+			if (LvIsSingleSelected(hWnd, L_TABLE))
+			{
+				RPC_L3TABLE t;
+				char *tmp1, *tmp2, *tmp3, *tmp4;
+
+				tmp1 = LvGetSelectedStrA(hWnd, L_TABLE, 0);
+				tmp2 = LvGetSelectedStrA(hWnd, L_TABLE, 1);
+				tmp3 = LvGetSelectedStrA(hWnd, L_TABLE, 2);
+				tmp4 = LvGetSelectedStrA(hWnd, L_TABLE, 3);
+
+				Zero(&t, sizeof(t));
+				StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+				t.NetworkAddress = StrToIP32(tmp1);
+				t.SubnetMask = StrToIP32(tmp2);
+				t.GatewayAddress = StrToIP32(tmp3);
+				t.Metric = ToInt(tmp4);
+
+				if (CALL(hWnd, ScDelL3Table(w->s->Rpc, &t)))
+				{
+					SmL3SwDlgRefresh(hWnd, w);
+				}
+
+				Free(tmp1);
+				Free(tmp2);
+				Free(tmp3);
+				Free(tmp4);
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_IF:
+		case L_TABLE:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmL3SwDlgUpdate(hWnd, w);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// コントロール更新
+void SmL3AddDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+	char *tmp;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	tmp = GetTextA(hWnd, E_NAME);
+
+	SetEnable(hWnd, IDOK, IsEmptyStr(tmp) == false && IsSafeStr(tmp));
+
+	Free(tmp);
+}
+
+// 新しい L3 スイッチの作成ダイアログ
+UINT SmL3AddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *s = (SM_SERVER *)param;
+	RPC_L3SW t;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		LimitText(hWnd, E_NAME, MAX_HUBNAME_LEN);
+		SmL3AddDlgUpdate(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_NAME:
+			SmL3AddDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			Zero(&t, sizeof(t));
+			GetTxtA(hWnd, E_NAME, t.Name, sizeof(t.Name));
+			if (CALL(hWnd, ScAddL3Switch(s->Rpc, &t)))
+			{
+				EndDialog(hWnd, 1);
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// ダイアログ初期化
+void SmL3DlgInit(HWND hWnd, SM_SERVER *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetFont(hWnd, S_BOLD, Font(0, true));
+
+	SetIcon(hWnd, 0, ICO_SWITCH);
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_L3_SW_COLUMN1"), 150);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_L3_SW_COLUMN2"), 120);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_L3_SW_COLUMN3"), 100);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_L3_SW_COLUMN4"), 100);
+
+	SmL3DlgRefresh(hWnd, s);
+}
+
+// ダイアログコントロール更新
+void SmL3DlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+	bool b = false;
+	bool active = false;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSingleSelected(hWnd, L_LIST))
+	{
+		wchar_t *tmp;
+		UINT i;
+		b = true;
+		i = LvGetSelected(hWnd, L_LIST);
+		if (i != INFINITE)
+		{
+			tmp = LvGetStr(hWnd, L_LIST, i, 1);
+			if (UniStrCmpi(tmp, _UU("SM_L3_SW_ST_F_F")) != 0)
+			{
+				active = true;
+			}
+			Free(tmp);
+		}
+	}
+
+	SetEnable(hWnd, B_START, b && (active == false));
+	SetEnable(hWnd, B_STOP, b && (active != false));
+	SetEnable(hWnd, IDOK, b);
+	SetEnable(hWnd, B_DELETE, b);
+}
+
+// ダイアログ内容更新
+void SmL3DlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+	RPC_ENUM_L3SW t;
+	UINT i;
+	LVB *v;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScEnumL3Switch(s->Rpc, &t)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	v = LvInsertStart();
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+		wchar_t tmp1[MAX_SIZE], *tmp2, tmp3[64], tmp4[64];
+
+		StrToUni(tmp1, sizeof(tmp1), e->Name);
+		if (e->Active == false)
+		{
+			tmp2 = _UU("SM_L3_SW_ST_F_F");
+		}
+		else if (e->Online == false)
+		{
+			tmp2 = _UU("SM_L3_SW_ST_T_F");
+		}
+		else
+		{
+			tmp2 = _UU("SM_L3_SW_ST_T_T");
+		}
+		UniToStru(tmp3, e->NumInterfaces);
+		UniToStru(tmp4, e->NumTables);
+
+		LvInsertAdd(v, e->Active ? ICO_SWITCH : ICO_SWITCH_OFFLINE, NULL,
+			4, tmp1, tmp2, tmp3, tmp4);
+	}
+
+	LvInsertEnd(v, hWnd, L_LIST);
+
+	FreeRpcEnumL3Sw(&t);
+
+	SmL3DlgUpdate(hWnd, s);
+}
+
+// L3 ダイアログプロシージャ
+UINT SmL3Dlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	SM_SERVER *s = (SM_SERVER *)param;
+	RPC_L3SW t;
+	char *name;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmL3DlgInit(hWnd, s);
+
+		SetTimer(hWnd, 1, 1000, NULL);
+		break;
+
+	case WM_TIMER:
+		KillTimer(hWnd, 1);
+		SmL3DlgRefresh(hWnd, s);
+		SetTimer(hWnd, 1, 1000, NULL);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_ADD:
+			// 追加
+			if (Dialog(hWnd, D_SM_L3_ADD, SmL3AddDlg, s))
+			{
+				SmL3DlgRefresh(hWnd, s);
+			}
+			break;
+
+		case B_START:
+			// 動作開始
+			name = LvGetSelectedStrA(hWnd, L_LIST, 0);
+			if (name != NULL)
+			{
+				Zero(&t, sizeof(t));
+				StrCpy(t.Name, sizeof(t.Name), name);
+
+				if (CALL(hWnd, ScStartL3Switch(s->Rpc, &t)))
+				{
+					SmL3DlgRefresh(hWnd, s);
+				}
+
+				Free(name);
+			}
+			break;
+
+		case B_STOP:
+			// 動作停止
+			name = LvGetSelectedStrA(hWnd, L_LIST, 0);
+			if (name != NULL)
+			{
+				Zero(&t, sizeof(t));
+				StrCpy(t.Name, sizeof(t.Name), name);
+
+				if (CALL(hWnd, ScStopL3Switch(s->Rpc, &t)))
+				{
+					SmL3DlgRefresh(hWnd, s);
+				}
+
+				Free(name);
+			}
+			break;
+
+		case IDOK:
+			// 編集
+			if (IsEnable(hWnd, IDOK))
+			{
+				name = LvGetSelectedStrA(hWnd, L_LIST, 0);
+				if (name != NULL)
+				{
+					SM_L3SW w;
+					Zero(&w, sizeof(w));
+					w.s = s;
+					w.SwitchName = name;
+
+					Dialog(hWnd, D_SM_L3_SW, SmL3SwDlg, &w);
+
+					Free(name);
+				}
+			}
+			break;
+
+		case B_DELETE:
+			// 削除
+			name = LvGetSelectedStrA(hWnd, L_LIST, 0);
+			if (name != NULL)
+			{
+				if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+					_UU("SM_L3_SW_DEL_MSG"), name) == IDYES)
+				{
+					Zero(&t, sizeof(t));
+					StrCpy(t.Name, sizeof(t.Name), name);
+
+					if (CALL(hWnd, ScDelL3Switch(s->Rpc, &t)))
+					{
+						SmL3DlgRefresh(hWnd, s);
+					}
+				}
+
+				Free(name);
+			}
+			break;
+
+		case IDCANCEL:
+			// 閉じる
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_LIST:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmL3DlgUpdate(hWnd, s);
+				break;
+
+			case NM_DBLCLK:
+				Command(hWnd, IDOK);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// L3 ダイアログ
+void SmL3(HWND hWnd, SM_SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_L3, SmL3Dlg, s);
+}
+
+// 管理オプション値用ダイアログ
+UINT SmHubAdminOptionValueDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_AO *a = (SM_EDIT_AO *)param;
+	UINT i;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		CbReset(hWnd, C_NAME);
+		for (i = 0;i < a->DefaultOptions.NumItem;i++)
+		{
+			wchar_t tmp[MAX_PATH];
+			StrToUni(tmp, sizeof(tmp), a->DefaultOptions.Items[i].Name);
+			CbAddStr(hWnd, C_NAME, tmp, 0);
+		}
+		if (a->NewMode == false)
+		{
+			char tmp[MAX_SIZE];
+
+			SetTextA(hWnd, C_NAME, a->Name);
+			ToStr(tmp, a->Value);
+
+			SetTextA(hWnd, E_VALUE, tmp);
+		}
+		else
+		{
+			SetTextA(hWnd, C_NAME, "");
+		}
+		SmHubAdminOptionValueDlgUpdate(hWnd, a);
+		if (a->NewMode == false)
+		{
+			FocusEx(hWnd, E_VALUE);
+			Disable(hWnd, C_NAME);
+		}
+		else
+		{
+			FocusEx(hWnd, C_NAME);
+		}
+
+		SetTimer(hWnd, 1, 100, NULL);
+		break;
+
+	case WM_TIMER:
+		SmHubAdminOptionValueDlgUpdate(hWnd, a);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (a->NewMode)
+			{
+				GetTxtA(hWnd, C_NAME, a->Name, sizeof(a->Name));
+			}
+
+			GetTxtA(hWnd, E_VALUE, tmp, sizeof(tmp));
+			a->Value = ToInt(tmp);
+
+			Trim(a->Name);
+
+			if (StartWith(a->Name, "no") || StartWith(a->Name, "allow") || StartWith(a->Name, "deny")
+				 || StartWith(a->Name, "filter") || StartWith(a->Name, "fix") || StartWith(a->Name, "force")
+				 || StartWith(a->Name, "use") || StartWith(a->Name, "b_") || StartWith(a->Name, "is")
+				 || StartWith(a->Name, "manage") || StartWith(a->Name, "yield")
+				 || StartWith(a->Name, "permit") || StartWith(a->Name, "yes") || StartWith(a->Name, "ok")
+				 || StartWith(a->Name, "do") || StartWith(a->Name, "only") || StartWith(a->Name, "disable"))
+			{
+				if (StrCmpi(tmp, "0") != 0 && StrCmpi(tmp, "1") != 0)
+				{
+					MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SM_TRUE_OR_FALSE"));
+					FocusEx(hWnd, E_VALUE);
+					break;
+				}
+			}
+
+			EndDialog(hWnd, true);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+
+		SmHubAdminOptionValueDlgUpdate(hWnd, a);
+
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 管理オプション値用ダイアログ コントロール更新
+void SmHubAdminOptionValueDlgUpdate(HWND hWnd, SM_EDIT_AO *a)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	GetTxtA(hWnd, C_NAME, tmp, sizeof(tmp));
+
+	SetEnable(hWnd, IDOK, IsEmpty(hWnd, C_NAME) == false && IsEmpty(hWnd, E_VALUE) == false &&
+		IsSafeStr(tmp));
+}
+
+// 初期化
+void SmHubAdminOptionDlgInit(HWND hWnd, SM_EDIT_AO *a)
+{
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_USER_ADMIN);
+
+	if (a->e->p->ServerAdminMode)
+	{
+		a->CanChange = true;
+	}
+	else
+	{
+		if (a->ExtOption == false)
+		{
+			for (i = 0;i < a->CurrentOptions.NumItem;i++)
+			{
+				if (StrCmpi(a->CurrentOptions.Items[i].Name, "allow_hub_admin_change_option") == 0)
+				{
+					if (a->CurrentOptions.Items[i].Value != 0)
+					{
+						a->CanChange = true;
+					}
+				}
+			}
+		}
+		else
+		{
+			a->CanChange = true;
+		}
+	}
+
+	FormatText(hWnd, S_INFO, a->e->HubName);
+
+	DlgFont(hWnd, S_BOLD, 0, true);
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_AO_COLUMN_1"), 260);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_AO_COLUMN_2"), 100);
+
+	for (i = 0;i < a->CurrentOptions.NumItem;i++)
+	{
+		ADMIN_OPTION *e = &a->CurrentOptions.Items[i];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+
+		StrToUni(tmp1, sizeof(tmp1), e->Name);
+		UniToStru(tmp2, e->Value);
+
+		LvInsert(hWnd, L_LIST, ICO_LOG, NULL, 2, tmp1, tmp2);
+			
+	}
+
+	if (a->ExtOption)
+	{
+		SetIcon(hWnd, S_ICON, ICO_LINK2);
+		SetIcon(hWnd, 0, ICO_LINK2);
+
+		SetText(hWnd, 0, _UU("SM_HUBEXT_OPTION_TITLE"));
+		SetText(hWnd, S_STATIC1, _UU("SM_HUBEXT_OPTION_STATIC1"));
+		SetText(hWnd, S_STATIC2, _UU("SM_HUBEXT_OPTION_STATIC2"));
+	}
+
+	// コントロール更新
+	SmHubAdminOptionDlgUpdate(hWnd, a);
+}
+
+// コントロール更新
+void SmHubAdminOptionDlgUpdate(HWND hWnd, SM_EDIT_AO *a)
+{
+	bool b = false;
+	wchar_t *helpstr;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	helpstr = _UU("HUB_AO_CLICK");
+
+	SetEnable(hWnd, IDOK, a->CanChange);
+	SetEnable(hWnd, B_ADD, a->CanChange);
+	SetEnable(hWnd, B_EDIT, a->CanChange && (LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false));
+
+	if (LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false)
+	{
+		UINT i;
+		i = LvGetSelected(hWnd, L_LIST);
+
+		if (a->CanChange)
+		{
+
+			b = true;
+
+			if (i != INFINITE)
+			{
+				char *name = LvGetStrA(hWnd, L_LIST, i, 0);
+				if (name != NULL)
+				{
+					UINT j;
+
+					for (j = 0;j < a->DefaultOptions.NumItem;j++)
+					{
+						if (StrCmpi(a->DefaultOptions.Items[j].Name, name) == 0)
+						{
+							b = false;
+						}
+					}
+					Free(name);
+				}
+			}
+		}
+
+		if (i != INFINITE)
+		{
+			char *name = LvGetStrA(hWnd, L_LIST, i, 0);
+			if (name != NULL)
+			{
+				helpstr = GetHubAdminOptionHelpString(name);
+			}
+			Free(name);
+		}
+	}
+	SetEnable(hWnd, B_DELETE, b);
+
+	SetText(hWnd, E_HELP, helpstr);
+}
+
+// 保存
+void SmHubAdminOptionDlgOk(HWND hWnd, SM_EDIT_AO *a)
+{
+	UINT i, num;
+	RPC_ADMIN_OPTION t;
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	num = LvNum(hWnd, L_LIST);
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), a->e->HubName);
+	t.NumItem = num;
+	t.Items = ZeroMalloc(sizeof(ADMIN_OPTION) * num);
+
+	for (i = 0;i < num;i++)
+	{
+		char *name = LvGetStrA(hWnd, L_LIST, i, 0);
+		char *s_value = LvGetStrA(hWnd, L_LIST, i, 1);
+		ADMIN_OPTION *a = &t.Items[i];
+
+		StrCpy(a->Name, sizeof(a->Name), name);
+		a->Value = ToInt(s_value);
+
+		Free(name);
+		Free(s_value);
+	}
+
+	if (a->ExtOption == false)
+	{
+		if (CALL(hWnd, ScSetHubAdminOptions(a->e->p->Rpc, &t)))
+		{
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_AO_SET_OK"));
+			EndDialog(hWnd, true);
+		}
+	}
+	else
+	{
+		if (CALL(hWnd, ScSetHubExtOptions(a->e->p->Rpc, &t)))
+		{
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_EXT_OPTION_SET_OK"));
+			EndDialog(hWnd, true);
+		}
+	}
+
+	FreeRpcAdminOption(&t);
+}
+
+// 仮想 HUB 管理オプションダイアログ
+UINT SmHubAdminOptionDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_AO *a = (SM_EDIT_AO *)param;
+	NMHDR *n;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmHubAdminOptionDlgInit(hWnd, a);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_ADD:
+			a->NewMode = true;
+			StrCpy(a->Name, sizeof(a->Name), "");
+			a->Value = 0;
+			if (Dialog(hWnd, D_SM_AO_VALUE, SmHubAdminOptionValueDlg,
+				a))
+			{
+				wchar_t tmp1[MAX_SIZE];
+				wchar_t tmp2[MAX_SIZE];
+				StrToUni(tmp1, sizeof(tmp1), a->Name);
+				UniToStru(tmp2, a->Value);
+
+				LvInsert(hWnd, L_LIST, ICO_LOG, NULL, 2, tmp1, tmp2);
+			}
+			break;
+
+		case B_EDIT:
+			i = LvGetSelected(hWnd, L_LIST);
+			if (i != INFINITE && a->CanChange)
+			{
+				char *name, *value;
+				name = LvGetStrA(hWnd, L_LIST, i, 0);
+				value = LvGetStrA(hWnd, L_LIST, i, 1);
+				a->NewMode = false;
+				StrCpy(a->Name, sizeof(a->Name), name);
+				a->Value = ToInt(value);
+
+				if (Dialog(hWnd, D_SM_AO_VALUE, SmHubAdminOptionValueDlg,
+					a))
+				{
+					char tmp[MAX_PATH];
+					ToStr(tmp, a->Value);
+					LvSetItemA(hWnd, L_LIST, i, 1, tmp);
+				}
+
+				Free(name);
+				Free(value);
+			}
+			break;
+
+		case B_DELETE:
+			i = LvGetSelected(hWnd, L_LIST);
+			if (i != INFINITE)
+			{
+				LvDeleteItem(hWnd, L_LIST, i);
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case IDOK:
+			SmHubAdminOptionDlgOk(hWnd, a);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_LIST:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmHubAdminOptionDlgUpdate(hWnd, a);
+				break;
+
+			case NM_DBLCLK:
+				Command(hWnd, B_EDIT);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// 仮想 HUB 拡張オプション
+void SmHubExtOption(HWND hWnd, SM_EDIT_HUB *e)
+{
+	SM_EDIT_AO a;
+	// 引数チェック
+	if (hWnd == NULL || e == NULL)
+	{
+		return;
+	}
+
+	Zero(&a, sizeof(a));
+	a.e = e;
+	a.ExtOption = true;
+
+	StrCpy(a.CurrentOptions.HubName, sizeof(a.CurrentOptions.HubName), e->HubName);
+
+	// 現在のサーバー上のオプションを取得する
+	if (CALL(hWnd, ScGetHubExtOptions(e->p->Rpc, &a.CurrentOptions)) == false)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_ADMIN_OPTION, SmHubAdminOptionDlg, &a);
+
+	FreeRpcAdminOption(&a.CurrentOptions);
+	FreeRpcAdminOption(&a.DefaultOptions);
+}
+
+// 仮想 HUB 管理オプション
+void SmHubAdminOption(HWND hWnd, SM_EDIT_HUB *e)
+{
+	SM_EDIT_AO a;
+	// 引数チェック
+	if (hWnd == NULL || e == NULL)
+	{
+		return;
+	}
+
+	Zero(&a, sizeof(a));
+	a.e = e;
+
+	StrCpy(a.CurrentOptions.HubName, sizeof(a.CurrentOptions.HubName), e->HubName);
+
+	// 現在のサーバー上のオプションを取得する
+	if (CALL(hWnd, ScGetHubAdminOptions(e->p->Rpc, &a.CurrentOptions)) == false)
+	{
+		return;
+	}
+
+	ScGetDefaultHubAdminOptions(e->p->Rpc, &a.DefaultOptions);
+
+	Dialog(hWnd, D_SM_ADMIN_OPTION, SmHubAdminOptionDlg, &a);
+
+	FreeRpcAdminOption(&a.CurrentOptions);
+	FreeRpcAdminOption(&a.DefaultOptions);
+}
+
+// 初期化
+void SmConfigDlgInit(HWND hWnd, SM_CONFIG *c)
+{
+	wchar_t *tmp;
+	UINT tmp_size;
+	// 引数チェック
+	if (hWnd == NULL || c == NULL)
+	{
+		return;
+	}
+
+	Focus(hWnd, IDCANCEL);
+
+	SetIcon(hWnd, 0, ICO_MACHINE);
+
+	SetFont(hWnd, E_CONFIG, GetFont(_SS("DEFAULT_FONT_2"), 0, false, false,
+		false, false));
+
+	FormatText(hWnd, IDC_INFO, c->s->ServerName);
+
+	// UTF-8 から Unicode に変換
+	tmp_size = CalcUtf8ToUni(c->Config.FileData, StrLen(c->Config.FileData)) + 1;
+	tmp = ZeroMalloc(tmp_size);
+	Utf8ToUni(tmp, tmp_size, c->Config.FileData, StrLen(c->Config.FileData));
+
+	SetText(hWnd, E_CONFIG, tmp);
+
+	Free(tmp);
+}
+
+// config 編集ダイアログ
+UINT SmConfigDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_CONFIG *c = (SM_CONFIG *)param;
+	char *filename;
+	wchar_t *filename_unicode;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmConfigDlgInit(hWnd, c);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_EXPORT:
+			StrToUni(tmp, sizeof(tmp), c->Config.FileName);
+			filename_unicode = SaveDlg(hWnd, _UU("DLG_CONFIG_FILES"), _UU("DLG_SAVE_CONFIG"), tmp, L".config");
+			if (filename_unicode != NULL)
+			{
+				BUF *b = NewBuf();
+				filename = CopyUniToStr(filename_unicode);
+				WriteBuf(b, c->Config.FileData, StrLen(c->Config.FileData));
+				if (DumpBuf(b, filename))
+				{
+					MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_CONFIG_SAVED"));
+				}
+				else
+				{
+					MsgBox(hWnd, MB_ICONSTOP, _UU("SM_CONFIG_SAVE_FAILED"));
+				}
+				FreeBuf(b);
+				Free(filename);
+				Free(filename_unicode);
+			}
+			break;
+
+		case B_IMPORT:
+			filename_unicode = OpenDlg(hWnd, _UU("DLG_CONFIG_FILES"), _UU("DLG_OPEN_CONFIG"));
+			if (filename_unicode != NULL)
+			{
+				BUF *b;
+				filename = CopyUniToStr(filename_unicode);
+				b = ReadDump(filename);
+				if (b != NULL)
+				{
+					RPC_CONFIG t;
+
+					if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_CONFIG_CONFIRM")) == IDYES)
+					{
+						Zero(&t, sizeof(t));
+						t.FileData = ZeroMalloc(b->Size + 1);
+						Copy(t.FileData, b->Buf, b->Size);
+
+						if (CALL(hWnd, ScSetConfig(c->s->Rpc, &t)))
+						{
+							// 成功
+							MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_CONFIG_WRITE_OK"));
+							_exit(0);
+						}
+
+						FreeRpcConfig(&t);
+
+						FreeRpcConfig(&t);
+						FreeBuf(b);
+					}
+				}
+				else
+				{
+					MsgBox(hWnd, MB_ICONSTOP, _UU("SM_CONFIG_OPEN_FAILED"));
+				}
+				Free(filename);
+				Free(filename_unicode);
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// config 編集ダイアログを表示する
+void SmConfig(HWND hWnd, SM_SERVER *s)
+{
+	SM_CONFIG c;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&c, sizeof(c));
+
+	c.s = s;
+
+	// 現在の config をサーバーから取得
+	if (CALL(hWnd, ScGetConfig(s->Rpc, &c.Config)) == false)
+	{
+		return;
+	}
+
+	// ダイアログ表示
+	Dialog(hWnd, D_SM_CONFIG, SmConfigDlg, &c);
+
+	// 解放
+	FreeRpcConfig(&c.Config);
+}
+
+// ブリッジダイアログ初期化
+void SmBridgeDlgInit(HWND hWnd, SM_SERVER *s)
+{
+	UINT i;
+	RPC_ENUM_ETH t;
+	RPC_SERVER_INFO si;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_BRIDGE_COLUMN_1"), 50);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_BRIDGE_COLUMN_2"), 145);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_BRIDGE_COLUMN_3"), 300);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_BRIDGE_COLUMN_4"), 100);
+
+	SmBridgeDlgRefresh(hWnd, s);
+
+	SetShow(hWnd, B_VLAN, GetCapsBool(s->CapsList, "b_support_eth_vlan"));
+
+	SetIcon(hWnd, 0, ICO_BRIDGE);
+
+	// サーバー情報を取得
+	Zero(&si, sizeof(si));
+	ScGetServerInfo(s->Rpc, &si);
+	if (GetCapsBool(s->CapsList, "b_tap_supported") == false)
+	{
+		// tap はサポートしていない
+		Hide(hWnd, R_TAP);
+		Hide(hWnd, S_TAP_1);
+		Hide(hWnd, E_TAPNAME);
+		Hide(hWnd, S_TAP_2);
+		Hide(hWnd, R_BRIDGE);
+		Hide(hWnd, S_STATIC5);
+	}
+	Check(hWnd, R_BRIDGE, true);
+	FreeRpcServerInfo(&si);
+
+	// Ethernet 列挙
+	Zero(&t, sizeof(t));
+	ScEnumEthernet(s->Rpc, &t);
+
+	CbReset(hWnd, E_NICNAME);
+	CbSetHeight(hWnd, E_NICNAME, 18);
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_ENUM_ETH_ITEM *e = &t.Items[i];
+		if(UniIsEmptyStr(e->NetworkConnectionName) == false)
+		{
+			wchar_t ncname[MAX_SIZE * 2];
+			UniFormat(ncname, sizeof(ncname), BRIDGE_NETWORK_CONNECTION_STR, e->NetworkConnectionName, e->DeviceName);
+			CbAddStr(hWnd, E_NICNAME, ncname, 0);
+		}
+		else
+		{
+			wchar_t *s = CopyStrToUni(e->DeviceName);
+			CbAddStr(hWnd, E_NICNAME, s, 0);
+			Free(s);
+		}
+	}
+
+	FreeRpcEnumEth(&t);
+
+	// 仮想 HUB 列挙
+	{
+		RPC_ENUM_HUB t;
+		Zero(&t, sizeof(t));
+
+		ScEnumHub(s->Rpc, &t);
+
+		CbReset(hWnd, E_HUBNAME);
+		CbSetHeight(hWnd, E_HUBNAME, 18);
+
+		for (i = 0;i < t.NumHub;i++)
+		{
+			RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+			wchar_t *s = CopyStrToUni(e->HubName);
+
+			if (e->HubType != HUB_TYPE_FARM_DYNAMIC)
+			{
+				CbAddStr(hWnd, E_HUBNAME, s, 0);
+			}
+			Free(s);
+		}
+
+		SetText(hWnd, E_HUBNAME, L"");
+
+		FreeRpcEnumHub(&t);
+	}
+
+	if (s->Bridge)
+	{
+		SetTextA(hWnd, E_HUBNAME, "BRIDGE");
+	}
+
+	Focus(hWnd, E_HUBNAME);
+	
+	SmBridgeDlgUpdate(hWnd, s);
+
+	SetTimer(hWnd, 1, 1000, NULL);
+}
+
+// ブリッジダイアログコントロール更新
+void SmBridgeDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false)
+	{
+		Enable(hWnd, B_DELETE);
+	}
+	else
+	{
+		Disable(hWnd, B_DELETE);
+	}
+
+	if (IsEmpty(hWnd, E_HUBNAME))
+	{
+		ok = false;
+	}
+
+	if (IsChecked(hWnd, R_TAP) == false)
+	{
+		// ブリッジモード
+		Enable(hWnd, S_ETH_1);
+		Enable(hWnd, E_NICNAME);
+		Disable(hWnd, S_TAP_1);
+		Disable(hWnd, S_TAP_2);
+		Disable(hWnd, E_TAPNAME);
+		SetText(hWnd, S_INFO, _UU("SM_BRIDGE_INFO_1"));
+		SetIcon(hWnd, S_ICON, ICO_NIC_ONLINE);
+		if (IsEmpty(hWnd, E_NICNAME))
+		{
+			ok = false;
+		}
+	}
+	else
+	{
+		char tmp[MAX_SIZE];
+		// tap モード
+		Disable(hWnd, S_ETH_1);
+		Disable(hWnd, E_NICNAME);
+		Enable(hWnd, S_TAP_1);
+		Enable(hWnd, S_TAP_2);
+		Enable(hWnd, E_TAPNAME);
+		SetText(hWnd, S_INFO, _UU("SM_BRIDGE_INFO_2"));
+		SetIcon(hWnd, S_ICON, ICO_PROTOCOL);
+		GetTxtA(hWnd, E_TAPNAME, tmp, sizeof(tmp));
+		if (IsEmptyStr(tmp))
+		{
+			ok = false;
+		}
+		else
+		{
+			if (IsSafeStr(tmp) == false)
+			{
+				ok = false;
+			}
+			if (StrLen(tmp) >= 12)
+			{
+				ok = false;
+			}
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// ブリッジダイアログ更新
+void SmBridgeDlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+	LVB *lvb;
+	RPC_ENUM_LOCALBRIDGE t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	lvb = LvInsertStart();
+
+	Zero(&t, sizeof(t));
+
+	ScEnumLocalBridge(s->Rpc, &t);
+
+	for (i = 0;i < t.NumItem;i++)
+	{
+		RPC_LOCALBRIDGE *e = &t.Items[i];
+		wchar_t name[MAX_SIZE];
+		wchar_t nic[MAX_SIZE];
+		wchar_t hub[MAX_SIZE];
+		wchar_t *status = _UU("SM_BRIDGE_OFFLINE");
+
+		UniToStru(name, i + 1);
+		StrToUni(nic, sizeof(nic), e->DeviceName);
+		StrToUni(hub, sizeof(hub), e->HubName);
+
+		if (e->Online)
+		{
+			status = e->Active ? _UU("SM_BRIDGE_ONLINE") : _UU("SM_BRIDGE_ERROR");
+		}
+
+		LvInsertAdd(lvb, e->TapMode == false ? (e->Active ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE) : ICO_PROTOCOL,
+			NULL, 4, name, hub, nic, status);
+	}
+
+	FreeRpcEnumLocalBridge(&t);
+
+	LvInsertEnd(lvb, hWnd, L_LIST);
+
+	SmBridgeDlgUpdate(hWnd, s);
+}
+
+// ローカルブリッジの追加
+void SmBridgeDlgOnOk(HWND hWnd, SM_SERVER *s)
+{
+	char nic[MAX_SIZE];
+	char hub[MAX_SIZE];
+	RPC_LOCALBRIDGE t;
+	bool tapmode = false;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	GetTxtA(hWnd, E_HUBNAME, hub, sizeof(hub));
+
+	Zero(nic, sizeof(nic));
+
+	if (IsChecked(hWnd, R_TAP) == false)
+	{
+		wchar_t nctmp[MAX_SIZE * 2];
+		if(GetCapsBool(s->CapsList, "b_support_network_connection_name") && GetTxt(hWnd, E_NICNAME, nctmp, sizeof(nctmp)))
+		{
+			RPC_ENUM_ETH et;
+			UINT i;
+			Zero(&et, sizeof(et));
+			ScEnumEthernet(s->Rpc, &et);
+			for(i = 0; i < et.NumItem; i++)
+			{
+				RPC_ENUM_ETH_ITEM *e = &et.Items[i];
+				if(UniIsEmptyStr(e->NetworkConnectionName) == false)
+				{
+					wchar_t ncname[MAX_SIZE * 2];
+					UniFormat(ncname, sizeof(ncname), BRIDGE_NETWORK_CONNECTION_STR, e->NetworkConnectionName, e->DeviceName);
+					if(UniStrCmp(ncname, nctmp) == 0)
+					{
+						StrCpy(nic, sizeof(nic), e->DeviceName);
+						break;
+					}
+				}		
+			}
+			FreeRpcEnumEth(&et);
+
+			if (IsEmptyStr(nic))
+			{
+				GetTxtA(hWnd, E_NICNAME, nic, sizeof(nic));
+			}
+		}
+		else
+		{
+			GetTxtA(hWnd, E_NICNAME, nic, sizeof(nic));
+		}
+	}
+	else
+	{
+		tapmode = true;
+		GetTxtA(hWnd, E_TAPNAME, nic, sizeof(nic));
+	}
+
+	Trim(hub);
+	Trim(nic);
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.DeviceName, sizeof(t.DeviceName), nic);
+	StrCpy(t.HubName, sizeof(t.HubName), hub);
+	t.TapMode = tapmode;
+
+	if (InStrEx(t.DeviceName, "vpn", false) || InStrEx(t.DeviceName, "tun", false)
+		|| InStrEx(t.DeviceName, "tap", false))
+	{
+		// VPN デバイスにローカルブリッジしようとしている
+		if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+			_UU("SM_BRIDGE_VPN"),
+			t.DeviceName) == IDNO)
+		{
+			return;
+		}
+	}
+
+	// Intel 製 LAN カードなどに関する警告
+	if (tapmode == false)
+	{
+		MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_INTEL"));
+	}
+
+	if (CALL(hWnd, ScAddLocalBridge(s->Rpc, &t)) == false)
+	{
+		Focus(hWnd, E_HUBNAME);
+		return;
+	}
+
+	SetText(hWnd, E_HUBNAME, L"");
+	Focus(hWnd, E_HUBNAME);
+
+	if (tapmode)
+	{
+		SetTextA(hWnd, E_TAPNAME, "");
+	}
+
+	SmBridgeDlgRefresh(hWnd, s);
+
+	MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_OK"));
+}
+
+// ブリッジダイアログプロシージャ
+UINT SmBridgeDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	SM_SERVER *s = (SM_SERVER *)param;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmBridgeDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_HUBNAME:
+		case E_NICNAME:
+		case R_BRIDGE:
+		case R_TAP:
+		case E_TAPNAME:
+			SmBridgeDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case R_BRIDGE:
+			Focus(hWnd, E_NICNAME);
+			break;
+
+		case R_TAP:
+			FocusEx(hWnd, E_TAPNAME);
+			break;
+
+		case IDOK:
+			// 追加
+			SmBridgeDlgOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// 閉じる
+			Close(hWnd);
+			break;
+
+		case B_VLAN:
+			// VLAN ユーティリティ
+			SmVLan(hWnd, s);
+			break;
+
+		case B_DELETE:
+			// 削除
+			i = LvGetSelected(hWnd, L_LIST);
+			if (i != INFINITE)
+			{
+				wchar_t *nic, *hub;
+				wchar_t tmp[MAX_SIZE];
+				RPC_LOCALBRIDGE t;
+
+				hub = LvGetStr(hWnd, L_LIST, i, 1);
+				nic = LvGetStr(hWnd, L_LIST, i, 2);
+
+				UniFormat(tmp, sizeof(tmp), _UU("SM_BRIDGE_DELETE"),
+					hub, nic);
+
+				if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, tmp) == IDYES)
+				{
+					Zero(&t, sizeof(t));
+					UniToStr(t.DeviceName, sizeof(t.DeviceName), nic);
+					UniToStr(t.HubName, sizeof(t.HubName), hub);
+
+					if (CALL(hWnd, ScDeleteLocalBridge(s->Rpc, &t)))
+					{
+						MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_DELETE_OK"));
+						SmBridgeDlgRefresh(hWnd, s);
+					}
+				}
+
+				Free(hub);
+				Free(nic);
+			}
+			break;
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			SmBridgeDlgRefresh(hWnd, s);
+			SetTimer(hWnd, 1, 1000, NULL);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->code)
+		{
+		case LVN_ITEMCHANGED:
+			switch (n->idFrom)
+			{
+			case L_LIST:
+				SmBridgeDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// WinPcap のインストール作業
+void SmInstallWinPcap(HWND hWnd, SM_SERVER *s)
+{
+	wchar_t temp_name[MAX_SIZE];
+	IO *io;
+	BUF *buf;
+
+	// インストールを開始するかどうか質問する
+	if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_BRIDGE_WPCAP_INSTALL")) == IDNO)
+	{
+		return;
+	}
+
+	// 一時ファイル名を生成
+	UniFormat(temp_name, sizeof(temp_name), L"%s\\winpcap_installer.exe", MsGetTempDirW());
+
+	// hamcore から読み込む
+	buf = ReadDump(MsIsNt() ? "|winpcap_installer.exe" : "|winpcap_installer_win9x.exe");
+	if (buf == NULL)
+	{
+RES_ERROR:
+		MsgBox(hWnd, MB_ICONSTOP, _UU("SM_BRIDGE_RESOURCE"));
+		return;
+	}
+
+	// 一時ファイルに書き出す
+	io = FileCreateW(temp_name);
+	if (io == NULL)
+	{
+		FreeBuf(buf);
+		goto RES_ERROR;
+	}
+
+	FileWrite(io, buf->Buf, buf->Size);
+	FileClose(io);
+
+	FreeBuf(buf);
+
+	// 実行する
+	if (RunW(temp_name, NULL, false, true) == false)
+	{
+		// 失敗
+		FileDeleteW(temp_name);
+		goto RES_ERROR;
+	}
+
+	FileDeleteW(temp_name);
+
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// 終了後のメッセージ
+	if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) == false)
+	{
+		// コンピュータの再起動が必要
+		MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_WPCAP_REBOOT1"));
+	}
+	else
+	{
+		// サービスの再起動が必要
+		if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_BRIDGE_WPCAP_REBOOT2")) == IDNO)
+		{
+			// 再起動しない
+		}
+		else
+		{
+			// 再起動する
+			RPC_TEST t;
+			Zero(&t, sizeof(t));
+			ScRebootServer(s->Rpc, &t);
+
+			SleepThread(500);
+
+			Zero(&t, sizeof(t));
+			CALL(hWnd, ScTest(s->Rpc, &t));
+		}
+	}
+}
+
+// ブリッジダイアログ
+void SmBridgeDlg(HWND hWnd, SM_SERVER *s)
+{
+	RPC_BRIDGE_SUPPORT t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	// まずサーバー側のブリッジ対応状況を調べる
+	Zero(&t, sizeof(t));
+	if (CALLEX(hWnd, ScGetBridgeSupport(s->Rpc, &t)) != ERR_NO_ERROR)
+	{
+		// 古いバージョンなので未対応
+		MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SM_BRIDGE_TOO_OLD_VER"));
+		return;
+	}
+
+	if (t.IsBridgeSupportedOs == false)
+	{
+		// OS がブリッジに対応していない
+		MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SM_BRIDGE_UNSUPPORTED"));
+		return;
+	}
+
+	if (t.IsWinPcapNeeded)
+	{
+		if (s->Rpc->Sock->RemoteIP.addr[0] != 127)
+		{
+			// WinPcap が必要だがリモート管理モードなので何も出来ない
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_WPCAP_REMOTE"));
+			return;
+		}
+		else
+		{
+			// WinPcap が必要でローカル管理モードである
+			if (MsIsAdmin())
+			{
+				// Administrators である
+				SmInstallWinPcap(hWnd, s);
+				return;
+			}
+			else
+			{
+				// Administrators でない
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_WPCAP_ROOT"));
+				return;
+			}
+		}
+	}
+
+	Dialog(hWnd, D_SM_BRIDGE, SmBridgeDlgProc, s);
+}
+
+// SecureNAT 画面更新
+void SmSNATDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+	bool b;
+	RPC_HUB_STATUS t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	if (CALL(hWnd, ScGetHubStatus(s->Rpc, &t)) == false)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	b = t.SecureNATEnabled;
+
+	if (b)
+	{
+		Disable(hWnd, B_ENABLE);
+		Enable(hWnd, B_DISABLE);
+		Enable(hWnd, B_NAT);
+		Enable(hWnd, B_DHCP);
+		Enable(hWnd, B_STATUS);
+	}
+	else
+	{
+		Enable(hWnd, B_ENABLE);
+		Disable(hWnd, B_DISABLE);
+		Disable(hWnd, B_NAT);
+		Disable(hWnd, B_DHCP);
+		Disable(hWnd, B_STATUS);
+	}
+}
+
+// SecureNAT 設定画面
+UINT SmSNATDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *s = (SM_HUB *)param;
+	RPC_HUB t;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetIcon(hWnd, 0, ICO_ROUTER);
+		DlgFont(hWnd, S_WARNING, (_GETLANG() == 0 || _GETLANG() == 2) ? 13 : 10, true);
+		FormatText(hWnd, S_TITLE, s->HubName);
+		SmSNATDlgUpdate(hWnd, s);
+
+		SetTimer(hWnd, 1, 1000, NULL);
+		break;
+
+	case WM_TIMER:
+		if (wParam == 1)
+		{
+			KillTimer(hWnd, 1);
+
+			SmSNATDlgUpdate(hWnd, s);
+
+			SetTimer(hWnd, 1, 1000, NULL);
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case B_ENABLE:
+			if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_OKCANCEL | MB_DEFBUTTON2,
+				_UU("SM_SECURE_NAT_MSG")) == IDOK)
+			{
+				Zero(&t, sizeof(t));
+				StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+				CALL(hWnd, ScEnableSecureNAT(s->Rpc, &t));
+				SmSNATDlgUpdate(hWnd, s);
+			}
+			break;
+
+		case B_DISABLE:
+			Zero(&t, sizeof(t));
+			StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+			CALL(hWnd, ScDisableSecureNAT(s->Rpc, &t));
+			SmSNATDlgUpdate(hWnd, s);
+			break;
+
+		case B_CONFIG:
+			NmEditVhOption(hWnd, s);
+			break;
+
+		case B_NAT:
+			NmNat(hWnd, s);
+			break;
+
+		case B_DHCP:
+			NmDhcp(hWnd, s);
+			break;
+
+		case B_STATUS:
+			SmStatusDlg(hWnd, s->p, s, false, true, _UU("SM_SNAT_STATUS"), ICO_ROUTER,
+				NULL, NmStatus);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// 初期化
+void SmCreateCertDlgInit(HWND hWnd, SM_CERT *s)
+{
+	UINT cert_sign;
+	UINT cert_days;
+	char *reg_o, *reg_ou, *reg_c, *reg_st, *reg_l;
+	UINT bits[] = {1024, 1536, 2048, 3072, 4096 };
+	UINT i;
+	UINT last_bit;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetTextA(hWnd, E_CN, s->default_cn);
+
+	last_bit = MsRegReadInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Bits");
+	if (last_bit == 0)
+	{
+		last_bit = 1024;
+	}
+
+	CbReset(hWnd, C_BITS);
+	for (i = 0;i < sizeof(bits) / sizeof(bits[0]);i++)
+	{
+		char tmp[MAX_PATH];
+		UINT index;
+
+		ToStr(tmp, bits[i]);
+
+		index = CbAddStrA(hWnd, C_BITS, tmp, bits[i]);
+	}
+
+	CbSelect(hWnd, C_BITS, 1024);
+	CbSelect(hWnd, C_BITS, last_bit);
+
+	reg_o = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "O");
+	reg_ou = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "OU");
+	reg_c = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "C");
+	reg_st = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "ST");
+	reg_l = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "L");
+	SetTextA(hWnd, E_O, reg_o);
+	SetTextA(hWnd, E_OU, reg_ou);
+	SetTextA(hWnd, E_C, reg_c);
+	SetTextA(hWnd, E_ST, reg_st);
+	SetTextA(hWnd, E_L, reg_l);
+	Free(reg_o);
+	Free(reg_ou);
+	Free(reg_c);
+	Free(reg_st);
+	Free(reg_l);
+
+	LimitText(hWnd, E_C, 2);
+
+	cert_sign = MsRegReadInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Sign");
+	cert_days = MsRegReadInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Days");
+
+	Check(hWnd, R_ROOT_CERT, cert_sign ? false : true);
+	Check(hWnd, R_SIGNED_CERT, cert_sign ? true : false);
+
+	if (cert_days == 0)
+	{
+		cert_days = 3650;
+	}
+
+	SetIntEx(hWnd, E_EXPIRE, cert_days);
+
+	SmCreateCertDlgUpdate(hWnd, s);
+
+	FocusEx(hWnd, E_CN);
+}
+
+// 更新
+void SmCreateCertDlgUpdate(HWND hWnd, SM_CERT *s)
+{
+	bool ok = true;
+	bool b;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (IsEmpty(hWnd, E_CN) && IsEmpty(hWnd, E_O) && IsEmpty(hWnd, E_OU) &&
+		IsEmpty(hWnd, E_ST) && IsEmpty(hWnd, E_L))
+	{
+		ok = false;
+	}
+
+	i = GetInt(hWnd, E_EXPIRE);
+	if (i == 0 || i >= (365 * 30))
+	{
+		ok = false;
+	}
+
+	b = IsChecked(hWnd, R_SIGNED_CERT);
+
+	SetEnable(hWnd, S_LOAD_1, b);
+	SetEnable(hWnd, B_LOAD, b);
+	SetEnable(hWnd, S_LOAD_2, b);
+
+	if (b && (s->root_k == NULL || s->root_x == NULL))
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// OK ボタン
+void SmCreateCertDlgOnOk(HWND hWnd, SM_CERT *s)
+{
+	wchar_t cn[MAX_SIZE], o[MAX_SIZE], ou[MAX_SIZE], c[MAX_SIZE], st[MAX_SIZE], l[MAX_SIZE];
+	char *reg_o, *reg_ou, *reg_c, *reg_st, *reg_l;
+	UINT days;
+	bool sign;
+	char serial[MAX_SIZE * 2];
+	X *x;
+	K *pub;
+	K *pri;
+	NAME *n;
+	X_SERIAL *x_serial;
+	BUF *buf;
+	UINT bits;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	GetTxt(hWnd, E_CN, cn, sizeof(cn));
+	GetTxt(hWnd, E_O, o, sizeof(o));
+	GetTxt(hWnd, E_OU, ou, sizeof(ou));
+	GetTxt(hWnd, E_C, c, sizeof(c));
+	GetTxt(hWnd, E_ST, st, sizeof(st));
+	GetTxt(hWnd, E_L, l, sizeof(l));
+	GetTxtA(hWnd, E_SERIAL, serial, sizeof(serial));
+
+	bits = CbGetSelect(hWnd, C_BITS);
+	if (bits == INFINITE)
+	{
+		bits = 1024;
+	}
+
+	buf = StrToBin(serial);
+	if (buf == NULL)
+	{
+		return;
+	}
+
+	if (buf->Size > 1)
+	{
+		x_serial = NewXSerial(buf->Buf, buf->Size);
+	}
+	else
+	{
+		x_serial = NULL;
+	}
+
+	FreeBuf(buf);
+
+	n = NewName(UniStrLen(cn) ? cn : NULL,
+		UniStrLen(o) ? o : NULL,
+		UniStrLen(ou) ? ou : NULL,
+		UniStrLen(c) ? c : NULL,
+		UniStrLen(st) ? st : NULL,
+		UniStrLen(l) ? l : NULL);
+
+	days = GetInt(hWnd, E_EXPIRE);
+
+	sign = IsChecked(hWnd, R_SIGNED_CERT);
+
+	MsRegWriteInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Sign", sign);
+	MsRegWriteInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Days", days);
+	MsRegWriteInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Bits", bits);
+
+	RsaGen(&pri, &pub, bits);
+
+	if (sign == false)
+	{
+		x = NewRootX(pub, pri, n, days, x_serial);
+	}
+	else
+	{
+		x = NewX(pub, s->root_k, s->root_x, n, days, x_serial);
+	}
+
+	FreeName(n);
+
+	FreeXSerial(x_serial);
+
+	if (x == NULL)
+	{
+		FreeX(x);
+		FreeK(pub);
+		FreeK(pri);
+		return;
+	}
+
+	if (s->do_not_save == false)
+	{
+		if (SmSaveKeyPairDlg(hWnd, x, pri) == false)
+		{
+			FreeX(x);
+			FreeK(pub);
+			FreeK(pri);
+			return;
+		}
+	}
+
+	s->x = x;
+	s->k = pri;
+	FreeK(pub);
+
+	reg_o = GetTextA(hWnd, E_O);
+	reg_ou = GetTextA(hWnd, E_OU);
+	reg_c = GetTextA(hWnd, E_C);
+	reg_st = GetTextA(hWnd, E_ST);
+	reg_l = GetTextA(hWnd, E_L);
+	MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "O", reg_o);
+	MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "OU", reg_ou);
+	MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "C", reg_c);
+	MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "ST", reg_st);
+	MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "L", reg_l);
+	Free(reg_o);
+	Free(reg_ou);
+	Free(reg_c);
+	Free(reg_st);
+	Free(reg_l);
+
+	EndDialog(hWnd, true);
+}
+
+// 証明書作成画面
+UINT SmCreateCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_CERT *s = (SM_CERT *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmCreateCertDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_ROOT_CERT:
+		case R_SIGNED_CERT:
+		case B_LOAD:
+		case E_CN:
+		case E_O:
+		case E_OU:
+		case E_C:
+		case E_ST:
+		case E_L:
+		case E_EXPIRE:
+			SmCreateCertDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmCreateCertDlgOnOk(hWnd, s);
+			break;
+
+		case R_ROOT_CERT:
+			if (IsChecked(hWnd, R_ROOT_CERT))
+			{
+				FocusEx(hWnd, E_CN);
+			}
+			break;
+
+		case B_LOAD:
+			// 証明書読み込み
+			if (1)
+			{
+				X *x;
+				K *k;
+				if (CmLoadXAndK(hWnd, &x, &k))
+				{
+					wchar_t tmp[MAX_SIZE];
+					FreeX(s->root_x);
+					FreeK(s->root_k);
+					s->root_x = x;
+					s->root_k = k;
+
+					SmGetCertInfoStr(tmp, sizeof(tmp), x);
+					SetText(hWnd, S_LOAD_2, tmp);
+					SmCreateCertDlgUpdate(hWnd, s);
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 証明書ツール
+bool SmCreateCert(HWND hWnd, X **x, K **k, bool do_not_save, char *default_cn)
+{
+	bool ret;
+	SM_CERT s;
+	Zero(&s, sizeof(s));
+
+	if (default_cn == NULL)
+	{
+		default_cn = "";
+	}
+
+	s.default_cn = default_cn;
+
+	s.do_not_save = do_not_save;
+
+	ret = Dialog(hWnd, D_SM_CREATE_CERT, SmCreateCertDlgProc, &s);
+
+	if (ret)
+	{
+		if (x != NULL)
+		{
+			*x = CloneX(s.x);
+		}
+
+		if (k != NULL)
+		{
+			*k = CloneK(s.k);
+		}
+	}
+
+	FreeX(s.x);
+	FreeK(s.k);
+	FreeX(s.root_x);
+	FreeK(s.root_k);
+
+	return ret;
+}
+
+// 初期化
+void SmIpTableDlgInit(HWND hWnd, SM_TABLE *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_PROTOCOL);
+	FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+	if (s->SessionName != NULL)
+	{
+		wchar_t tmp[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		GetTxt(hWnd, S_TITLE, tmp, sizeof(tmp));
+		UniFormat(tmp2, sizeof(tmp2), _UU("SM_SESSION_FILTER"), s->SessionName);
+		UniStrCat(tmp, sizeof(tmp), tmp2);
+		SetText(hWnd, S_TITLE, tmp);
+	}
+
+	LvInit(hWnd, L_TABLE);
+	LvInsertColumn(hWnd, L_TABLE, 0, _UU("SM_IP_COLUMN_1"), 190);
+	LvInsertColumn(hWnd, L_TABLE, 1, _UU("SM_IP_COLUMN_2"), 140);
+	LvInsertColumn(hWnd, L_TABLE, 2, _UU("SM_IP_COLUMN_3"), 133);
+	LvInsertColumn(hWnd, L_TABLE, 3, _UU("SM_IP_COLUMN_4"), 133);
+	LvInsertColumn(hWnd, L_TABLE, 4, _UU("SM_IP_COLUMN_5"), 133);
+	LvSetStyle(hWnd, L_TABLE, LVS_EX_GRIDLINES);
+
+	SmIpTableDlgRefresh(hWnd, s);
+}
+
+// コントロール更新
+void SmIpTableDlgUpdate(HWND hWnd, SM_TABLE *s)
+{
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_TABLE) == false || LvIsMultiMasked(hWnd, L_TABLE))
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, B_DELETE, ok);
+}
+
+// 内容更新
+void SmIpTableDlgRefresh(HWND hWnd, SM_TABLE *s)
+{
+	UINT i;
+	RPC_ENUM_IP_TABLE t;
+	UINT old_selected = 0;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+
+	if (CALL(hWnd, ScEnumIpTable(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	i = LvGetSelected(hWnd, L_TABLE);
+	if (i != INFINITE)
+	{
+		old_selected = (UINT)LvGetParam(hWnd, L_TABLE, i);
+	}
+
+	LvReset(hWnd, L_TABLE);
+
+	for (i = 0;i < t.NumIpTable;i++)
+	{
+		char str[MAX_SIZE];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp4[MAX_SIZE];
+		wchar_t tmp5[MAX_SIZE];
+		RPC_ENUM_IP_TABLE_ITEM *e = &t.IpTables[i];
+
+		if (s->SessionName == NULL || StrCmpi(e->SessionName, s->SessionName) == 0)
+		{
+			StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+			if (e->DhcpAllocated == false)
+			{
+				IPToStr(str, sizeof(str), &e->IpV6);
+				StrToUni(tmp2, sizeof(tmp2), str);
+			}
+			else
+			{
+				IPToStr(str, sizeof(str), &e->IpV6);
+				UniFormat(tmp2, sizeof(tmp2), _UU("SM_MAC_IP_DHCP"), str);
+			}
+
+			GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+			GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+			if (StrLen(e->RemoteHostname) == 0)
+			{
+				UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+			}
+			else
+			{
+				UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+			}
+
+			LvInsert(hWnd, L_TABLE, e->DhcpAllocated ? ICO_PROTOCOL_DHCP : ICO_PROTOCOL, (void *)e->Key, 5,
+				tmp1, tmp2, tmp3, tmp4, tmp5);
+		}
+	}
+
+	FreeRpcEnumIpTable(&t);
+
+	if (old_selected != 0)
+	{
+		LvSelect(hWnd, L_TABLE, LvSearchParam(hWnd, L_TABLE, (void *)old_selected));
+	}
+
+	SmIpTableDlgUpdate(hWnd, s);
+}
+
+// IP アドレステーブルダイアログプロシージャ
+UINT SmIpTableDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_TABLE *s = (SM_TABLE *)param;
+	NMHDR *n;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmIpTableDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_DELETE:
+			// 削除
+			i = LvGetSelected(hWnd, L_TABLE);
+			if (i != INFINITE)
+			{
+				RPC_DELETE_TABLE t;
+				UINT key = (UINT)LvGetParam(hWnd, L_TABLE, i);
+
+				Zero(&t, sizeof(t));
+				StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+				t.Key = key;
+				if (CALL(hWnd, ScDeleteIpTable(s->Rpc, &t)))
+				{
+					LvDeleteItem(hWnd, L_TABLE, i);
+				}
+			}
+			break;
+
+		case B_REFRESH:
+			// 更新
+			SmIpTableDlgRefresh(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_TABLE:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmIpTableDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+	return 0;
+}
+
+// IP アドレステーブルダイアログ
+void SmIpTableDlg(HWND hWnd, SM_HUB *s, char *session_name)
+{
+	SM_TABLE t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Hub = s;
+	t.Rpc = s->Rpc;
+	t.SessionName = session_name;
+
+	Dialog(hWnd, D_SM_IP, SmIpTableDlgProc, &t);
+}
+
+
+// 初期化
+void SmMacTableDlgInit(HWND hWnd, SM_TABLE *s)
+{
+	UINT i = 0;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+	FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+	if (s->SessionName != NULL)
+	{
+		wchar_t tmp[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		GetTxt(hWnd, S_TITLE, tmp, sizeof(tmp));
+		UniFormat(tmp2, sizeof(tmp2), _UU("SM_SESSION_FILTER"), s->SessionName);
+		UniStrCat(tmp, sizeof(tmp), tmp2);
+		SetText(hWnd, S_TITLE, tmp);
+	}
+
+	LvInit(hWnd, L_TABLE);
+	LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_1"), 190);
+	if (GetCapsBool(s->Hub->p->CapsList, "b_support_vlan"))
+	{
+		LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_1A"), 65);
+	}
+	LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_2"), 140);
+	LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_3"), 133);
+	LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_4"), 133);
+	LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_5"), 133);
+	LvSetStyle(hWnd, L_TABLE, LVS_EX_GRIDLINES);
+
+	SmMacTableDlgRefresh(hWnd, s);
+}
+
+// コントロール更新
+void SmMacTableDlgUpdate(HWND hWnd, SM_TABLE *s)
+{
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_TABLE) == false || LvIsMultiMasked(hWnd, L_TABLE))
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, B_DELETE, ok);
+}
+
+// 内容更新
+void SmMacTableDlgRefresh(HWND hWnd, SM_TABLE *s)
+{
+	UINT i;
+	RPC_ENUM_MAC_TABLE t;
+	UINT old_selected = 0;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+
+	if (CALL(hWnd, ScEnumMacTable(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	i = LvGetSelected(hWnd, L_TABLE);
+	if (i != INFINITE)
+	{
+		old_selected = (UINT)LvGetParam(hWnd, L_TABLE, i);
+	}
+
+	LvReset(hWnd, L_TABLE);
+
+	for (i = 0;i < t.NumMacTable;i++)
+	{
+		char str[MAX_SIZE];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp4[MAX_SIZE];
+		wchar_t tmp5[MAX_SIZE];
+		wchar_t tmp6[MAX_SIZE];
+		RPC_ENUM_MAC_TABLE_ITEM *e = &t.MacTables[i];
+
+		if (s->SessionName == NULL || StrCmpi(e->SessionName, s->SessionName) == 0)
+		{
+			StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+			MacToStr(str, sizeof(str), e->MacAddress);
+			StrToUni(tmp2, sizeof(tmp2), str);
+
+			GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+			GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+			if (StrLen(e->RemoteHostname) == 0)
+			{
+				UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+			}
+			else
+			{
+				UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+			}
+
+			UniToStru(tmp6, e->VlanId);
+			if (e->VlanId == 0)
+			{
+				UniStrCpy(tmp6, sizeof(tmp6), _UU("CM_ST_NONE"));
+			}
+
+			if (GetCapsBool(s->Hub->p->CapsList, "b_support_vlan"))
+			{
+				LvInsert(hWnd, L_TABLE, ICO_NIC_ONLINE, (void *)e->Key, 6,
+					tmp1, tmp6, tmp2, tmp3, tmp4, tmp5);
+			}
+			else
+			{
+				LvInsert(hWnd, L_TABLE, ICO_NIC_ONLINE, (void *)e->Key, 5,
+					tmp1, tmp2, tmp3, tmp4, tmp5);
+			}
+		}
+	}
+
+	FreeRpcEnumMacTable(&t);
+
+	if (old_selected != 0)
+	{
+		LvSelect(hWnd, L_TABLE, LvSearchParam(hWnd, L_TABLE, (void *)old_selected));
+	}
+
+	SmMacTableDlgUpdate(hWnd, s);
+}
+
+// MAC アドレステーブルダイアログプロシージャ
+UINT SmMacTableDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_TABLE *s = (SM_TABLE *)param;
+	NMHDR *n;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmMacTableDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_DELETE:
+			// 削除
+			i = LvGetSelected(hWnd, L_TABLE);
+			if (i != INFINITE)
+			{
+				RPC_DELETE_TABLE t;
+				UINT key = (UINT)LvGetParam(hWnd, L_TABLE, i);
+
+				Zero(&t, sizeof(t));
+				StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+				t.Key = key;
+				if (CALL(hWnd, ScDeleteMacTable(s->Rpc, &t)))
+				{
+					LvDeleteItem(hWnd, L_TABLE, i);
+				}
+			}
+			break;
+
+		case B_REFRESH:
+			// 更新
+			SmMacTableDlgRefresh(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_TABLE:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmMacTableDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+	return 0;
+}
+
+// MAC アドレステーブルダイアログ
+void SmMacTableDlg(HWND hWnd, SM_HUB *s, char *session_name)
+{
+	SM_TABLE t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Hub = s;
+	t.Rpc = s->Rpc;
+	t.SessionName = session_name;
+
+	Dialog(hWnd, D_SM_MAC, SmMacTableDlgProc, &t);
+}
+
+// 初期化
+void SmSessionDlgInit(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_VPN);
+	FormatText(hWnd, 0, s->HubName);
+	FormatText(hWnd, S_TITLE, s->HubName);
+
+	LvInit(hWnd, L_LIST);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_SESS_COLUMN_1"), 176);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_SESS_COLUMN_8"), 58);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_SESS_COLUMN_2"), 62);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_SESS_COLUMN_3"), 78);
+	LvInsertColumn(hWnd, L_LIST, 4, _UU("SM_SESS_COLUMN_4"), 122);
+	LvInsertColumn(hWnd, L_LIST, 5, _UU("SM_SESS_COLUMN_5"), 68);
+	LvInsertColumn(hWnd, L_LIST, 6, _UU("SM_SESS_COLUMN_6"), 100);
+	LvInsertColumn(hWnd, L_LIST, 7, _UU("SM_SESS_COLUMN_7"), 100);
+	LvSetStyle(hWnd, L_LIST, LVS_EX_GRIDLINES);
+
+	if (s->p->ServerType == SERVER_TYPE_FARM_CONTROLLER && GetCapsBool(s->p->CapsList, "b_support_cluster_admin") == false)
+	{
+		Show(hWnd, S_FARM_INFO_1);
+		Show(hWnd, S_FARM_INFO_2);
+	}
+
+	SmSessionDlgRefresh(hWnd, s);
+}
+
+// コントロールを更新する
+void SmSessionDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+	bool ok = true;
+	bool ok2 = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_LIST) == false || LvIsMultiMasked(hWnd, L_LIST))
+	{
+		ok = false;
+		ok2 = false;
+	}
+	else
+	{
+		UINT i = LvGetSelected(hWnd, L_LIST);
+		if (i != INFINITE)
+		{
+			void *p = LvGetParam(hWnd, L_LIST, i);
+			if (((bool)p) != false)
+			{
+				if (GetCapsBool(s->p->CapsList, "b_support_cluster_admin") == false)
+				{
+					ok = false;
+				}
+			}
+		}
+	}
+
+	if (s->p->ServerInfo.ServerBuildInt < 2844)
+	{
+		// セッションのリモート管理非対応 Ver
+		ok2 = ok;
+	}
+
+	SetEnable(hWnd, IDOK, ok2);
+	SetEnable(hWnd, B_DISCONNECT, ok2);
+	SetEnable(hWnd, B_SESSION_IP_TABLE, ok);
+	SetEnable(hWnd, B_SESSION_MAC_TABLE, ok);
+}
+
+// リストを更新する
+void SmSessionDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+	LVB *b;
+	UINT i;
+	wchar_t *old_select;
+	RPC_ENUM_SESSION t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+	if (CALL(hWnd, ScEnumSession(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	old_select = LvGetSelectedStr(hWnd, L_LIST, 0);
+
+	LvReset(hWnd, L_LIST);
+
+	b = LvInsertStart();
+
+	for (i = 0;i < t.NumSession;i++)
+	{
+		RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t *tmp2;
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp4[MAX_SIZE];
+		wchar_t tmp5[MAX_SIZE];
+		wchar_t tmp6[MAX_SIZE];
+		wchar_t tmp7[MAX_SIZE];
+		wchar_t tmp8[MAX_SIZE];
+		bool free_tmp2 = false;
+		UINT icon;
+
+		StrToUni(tmp1, sizeof(tmp1), e->Name);
+
+		tmp2 = _UU("SM_SESS_NORMAL");
+		icon = ICO_VPN;
+		if (s->p->ServerType != SERVER_TYPE_STANDALONE)
+		{
+			if (e->RemoteSession)
+			{
+				tmp2 = ZeroMalloc(MAX_SIZE);
+				UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_REMOTE"), e->RemoteHostname);
+				icon = ICO_VPN;
+				free_tmp2 = true;
+			}
+			else
+			{
+				if (StrLen(e->RemoteHostname) == 0)
+				{
+					tmp2 = _UU("SM_SESS_LOCAL");
+				}
+				else
+				{
+					tmp2 = ZeroMalloc(MAX_SIZE);
+					UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_LOCAL_2"), e->RemoteHostname);
+					free_tmp2 = true;
+				}
+			}
+		}
+		if (e->LinkMode)
+		{
+			if (free_tmp2)
+			{
+				Free(tmp2);
+				free_tmp2 = false;
+			}
+			tmp2 = _UU("SM_SESS_LINK");
+			icon = ICO_CASCADE;
+		}
+		else if (e->SecureNATMode)
+		{
+			/*if (free_tmp2)
+			{
+				Free(tmp2);
+				free_tmp2 = false;
+			}
+			tmp2 = _UU("SM_SESS_SNAT");*/
+			icon = ICO_ROUTER;
+		}
+		else if (e->BridgeMode)
+		{
+			icon = ICO_BRIDGE;
+		}
+		else if (e->Layer3Mode)
+		{
+			icon = ICO_SWITCH;
+		}
+
+		StrToUni(tmp3, sizeof(tmp3), e->Username);
+
+		StrToUni(tmp4, sizeof(tmp4), e->Hostname);
+		if (e->LinkMode)
+		{
+			UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LINK_HOSTNAME"));
+		}
+		else if (e->SecureNATMode)
+		{
+			UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_SNAT_HOSTNAME"));
+		}
+		else if (e->BridgeMode)
+		{
+			UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_BRIDGE_HOSTNAME"));
+		}
+		else if (StartWith(e->Username, L3_USERNAME))
+		{
+			UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LAYER3_HOSTNAME"));
+		}
+
+		UniFormat(tmp5, sizeof(tmp5), L"%u / %u", e->CurrentNumTcp, e->MaxNumTcp);
+		if (e->LinkMode)
+		{
+			UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_LINK_TCP"));
+		}
+		else if (e->SecureNATMode)
+		{
+			UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_SNAT_TCP"));
+		}
+		else if (e->BridgeMode)
+		{
+			UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_BRIDGE_TCP"));
+		}
+
+		if (e->VLanId == 0)
+		{
+			UniStrCpy(tmp8, sizeof(tmp8), _UU("CM_ST_NO_VLAN"));
+		}
+		else
+		{
+			UniToStru(tmp8, e->VLanId);
+		}
+
+		UniToStr3(tmp6, sizeof(tmp6), e->PacketSize);
+		UniToStr3(tmp7, sizeof(tmp7), e->PacketNum);
+
+		if (icon == ICO_VPN)
+		{
+			if (e->Client_BridgeMode)
+			{
+				icon = ICO_SESSION_BRIDGE;
+			}
+			else if (e->Client_MonitorMode)
+			{
+				icon = ICO_SESSION_MONITOR;
+			}
+		}
+
+		LvInsertAdd(b, icon, (void *)(e->RemoteSession), 8, tmp1, tmp8, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7);
+
+		if (free_tmp2)
+		{
+			Free(tmp2);
+		}
+	}
+
+	LvInsertEnd(b, hWnd, L_LIST);
+
+	if (old_select != NULL && UniStrLen(old_select) != 0)
+	{
+		UINT i = LvSearchStr(hWnd, L_LIST, 0, old_select);
+		if (i != INFINITE)
+		{
+			LvSelect(hWnd, L_LIST, i);
+		}
+	}
+
+	Free(old_select);
+
+	FreeRpcEnumSession(&t);
+
+	SmSessionDlgUpdate(hWnd, s);
+}
+
+// NODE_INFO の表示
+void SmPrintNodeInfo(LVB *b, NODE_INFO *info)
+{
+	wchar_t tmp[MAX_SIZE];
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (b == NULL || info == NULL)
+	{
+		return;
+	}
+
+	StrToUni(tmp, sizeof(tmp), info->ClientProductName);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_NAME"), tmp);
+
+	UniFormat(tmp, sizeof(tmp), L"%u.%02u", Endian32(info->ClientProductVer) / 100, Endian32(info->ClientProductVer) % 100);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_VER"), tmp);
+
+	UniFormat(tmp, sizeof(tmp), L"Build %u", Endian32(info->ClientProductBuild));
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_BUILD"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ClientOsName);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_OS_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ClientOsVer);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_OS_VER"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ClientOsProductId);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_OS_PID"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ClientHostname);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_HOST"), tmp);
+
+	IPToStr4or6(str, sizeof(str), info->ClientIpAddress, info->ClientIpAddress6);
+	StrToUni(tmp, sizeof(tmp), str);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_IP"), tmp);
+
+	UniToStru(tmp, Endian32(info->ClientPort));
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_PORT"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), info->ServerHostname);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_SERVER_HOST"), tmp);
+
+	IPToStr4or6(str, sizeof(str), info->ServerIpAddress, info->ServerIpAddress6);
+	StrToUni(tmp, sizeof(tmp), str);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_SERVER_IP"), tmp);
+
+	UniToStru(tmp, Endian32(info->ServerPort));
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_SERVER_PORT"), tmp);
+
+	if (StrLen(info->ProxyHostname) != 0)
+	{
+		StrToUni(tmp, sizeof(tmp), info->ProxyHostname);
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_PROXY_HOSTNAME"), tmp);
+
+		IPToStr4or6(str, sizeof(str), info->ProxyIpAddress, info->ProxyIpAddress6);
+		StrToUni(tmp, sizeof(tmp), str);
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_PROXY_IP"), tmp);
+
+		UniToStru(tmp, Endian32(info->ProxyPort));
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_PROXY_PORT"), tmp);
+	}
+}
+
+// セッション ステータスの更新
+bool SmRefreshSessionStatus(HWND hWnd, SM_SERVER *s, void *param)
+{
+	LVB *b;
+	SM_SESSION_STATUS *status = (SM_SESSION_STATUS *)param;
+	RPC_SESSION_STATUS t;
+	wchar_t tmp[MAX_SIZE];
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL || param == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), status->Hub->HubName);
+	StrCpy(t.Name, sizeof(t.Name), status->SessionName);
+
+	if (CALL(hWnd, ScGetSessionStatus(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	if (t.ClientIp != 0)
+	{
+		IPToStr4or6(str, sizeof(str), t.ClientIp, t.ClientIp6);
+		StrToUni(tmp, sizeof(tmp), str);
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_CLIENT_IP"), tmp);
+	}
+
+	if (StrLen(t.ClientHostName) != 0)
+	{
+		StrToUni(tmp, sizeof(tmp), t.ClientHostName);
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_CLIENT_HOSTNAME"), tmp);
+	}
+
+	StrToUni(tmp, sizeof(tmp), t.Username);
+	LvInsertAdd(b, 0, NULL, 2, _UU("SM_SESS_STATUS_USERNAME"), tmp);
+
+	if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0)
+	{
+		StrToUni(tmp, sizeof(tmp), t.RealUsername);
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_SESS_STATUS_REALUSER"), tmp);
+	}
+
+	if (IsEmptyStr(t.GroupName) == false)
+	{
+		StrToUni(tmp, sizeof(tmp), t.GroupName);
+		LvInsertAdd(b, 0, NULL, 2, _UU("SM_SESS_STATUS_GROUPNAME"), tmp);
+	}
+
+	CmPrintStatusToListViewEx(b, &t.Status, true);
+
+	if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0 &&
+		StartWith(t.Username, L3_USERNAME) == false)
+	{
+		SmPrintNodeInfo(b, &t.NodeInfo);
+	}
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	FreeRpcSessionStatus(&t);
+
+	return true;
+}
+
+// セッション管理ダイアログプロシージャ
+UINT SmSessionDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *s = (SM_HUB *)param;
+	wchar_t *tmp;
+	wchar_t tmp2[MAX_SIZE];
+	char name[MAX_SIZE];
+	NMHDR *n;
+	SM_SESSION_STATUS status;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	tmp = LvGetSelectedStr(hWnd, L_LIST, 0);
+	UniToStr(name, sizeof(name), tmp);
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmSessionDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (IsEnable(hWnd, IDOK))
+			{
+				// セッション状態表示
+				UniFormat(tmp2, sizeof(tmp2), _UU("SM_SESS_STATUS_CAPTION"), name);
+				Zero(&status, sizeof(status));
+				status.Hub = s;
+				status.SessionName = name;
+				SmStatusDlg(hWnd, s->p, &status, true, true, tmp2, ICO_VPN,
+					NULL, SmRefreshSessionStatus);
+			}
+			break;
+
+		case B_DISCONNECT:
+			// 切断
+			if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+				_UU("SM_SESS_DISCONNECT_MSG"), name) == IDYES)
+			{
+				RPC_DELETE_SESSION t;
+				Zero(&t, sizeof(t));
+				StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+				StrCpy(t.Name, sizeof(t.Name), name);
+
+				if (CALL(hWnd, ScDeleteSession(s->Rpc, &t)))
+				{
+					SmSessionDlgRefresh(hWnd, s);
+				}
+			}
+			break;
+
+		case B_REFRESH:
+			// 更新
+			SmSessionDlgRefresh(hWnd, s);
+			break;
+
+		case B_SESSION_IP_TABLE:
+			// IP テーブル
+			SmIpTableDlg(hWnd, s, name);
+			break;
+
+		case B_SESSION_MAC_TABLE:
+			// MAC テーブル
+			SmMacTableDlg(hWnd, s, name);
+			break;
+
+		case B_MAC_TABLE:
+			// MAC テーブル一覧
+			SmMacTableDlg(hWnd, s, NULL);
+			break;
+
+		case B_IP_TABLE:
+			// IP テーブル一覧
+			SmIpTableDlg(hWnd, s, NULL);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->code)
+		{
+		case LVN_ITEMCHANGED:
+			switch (n->idFrom)
+			{
+			case L_LIST:
+				SmSessionDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	Free(tmp);
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+	return 0;
+}
+
+// セッション管理ダイアログ
+void SmSessionDlg(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_SESSION, SmSessionDlgProc, s);
+}
+
+// 証明書一覧更新
+void SmCaDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+	LVB *b;
+	UINT i;
+	RPC_HUB_ENUM_CA t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	if (CALL(hWnd, ScEnumCa(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	b = LvInsertStart();
+
+	for (i = 0;i < t.NumCa;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		RPC_HUB_ENUM_CA_ITEM *e = &t.Ca[i];
+
+		GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(e->Expires), NULL);
+
+		LvInsertAdd(b, ICO_SERVER_CERT, (void *)e->Key, 3,
+			e->SubjectName, e->IssuerName, tmp);
+	}
+
+	LvInsertEnd(b, hWnd, L_CERT);
+
+	FreeRpcHubEnumCa(&t);
+
+	SmCaDlgUpdate(hWnd, s);
+}
+
+// 初期化
+void SmCaDlgInit(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_SERVER_CERT);
+
+	LvInit(hWnd, L_CERT);
+	LvInsertColumn(hWnd, L_CERT, 0, _UU("CM_CERT_COLUMN_1"), 190);
+	LvInsertColumn(hWnd, L_CERT, 1, _UU("CM_CERT_COLUMN_2"), 190);
+	LvInsertColumn(hWnd, L_CERT, 2, _UU("CM_CERT_COLUMN_3"), 160);
+
+	SmCaDlgRefresh(hWnd, s);
+}
+
+// コントロール更新
+void SmCaDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, B_DELETE, LvIsSelected(hWnd, L_CERT));
+	SetEnable(hWnd, IDOK, LvIsSelected(hWnd, L_CERT));
+}
+
+// OK
+void SmCaDlgOnOk(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+}
+
+// CA 追加ダイアログ
+bool SmCaDlgAdd(HWND hWnd, SM_HUB *s)
+{
+	X *x;
+	RPC_HUB_ADD_CA t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	if (CmLoadXFromFileOrSecureCard(hWnd, &x) == false)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	t.Cert = x;
+
+	if (CALL(hWnd, ScAddCa(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	FreeRpcHubAddCa(&t);
+
+	return true;
+}
+
+// CA 一覧ダイアログプロシージャ
+UINT SmCaDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	SM_HUB *s = (SM_HUB *)param;
+	UINT i, key;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmCaDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_IMPORT:
+			// 追加
+			if (SmCaDlgAdd(hWnd, s))
+			{
+				SmCaDlgRefresh(hWnd, s);
+			}
+			break;
+
+		case B_DELETE:
+			// 削除
+			i = LvGetSelected(hWnd, L_CERT);
+			if (i != INFINITE)
+			{
+				key = (UINT)LvGetParam(hWnd, L_CERT, i);
+				if (key != 0)
+				{
+					if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+						_UU("CM_CERT_DELETE_MSG")) == IDYES)
+					{
+						RPC_HUB_DELETE_CA t;
+						Zero(&t, sizeof(t));
+						StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+						t.Key = key;
+
+						if (CALL(hWnd, ScDeleteCa(s->Rpc, &t)))
+						{
+							SmCaDlgRefresh(hWnd, s);
+						}
+					}
+				}
+			}
+			break;
+
+		case IDOK:
+			// 表示
+			i = LvGetSelected(hWnd, L_CERT);
+			if (i != INFINITE)
+			{
+				key = (UINT)LvGetParam(hWnd, L_CERT, i);
+				if (key != 0)
+				{
+					RPC_HUB_GET_CA t;
+					Zero(&t, sizeof(t));
+					StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+					t.Key = key;
+
+					if (CALL(hWnd, ScGetCa(s->Rpc, &t)))
+					{
+						CertDlg(hWnd, t.Cert, NULL, true);
+						FreeRpcHubGetCa(&t);
+					}
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_CERT:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmCaDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_CERT);
+
+	return 0;
+}
+
+// CA 一覧ダイアログ
+void SmCaDlg(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_CA, SmCaDlgProc, s);
+}
+
+// 初期化
+void SmLogDlgInit(HWND hWnd, SM_HUB *s)
+{
+	RPC_HUB_LOG t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_LOG2);
+
+	FormatText(hWnd, S_TITLE, s->HubName);
+
+	CbSetHeight(hWnd, C_SEC_SWITCH, 18);
+	CbSetHeight(hWnd, C_PACKET_SWITCH, 18);
+
+	// コントロール初期化
+	CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_0"), 0);
+	CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_1"), 1);
+	CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_2"), 2);
+	CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_3"), 3);
+	CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_4"), 4);
+	CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_5"), 5);
+	CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_0"), 0);
+	CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_1"), 1);
+	CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_2"), 2);
+	CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_3"), 3);
+	CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_4"), 4);
+	CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_5"), 5);
+
+	// ログ設定を取得
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	if (CALL(hWnd, ScGetHubLog(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	Check(hWnd, B_SEC, t.LogSetting.SaveSecurityLog);
+	CbSelect(hWnd, C_SEC_SWITCH, t.LogSetting.SecurityLogSwitchType);
+
+	Check(hWnd, B_PACKET, t.LogSetting.SavePacketLog);
+	CbSelect(hWnd, C_PACKET_SWITCH, t.LogSetting.PacketLogSwitchType);
+
+	Check(hWnd, B_PACKET_0_0, t.LogSetting.PacketLogConfig[0] == 0);
+	Check(hWnd, B_PACKET_0_1, t.LogSetting.PacketLogConfig[0] == 1);
+	Check(hWnd, B_PACKET_0_2, t.LogSetting.PacketLogConfig[0] == 2);
+
+	Check(hWnd, B_PACKET_1_0, t.LogSetting.PacketLogConfig[1] == 0);
+	Check(hWnd, B_PACKET_1_1, t.LogSetting.PacketLogConfig[1] == 1);
+	Check(hWnd, B_PACKET_1_2, t.LogSetting.PacketLogConfig[1] == 2);
+
+	Check(hWnd, B_PACKET_2_0, t.LogSetting.PacketLogConfig[2] == 0);
+	Check(hWnd, B_PACKET_2_1, t.LogSetting.PacketLogConfig[2] == 1);
+	Check(hWnd, B_PACKET_2_2, t.LogSetting.PacketLogConfig[2] == 2);
+
+	Check(hWnd, B_PACKET_3_0, t.LogSetting.PacketLogConfig[3] == 0);
+	Check(hWnd, B_PACKET_3_1, t.LogSetting.PacketLogConfig[3] == 1);
+	Check(hWnd, B_PACKET_3_2, t.LogSetting.PacketLogConfig[3] == 2);
+
+	Check(hWnd, B_PACKET_4_0, t.LogSetting.PacketLogConfig[4] == 0);
+	Check(hWnd, B_PACKET_4_1, t.LogSetting.PacketLogConfig[4] == 1);
+	Check(hWnd, B_PACKET_4_2, t.LogSetting.PacketLogConfig[4] == 2);
+
+	Check(hWnd, B_PACKET_5_0, t.LogSetting.PacketLogConfig[5] == 0);
+	Check(hWnd, B_PACKET_5_1, t.LogSetting.PacketLogConfig[5] == 1);
+	Check(hWnd, B_PACKET_5_2, t.LogSetting.PacketLogConfig[5] == 2);
+
+	Check(hWnd, B_PACKET_6_0, t.LogSetting.PacketLogConfig[6] == 0);
+	Check(hWnd, B_PACKET_6_1, t.LogSetting.PacketLogConfig[6] == 1);
+	Check(hWnd, B_PACKET_6_2, t.LogSetting.PacketLogConfig[6] == 2);
+
+	Check(hWnd, B_PACKET_7_0, t.LogSetting.PacketLogConfig[7] == 0);
+	Check(hWnd, B_PACKET_7_1, t.LogSetting.PacketLogConfig[7] == 1);
+	Check(hWnd, B_PACKET_7_2, t.LogSetting.PacketLogConfig[7] == 2);
+
+	SmLogDlgUpdate(hWnd, s);
+}
+
+// コントロール更新
+void SmLogDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+	bool b;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	b = IsChecked(hWnd, B_SEC);
+	SetEnable(hWnd, S_SEC, b);
+	SetEnable(hWnd, C_SEC_SWITCH, b);
+
+	b = IsChecked(hWnd, B_PACKET);
+	SetEnable(hWnd, S_PACKET, b);
+	SetEnable(hWnd, C_PACKET_SWITCH, b);
+	SetEnable(hWnd, S_PACKET_0, b);
+	SetEnable(hWnd, S_PACKET_1, b);
+	SetEnable(hWnd, S_PACKET_2, b);
+	SetEnable(hWnd, S_PACKET_3, b);
+	SetEnable(hWnd, S_PACKET_4, b);
+	SetEnable(hWnd, S_PACKET_5, b);
+	SetEnable(hWnd, S_PACKET_6, b);
+	SetEnable(hWnd, S_PACKET_7, b);
+	SetEnable(hWnd, B_PACKET_0_0, b); SetEnable(hWnd, B_PACKET_0_1, b); SetEnable(hWnd, B_PACKET_0_2, b);
+	SetEnable(hWnd, B_PACKET_1_0, b); SetEnable(hWnd, B_PACKET_1_1, b); SetEnable(hWnd, B_PACKET_1_2, b);
+	SetEnable(hWnd, B_PACKET_2_0, b); SetEnable(hWnd, B_PACKET_2_1, b); SetEnable(hWnd, B_PACKET_2_2, b);
+	SetEnable(hWnd, B_PACKET_3_0, b); SetEnable(hWnd, B_PACKET_3_1, b); SetEnable(hWnd, B_PACKET_3_2, b);
+	SetEnable(hWnd, B_PACKET_4_0, b); SetEnable(hWnd, B_PACKET_4_1, b); SetEnable(hWnd, B_PACKET_4_2, b);
+	SetEnable(hWnd, B_PACKET_5_0, b); SetEnable(hWnd, B_PACKET_5_1, b); SetEnable(hWnd, B_PACKET_5_2, b);
+	SetEnable(hWnd, B_PACKET_6_0, b); SetEnable(hWnd, B_PACKET_6_1, b); SetEnable(hWnd, B_PACKET_6_2, b);
+	SetEnable(hWnd, B_PACKET_7_0, b); SetEnable(hWnd, B_PACKET_7_1, b); SetEnable(hWnd, B_PACKET_7_2, b);
+}
+
+// OK
+void SmLogDlgOnOk(HWND hWnd, SM_HUB *s)
+{
+	HUB_LOG g;
+	RPC_HUB_LOG t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&g, sizeof(g));
+	g.SaveSecurityLog = IsChecked(hWnd, B_SEC);
+	g.SavePacketLog = IsChecked(hWnd, B_PACKET);
+	g.SecurityLogSwitchType = CbGetSelect(hWnd, C_SEC_SWITCH);
+	g.PacketLogSwitchType = CbGetSelect(hWnd, C_PACKET_SWITCH);
+
+	g.PacketLogConfig[0] = IsChecked(hWnd, B_PACKET_0_0) ? 0 : IsChecked(hWnd, B_PACKET_0_1) ? 1 : 2;
+	g.PacketLogConfig[1] = IsChecked(hWnd, B_PACKET_1_0) ? 0 : IsChecked(hWnd, B_PACKET_1_1) ? 1 : 2;
+	g.PacketLogConfig[2] = IsChecked(hWnd, B_PACKET_2_0) ? 0 : IsChecked(hWnd, B_PACKET_2_1) ? 1 : 2;
+	g.PacketLogConfig[3] = IsChecked(hWnd, B_PACKET_3_0) ? 0 : IsChecked(hWnd, B_PACKET_3_1) ? 1 : 2;
+	g.PacketLogConfig[4] = IsChecked(hWnd, B_PACKET_4_0) ? 0 : IsChecked(hWnd, B_PACKET_4_1) ? 1 : 2;
+	g.PacketLogConfig[5] = IsChecked(hWnd, B_PACKET_5_0) ? 0 : IsChecked(hWnd, B_PACKET_5_1) ? 1 : 2;
+	g.PacketLogConfig[6] = IsChecked(hWnd, B_PACKET_6_0) ? 0 : IsChecked(hWnd, B_PACKET_6_1) ? 1 : 2;
+	g.PacketLogConfig[7] = IsChecked(hWnd, B_PACKET_7_0) ? 0 : IsChecked(hWnd, B_PACKET_7_1) ? 1 : 2;
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	Copy(&t.LogSetting, &g, sizeof(HUB_LOG));
+
+	if (CALL(hWnd, ScSetHubLog(s->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	EndDialog(hWnd, true);
+}
+
+// ログ保存設定ダイアログ
+UINT SmLogDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *s = (SM_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmLogDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case B_SEC:
+		case B_PACKET:
+			SmLogDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmLogDlgOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// カスケード接続のステータスの表示
+bool SmRefreshLinkStatus(HWND hWnd, SM_SERVER *s, void *param)
+{
+	SM_LINK *k = (SM_LINK *)param;
+	RPC_LINK_STATUS t;
+	LVB *b;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL || param == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), k->Hub->HubName);
+	UniStrCpy(t.AccountName, sizeof(t.AccountName), k->AccountName);
+
+	if (CALL(hWnd, ScGetLinkStatus(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	CmPrintStatusToListView(b, &t.Status);
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	FreeRpcLinkStatus(&t);
+
+	return true;
+}
+
+// リンクの編集
+bool SmLinkEdit(HWND hWnd, SM_HUB *s, wchar_t *name)
+{
+	CM_ACCOUNT a;
+	RPC_CREATE_LINK t;
+	bool ret = false;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	Zero(&a, sizeof(a));
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), name);
+
+	if (CALL(hWnd, ScGetLink(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	a.Hub = s;
+	a.EditMode = true;
+	a.LinkMode = true;
+	a.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	a.OnlineFlag = t.Online;
+	Copy(a.ClientOption, t.ClientOption, sizeof(CLIENT_OPTION));
+	a.ClientAuth = CopyClientAuth(t.ClientAuth);
+	Copy(&a.Policy, &t.Policy, sizeof(POLICY));
+	a.CheckServerCert = t.CheckServerCert;
+	a.ServerCert = CloneX(t.ServerCert);
+	a.HideTrustCert = GetCapsBool(s->p->CapsList, "b_support_config_hub");
+	FreeRpcCreateLink(&t);
+
+	a.PolicyVer = s->p->PolicyVer;
+
+	if (GetCapsBool(s->p->CapsList, "b_support_cascade_client_cert") == false)
+	{
+		a.HideClientCertAuth = true;
+	}
+
+	a.HideSecureAuth = true;
+
+	ret = CmEditAccountDlg(hWnd, &a);
+
+	FreeX(a.ServerCert);
+	Free(a.ClientOption);
+	CiFreeClientAuth(a.ClientAuth);
+
+	return ret;
+}
+
+// 新しいリンクの作成
+bool SmLinkCreate(HWND hWnd, SM_HUB *s)
+{
+	return SmLinkCreateEx(hWnd, s, false);
+}
+bool SmLinkCreateEx(HWND hWnd, SM_HUB *s, bool connectNow)
+{
+	CM_ACCOUNT a;
+	bool ret = false;;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&a, sizeof(a));
+
+	a.Hub = s;
+	a.EditMode = false;
+	a.LinkMode = true;
+	a.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+	a.OnlineFlag = false;
+	a.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+	a.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+	Copy(&a.Policy, GetDefaultPolicy(), sizeof(POLICY));
+	a.ClientOption->Port = 443;	// デフォルトポート番号
+	a.ClientOption->NumRetry = INFINITE;
+	a.ClientOption->RetryInterval = 15;
+	a.ClientOption->MaxConnection = 8;
+	a.ClientOption->UseEncrypt = true;
+	a.ClientOption->HalfConnection = false;
+	a.ClientOption->AdditionalConnectionInterval = 1;
+	a.ClientOption->RequireBridgeRoutingMode = true;
+	a.Link_ConnectNow = connectNow;
+
+	a.PolicyVer = s->p->PolicyVer;
+
+	if (GetCapsBool(s->p->CapsList, "b_support_cascade_client_cert") == false)
+	{
+		a.HideClientCertAuth = true;
+	}
+
+	a.HideSecureAuth = true;
+
+	ret = CmEditAccountDlg(hWnd, &a);
+
+	FreeX(a.ServerCert);
+	Free(a.ClientOption);
+	CiFreeClientAuth(a.ClientAuth);
+
+	return ret;
+}
+
+// 初期化
+void SmLinkDlgInit(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_LINK);
+
+	FormatText(hWnd, 0, s->HubName);
+
+	LvInit(hWnd, L_LINK);
+
+	LvInsertColumn(hWnd, L_LINK, 0, _UU("SM_LINK_COLUMN_1"), 120);
+	LvInsertColumn(hWnd, L_LINK, 1, _UU("SM_LINK_COLUMN_2"), 150);
+	LvInsertColumn(hWnd, L_LINK, 2, _UU("SM_LINK_COLUMN_3"), 180);
+	LvInsertColumn(hWnd, L_LINK, 3, _UU("SM_LINK_COLUMN_4"), 130);
+	LvInsertColumn(hWnd, L_LINK, 4, _UU("SM_LINK_COLUMN_5"), 130);
+
+	LvSetStyle(hWnd, L_LINK, LVS_EX_GRIDLINES);
+
+	SmLinkDlgRefresh(hWnd, s);
+}
+
+// コントロール更新
+void SmLinkDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+	bool ok = true;
+	bool online = false;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_LINK) == false || LvIsMultiMasked(hWnd, L_LINK))
+	{
+		ok = false;
+	}
+	else
+	{
+		online = (bool)LvGetParam(hWnd, L_LINK, LvGetSelected(hWnd, L_LINK));
+	}
+
+	SetEnable(hWnd, B_EDIT, ok);
+	SetEnable(hWnd, B_ONLINE, ok && (online == false));
+	SetEnable(hWnd, B_OFFLINE, ok && online);
+	SetEnable(hWnd, IDOK, ok && online);
+	SetEnable(hWnd, B_DELETE, ok);
+	SetEnable(hWnd, B_RENAME, ok);
+}
+
+// 内容更新
+void SmLinkDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+	LVB *b;
+	RPC_ENUM_LINK t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	if (CALL(hWnd, ScEnumLink(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	b = LvInsertStart();
+
+	for (i = 0;i < t.NumLink;i++)
+	{
+		RPC_ENUM_LINK_ITEM *e = &t.Links[i];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp4[MAX_SIZE];
+		UINT icon = ICO_CASCADE;
+
+		GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+		StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+		StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+		if (e->Online == false)
+		{
+			UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_OFFLINE"));
+		}
+		else
+		{
+			if (e->Connected)
+			{
+				UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ONLINE"));
+			}
+			else
+			{
+				if (e->LastError != 0)
+				{
+					UniFormat(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ERROR"), e->LastError, _E(e->LastError));
+				}
+				else
+				{
+					UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_CONNECTING"));
+				}
+			}
+		}
+
+		if (e->Online == false)
+		{
+			icon = ICO_CASCADE_OFFLINE;
+		}
+		else
+		{
+			if (e->Connected == false && e->LastError != 0)
+			{
+				icon = ICO_CASCADE_ERROR;
+			}
+			else
+			{
+				icon = ICO_CASCADE;
+			}
+		}
+
+		LvInsertAdd(b,
+			icon, (void *)e->Online, 5,
+			e->AccountName, tmp4, tmp1, tmp2, tmp3);
+	}
+
+	LvInsertEnd(b, hWnd, L_LINK);
+
+	FreeRpcEnumLink(&t);
+
+	SmLinkDlgUpdate(hWnd, s);
+}
+
+
+// リンク一覧ダイアログプロシージャ
+UINT SmLinkDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *s = (SM_HUB *)param;
+	wchar_t *str;
+	NMHDR *n;
+	NMLVDISPINFOW *disp_info;
+	NMLVKEYDOWN *key;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	str = LvGetSelectedStr(hWnd, L_LINK, 0);
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmLinkDlgInit(hWnd, s);
+
+		if (link_create_now)
+		{
+			if (SmLinkCreateEx(hWnd, s, true))
+			{
+				SmLinkDlgRefresh(hWnd, s);
+			}
+		}
+
+		SetTimer(hWnd, 1, 1000, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			SmLinkDlgRefresh(hWnd, s);
+			SetTimer(hWnd, 1, 1000, NULL);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_CREATE:
+			// 新規作成
+			if (SmLinkCreate(hWnd, s))
+			{
+				SmLinkDlgRefresh(hWnd, s);
+			}
+			break;
+
+		case B_EDIT:
+			// 編集
+			if (str != NULL)
+			{
+				if (SmLinkEdit(hWnd, s, str))
+				{
+					SmLinkDlgRefresh(hWnd, s);
+				}
+			}
+			break;
+
+		case B_ONLINE:
+			// オンライン
+			if (str != NULL)
+			{
+				RPC_LINK t;
+				Zero(&t, sizeof(t));
+				UniStrCpy(t.AccountName, sizeof(t.AccountName), str);
+				StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+				if (CALL(hWnd, ScSetLinkOnline(s->Rpc, &t)))
+				{
+					SmLinkDlgRefresh(hWnd, s);
+				}
+			}
+			break;
+
+		case B_OFFLINE:
+			// オフライン
+			if (str != NULL)
+			{
+				RPC_LINK t;
+				Zero(&t, sizeof(t));
+				UniStrCpy(t.AccountName, sizeof(t.AccountName), str);
+				StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+				if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+					_UU("SM_LINK_OFFLINE_MSG"), t.AccountName) == IDYES)
+				{
+					if (CALL(hWnd, ScSetLinkOffline(s->Rpc, &t)))
+					{
+						SmLinkDlgRefresh(hWnd, s);
+					}
+				}
+			}
+			break;
+
+		case IDOK:
+			// 状態
+			if (str != NULL)
+			{
+				wchar_t tmp[MAX_SIZE];
+				SM_LINK t;
+				Zero(&t, sizeof(t));
+				t.Hub = s;
+				t.AccountName = str;
+				UniFormat(tmp, sizeof(tmp), _UU("SM_LINK_STATUS_CAPTION"), str);
+				SmStatusDlg(hWnd, s->p, &t, true, true, tmp,
+					ICO_CASCADE, NULL, SmRefreshLinkStatus);
+			}
+			break;
+
+		case B_DELETE:
+			// 削除
+			if (str != NULL)
+			{
+				RPC_LINK t;
+				Zero(&t, sizeof(t));
+				UniStrCpy(t.AccountName, sizeof(t.AccountName), str);
+				StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+				if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+					_UU("SM_LINK_DELETE_MSG"), t.AccountName) == IDYES)
+				{
+					if (CALL(hWnd, ScDeleteLink(s->Rpc, &t)))
+					{
+						SmLinkDlgRefresh(hWnd, s);
+					}
+				}
+			}
+			break;
+
+		case B_REFRESH:
+			// 更新
+			SmLinkDlgRefresh(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case B_RENAME:
+			// 名前の変更
+			Focus(hWnd, L_LINK);
+			LvRename(hWnd, L_LINK, LvGetSelected(hWnd, L_LINK));
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_LINK:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				// 選択状態の変更
+				SmLinkDlgUpdate(hWnd, s);
+				break;
+
+			case LVN_ENDLABELEDITW:
+				// 名前の変更
+				disp_info = (NMLVDISPINFOW *)n;
+				if (disp_info->item.pszText != NULL)
+				{
+					wchar_t *new_name = disp_info->item.pszText;
+					wchar_t *old_name = LvGetStr(hWnd, L_LINK, disp_info->item.iItem, 0);
+
+					if (old_name != NULL)
+					{
+						if (UniStrCmp(new_name, old_name) != 0 && UniIsEmptyStr(new_name) == false)
+						{
+							RPC_RENAME_LINK t;
+							Zero(&t, sizeof(t));
+							StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+							UniStrCpy(t.OldAccountName, sizeof(t.OldAccountName), old_name);
+							UniStrCpy(t.NewAccountName, sizeof(t.NewAccountName), new_name);
+							if (CALL(hWnd, ScRenameLink(s->Rpc, &t)))
+							{
+								SmLinkDlgRefresh(hWnd, s);
+							}
+						}
+
+						Free(old_name);
+					}
+				}
+				break;
+
+			case LVN_KEYDOWN:
+				// キー押下
+				key = (NMLVKEYDOWN *)n;
+				if (key != NULL)
+				{
+					bool ctrl, alt;
+					UINT code = key->wVKey;
+					ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+					alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+
+					if (code == VK_F2)
+					{
+						Command(hWnd, B_RENAME);
+					}
+				}
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	Free(str);
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_LINK);
+
+	return 0;
+}
+
+// リンク一覧ダイアログ
+void SmLinkDlg(HWND hWnd, SM_HUB *s)
+{
+	SmLinkDlgEx(hWnd, s, false);
+}
+void SmLinkDlgEx(HWND hWnd, SM_HUB *s, bool createNow)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	link_create_now = createNow;
+
+	Dialog(hWnd, D_SM_LINK, SmLinkDlgProc, s);
+}
+
+// 初期化
+void SmRadiusDlgInit(HWND hWnd, SM_HUB *s)
+{
+	RPC_RADIUS t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_TOWER);
+
+	FormatText(hWnd, S_TITLE, s->HubName);
+	FormatText(hWnd, S_RADIUS_7, RADIUS_RETRY_INTERVAL, RADIUS_RETRY_TIMEOUT);
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+	if (CALL(hWnd, ScGetHubRadius(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	Check(hWnd, R_USE_RADIUS, StrLen(t.RadiusServerName) != 0);
+
+	if (StrLen(t.RadiusServerName) != 0)
+	{
+		SetTextA(hWnd, E_HOSTNAME, t.RadiusServerName);
+		SetIntEx(hWnd, E_PORT, t.RadiusPort);
+		SetTextA(hWnd, E_SECRET1, t.RadiusSecret);
+		SetTextA(hWnd, E_SECRET2, t.RadiusSecret);
+		SetIntEx(hWnd, E_RADIUS_RETRY_INTERVAL, t.RadiusRetryInterval);
+		FocusEx(hWnd, E_HOSTNAME);
+	}
+	else
+	{
+		SetInt(hWnd, E_PORT, RADIUS_DEFAULT_PORT);
+		SetInt(hWnd, E_RADIUS_RETRY_INTERVAL, RADIUS_RETRY_INTERVAL);
+	}
+
+	SmRadiusDlgUpdate(hWnd, s);
+}
+
+// コントロール更新
+void SmRadiusDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+	bool ok = true;
+	bool b, b1;
+	char tmp1[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	b1 = GetCapsBool(s->p->CapsList, "b_support_radius_retry_interval_and_several_servers");
+	if(b1 == false)
+	{
+		Hide(hWnd, S_RADIUS_7);
+		Hide(hWnd, S_RADIUS_8);
+		Hide(hWnd, S_RADIUS_9);
+		Hide(hWnd, E_RADIUS_RETRY_INTERVAL);
+	}
+
+	b = IsChecked(hWnd, R_USE_RADIUS);
+
+	SetEnable(hWnd, S_RADIUS_1, b);
+	SetEnable(hWnd, S_RADIUS_2, b);
+	SetEnable(hWnd, S_RADIUS_3, b);
+	SetEnable(hWnd, S_RADIUS3, b);
+	SetEnable(hWnd, S_RADIUS_4, b);
+	SetEnable(hWnd, S_RADIUS_5, b);
+	SetEnable(hWnd, S_RADIUS_6, b);
+	SetEnable(hWnd, S_RADIUS_7, b);
+	SetEnable(hWnd, S_RADIUS_8, b);
+	SetEnable(hWnd, S_RADIUS_9, b);
+	SetEnable(hWnd, E_HOSTNAME, b);
+	SetEnable(hWnd, E_PORT, b);
+	SetEnable(hWnd, E_SECRET1, b);
+	SetEnable(hWnd, E_SECRET2, b);
+	SetEnable(hWnd, E_RADIUS_RETRY_INTERVAL, b);
+
+	if (b)
+	{
+		UINT p, m;
+		GetTxtA(hWnd, E_SECRET1, tmp1, sizeof(tmp1));
+		GetTxtA(hWnd, E_SECRET2, tmp2, sizeof(tmp2));
+
+		if (StrCmp(tmp1, tmp2) != 0)
+		{
+			ok = false;
+		}
+
+		if (IsEmpty(hWnd, E_HOSTNAME))
+		{
+			ok = false;
+		}
+
+		p = GetInt(hWnd, E_PORT);
+
+		if (p == 0 || p >= 65536)
+		{
+			ok = false;
+		}
+
+		m = GetInt(hWnd, E_RADIUS_RETRY_INTERVAL);
+		if (m > RADIUS_RETRY_TIMEOUT || m < RADIUS_RETRY_INTERVAL)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// OK ボタン
+void SmRadiusDlgOnOk(HWND hWnd, SM_HUB *s)
+{
+	RPC_RADIUS t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+	if (IsChecked(hWnd, R_USE_RADIUS))
+	{
+		GetTxtA(hWnd, E_HOSTNAME, t.RadiusServerName, sizeof(t.RadiusServerName));
+		t.RadiusPort = GetInt(hWnd, E_PORT);
+		GetTxtA(hWnd, E_SECRET1,t.RadiusSecret, sizeof(t.RadiusSecret));
+		t.RadiusRetryInterval = GetInt(hWnd, E_RADIUS_RETRY_INTERVAL);
+	}
+
+	if (CALL(hWnd, ScSetHubRadius(s->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	EndDialog(hWnd, true);
+}
+
+
+// Radius ダイアログ プロシージャ
+UINT SmRadiusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *s = (SM_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmRadiusDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_HOSTNAME:
+		case E_PORT:
+		case E_SECRET1:
+		case E_SECRET2:
+		case E_RADIUS_RETRY_INTERVAL:
+		case R_USE_RADIUS:
+			SmRadiusDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmRadiusDlgOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case R_USE_RADIUS:
+			if (IsChecked(hWnd, R_USE_RADIUS))
+			{
+				FocusEx(hWnd, E_HOSTNAME);
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// Radius 設定ダイアログ
+void SmRadiusDlg(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_RADIUS, SmRadiusDlgProc, s);
+}
+
+
+// 初期化
+void SmEditAccessInit(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+	ACCESS *a;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_PASS);
+
+	GetTxt(hWnd, 0, tmp, sizeof(tmp));
+
+	UniStrCat(tmp, sizeof(tmp), s->Access->IsIPv6 ? L" (IPv6)" : L" (IPv4)");
+
+	SetText(hWnd, 0, tmp);
+
+	s->Inited = false;
+	a = s->Access;
+
+	SetText(hWnd, E_NOTE, a->Note);
+
+	Check(hWnd, R_DISCARD, a->Discard);
+	Check(hWnd, R_PASS, a->Discard == false);
+	SetIntEx(hWnd, E_PRIORITY, a->Priority);
+
+	if (a->IsIPv6 == false)
+	{
+		// IPv4
+		if (a->SrcIpAddress == 0 && a->SrcSubnetMask == 0)
+		{
+			Check(hWnd, R_SRC_ALL, true);
+		}
+		else
+		{
+			IpSet(hWnd, E_SRC_IP, a->SrcIpAddress);
+			IpSet(hWnd, E_SRC_MASK, a->SrcSubnetMask);
+		}
+
+		if (a->DestIpAddress == 0 && a->DestSubnetMask == 0)
+		{
+			Check(hWnd, R_DST_ALL, true);
+		}
+		else
+		{
+			IpSet(hWnd, E_DST_IP, a->DestIpAddress);
+			IpSet(hWnd, E_DST_MASK, a->DestSubnetMask);
+		}
+	}
+	else
+	{
+		// IPv6
+		if (IsZeroIP6Addr(&a->SrcIpAddress6) && IsZeroIP6Addr(&a->SrcSubnetMask6))
+		{
+			Check(hWnd, R_SRC_ALL, true);
+		}
+		else
+		{
+			char tmp[MAX_SIZE];
+
+			IP6AddrToStr(tmp, sizeof(tmp), &a->SrcIpAddress6);
+			SetTextA(hWnd, E_SRC_IP_V6, tmp);
+
+			Mask6AddrToStrEx(tmp, sizeof(tmp), &a->SrcSubnetMask6, false);
+
+			if (IsNum(tmp))
+			{
+				StrCatLeft(tmp, sizeof(tmp), "/");
+			}
+
+			SetTextA(hWnd, E_SRC_MASK_V6, tmp);
+		}
+
+		if (IsZeroIP6Addr(&a->DestIpAddress6) && IsZeroIP6Addr(&a->DestSubnetMask6))
+		{
+			Check(hWnd, R_DST_ALL, true);
+		}
+		else
+		{
+			char tmp[MAX_SIZE];
+
+			IP6AddrToStr(tmp, sizeof(tmp), &a->DestIpAddress6);
+			SetTextA(hWnd, E_DST_IP_V6, tmp);
+
+			Mask6AddrToStrEx(tmp, sizeof(tmp), &a->DestSubnetMask6, false);
+
+			if (IsNum(tmp))
+			{
+				StrCatLeft(tmp, sizeof(tmp), "/");
+			}
+
+			SetTextA(hWnd, E_DST_MASK_V6, tmp);
+		}
+	}
+
+	CbSetHeight(hWnd, C_PROTOCOL, 18);
+	CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_1"), 0);
+	CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_2"), 0);
+	CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_3"), 0);
+	CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_4"), 0);
+	CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_5"), 0);
+	CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_6"), 0);
+
+	switch (a->Protocol)
+	{
+	case 0:
+		CbSelectIndex(hWnd, C_PROTOCOL, 0);
+		break;
+	case 6:
+		CbSelectIndex(hWnd, C_PROTOCOL, 1);
+		break;
+	case 17:
+		CbSelectIndex(hWnd, C_PROTOCOL, 2);
+		break;
+	case 1:
+		CbSelectIndex(hWnd, C_PROTOCOL, 3);
+		break;
+	case 58:
+		CbSelectIndex(hWnd, C_PROTOCOL, 4);
+		break;
+	default:
+		CbSelectIndex(hWnd, C_PROTOCOL, 5);
+		break;
+	}
+
+	Check(hWnd, R_DISABLE, a->Active ? false : true);
+
+	SetIntEx(hWnd, E_IP_PROTO, a->Protocol);
+
+	SetIntEx(hWnd, E_SRC_PORT_1, a->SrcPortStart);
+	SetIntEx(hWnd, E_SRC_PORT_2, a->SrcPortEnd);
+	SetIntEx(hWnd, E_DST_PORT_1, a->DestPortStart);
+	SetIntEx(hWnd, E_DST_PORT_2, a->DestPortEnd);
+
+	SetTextA(hWnd, E_USERNAME1, a->SrcUsername);
+	SetTextA(hWnd, E_USERNAME2, a->DestUsername);
+
+	if(a->CheckSrcMac != false)
+	{
+		char mac[MAX_SIZE], mask[MAX_SIZE];
+		MacToStr(mac, sizeof(mac), a->SrcMacAddress);
+		MacToStr(mask, sizeof(mask), a->SrcMacMask);
+		SetTextA(hWnd, E_SRC_MAC, mac); 
+		SetTextA(hWnd, E_SRC_MAC_MASK, mask);
+	}
+	if(a->CheckDstMac != false)
+	{
+		char mac[MAX_SIZE], mask[MAX_SIZE];
+		MacToStr(mac, sizeof(mac), a->DstMacAddress);
+		MacToStr(mask, sizeof(mask), a->DstMacMask);
+		SetTextA(hWnd, E_DST_MAC, mac); 
+		SetTextA(hWnd, E_DST_MAC_MASK, mask);
+	}
+	Check(hWnd, R_CHECK_SRC_MAC, !a->CheckSrcMac);
+	Check(hWnd, R_CHECK_DST_MAC, !a->CheckDstMac);
+
+	Check(hWnd, R_CHECK_TCP_STATE, a->CheckTcpState);
+	if(a->CheckTcpState != false)
+	{
+		Check(hWnd, R_ESTABLISHED, a->Established);
+		Check(hWnd, R_UNESTABLISHED, !a->Established);
+	}
+
+	if (GetCapsBool(s->Hub->p->CapsList, "b_support_acl_group") == false)
+	{
+		SetText(hWnd, S_STATIC11, _UU("D_SM_EDIT_ACCESS@STATIC11_OLD"));
+		SetText(hWnd, S_STATIC12, _UU("D_SM_EDIT_ACCESS@STATIC12_OLD"));
+		SetText(hWnd, S_STATIC15, _UU("D_SM_EDIT_ACCESS@STATIC15_OLD"));
+	}
+
+	s->Inited = true;
+
+	SmEditAccessUpdate(hWnd, s);
+}
+
+// コントロール更新
+void SmEditAccessUpdate(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+	bool ok = true;
+	bool tcp;
+	bool b;
+	bool check_srcmac, check_dstmac, support_mac;
+	bool check_state, support_check_state;
+	char srcmac[MAX_SIZE], srcmac_mask[MAX_SIZE], dstmac[MAX_SIZE], dstmac_mask[MAX_SIZE];
+	char tmp[MAX_SIZE];
+	wchar_t unitmp[MAX_SIZE];
+	ACCESS *a;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (s->Inited == false)
+	{
+		return;
+	}
+
+	a = s->Access;
+
+	GetTxt(hWnd, E_NOTE, a->Note, sizeof(a->Note));
+
+	a->Discard = IsChecked(hWnd, R_DISCARD);
+
+	a->Priority = GetInt(hWnd, E_PRIORITY);
+	if (a->Priority == 0)
+	{
+		ok = false;
+	}
+
+
+	b = IsChecked(hWnd, R_SRC_ALL) ? false : true;
+	if (b == false)
+	{
+		if (a->IsIPv6 == false)
+		{
+			a->SrcIpAddress = 0;
+			a->SrcSubnetMask = 0;
+		}
+		else
+		{
+			Zero(&a->SrcIpAddress6, sizeof(IPV6_ADDR));
+			Zero(&a->SrcSubnetMask6, sizeof(IPV6_ADDR));
+		}
+	}
+	else
+	{
+		if (a->IsIPv6 == false)
+		{
+			if (IpIsFilled(hWnd, E_SRC_IP) == false || IpIsFilled(hWnd, E_SRC_MASK) == false)
+			{
+				ok = false;
+			}
+			else
+			{
+				a->SrcIpAddress = IpGet(hWnd, E_SRC_IP);
+				a->SrcSubnetMask = IpGet(hWnd, E_SRC_MASK);
+			}
+		}
+		else
+		{
+			char tmp1[MAX_SIZE];
+			char tmp2[MAX_SIZE];
+
+			GetTxtA(hWnd, E_SRC_IP_V6, tmp1, sizeof(tmp1));
+			GetTxtA(hWnd, E_SRC_MASK_V6, tmp2, sizeof(tmp2));
+
+			if (StrToIP6Addr(&a->SrcIpAddress6, tmp1) == false ||
+				StrToMask6Addr(&a->SrcSubnetMask6, tmp2) == false)
+			{
+				ok = false;
+			}
+		}
+	}
+	SetEnable(hWnd, S_SRC_IP_1, b);
+	SetEnable(hWnd, S_SRC_IP_2, b);
+	SetEnable(hWnd, S_SRC_IP_3, b);
+	SetEnable(hWnd, E_SRC_IP, b);
+	SetEnable(hWnd, E_SRC_MASK, b);
+	SetEnable(hWnd, E_SRC_IP_V6, b);
+	SetEnable(hWnd, E_SRC_MASK_V6, b);
+
+	b = IsChecked(hWnd, R_DST_ALL) ? false : true;
+	if (b == false)
+	{
+		if (a->IsIPv6 == false)
+		{
+			a->DestIpAddress = 0;
+			a->DestSubnetMask = 0;
+		}
+		else
+		{
+			Zero(&a->DestIpAddress6, sizeof(IPV6_ADDR));
+			Zero(&a->DestSubnetMask6, sizeof(IPV6_ADDR));
+		}
+	}
+	else
+	{
+		if (a->IsIPv6 == false)
+		{
+			if (IpIsFilled(hWnd, E_DST_IP) == false || IpIsFilled(hWnd, E_DST_MASK) == false)
+			{
+				ok = false;
+			}
+			else
+			{
+				a->DestIpAddress = IpGet(hWnd, E_DST_IP);
+				a->DestSubnetMask = IpGet(hWnd, E_DST_MASK);
+			}
+		}
+		else
+		{
+			char tmp1[MAX_SIZE];
+			char tmp2[MAX_SIZE];
+
+			GetTxtA(hWnd, E_DST_IP_V6, tmp1, sizeof(tmp1));
+			GetTxtA(hWnd, E_DST_MASK_V6, tmp2, sizeof(tmp2));
+
+			if (StrToIP6Addr(&a->DestIpAddress6, tmp1) == false ||
+				StrToMask6Addr(&a->DestSubnetMask6, tmp2) == false)
+			{
+				ok = false;
+			}
+		}
+	}
+	SetEnable(hWnd, S_IP_DST_1, b);
+	SetEnable(hWnd, S_IP_DST_2, b);
+	SetEnable(hWnd, S_IP_DST_3, b);
+	SetEnable(hWnd, E_DST_IP, b);
+	SetEnable(hWnd, E_DST_MASK, b);
+	SetEnable(hWnd, E_DST_IP_V6, b);
+	SetEnable(hWnd, E_DST_MASK_V6, b);
+
+	a->Protocol = GetInt(hWnd, C_PROTOCOL);
+
+	GetTxtA(hWnd, C_PROTOCOL, tmp, sizeof(tmp));
+	GetTxt(hWnd, C_PROTOCOL, unitmp, sizeof(unitmp));
+
+	if (UniStrCmpi(unitmp, _UU("SM_ACCESS_PROTO_6")) == 0 || StrCmpi(tmp, _SS("SM_ACCESS_PROTO_6")) == 0)
+	{
+		a->Protocol = GetInt(hWnd, E_IP_PROTO);
+
+		if (IsEmpty(hWnd, E_IP_PROTO))
+		{
+			ok = false;
+		}
+
+		Enable(hWnd, S_PROTOID);
+		Enable(hWnd, E_IP_PROTO);
+	}
+	else
+	{
+		Disable(hWnd, E_IP_PROTO);
+		Disable(hWnd, S_PROTOID);
+	}
+
+	tcp = false;
+	if (a->Protocol == 17 || a->Protocol == 6)
+	{
+		tcp = true;
+	}
+
+	SetEnable(hWnd, S_TCP_1, tcp);
+	SetEnable(hWnd, S_TCP_2, tcp);
+	SetEnable(hWnd, S_TCP_3, tcp);
+	SetEnable(hWnd, S_TCP_4, tcp);
+	SetEnable(hWnd, S_TCP_5, tcp);
+	SetEnable(hWnd, S_TCP_6, tcp);
+	SetEnable(hWnd, S_TCP_7, tcp);
+	SetEnable(hWnd, E_SRC_PORT_1, tcp);
+	SetEnable(hWnd, E_SRC_PORT_2, tcp);
+	SetEnable(hWnd, E_DST_PORT_1, tcp);
+	SetEnable(hWnd, E_DST_PORT_2, tcp);
+
+	if (tcp == false)
+	{
+		a->SrcPortEnd = a->SrcPortStart = a->DestPortEnd = a->DestPortStart = 0;
+	}
+	else
+	{
+		a->SrcPortStart = GetInt(hWnd, E_SRC_PORT_1);
+		a->SrcPortEnd = GetInt(hWnd, E_SRC_PORT_2);
+		a->DestPortStart = GetInt(hWnd, E_DST_PORT_1);
+		a->DestPortEnd = GetInt(hWnd, E_DST_PORT_2);
+
+		if (a->SrcPortStart != 0)
+		{
+			if (a->SrcPortEnd != 0)
+			{
+				if (a->SrcPortStart > a->SrcPortEnd)
+				{
+					ok = false;
+				}
+			}
+		}
+		else
+		{
+			if (a->SrcPortEnd != 0)
+			{
+				ok = false;
+			}
+		}
+
+		if (a->DestPortStart != 0)
+		{
+			if (a->DestPortEnd != 0)
+			{
+				if (a->DestPortStart > a->DestPortEnd)
+				{
+					ok = false;
+				}
+			}
+		}
+		else
+		{
+			if (a->DestPortEnd != 0)
+			{
+				ok = false;
+			}
+		}
+
+		if (a->DestPortEnd < a->DestPortStart)
+		{
+			a->DestPortEnd = a->DestPortStart;
+		}
+
+		if (a->SrcPortEnd < a->SrcPortStart)
+		{
+			a->SrcPortEnd = a->SrcPortStart;
+		}
+	}
+
+	a->SrcUsernameHash = a->DestUsernameHash = 0;
+	GetTxtA(hWnd, E_USERNAME1, a->SrcUsername, sizeof(a->SrcUsername));
+	GetTxtA(hWnd, E_USERNAME2, a->DestUsername, sizeof(a->DestUsername));
+
+	Trim(a->SrcUsername);
+	/*
+	if (StrLen(a->SrcUsername) != 0)
+	{
+		if (IsUserName(a->SrcUsername) == false)
+		{
+			ok = false;
+		}
+	}*/
+
+	Trim(a->DestUsername);
+	/*
+	if (StrLen(a->DestUsername) != 0)
+	{
+		if (IsUserName(a->DestUsername) == false)
+		{
+			ok = false;
+		}
+	}*/
+
+	support_mac = GetCapsBool(s->Hub->p->CapsList, "b_support_check_mac");
+
+	// 送信元 MAC アドレスの設定
+	check_srcmac = a->CheckSrcMac = support_mac && (IsChecked(hWnd, R_CHECK_SRC_MAC) ? false : true);
+	if(check_srcmac == false)
+	{
+		Zero(a->SrcMacAddress, sizeof(a->SrcMacAddress));
+		Zero(a->SrcMacMask, sizeof(a->SrcMacMask));
+	}
+	else
+	{
+		GetTxtA(hWnd, E_SRC_MAC, srcmac, sizeof(srcmac));
+		GetTxtA(hWnd, E_SRC_MAC_MASK, srcmac_mask, sizeof(srcmac_mask));
+		Trim(srcmac);
+		Trim(srcmac_mask);
+		if(StrLen(srcmac) != 0 && StrLen(srcmac_mask) != 0)
+		{
+			UCHAR mac[6], mask[6];
+			if(StrToMac(mac, srcmac) && StrToMac(mask, srcmac_mask))
+			{
+				Copy(a->SrcMacAddress, mac, 6);
+				Copy(a->SrcMacMask, mask, 6);
+			}
+			else
+			{
+				ok = false;
+			}
+		}
+		else
+		{
+			ok = false;
+		}
+	}
+	SetEnable(hWnd, S_CHECK_SRC_MAC, support_mac);
+	SetEnable(hWnd, R_CHECK_SRC_MAC, support_mac);
+	SetEnable(hWnd, S_SRC_MAC, check_srcmac);
+	SetEnable(hWnd, S_SRC_MAC_MASK, check_srcmac);
+	SetEnable(hWnd, E_SRC_MAC, check_srcmac);
+	SetEnable(hWnd, E_SRC_MAC_MASK, check_srcmac);
+
+	// 宛先 MAC アドレスの設定
+	check_dstmac = a->CheckDstMac = support_mac && (IsChecked(hWnd, R_CHECK_DST_MAC) ? false : true);
+	if(check_dstmac == false)
+	{
+		Zero(a->DstMacAddress, sizeof(a->DstMacAddress));
+		Zero(a->DstMacMask, sizeof(a->DstMacMask));
+	}
+	else
+	{
+		GetTxtA(hWnd, E_DST_MAC, dstmac, sizeof(dstmac));
+		GetTxtA(hWnd, E_DST_MAC_MASK, dstmac_mask, sizeof(dstmac_mask));
+		Trim(dstmac);
+		Trim(dstmac_mask);
+		if(StrLen(dstmac) != 0 && StrLen(dstmac_mask) != 0)
+		{
+			UCHAR mac[6], mask[6];
+			if(StrToMac(mac, dstmac) && StrToMac(mask, dstmac_mask))
+			{
+				Copy(a->DstMacAddress, mac, 6);
+				Copy(a->DstMacMask, mask, 6);
+			}
+			else
+			{
+				ok = false;
+			}
+		}
+		else
+		{
+			ok = false;
+		}
+	}
+	SetEnable(hWnd, S_CHECK_DST_MAC, support_mac);
+	SetEnable(hWnd, R_CHECK_DST_MAC, support_mac);
+	SetEnable(hWnd, S_DST_MAC, check_dstmac);
+	SetEnable(hWnd, S_DST_MAC_MASK, check_dstmac);
+	SetEnable(hWnd, E_DST_MAC, check_dstmac);
+	SetEnable(hWnd, E_DST_MAC_MASK, check_dstmac);
+
+	SetEnable(hWnd, S_MAC_NOTE, check_srcmac || check_dstmac);
+
+	// TCP コネクションの状態
+	support_check_state = GetCapsBool(s->Hub->p->CapsList, "b_support_check_tcp_state") && a->Protocol == 6;
+	SetEnable(hWnd, R_CHECK_TCP_STATE, support_check_state);
+	check_state = a->CheckTcpState = support_check_state && IsChecked(hWnd, R_CHECK_TCP_STATE);
+
+	a->Established = IsChecked(hWnd, R_ESTABLISHED) && check_state;
+	SetEnable(hWnd, R_ESTABLISHED, check_state);
+	SetEnable(hWnd, R_UNESTABLISHED, check_state);
+	if(check_state != false && IsChecked(hWnd, R_ESTABLISHED) == false && IsChecked(hWnd, R_UNESTABLISHED) == false)
+	{
+		ok = false;
+	}
+
+	a->Active = IsChecked(hWnd, R_DISABLE) ? false : true;
+
+	SetEnable(hWnd, B_SIMULATION, a->Discard == false && GetCapsBool(s->Hub->p->CapsList, "b_support_ex_acl"));
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// OK クリック
+void SmEditAccessOnOk(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SmEditAccessUpdate(hWnd, s);
+
+	EndDialog(hWnd, true);
+}
+
+
+// アクセスリスト編集ダイアログ
+UINT SmEditAccessDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_ACCESS *s = (SM_EDIT_ACCESS *)param;
+	UINT ico;
+	ACCESS *a;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmEditAccessInit(hWnd, s);
+
+		goto REFRESH_ICON;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_PASS:
+		case R_DISCARD:
+		case E_PRIORITY:
+		case R_SRC_ALL:
+		case E_SRC_IP:
+		case E_SRC_MASK:
+		case R_DST_ALL:
+		case E_DST_MASK:
+		case E_SRC_IP_V6:
+		case E_SRC_MASK_V6:
+		case E_DST_MASK_V6:
+		case E_DST_IP_V6:
+		case C_PROTOCOL:
+		case E_SRC_PORT_1:
+		case E_SRC_PORT_2:
+		case E_DST_PORT_1:
+		case E_DST_PORT_2:
+		case E_USERNAME1:
+		case E_USERNAME2:
+		case R_DISABLE:
+		case E_IP_PROTO:
+		case R_CHECK_SRC_MAC:
+		case E_SRC_MAC:
+		case E_SRC_MAC_MASK:
+		case R_CHECK_DST_MAC:
+		case E_DST_MAC:
+		case E_DST_MAC_MASK:
+		case R_CHECK_TCP_STATE:
+		case R_ESTABLISHED:
+		case R_UNESTABLISHED:
+			SmEditAccessUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case B_USER1:
+			if (GetTxtA(hWnd, E_USERNAME1, tmp, sizeof(tmp)))
+			{
+				char *ret = SmSelectUserDlgEx(hWnd, s->Hub, tmp, GetCapsBool(s->Hub->p->CapsList, "b_support_acl_group"));
+				if (ret == NULL)
+				{
+					SetTextA(hWnd, E_USERNAME1, "");
+				}
+				else
+				{
+					SetTextA(hWnd, E_USERNAME1, ret);
+					Free(ret);
+				}
+				FocusEx(hWnd, E_USERNAME1);
+			}
+			break;
+
+		case B_USER2:
+			if (GetTxtA(hWnd, E_USERNAME2, tmp, sizeof(tmp)))
+			{
+				char *ret = SmSelectUserDlgEx(hWnd, s->Hub, tmp, GetCapsBool(s->Hub->p->CapsList, "b_support_acl_group"));
+				if (ret == NULL)
+				{
+					SetTextA(hWnd, E_USERNAME2, "");
+				}
+				else
+				{
+					SetTextA(hWnd, E_USERNAME2, ret);
+					Free(ret);
+				}
+				FocusEx(hWnd, E_USERNAME2);
+			}
+			break;
+
+		case IDOK:
+			// OK ボタン
+			SmEditAccessOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case R_SRC_ALL:
+			if (IsChecked(hWnd, R_SRC_ALL) == false)
+			{
+				if (s->Access->IsIPv6)
+				{
+					FocusEx(hWnd, E_SRC_IP_V6);
+				}
+				else
+				{
+					Focus(hWnd, E_SRC_IP);
+				}
+			}
+			break;
+
+		case R_DST_ALL:
+			if (IsChecked(hWnd, R_DST_ALL) == false)
+			{
+				if (s->Access->IsIPv6)
+				{
+					FocusEx(hWnd, E_DST_IP_V6);
+				}
+				else
+				{
+					Focus(hWnd, E_DST_IP);
+				}
+			}
+			break;
+		case R_CHECK_SRC_MAC:
+			if(IsChecked(hWnd, R_CHECK_SRC_MAC) == false)
+			{
+				Focus(hWnd, E_SRC_MAC);
+			}
+			break;
+		case R_CHECK_DST_MAC:
+			if(IsChecked(hWnd, R_CHECK_DST_MAC) == false)
+			{
+				Focus(hWnd, E_DST_MAC);
+			}
+			break;
+
+		case R_PASS:
+		case R_DISCARD:
+		case R_DISABLE:
+REFRESH_ICON:
+			a = s->Access;
+			if (a->Discard == false && a->Active == false)
+			{
+				ico = ICO_PASS_DISABLE;
+			}
+			else if (a->Discard == false && a->Active)
+			{
+				ico = ICO_PASS;
+			}
+			else if (a->Discard && a->Active == false)
+			{
+				ico = ICO_DISCARD_DISABLE;
+			}
+			else
+			{
+				ico = ICO_DISCARD;
+			}
+
+			SetIcon(hWnd, S_ICON, ico);
+			break;
+
+		case B_SIMULATION:
+			// シミュレーション
+			Dialog(hWnd, D_SM_SIMULATION, SmSimulationDlg, s);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 遅延・ジッタ・パケットロスダイアログ
+UINT SmSimulationDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_ACCESS *s = (SM_EDIT_ACCESS *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmSimulationInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_DELAY:
+		case E_JITTER:
+		case E_LOSS:
+			SmSimulationUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			SmSimulationOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case C_DELAY:
+			SmSimulationUpdate(hWnd, s);
+			if (IsChecked(hWnd, C_DELAY))
+			{
+				FocusEx(hWnd, E_DELAY);
+			}
+			break;
+
+		case C_JITTER:
+			SmSimulationUpdate(hWnd, s);
+			if (IsChecked(hWnd, C_JITTER))
+			{
+				FocusEx(hWnd, E_JITTER);
+			}
+			break;
+
+		case C_LOSS:
+			SmSimulationUpdate(hWnd, s);
+			if (IsChecked(hWnd, C_LOSS))
+			{
+				FocusEx(hWnd, E_LOSS);
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 遅延・ジッタ・パケットロスダイアログの更新
+void SmSimulationUpdate(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+	bool b1, b2, b3;
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	b1 = IsChecked(hWnd, C_DELAY);
+	b2 = IsChecked(hWnd, C_JITTER);
+	b3 = IsChecked(hWnd, C_LOSS);
+
+	SetEnable(hWnd, S_DELAY, b1);
+	SetEnable(hWnd, S_DELAY2, b1);
+	SetEnable(hWnd, E_DELAY, b1);
+
+	SetEnable(hWnd, C_JITTER, b1);
+
+	if (b1 == false)
+	{
+		b2 = false;
+	}
+
+	SetEnable(hWnd, S_JITTER, b2);
+	SetEnable(hWnd, S_JITTER2, b2);
+	SetEnable(hWnd, E_JITTER, b2);
+
+	SetEnable(hWnd, S_LOSS, b3);
+	SetEnable(hWnd, S_LOSS2, b3);
+	SetEnable(hWnd, E_LOSS, b3);
+
+	if (b1)
+	{
+		UINT i = GetInt(hWnd, E_DELAY);
+		if (i == 0 || i > HUB_ACCESSLIST_DELAY_MAX)
+		{
+			ok = false;
+		}
+	}
+
+	if (b2)
+	{
+		UINT i = GetInt(hWnd, E_JITTER);
+		if (i == 0 || i > HUB_ACCESSLIST_JITTER_MAX)
+		{
+			ok = false;
+		}
+	}
+
+	if (b3)
+	{
+		UINT i = GetInt(hWnd, E_LOSS);
+		if (i == 0 || i > HUB_ACCESSLIST_LOSS_MAX)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// 遅延・ジッタ・パケットロスダイアログの初期化
+void SmSimulationInit(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+	ACCESS *a;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	a = s->Access;
+
+	Check(hWnd, C_DELAY, a->Delay != 0);
+	Check(hWnd, C_JITTER, a->Jitter != 0);
+	Check(hWnd, C_LOSS, a->Loss != 0);
+
+	SetIntEx(hWnd, E_DELAY, a->Delay);
+	if (a->Delay != 0)
+	{
+		SetIntEx(hWnd, E_JITTER, a->Jitter);
+	}
+	SetIntEx(hWnd, E_LOSS, a->Loss);
+
+	SmSimulationUpdate(hWnd, s);
+
+	if (a->Delay != 0)
+	{
+		FocusEx(hWnd, E_DELAY);
+	}
+	else
+	{
+		Focus(hWnd, C_DELAY);
+	}
+}
+
+// 遅延・ジッタ・パケットロスダイアログの保存
+void SmSimulationOnOk(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+	ACCESS *a;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	a = s->Access;
+
+	a->Jitter = a->Loss = a->Delay = 0;
+
+	if (IsChecked(hWnd, C_DELAY))
+	{
+		a->Delay = GetInt(hWnd, E_DELAY);
+	}
+
+	if (IsChecked(hWnd, C_JITTER))
+	{
+		a->Jitter = GetInt(hWnd, E_JITTER);
+	}
+
+	if (IsChecked(hWnd, C_LOSS))
+	{
+		a->Loss = GetInt(hWnd, E_LOSS);
+	}
+
+	EndDialog(hWnd, 1);
+}
+
+// アクセスリストの編集
+bool SmEditAccess(HWND hWnd, SM_ACCESS_LIST *s, ACCESS *a)
+{
+	SM_EDIT_ACCESS edit;
+	bool ret;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&edit, sizeof(edit));
+	edit.AccessList = s;
+	edit.EditMode = true;
+	edit.Access = ZeroMalloc(sizeof(ACCESS));
+	edit.Hub = s->Hub;
+	Copy(edit.Access, a, sizeof(ACCESS));
+
+	if (edit.Access->IsIPv6 == false)
+	{
+		ret = Dialog(hWnd, D_SM_EDIT_ACCESS, SmEditAccessDlg, &edit);
+	}
+	else
+	{
+		ret = Dialog(hWnd, D_SM_EDIT_ACCESS_V6, SmEditAccessDlg, &edit);
+	}
+
+	if (ret)
+	{
+		Copy(a, edit.Access, sizeof(ACCESS));
+		Free(edit.Access);
+		Sort(s->AccessList);
+
+		// ID を振り直す
+		for (i = 0;i < LIST_NUM(s->AccessList);i++)
+		{
+			ACCESS *a = LIST_DATA(s->AccessList, i);
+			a->Id = (i + 1);
+		}
+	}
+	else
+	{
+		Free(edit.Access);
+	}
+
+	return ret;
+}
+
+// アクセスリストの追加
+bool SmAddAccess(HWND hWnd, SM_ACCESS_LIST *s, bool ipv6)
+{
+	SM_EDIT_ACCESS edit;
+	bool ret;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&edit, sizeof(edit));
+	edit.AccessList = s;
+	edit.Access = ZeroMalloc(sizeof(ACCESS));
+	edit.Access->Active = true;
+	edit.Access->Priority = 0;
+	edit.Access->IsIPv6 = ipv6;
+	edit.Hub = s->Hub;
+
+	// 新しい優先順位の取得
+	for (i = 0;i < LIST_NUM(s->AccessList);i++)
+	{
+		ACCESS *a = LIST_DATA(s->AccessList, i);
+		edit.Access->Priority = MAX(edit.Access->Priority, a->Priority);
+	}
+
+	if (edit.Access->Priority == 0)
+	{
+		edit.Access->Priority = 900;
+	}
+
+	edit.Access->Priority += 100;
+
+	if (edit.Access->IsIPv6 == false)
+	{
+		ret = Dialog(hWnd, D_SM_EDIT_ACCESS, SmEditAccessDlg, &edit);
+	}
+	else
+	{
+		ret = Dialog(hWnd, D_SM_EDIT_ACCESS_V6, SmEditAccessDlg, &edit);
+	}
+
+	if (ret)
+	{
+		Insert(s->AccessList, edit.Access);
+
+		// ID を振り直す
+		for (i = 0;i < LIST_NUM(s->AccessList);i++)
+		{
+			ACCESS *a = LIST_DATA(s->AccessList, i);
+			a->Id = (i + 1);
+		}
+	}
+	else
+	{
+		Free(edit.Access);
+	}
+
+	return ret;
+}
+
+// 初期化
+void SmAccessListInit(HWND hWnd, SM_ACCESS_LIST *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_PASS);
+	FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+	LvInit(hWnd, L_ACCESS_LIST);
+	LvInsertColumn(hWnd, L_ACCESS_LIST, 0, _UU("SM_ACCESS_COLUMN_0"), 60);
+	LvInsertColumn(hWnd, L_ACCESS_LIST, 1, _UU("SM_ACCESS_COLUMN_1"), 60);
+	LvInsertColumn(hWnd, L_ACCESS_LIST, 2, _UU("SM_ACCESS_COLUMN_2"), 60);
+	LvInsertColumn(hWnd, L_ACCESS_LIST, 3, _UU("SM_ACCESS_COLUMN_3"), 70);
+	LvInsertColumn(hWnd, L_ACCESS_LIST, 4, _UU("SM_ACCESS_COLUMN_4"), 150);
+	LvInsertColumn(hWnd, L_ACCESS_LIST, 5, _UU("SM_ACCESS_COLUMN_5"), 600);
+
+	LvSetStyle(hWnd, L_ACCESS_LIST, LVS_EX_GRIDLINES);
+
+	SetEnable(hWnd, B_ADD_V6, GetCapsBool(s->Hub->p->CapsList, "b_support_ipv6_acl"));
+
+	SmAccessListRefresh(hWnd, s);
+}
+
+// コントロール更新
+void SmAccessListUpdate(HWND hWnd, SM_ACCESS_LIST *s)
+{
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_ACCESS_LIST) == false || LvIsMultiMasked(hWnd, L_ACCESS_LIST))
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+	SetEnable(hWnd, B_DELETE, ok);
+
+	SetEnable(hWnd, B_CREATE, LIST_NUM(s->AccessList) < MAX_ACCESSLISTS);
+}
+
+// 内容更新
+void SmAccessListRefresh(HWND hWnd, SM_ACCESS_LIST *s)
+{
+	LVB *b;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	b = LvInsertStart();
+
+	Sort(s->AccessList);
+
+	for (i = 0;i < LIST_NUM(s->AccessList);i++)
+	{
+		ACCESS *a = LIST_DATA(s->AccessList, i);
+		char tmp[MAX_SIZE];
+		UINT ico = ICO_PASS;
+		wchar_t tmp3[MAX_SIZE];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		GetAccessListStr(tmp, sizeof(tmp), a);
+		UniToStru(tmp1, a->Priority);
+		StrToUni(tmp2, sizeof(tmp2), tmp);
+
+		if (a->Discard == false && a->Active == false)
+		{
+			ico = ICO_PASS_DISABLE;
+		}
+		else if (a->Discard == false && a->Active)
+		{
+			ico = ICO_PASS;
+		}
+		else if (a->Discard && a->Active == false)
+		{
+			ico = ICO_DISCARD_DISABLE;
+		}
+		else
+		{
+			ico = ICO_DISCARD;
+		}
+
+		UniToStru(tmp3, a->Id);
+
+		LvInsertAdd(b, ico, (void *)a, 6,
+			tmp3,
+			a->Discard ? _UU("SM_ACCESS_DISCARD") : _UU("SM_ACCESS_PASS"),
+			a->Active ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"),
+			tmp1,
+			a->Note,
+			tmp2);
+	}
+
+	LvInsertEnd(b, hWnd, L_ACCESS_LIST);
+	LvSortEx(hWnd, L_ACCESS_LIST, 0, false, true);
+
+	SmAccessListUpdate(hWnd, s);
+}
+
+// アクセスリストダイアログプロシージャ
+UINT SmAccessListProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_ACCESS_LIST *s = (SM_ACCESS_LIST *)param;
+	NMHDR *n;
+	ACCESS *a;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmAccessListInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_ADD:
+			// 追加 (IPv4)
+			if (SmAddAccess(hWnd, s, false))
+			{
+				SmAccessListRefresh(hWnd, s);
+			}
+			break;
+
+		case B_ADD_V6:
+			// 追加 (IPv6)
+			if (SmAddAccess(hWnd, s, true))
+			{
+				SmAccessListRefresh(hWnd, s);
+			}
+			break;
+
+		case IDOK:
+			// 編集
+			a = LvGetParam(hWnd, L_ACCESS_LIST, LvGetSelected(hWnd, L_ACCESS_LIST));
+			if (a != NULL)
+			{
+				if (SmEditAccess(hWnd, s, a))
+				{
+					SmAccessListRefresh(hWnd, s);
+				}
+			}
+			break;
+
+		case B_DELETE:
+			// 削除
+			a = LvGetParam(hWnd, L_ACCESS_LIST, LvGetSelected(hWnd, L_ACCESS_LIST));
+			if (a != NULL)
+			{
+				UINT i;
+				if (IsInList(s->AccessList, a))
+				{
+					Delete(s->AccessList, a);
+					Free(a);
+					// ID を振り直す
+					for (i = 0;i < LIST_NUM(s->AccessList);i++)
+					{
+						ACCESS *a = LIST_DATA(s->AccessList, i);
+						a->Id = (i + 1);
+					}
+					SmAccessListRefresh(hWnd, s);
+				}
+			}
+			break;
+
+		case B_SAVE:
+			// 保存
+			{
+				UINT i;
+				bool ok;
+				// アクセスリストを保存する
+				RPC_ENUM_ACCESS_LIST t;
+				Zero(&t, sizeof(t));
+				StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+				t.NumAccess = LIST_NUM(s->AccessList);
+				t.Accesses = ZeroMalloc(sizeof(ACCESS) * t.NumAccess);
+				for (i = 0;i < LIST_NUM(s->AccessList);i++)
+				{
+					ACCESS *access = LIST_DATA(s->AccessList, i);
+					Copy(&t.Accesses[i], access, sizeof(ACCESS));
+				}
+
+				ok = CALL(hWnd, ScSetAccessList(s->Rpc, &t));
+				FreeRpcEnumAccessList(&t);
+				if (ok)
+				{
+					EndDialog(hWnd, true);
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_ACCESS_LIST:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmAccessListUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_ACCESS_LIST);
+
+	return 0;
+}
+
+
+// アクセスリストダイアログ
+void SmAccessListDlg(HWND hWnd, SM_HUB *s)
+{
+	SM_ACCESS_LIST a;
+	UINT i;
+	RPC_ENUM_ACCESS_LIST t;
+	bool ret;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&a, sizeof(a));
+	a.Hub = s;
+	a.Rpc = s->Rpc;
+
+	// アクセスリストの取得
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	if (CALL(hWnd, ScEnumAccess(s->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	a.AccessList = NewListFast(CmpAccessList);
+	// リストに追加
+	for (i = 0;i < t.NumAccess;i++)
+	{
+		ACCESS *access = ZeroMalloc(sizeof(ACCESS));
+		Copy(access, &t.Accesses[i], sizeof(ACCESS));
+
+		Add(a.AccessList, access);
+	}
+
+	// ソート
+	Sort(a.AccessList);
+	FreeRpcEnumAccessList(&t);
+
+	// ダイアログ表示
+	ret = Dialog(hWnd, D_SM_ACCESS_LIST, SmAccessListProc, &a);
+
+	for (i = 0;i < LIST_NUM(a.AccessList);i++)
+	{
+		ACCESS *access = LIST_DATA(a.AccessList, i);
+		Free(access);
+	}
+	ReleaseList(a.AccessList);
+}
+
+// 初期化
+void SmEditGroupDlgInit(HWND hWnd, SM_EDIT_GROUP *g)
+{
+	RPC_SET_GROUP *group;
+	LVB *b;
+	// 引数チェック
+	if (hWnd == NULL || g == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_GROUP);
+
+	group = &g->SetGroup;
+
+	if (g->EditMode == false)
+	{
+		SetText(hWnd, 0, _UU("SM_EDIT_GROUP_CAPTION_1"));
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		UniFormat(tmp, sizeof(tmp), _UU("SM_EDIT_GROUP_CAPTION_2"), group->Name);
+		SetText(hWnd, 0, tmp);
+	}
+
+	SetTextA(hWnd, E_GROUPNAME, group->Name);
+	SetText(hWnd, E_REALNAME, group->Realname);
+	SetText(hWnd, E_NOTE, group->Note);
+
+	g->Inited = true;
+
+	if (g->EditMode == false)
+	{
+		Disable(hWnd, L_STATUS);
+	}
+	else
+	{
+		LvInit(hWnd, L_STATUS);
+		LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 0);
+		LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 0);
+		LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+
+		b = LvInsertStart();
+
+		SmInsertTrafficInfo(b, &group->Traffic);
+
+		LvInsertEnd(b, hWnd, L_STATUS);
+
+		LvAutoSize(hWnd, L_STATUS);
+	}
+
+	Check(hWnd, R_POLICY, group->Policy != NULL);
+
+	if (g->EditMode)
+	{
+		Disable(hWnd, E_GROUPNAME);
+		FocusEx(hWnd, E_REALNAME);
+	}
+
+	SmEditGroupDlgUpdate(hWnd, g);
+}
+
+// 更新
+void SmEditGroupDlgUpdate(HWND hWnd, SM_EDIT_GROUP *g)
+{
+	bool ok = true;
+	RPC_SET_GROUP *group;
+	// 引数チェック
+	if (hWnd == NULL || g == NULL)
+	{
+		return;
+	}
+
+	if (g->Inited == false)
+	{
+		return;
+	}
+
+	group = &g->SetGroup;
+
+	GetTxtA(hWnd, E_GROUPNAME, group->Name, sizeof(group->Name));
+	Trim(group->Name);
+
+	if (IsUserName(group->Name) == false)
+	{
+		ok = false;
+	}
+
+	GetTxt(hWnd, E_REALNAME, group->Realname, sizeof(group->Realname));
+	UniTrim(group->Realname);
+
+	GetTxt(hWnd, E_NOTE, group->Note, sizeof(group->Note));
+	UniTrim(group->Note);
+
+	SetEnable(hWnd, B_POLICY, IsChecked(hWnd, R_POLICY));
+
+	if (IsChecked(hWnd, R_POLICY))
+	{
+		if (group->Policy == NULL)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// OK
+void SmEditGroupDlgOnOk(HWND hWnd, SM_EDIT_GROUP *g)
+{
+	RPC_SET_GROUP *group;
+	RPC_SET_GROUP t;
+	// 引数チェック
+	if (hWnd == NULL || g == NULL)
+	{
+		return;
+	}
+
+	SmEditGroupDlgUpdate(hWnd, g);
+
+	group = &g->SetGroup;
+
+	if (IsChecked(hWnd, R_POLICY) == false)
+	{
+		if (group->Policy != NULL)
+		{
+			Free(group->Policy);
+			group->Policy = NULL;
+		}
+	}
+
+	Zero(&t, sizeof(t));
+	Copy(&t, group, sizeof(RPC_SET_GROUP));
+
+	t.Policy = ClonePolicy(group->Policy);
+
+	if (g->EditMode == false)
+	{
+		if (CALL(hWnd, ScCreateGroup(g->Rpc, &t)) == false)
+		{
+			FocusEx(hWnd, E_GROUPNAME);
+			return;
+		}
+	}
+	else
+	{
+		if (CALL(hWnd, ScSetGroup(g->Rpc, &t)) == false)
+		{
+			return;
+		}
+	}
+
+	FreeRpcSetGroup(&t);
+
+	if (g->EditMode == false)
+	{
+		MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_GROUP_CREATED"), group->Name);
+	}
+
+	EndDialog(hWnd, true);
+}
+
+// グループ編集ダイアログプロシージャ
+UINT SmEditGroupDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_GROUP *g = (SM_EDIT_GROUP *)param;
+	wchar_t tmp[MAX_SIZE];
+	NMHDR *n;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmEditGroupDlgInit(hWnd, g);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_GROUPNAME:
+		case E_REALNAME:
+		case E_NOTE:
+		case R_POLICY:
+			SmEditGroupDlgUpdate(hWnd, g);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmEditGroupDlgOnOk(hWnd, g);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case R_POLICY:
+			if (IsChecked(hWnd, R_POLICY))
+			{
+				Focus(hWnd, B_POLICY);
+			}
+			break;
+
+		case B_POLICY:
+			// セキュリティ ポリシー
+			UniFormat(tmp, sizeof(tmp), _UU("SM_GROUP_POLICY_CAPTION"), g->SetGroup.Name);
+			if (g->SetGroup.Policy == NULL)
+			{
+				POLICY *p = ClonePolicy(GetDefaultPolicy());
+				if (SmPolicyDlgEx2(hWnd, p, tmp, false, g->p->PolicyVer))
+				{
+					g->SetGroup.Policy = p;
+					SmEditGroupDlgUpdate(hWnd, g);
+				}
+				else
+				{
+					Free(p);
+				}
+			}
+			else
+			{
+				SmPolicyDlgEx2(hWnd, g->SetGroup.Policy, tmp, false, g->p->PolicyVer);
+			}
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_STATUS:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmEditGroupDlgUpdate(hWnd, g);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// グループ編集ダイアログ
+bool SmEditGroupDlg(HWND hWnd, SM_GROUP *s, char *name)
+{
+	SM_EDIT_GROUP g;
+	RPC_SET_GROUP *group;
+	bool ret;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&g, sizeof(g));
+	g.EditMode = true;
+	g.Hub = s->Hub;
+	g.p = s->p;
+	g.Rpc = s->Rpc;
+
+	group = &g.SetGroup;
+
+	StrCpy(group->Name, sizeof(group->Name), name);
+	StrCpy(group->HubName, sizeof(group->HubName), s->Hub->HubName);
+
+	if (CALL(hWnd, ScGetGroup(s->Rpc, group)) == false)
+	{
+		return false;
+	}
+
+	ret = Dialog(hWnd, D_SM_EDIT_GROUP, SmEditGroupDlgProc, &g);
+
+	FreeRpcSetGroup(group);
+
+	return ret;
+}
+
+// グループ作成ダイアログ
+bool SmCreateGroupDlg(HWND hWnd, SM_GROUP *s)
+{
+	SM_EDIT_GROUP g;
+	RPC_SET_GROUP *group;
+	bool ret;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&g, sizeof(g));
+	g.EditMode = false;
+	g.Hub = s->Hub;
+	g.p = s->p;
+	g.Rpc = s->Rpc;
+
+	group = &g.SetGroup;
+
+	StrCpy(group->HubName, sizeof(group->HubName), s->Hub->HubName);
+
+	ret = Dialog(hWnd, D_SM_EDIT_GROUP, SmEditGroupDlgProc, &g);
+
+	FreeRpcSetGroup(group);
+
+	return ret;
+}
+
+// 初期化
+void SmGroupListDlgInit(HWND hWnd, SM_GROUP *s)
+{
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_GROUP);
+
+	// カラム初期化
+	LvInit(hWnd, L_GROUP);
+	LvInsertColumn(hWnd, L_GROUP, 0, _UU("SM_GROUPLIST_NAME"), 130);
+	LvInsertColumn(hWnd, L_GROUP, 1, _UU("SM_GROUPLIST_REALNAME"), 130);
+	LvInsertColumn(hWnd, L_GROUP, 2, _UU("SM_GROUPLIST_NOTE"), 170);
+	LvInsertColumn(hWnd, L_GROUP, 3, _UU("SM_GROUPLIST_NUMUSERS"), 80);
+	LvSetStyle(hWnd, L_GROUP, LVS_EX_GRIDLINES);
+
+	FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+	SmGroupListDlgRefresh(hWnd, s);
+
+	if (s->SelectMode)
+	{
+		SetStyle(hWnd, L_GROUP, LVS_SINGLESEL);
+	}
+
+	if (s->SelectMode)
+	{
+		wchar_t tmp[MAX_SIZE];
+		SetText(hWnd, IDOK, _UU("SM_SELECT_GROUP"));
+
+		if (s->SelectedGroupName != NULL)
+		{
+			UINT i;
+			StrToUni(tmp, sizeof(tmp), s->SelectedGroupName);
+			i = LvSearchStr(hWnd, L_GROUP, 0, tmp);
+			if (i != INFINITE)
+			{
+				LvSelect(hWnd, L_GROUP, i);
+			}
+		}
+	}
+}
+
+// コントロール更新
+void SmGroupListDlgUpdate(HWND hWnd, SM_GROUP *s)
+{
+	bool ok = true;
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_GROUP) == false || LvIsMultiMasked(hWnd, L_GROUP))
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+	SetEnable(hWnd, B_USER, ok);
+	SetEnable(hWnd, B_STATUS, ok);
+
+	if (s->SelectMode == false)
+	{
+		SetEnable(hWnd, B_DELETE, ok);
+	}
+	else
+	{
+		SetEnable(hWnd, B_DELETE, false);
+		SetEnable(hWnd, B_USER, false);
+		SetText(hWnd, IDCANCEL, _UU("SM_SELECT_NO_GROUP"));
+	}
+}
+
+// 内容更新
+void SmGroupListDlgRefresh(HWND hWnd, SM_GROUP *s)
+{
+	RPC_ENUM_GROUP t;
+	UINT i;
+	LVB *b;
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+
+	if (CALL(hWnd, ScEnumGroup(s->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	b = LvInsertStart();
+
+	for (i = 0;i < t.NumGroup;i++)
+	{
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		RPC_ENUM_GROUP_ITEM *e = &t.Groups[i];
+
+		StrToUni(tmp1, sizeof(tmp1), e->Name);
+		UniToStru(tmp2, e->NumUsers);
+
+		LvInsertAdd(b, e->DenyAccess == false ? ICO_GROUP : ICO_GROUP_DENY,
+			NULL, 4, tmp1, e->Realname, e->Note, tmp2);
+	}
+
+	LvInsertEnd(b, hWnd, L_GROUP);
+
+	SmGroupListDlgUpdate(hWnd, s);
+
+	FreeRpcEnumGroup(&t);
+}
+
+// グループリストダイアログプロシージャ
+UINT SmGroupListDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_GROUP *s = (SM_GROUP *)param;
+	NMHDR *n;
+	wchar_t *tmp;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmGroupListDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_CREATE:
+			// 新規作成
+			if (SmCreateGroupDlg(hWnd, s))
+			{
+				SmGroupListDlgRefresh(hWnd, s);
+			}
+			break;
+
+		case IDOK:
+			// 編集
+			tmp = LvGetSelectedStr(hWnd, L_GROUP, 0);
+			if (tmp != NULL)
+			{
+				char name[MAX_SIZE];
+				UniToStr(name, sizeof(name), tmp);
+
+				if (s->SelectMode == false)
+				{
+					if (SmEditGroupDlg(hWnd, s, name))
+					{
+						SmGroupListDlgRefresh(hWnd, s);
+					}
+				}
+				else
+				{
+					s->SelectedGroupName = CopyStr(name);
+					EndDialog(hWnd, true);
+				}
+				Free(tmp);
+			}
+			break;
+
+		case B_DELETE:
+			// 削除
+			tmp = LvGetSelectedStr(hWnd, L_GROUP, 0);
+			if (tmp != NULL)
+			{
+				char name[MAX_SIZE];
+				RPC_DELETE_USER t;
+				UniToStr(name, sizeof(name), tmp);
+
+				if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+					_UU("SM_GROUP_DELETE_MSG"), name) == IDYES)
+				{
+					Zero(&t, sizeof(t));
+					StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+					StrCpy(t.Name, sizeof(t.Name), name);
+
+					if (CALL(hWnd, ScDeleteGroup(s->Rpc, &t)))
+					{
+						SmGroupListDlgRefresh(hWnd, s);
+					}
+				}
+
+				Free(tmp);
+			}
+			break;
+
+		case B_USER:
+			// メンバ一覧
+			tmp = LvGetSelectedStr(hWnd, L_GROUP, 0);
+			if (tmp != NULL)
+			{
+				char name[MAX_SIZE];
+				UniToStr(name, sizeof(name), tmp);
+				SmUserListDlgEx(hWnd, s->Hub, name, false);
+				Free(tmp);
+			}
+			break;
+
+		case B_REFRESH:
+			// 最新情報に更新
+			SmGroupListDlgRefresh(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_GROUP:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmGroupListDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_GROUP);
+
+	return 0;
+}
+
+// グループリストダイアログ (選択モード)
+char *SmSelectGroupDlg(HWND hWnd, SM_HUB *s, char *default_name)
+{
+	SM_GROUP g;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&g, sizeof(g));
+	g.Hub = s;
+	g.p = s->p;
+	g.Rpc = s->Rpc;
+	g.SelectMode = true;
+	g.SelectedGroupName = default_name;
+
+	if (Dialog(hWnd, D_SM_GROUP, SmGroupListDlgProc, &g) == false)
+	{
+		return NULL;
+	}
+
+	return g.SelectedGroupName;
+}
+
+// グループリストダイアログ
+void SmGroupListDlg(HWND hWnd, SM_HUB *s)
+{
+	SM_GROUP g;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&g, sizeof(g));
+	g.Hub = s;
+	g.p = s->p;
+	g.Rpc = s->Rpc;
+	g.SelectMode = false;
+
+	Dialog(hWnd, D_SM_GROUP, SmGroupListDlgProc, &g);
+}
+
+// ユーザー情報の更新
+bool SmRefreshUserInfo(HWND hWnd, SM_SERVER *s, void *param)
+{
+	RPC_SET_USER t;
+	SM_USER_INFO *p = (SM_USER_INFO *)param;
+	LVB *b;
+	wchar_t tmp[MAX_SIZE];
+	char *username;
+
+	// 引数チェック
+	if (hWnd == NULL || s == NULL || param == NULL)
+	{
+		return false;
+	}
+
+	username = p->Username;
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.HubName, sizeof(t.HubName), p->Hub->HubName);
+	StrCpy(t.Name, sizeof(t.Name), username);
+
+	if (CALL(hWnd, ScGetUser(s->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	StrToUni(tmp, sizeof(tmp), t.Name);
+	LvInsertAdd(b, ICO_USER, NULL, 2, _UU("SM_USERINFO_NAME"), tmp);
+
+	if (StrLen(t.GroupName) != 0)
+	{
+		StrToUni(tmp, sizeof(tmp), t.GroupName);
+		LvInsertAdd(b, ICO_GROUP, NULL, 2, _UU("SM_USERINFO_GROUP"), tmp);
+	}
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime), NULL);
+	LvInsertAdd(b, ICO_USER_ADMIN, NULL, 2, _UU("SM_USERINFO_CREATE"), tmp);
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.UpdatedTime), NULL);
+	LvInsertAdd(b, ICO_USER_ADMIN, NULL, 2, _UU("SM_USERINFO_UPDATE"), tmp);
+
+	if (t.ExpireTime != 0)
+	{
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ExpireTime), NULL);
+		LvInsertAdd(b, ICO_WARNING, NULL, 2, _UU("SM_USERINFO_EXPIRE"), tmp);
+	}
+
+	SmInsertTrafficInfo(b, &t.Traffic);
+
+	UniToStru(tmp, t.NumLogin);
+	LvInsertAdd(b, ICO_LINK, NULL, 2, _UU("SM_USERINFO_NUMLOGIN"), tmp);
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	FreeRpcSetUser(&t);
+
+	return true;
+}
+
+// 初期化
+void SmPolicyDlgInit(HWND hWnd, SM_POLICY *s)
+{
+	CM_POLICY cp;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_MACHINE);
+	SetText(hWnd, 0, s->Caption);
+	SetText(hWnd, S_TITLE, s->Caption);
+	DlgFont(hWnd, S_BOLD, 10, true);
+	DlgFont(hWnd, S_BOLD2, 10, true);
+
+	DlgFont(hWnd, S_POLICY_TITLE, 11, false);
+	DlgFont(hWnd, E_POLICY_DESCRIPTION, 10, false);
+
+	Zero(&cp, sizeof(cp));
+	cp.Policy = s->Policy;
+	cp.Extension = true;
+
+	LvInit(hWnd, L_POLICY);
+	LvInsertColumn(hWnd, L_POLICY, 0, _UU("POL_TITLE_STR"), 250);
+	LvInsertColumn(hWnd, L_POLICY, 1, _UU("POL_VALUE_STR"), 150);
+	LvSetStyle(hWnd, L_POLICY, LVS_EX_GRIDLINES);
+
+	CmPolicyDlgPrintEx2(hWnd, &cp, s->CascadeMode, s->Ver);
+
+	LvSelect(hWnd, L_POLICY, 0);
+
+	s->Inited = true;
+	SmPolicyDlgUpdate(hWnd, s);
+}
+
+// 更新
+void SmPolicyDlgUpdate(HWND hWnd, SM_POLICY *s)
+{
+	bool ok = true;
+	bool value_changed = false;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (s->Inited == false)
+	{
+		return;
+	}
+
+	i = LvGetSelected(hWnd, L_POLICY);
+	if (i != INFINITE)
+	{
+		i = (UINT)LvGetParam(hWnd, L_POLICY, i);
+	}
+	if (i == INFINITE || i >= NUM_POLICY_ITEM)
+	{
+		SetText(hWnd, S_POLICY_TITLE, _UU("SM_POLICY_INIT_TITLE"));
+		SetText(hWnd, E_POLICY_DESCRIPTION, L"");
+		Disable(hWnd, S_POLICY_TITLE);
+		Disable(hWnd, S_BOLD);
+		Hide(hWnd, S_BOLD2);
+		Hide(hWnd, R_ENABLE);
+		Hide(hWnd, R_DISABLE);
+		Hide(hWnd, R_DEFINE);
+		Hide(hWnd, E_VALUE);
+		Hide(hWnd, S_TANI);
+		Hide(hWnd, S_LIMIT);
+	}
+	else
+	{
+		POLICY_ITEM *item = &policy_item[i];
+		bool changed = false;
+		wchar_t *tmp = GetText(hWnd, S_POLICY_TITLE);
+		if (UniStrCmp(tmp, GetPolicyTitle(i)) != 0)
+		{
+			changed = true;
+		}
+		Free(tmp);
+		SetText(hWnd, S_POLICY_TITLE, GetPolicyTitle(i));
+		SetText(hWnd, E_POLICY_DESCRIPTION, GetPolicyDescription(i));
+		Enable(hWnd, S_POLICY_TITLE);
+		Enable(hWnd, S_BOLD);
+		Show(hWnd, S_BOLD2);
+
+		if (item->TypeInt == false)
+		{
+			Show(hWnd, R_ENABLE);
+			Show(hWnd, R_DISABLE);
+			Hide(hWnd, R_DEFINE);
+			Hide(hWnd, E_VALUE);
+			Hide(hWnd, S_TANI);
+			Hide(hWnd, S_LIMIT);
+
+			if (changed)
+			{
+				if (POLICY_BOOL(s->Policy, i))
+				{
+					Check(hWnd, R_ENABLE, true);
+					Check(hWnd, R_DISABLE, false);
+				}
+				else
+				{
+					Check(hWnd, R_ENABLE, false);
+					Check(hWnd, R_DISABLE, true);
+				}
+			}
+
+			if ((!(POLICY_BOOL(s->Policy, i))) != (!(IsChecked(hWnd, R_ENABLE))))
+			{
+				POLICY_BOOL(s->Policy, i) = IsChecked(hWnd, R_ENABLE);
+				value_changed = true;
+			}
+		}
+		else
+		{
+			wchar_t tmp[MAX_SIZE];
+			UINT value;
+			if (item->AllowZero)
+			{
+				if (changed)
+				{
+					Check(hWnd, R_DEFINE, POLICY_INT(s->Policy, i) != 0);
+					Enable(hWnd, R_DEFINE);
+					SetIntEx(hWnd, E_VALUE, POLICY_INT(s->Policy, i));
+				}
+
+				SetEnable(hWnd, E_VALUE, IsChecked(hWnd, R_DEFINE));
+				SetEnable(hWnd, S_TANI, IsChecked(hWnd, R_DEFINE));
+				SetEnable(hWnd, S_LIMIT, IsChecked(hWnd, R_DEFINE));
+			}
+			else
+			{
+				if (changed)
+				{
+					Check(hWnd, R_DEFINE, true);
+					Disable(hWnd, R_DEFINE);
+					SetInt(hWnd, E_VALUE, POLICY_INT(s->Policy, i));
+				}
+
+				SetEnable(hWnd, E_VALUE, IsChecked(hWnd, R_DEFINE));
+				SetEnable(hWnd, S_TANI, IsChecked(hWnd, R_DEFINE));
+				SetEnable(hWnd, S_LIMIT, IsChecked(hWnd, R_DEFINE));
+			}
+
+			UniReplaceStrEx(tmp, sizeof(tmp), _UU(policy_item[i].FormatStr),
+				L"%u ", L"", false);
+			UniReplaceStrEx(tmp, sizeof(tmp), tmp,
+				L"%u", L"", false);
+
+			SetText(hWnd, S_TANI, tmp);
+
+			UniFormat(tmp, sizeof(tmp), _UU("SM_LIMIT_STR"), policy_item[i].MinValue, policy_item[i].MaxValue);
+			SetText(hWnd, S_LIMIT, tmp);
+
+			Hide(hWnd, R_ENABLE);
+			Hide(hWnd, R_DISABLE);
+			Show(hWnd, E_VALUE);
+			Show(hWnd, R_DEFINE);
+			Show(hWnd, S_TANI);
+			Show(hWnd, S_LIMIT);
+
+			value = GetInt(hWnd, E_VALUE);
+
+			if (item->AllowZero && (IsChecked(hWnd, R_DEFINE) == false))
+			{
+				value = 0;
+			}
+			else
+			{
+				if (value < policy_item[i].MinValue || value > policy_item[i].MaxValue)
+				{
+					ok = false;
+				}
+			}
+
+			if (ok)
+			{
+				if (POLICY_INT(s->Policy, i) != value)
+				{
+					POLICY_INT(s->Policy, i) = value;
+					value_changed = true;
+				}
+			}
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+	SetEnable(hWnd, L_POLICY, ok);
+
+	if (value_changed)
+	{
+		CM_POLICY cp;
+		Zero(&cp, sizeof(cp));
+		cp.Policy = s->Policy;
+		cp.Extension = true;
+
+		CmPolicyDlgPrintEx(hWnd, &cp, s->CascadeMode);
+	}
+}
+
+// 確定
+void SmPolicyDlgOk(HWND hWnd, SM_POLICY *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	EndDialog(hWnd, true);
+}
+
+// ポリシー ダイアログ ボックス プロシージャ
+UINT SmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_POLICY *s = (SM_POLICY *)param;
+	NMHDR *n;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmPolicyDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_DEFINE:
+		case R_ENABLE:
+		case R_DISABLE:
+		case E_VALUE:
+			SmPolicyDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmPolicyDlgOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case R_DEFINE:
+			if (IsChecked(hWnd, R_DEFINE))
+			{
+				FocusEx(hWnd, E_VALUE);
+			}
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_POLICY:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmPolicyDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ポリシー ダイアログ ボックスの表示
+bool SmPolicyDlg(HWND hWnd, POLICY *p, wchar_t *caption)
+{
+	return SmPolicyDlgEx(hWnd, p, caption, false);
+}
+bool SmPolicyDlgEx(HWND hWnd, POLICY *p, wchar_t *caption, bool cascade_mode)
+{
+	return SmPolicyDlgEx2(hWnd, p, caption, cascade_mode, POLICY_CURRENT_VERSION);
+}
+bool SmPolicyDlgEx2(HWND hWnd, POLICY *p, wchar_t *caption, bool cascade_mode, UINT ver)
+{
+	SM_POLICY s;
+	bool ret;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	if (caption == NULL)
+	{
+		caption = _UU("SM_POLICY_DEF_CAPTION");
+	}
+
+	Zero(&s, sizeof(s));
+	s.Caption = caption;
+	s.Policy = ClonePolicy(p);
+	s.CascadeMode = cascade_mode;
+	s.Ver = ver;
+
+	ret = Dialog(hWnd, D_SM_POLICY, SmPolicyDlgProc, &s);
+
+	if (ret)
+	{
+		Copy(p, s.Policy, sizeof(POLICY));
+	}
+
+	Free(s.Policy);
+
+	return ret;
+}
+
+// ユーザー編集確定
+void SmEditUserDlgOk(HWND hWnd, SM_EDIT_USER *s)
+{
+	RPC_SET_USER t;
+	RPC_SET_USER *u;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SmEditUserDlgUpdate(hWnd, s);
+
+	Zero(&t, sizeof(t));
+	u = &s->SetUser;
+
+	StrCpy(t.HubName, sizeof(t.HubName), u->HubName);
+	StrCpy(t.Name, sizeof(t.Name), u->Name);
+	StrCpy(t.GroupName, sizeof(t.GroupName), u->GroupName);
+	UniStrCpy(t.Realname, sizeof(t.Realname), u->Realname);
+	UniStrCpy(t.Note, sizeof(t.Note), u->Note);
+	t.ExpireTime = u->ExpireTime;
+	t.AuthType = u->AuthType;
+	t.AuthData = CopyAuthData(u->AuthData, t.AuthType);
+
+	if (IsChecked(hWnd, R_POLICY))
+	{
+		t.Policy = ClonePolicy(u->Policy);
+	}
+	else
+	{
+		t.Policy = NULL;
+	}
+
+	if (s->EditMode == false)
+	{
+		if (CALL(hWnd, ScCreateUser(s->Rpc, &t)) == false)
+		{
+			FocusEx(hWnd, E_USERNAME);
+			return;
+		}
+		FreeRpcSetUser(&t);
+
+		MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_USER_CREEATE_OK"), u->Name);
+	}
+	else
+	{
+		if (CALL(hWnd, ScSetUser(s->Rpc, &t)) == false)
+		{
+			FocusEx(hWnd, E_REALNAME);
+			return;
+		}
+		FreeRpcSetUser(&t);
+	}
+
+	EndDialog(hWnd, true);
+}
+
+// ユーザー編集初期化
+void SmEditUserDlgInit(HWND hWnd, SM_EDIT_USER *s)
+{
+	RPC_SET_USER *u;
+	wchar_t tmp[MAX_SIZE];
+	UINT i;
+	UINT icons[6] = {ICO_PASS, ICO_KEY, ICO_CERT, ICO_SERVER_CERT,
+		ICO_TOWER, ICO_LINK};
+	RECT rect;
+
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_USER);
+
+	u = &s->SetUser;
+
+	// カラム初期化
+	LvInit(hWnd, L_AUTH);
+	LvSetStyle(hWnd, L_AUTH, LVS_EX_GRIDLINES);
+
+	GetClientRect(DlgItem(hWnd, L_AUTH), &rect);
+	LvInsertColumn(hWnd, L_AUTH, 0, L"Name", rect.right - rect.left);
+
+	for (i = 0;i < 6;i++)
+	{
+		LvInsert(hWnd, L_AUTH, icons[i], (void *)i, 1, SmGetAuthTypeStr(i));
+	}
+
+	// ユーザー名など
+	SetTextA(hWnd, E_USERNAME, u->Name);
+	SetText(hWnd, E_REALNAME, u->Realname);
+	SetText(hWnd, E_NOTE, u->Note);
+
+
+	// 有効期限
+	if (u->ExpireTime == 0)
+	{
+		SYSTEMTIME st;
+		Check(hWnd, R_EXPIRES, false);
+		GetLocalTime(&st);
+		UINT64ToSystem(&st, SystemToUINT64(&st) + (60 * 60 * 24 * 1000));
+		st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
+		DateTime_SetSystemtime(DlgItem(hWnd, E_EXPIRES_DATE), GDT_VALID, &st);
+		DateTime_SetSystemtime(DlgItem(hWnd, E_EXPIRES_TIME), GDT_VALID, &st);
+	}
+	else
+	{
+		SYSTEMTIME st;
+		UINT64ToSystem(&st, SystemToLocal64(u->ExpireTime));
+		Check(hWnd, R_EXPIRES, true);
+		DateTime_SetSystemtime(DlgItem(hWnd, E_EXPIRES_DATE), GDT_VALID, &st);
+		DateTime_SetSystemtime(DlgItem(hWnd, E_EXPIRES_TIME), GDT_VALID, &st);
+	}
+
+	SetStyle(hWnd, E_EXPIRES_DATE, DTS_LONGDATEFORMAT);
+	SetWindowLong(DlgItem(hWnd, E_EXPIRES_TIME), GWL_STYLE, WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | DTS_RIGHTALIGN | DTS_TIMEFORMAT | DTS_UPDOWN);
+
+	// グループ名
+	SetTextA(hWnd, E_GROUP, u->GroupName);
+
+	// 認証方法
+	LvSelect(hWnd, L_AUTH, u->AuthType);
+
+	SetText(hWnd, S_CERT_INFO, _UU("SM_EDIT_USER_CERT_INFO"));
+
+	switch (u->AuthType)
+	{
+	case AUTHTYPE_PASSWORD:
+		if (s->EditMode)
+		{
+			SetTextA(hWnd, E_PASSWORD1, HIDDEN_PASSWORD);
+			SetTextA(hWnd, E_PASSWORD2, HIDDEN_PASSWORD);
+		}
+		break;
+
+	case AUTHTYPE_USERCERT:
+		SmGetCertInfoStr(tmp, sizeof(tmp), ((AUTHUSERCERT *)u->AuthData)->UserX);
+		break;
+
+	case AUTHTYPE_ROOTCERT:
+		if (u->AuthData != NULL)
+		{
+			AUTHROOTCERT *c = (AUTHROOTCERT *)u->AuthData;
+			if (c->CommonName != NULL && UniStrLen(c->CommonName) != 0)
+			{
+				Check(hWnd, R_CN, true);
+				SetText(hWnd, E_CN, c->CommonName);
+			}
+			else
+			{
+				Check(hWnd, R_CN, false);
+			}
+			if (c->Serial != NULL && c->Serial->size != 0)
+			{
+				X_SERIAL *s = c->Serial;
+				char *tmp;
+				UINT tmp_size = s->size * 3 + 1;
+				tmp = ZeroMalloc(tmp_size);
+				BinToStrEx(tmp, tmp_size, s->data, s->size);
+				SetTextA(hWnd, E_SERIAL, tmp);
+				Free(tmp);
+				Check(hWnd, R_SERIAL, true);
+			}
+			else
+			{
+				Check(hWnd, R_SERIAL, false);
+			}
+		}
+		break;
+
+	case AUTHTYPE_RADIUS:
+		if (u->AuthData != NULL)
+		{
+			AUTHRADIUS *r = (AUTHRADIUS *)u->AuthData;
+			if (UniStrLen(r->RadiusUsername) != 0)
+			{
+				Check(hWnd, R_SET_RADIUS_USERNAME, true);
+				SetText(hWnd, E_RADIUS_USERNAME, r->RadiusUsername);
+			}
+			else
+			{
+				Check(hWnd, R_SET_RADIUS_USERNAME, false);
+			}
+		}
+		break;
+
+	case AUTHTYPE_NT:
+		if (u->AuthData != NULL)
+		{
+			AUTHNT *n = (AUTHNT *)u->AuthData;
+			if (UniStrLen(n->NtUsername) != 0)
+			{
+				Check(hWnd, R_SET_RADIUS_USERNAME, true);
+				SetText(hWnd, E_RADIUS_USERNAME, n->NtUsername);
+			}
+			else
+			{
+				Check(hWnd, R_SET_RADIUS_USERNAME, false);
+			}
+		}
+		break;
+	}
+
+	if (u->Policy != NULL)
+	{
+		Check(hWnd, R_POLICY, true);
+	}
+
+	s->Inited = true;
+
+	SmEditUserDlgUpdate(hWnd, s);
+
+	if (s->EditMode == false)
+	{
+		Focus(hWnd, E_USERNAME);
+		SetText(hWnd, 0, _UU("SM_EDIT_USER_CAPTION_1"));
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		UniFormat(tmp, sizeof(tmp), _UU("SM_EDIT_USER_CAPTION_2"), s->SetUser.Name);
+		SetText(hWnd, 0, tmp);
+
+		Disable(hWnd, E_USERNAME);
+		FocusEx(hWnd, E_REALNAME);
+	}
+}
+
+// ユーザー編集コントロール更新
+void SmEditUserDlgUpdate(HWND hWnd, SM_EDIT_USER *s)
+{
+	RPC_SET_USER *u;
+	bool ok = true;
+	UINT old_authtype;
+	char tmp1[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	bool authtype_changed = false;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (s->Inited == false)
+	{
+		return;
+	}
+
+	u = &s->SetUser;
+
+	// ユーザー名
+	GetTxtA(hWnd, E_USERNAME, u->Name, sizeof(u->Name));
+	Trim(u->Name);
+	if (StrLen(u->Name) == 0 || IsUserName(u->Name) == false)
+	{
+		ok = false;
+	}
+
+	// 本名
+	GetTxt(hWnd, E_REALNAME, u->Realname, sizeof(u->Realname));
+	UniTrim(u->Realname);
+
+	// メモ
+	GetTxt(hWnd, E_NOTE, u->Note, sizeof(u->Note));
+	UniTrim(u->Realname);
+
+	// グループ
+	GetTxtA(hWnd, E_GROUP, u->GroupName, sizeof(u->GroupName));
+	Trim(u->GroupName);
+
+	// 有効期限
+	if (IsChecked(hWnd, R_EXPIRES) == false)
+	{
+		u->ExpireTime = 0;
+		Disable(hWnd, E_EXPIRES_DATE);
+		Disable(hWnd, E_EXPIRES_TIME);
+	}
+	else
+	{
+		SYSTEMTIME st1, st2;
+		Enable(hWnd, E_EXPIRES_DATE);
+		Enable(hWnd, E_EXPIRES_TIME);
+		DateTime_GetSystemtime(DlgItem(hWnd, E_EXPIRES_DATE), &st1);
+		DateTime_GetSystemtime(DlgItem(hWnd, E_EXPIRES_TIME), &st2);
+		st1.wHour = st2.wHour;
+		st1.wMinute = st2.wMinute;
+		st1.wSecond = st2.wSecond;
+		st1.wMilliseconds = st2.wMilliseconds;
+		u->ExpireTime = LocalToSystem64(SystemToUINT64(&st1));
+	}
+
+	// 認証方法
+	old_authtype = u->AuthType;
+	u->AuthType = LvGetSelected(hWnd, L_AUTH);
+
+	if (StrCmpi(u->Name, "*") == 0)
+	{
+		if (u->AuthType != AUTHTYPE_RADIUS && u->AuthType != AUTHTYPE_NT)
+		{
+			ok = false;
+		}
+	}
+
+	if (u->AuthType == INFINITE)
+	{
+		ok = false;
+		u->AuthType = 0;
+	}
+	if (old_authtype != u->AuthType)
+	{
+		authtype_changed = true;
+	}
+
+	if (authtype_changed)
+	{
+		FreeAuthData(old_authtype, u->AuthData);
+		u->AuthData = NULL;
+		switch (u->AuthType)
+		{
+		case AUTHTYPE_ANONYMOUS:
+			u->AuthData = NULL;
+			break;
+
+		case AUTHTYPE_PASSWORD:
+			u->AuthData = NewPasswordAuthData("", "");
+			GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+			if (StrCmp(tmp1, HIDDEN_PASSWORD) == 0)
+			{
+				SetTextA(hWnd, E_PASSWORD1, "");
+			}
+			GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+			if (StrCmp(tmp2, HIDDEN_PASSWORD) == 0)
+			{
+				SetTextA(hWnd, E_PASSWORD2, "");
+			}
+			break;
+
+		case AUTHTYPE_USERCERT:
+			u->AuthData = NewUserCertAuthData(NULL);
+			SetText(hWnd, S_CERT_INFO, _UU("SM_EDIT_USER_CERT_INFO"));
+			break;
+
+		case AUTHTYPE_ROOTCERT:
+			u->AuthData = NewRootCertAuthData(NULL, NULL);
+			break;
+
+		case AUTHTYPE_NT:
+			u->AuthData = NewNTAuthData(L"");
+			break;
+
+		case AUTHTYPE_RADIUS:
+			u->AuthData = NewRadiusAuthData(L"");
+			break;
+		}
+	}
+
+	SetEnable(hWnd, S_RADIUS_3, (u->AuthType == AUTHTYPE_RADIUS) || (u->AuthType == AUTHTYPE_NT));
+	SetEnable(hWnd, R_SET_RADIUS_USERNAME, (u->AuthType == AUTHTYPE_RADIUS) || (u->AuthType == AUTHTYPE_NT));
+	SetEnable(hWnd, S_RADIUS_1, (u->AuthType == AUTHTYPE_RADIUS) || (u->AuthType == AUTHTYPE_NT));
+
+	if (StrCmp(u->Name, "*") == 0)
+	{
+		Check(hWnd, R_SET_RADIUS_USERNAME, false);
+		Disable(hWnd, R_SET_RADIUS_USERNAME);
+	}
+
+	if ((u->AuthType == AUTHTYPE_RADIUS) || (u->AuthType == AUTHTYPE_NT))
+	{
+		SetEnable(hWnd, E_RADIUS_USERNAME, IsChecked(hWnd, R_SET_RADIUS_USERNAME));
+		SetEnable(hWnd, S_RADIUS_2, IsChecked(hWnd, R_SET_RADIUS_USERNAME));
+	}
+	else
+	{
+		SetEnable(hWnd, E_RADIUS_USERNAME, false);
+		SetEnable(hWnd, S_RADIUS_2, false);
+	}
+
+	SetEnable(hWnd, S_PASSWORD_1, u->AuthType == AUTHTYPE_PASSWORD);
+	SetEnable(hWnd, S_PASSWORD_2, u->AuthType == AUTHTYPE_PASSWORD);
+	SetEnable(hWnd, S_PASSWORD_3, u->AuthType == AUTHTYPE_PASSWORD);
+	SetEnable(hWnd, E_PASSWORD1, u->AuthType == AUTHTYPE_PASSWORD);
+	SetEnable(hWnd, E_PASSWORD2, u->AuthType == AUTHTYPE_PASSWORD);
+
+	SetEnable(hWnd, S_USER_CERT_1, u->AuthType == AUTHTYPE_USERCERT);
+	SetEnable(hWnd, S_CERT_INFO, u->AuthType == AUTHTYPE_USERCERT);
+	SetEnable(hWnd, B_LOAD_CERT, u->AuthType == AUTHTYPE_USERCERT);
+
+	if (u->AuthType == AUTHTYPE_USERCERT)
+	{
+		SetEnable(hWnd, B_VIEW_CERT, ((AUTHUSERCERT *)u->AuthData)->UserX != NULL);
+	}
+	else
+	{
+		SetEnable(hWnd, B_VIEW_CERT, false);
+	}
+
+	SetEnable(hWnd, S_ROOT_CERT_1, u->AuthType == AUTHTYPE_ROOTCERT);
+	SetEnable(hWnd, S_ROOT_CERT_2, u->AuthType == AUTHTYPE_ROOTCERT);
+	SetEnable(hWnd, S_ROOT_CERT_3, u->AuthType == AUTHTYPE_ROOTCERT);
+	SetEnable(hWnd, R_CN, u->AuthType == AUTHTYPE_ROOTCERT);
+	SetEnable(hWnd, R_SERIAL, u->AuthType == AUTHTYPE_ROOTCERT);
+
+	if (u->AuthType == AUTHTYPE_ROOTCERT)
+	{
+		SetEnable(hWnd, E_CN, IsChecked(hWnd, R_CN));
+		SetEnable(hWnd, E_SERIAL, IsChecked(hWnd, R_SERIAL));
+	}
+	else
+	{
+		Disable(hWnd, E_CN);
+		Disable(hWnd, E_SERIAL);
+	}
+
+	switch (u->AuthType)
+	{
+	case AUTHTYPE_PASSWORD:
+		GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+		GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+		if (StrCmp(tmp1, tmp2) != 0)
+		{
+			ok = false;
+		}
+		else
+		{
+			if (StrCmp(tmp1, HIDDEN_PASSWORD) != 0)
+			{
+				HashPassword(((AUTHPASSWORD *)u->AuthData)->HashedKey, u->Name, tmp1);
+			}
+		}
+		break;
+
+	case AUTHTYPE_USERCERT:
+		if (((AUTHUSERCERT *)u->AuthData)->UserX == NULL)
+		{
+			ok = false;
+		}
+		break;
+
+	case AUTHTYPE_ROOTCERT:
+		Free(((AUTHROOTCERT *)u->AuthData)->CommonName);
+		((AUTHROOTCERT *)u->AuthData)->CommonName = NULL;
+		if (IsChecked(hWnd, R_CN) && (IsEmpty(hWnd, E_CN) == false))
+		{
+			((AUTHROOTCERT *)u->AuthData)->CommonName = GetText(hWnd, E_CN);
+			UniTrim(((AUTHROOTCERT *)u->AuthData)->CommonName);
+		}
+		if (IsChecked(hWnd, R_CN) && ((AUTHROOTCERT *)u->AuthData)->CommonName == NULL)
+		{
+			ok = false;
+		}
+		FreeXSerial(((AUTHROOTCERT *)u->AuthData)->Serial);
+		((AUTHROOTCERT *)u->AuthData)->Serial = NULL;
+		if (IsChecked(hWnd, R_SERIAL))
+		{
+			char *serial_str = GetTextA(hWnd, E_SERIAL);
+			if (serial_str != NULL)
+			{
+				BUF *b = StrToBin(serial_str);
+				if (b->Size >= 1)
+				{
+					((AUTHROOTCERT *)u->AuthData)->Serial = NewXSerial(b->Buf, b->Size);
+				}
+				FreeBuf(b);
+				Free(serial_str);
+			}
+		}
+		if (IsChecked(hWnd, R_SERIAL) && ((AUTHROOTCERT *)u->AuthData)->Serial == NULL)
+		{
+			ok = false;
+		}
+		break;
+
+	case AUTHTYPE_RADIUS:
+		Free(((AUTHRADIUS *)u->AuthData)->RadiusUsername);
+		((AUTHRADIUS *)u->AuthData)->RadiusUsername = NULL;
+		if (IsChecked(hWnd, R_SET_RADIUS_USERNAME) && (IsEmpty(hWnd, E_RADIUS_USERNAME) == false))
+		{
+			((AUTHRADIUS *)u->AuthData)->RadiusUsername = GetText(hWnd, E_RADIUS_USERNAME);
+		}
+		if (IsChecked(hWnd, R_SET_RADIUS_USERNAME) && ((AUTHRADIUS *)u->AuthData)->RadiusUsername == NULL)
+		{
+			ok = false;
+		}
+		break;
+
+	case AUTHTYPE_NT:
+		Free(((AUTHNT *)u->AuthData)->NtUsername);
+		((AUTHNT *)u->AuthData)->NtUsername = NULL;
+		if (IsChecked(hWnd, R_SET_RADIUS_USERNAME) && (IsEmpty(hWnd, E_RADIUS_USERNAME) == false))
+		{
+			((AUTHNT *)u->AuthData)->NtUsername = GetText(hWnd, E_RADIUS_USERNAME);
+		}
+		if (IsChecked(hWnd, R_SET_RADIUS_USERNAME) && ((AUTHNT *)u->AuthData)->NtUsername == NULL)
+		{
+			ok = false;
+		}
+		break;
+	}
+
+	SetEnable(hWnd, B_POLICY, IsChecked(hWnd, R_POLICY));
+	if (IsChecked(hWnd, R_POLICY))
+	{
+		if (u->Policy == NULL)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// ユーザー編集ダイアログプロシージャ
+UINT SmEditUserDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_USER *s = (SM_EDIT_USER *)param;
+	NMHDR *n;
+	POLICY *policy;
+	X *x = NULL;
+	wchar_t tmp[MAX_SIZE];
+	char name[MAX_SIZE];
+	char *ret;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmEditUserDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_USERNAME:
+		case E_REALNAME:
+		case E_NOTE:
+		case R_EXPIRES:
+		case E_EXPIRES_DATE:
+		case E_EXPIRES_TIME:
+		case E_GROUP:
+		case L_AUTH:
+		case R_SET_RADIUS_USERNAME:
+		case E_RADIUS_USERNAME:
+		case R_POLICY:
+		case E_PASSWORD1:
+		case E_PASSWORD2:
+		case R_CN:
+		case E_CN:
+		case R_SERIAL:
+		case E_SERIAL:
+			SmEditUserDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmEditUserDlgOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case B_POLICY:
+			UniFormat(tmp, sizeof(tmp), _UU("SM_EDIT_USER_POL_DLG"), s->SetUser.Name);
+			// ポリシー
+			if (s->SetUser.Policy == NULL)
+			{
+				policy = ClonePolicy(GetDefaultPolicy());
+				if (SmPolicyDlgEx2(hWnd, policy, tmp, false, s->p->PolicyVer))
+				{
+					s->SetUser.Policy = policy;
+					SmEditUserDlgUpdate(hWnd, s);
+				}
+				else
+				{
+					Free(policy);
+				}
+			}
+			else
+			{
+				SmPolicyDlgEx2(hWnd, s->SetUser.Policy, tmp, false, s->p->PolicyVer);
+			}
+			break;
+
+		case B_GROUP:
+			// グループの参照
+			GetTxtA(hWnd, E_GROUP, name, sizeof(name));
+			Trim(name);
+			ret = SmSelectGroupDlg(hWnd, s->Hub, StrLen(name) == 0 ? NULL : name);
+			if (ret != NULL)
+			{
+				SetTextA(hWnd, E_GROUP, ret);
+				Free(ret);
+			}
+			else
+			{
+				SetTextA(hWnd, E_GROUP, "");
+			}
+			FocusEx(hWnd, E_GROUP);
+			break;
+
+		case B_LOAD_CERT:
+			// 証明書の指定
+			if (CmLoadXFromFileOrSecureCard(hWnd, &x))
+			{
+UPDATE_CERT:
+				if (s->SetUser.AuthType == AUTHTYPE_USERCERT)
+				{
+					wchar_t tmp[MAX_SIZE];
+					FreeX(((AUTHUSERCERT *)s->SetUser.AuthData)->UserX);
+					((AUTHUSERCERT *)s->SetUser.AuthData)->UserX = x;
+					SmGetCertInfoStr(tmp, sizeof(tmp), x);
+					SetText(hWnd, S_CERT_INFO, tmp);
+					SmEditUserDlgUpdate(hWnd, s);
+				}
+				else
+				{
+					if (x != NULL)
+					{
+						FreeX(x);
+						x = NULL;
+					}
+				}
+			}
+			break;
+
+		case B_VIEW_CERT:
+			// 証明書の表示
+			if (s->SetUser.AuthType == AUTHTYPE_USERCERT)
+			{
+				CertDlg(hWnd, ((AUTHUSERCERT *)s->SetUser.AuthData)->UserX, NULL, true);
+			}
+			break;
+
+		case B_CREATE:
+			// 作成
+			GetTxtA(hWnd, E_USERNAME, name, sizeof(name));
+			Trim(name);
+			if (SmCreateCert(hWnd, &x, NULL, false, name))
+			{
+				if (s->SetUser.AuthType != AUTHTYPE_USERCERT)
+				{
+					LvSelect(hWnd, L_AUTH, 2);
+				}
+				goto UPDATE_CERT;
+			}
+			break;
+
+		case R_SET_RADIUS_USERNAME:
+			if (IsChecked(hWnd, R_SET_RADIUS_USERNAME))
+			{
+				FocusEx(hWnd, E_RADIUS_USERNAME);
+			}
+			break;
+
+		case R_EXPIRES:
+			if (IsChecked(hWnd, R_EXPIRES))
+			{
+				Focus(hWnd, E_EXPIRES_DATE);
+			}
+			break;
+
+		case R_POLICY:
+			if (IsChecked(hWnd, R_POLICY))
+			{
+				Focus(hWnd, B_POLICY);
+			}
+			break;
+
+		case R_CN:
+			if (IsChecked(hWnd, R_CN))
+			{
+				Focus(hWnd, E_CN);
+			}
+			break;
+
+		case R_SERIAL:
+			if (IsChecked(hWnd, R_SERIAL))
+			{
+				Focus(hWnd, E_SERIAL);
+			}
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_AUTH:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmEditUserDlgUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ユーザーの編集ダイアログ
+bool SmEditUserDlg(HWND hWnd, SM_HUB *s, char *username)
+{
+	SM_EDIT_USER e;
+	bool ret;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL || username == NULL)
+	{
+		return false;
+	}
+
+	Zero(&e, sizeof(e));
+	e.p = s->p;
+	e.Rpc = s->Rpc;
+	e.Hub = s;
+
+	// ユーザーの取得
+	StrCpy(e.SetUser.HubName, sizeof(e.SetUser.HubName), e.Hub->HubName);
+	StrCpy(e.SetUser.Name, sizeof(e.SetUser.Name), username);
+
+	if (CALL(hWnd, ScGetUser(s->Rpc, &e.SetUser)) == false)
+	{
+		return false;
+	}
+
+	e.EditMode = true;
+
+	ret = Dialog(hWnd, D_SM_EDIT_USER, SmEditUserDlgProc, &e);
+
+	FreeRpcSetUser(&e.SetUser);
+
+	return ret;
+}
+
+// ユーザーの新規作成ダイアログ
+bool SmCreateUserDlg(HWND hWnd, SM_HUB *s)
+{
+	SM_EDIT_USER e;
+	bool ret;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Zero(&e, sizeof(e));
+	e.EditMode = false;
+	e.p = s->p;
+	e.Rpc = s->Rpc;
+	e.Hub = s;
+
+	// 新しいユーザーの設定
+	StrCpy(e.SetUser.HubName, sizeof(e.SetUser.HubName), e.Hub->HubName);
+	e.SetUser.AuthType = CLIENT_AUTHTYPE_PASSWORD;
+	e.SetUser.AuthData = NewPasswordAuthData("", "");
+
+	ret = Dialog(hWnd, D_SM_EDIT_USER, SmEditUserDlgProc, &e);
+
+	FreeRpcSetUser(&e.SetUser);
+
+	return ret;
+}
+
+// ユーザー認証方法の文字列の取得
+wchar_t *SmGetAuthTypeStr(UINT id)
+{
+	return GetAuthTypeStr(id);
+}
+
+// ユーザーリスト初期化
+void SmUserListInit(HWND hWnd, SM_USER *s)
+{
+	wchar_t tmp1[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_USER);
+
+	// カラム初期化
+	LvInit(hWnd, L_USER);
+	LvSetStyle(hWnd, L_USER, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_USER, 0, _UU("SM_USER_COLUMN_1"), 120);
+	LvInsertColumn(hWnd, L_USER, 1, _UU("SM_USER_COLUMN_2"), 100);
+	LvInsertColumn(hWnd, L_USER, 2, _UU("SM_USER_COLUMN_3"), 100);
+	LvInsertColumn(hWnd, L_USER, 3, _UU("SM_USER_COLUMN_4"), 130);
+	LvInsertColumn(hWnd, L_USER, 4, _UU("SM_USER_COLUMN_5"), 100);
+	LvInsertColumn(hWnd, L_USER, 5, _UU("SM_USER_COLUMN_6"), 90);
+	LvInsertColumn(hWnd, L_USER, 6, _UU("SM_USER_COLUMN_7"), 120);
+
+	FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+	if (s->GroupName != NULL)
+	{
+		GetTxt(hWnd, 0, tmp1, sizeof(tmp1));
+		UniFormat(tmp2, sizeof(tmp2), _UU("SM_GROUP_MEMBER_STR"), s->GroupName);
+		UniStrCat(tmp1, sizeof(tmp1), tmp2);
+		SetText(hWnd, S_TITLE, tmp1);
+		Disable(hWnd, B_CREATE);
+	}
+
+	if (s->SelectMode)
+	{
+		SetStyle(hWnd, L_USER, LVS_SINGLESEL);
+	}
+
+	SmUserListRefresh(hWnd, s);
+
+	if (s->SelectMode)
+	{
+		wchar_t tmp[MAX_SIZE];
+		UINT i;
+		StrToUni(tmp, sizeof(tmp), s->SelectedName);
+		i = LvSearchStr(hWnd, L_USER, 0, tmp);
+		if (i != INFINITE)
+		{
+			LvSelect(hWnd, L_USER, i);
+		}
+
+		if (s->AllowGroup)
+		{
+			SetText(hWnd, B_DELETE, _UU("SM_SELECT_ALT_GROUP"));
+		}
+	}
+}
+
+// ユーザーリスト更新
+void SmUserListRefresh(HWND hWnd, SM_USER *s)
+{
+	LVB *b;
+	RPC_ENUM_USER t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+
+	StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+	if (CALL(hWnd, ScEnumUser(s->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	b = LvInsertStart();
+
+	for (i = 0;i < t.NumUser;i++)
+	{
+		RPC_ENUM_USER_ITEM *e = &t.Users[i];
+		wchar_t name[MAX_SIZE];
+		wchar_t group[MAX_SIZE];
+		wchar_t num[MAX_SIZE];
+		wchar_t time[MAX_SIZE];
+
+		if (s->GroupName != NULL)
+		{
+			if (StrCmpi(s->GroupName, e->GroupName) != 0)
+			{
+				continue;
+			}
+		}
+
+		StrToUni(name, sizeof(name), e->Name);
+
+		if (StrLen(e->GroupName) != 0)
+		{
+			StrToUni(group, sizeof(group), e->GroupName);
+		}
+		else
+		{
+			UniStrCpy(group, sizeof(group), _UU("SM_NO_GROUP"));
+		}
+
+		UniToStru(num, e->NumLogin);
+
+		GetDateTimeStrEx64(time, sizeof(time), SystemToLocal64(e->LastLoginTime), NULL);
+
+		LvInsertAdd(b, e->DenyAccess ? ICO_USER_DENY : ICO_USER, NULL, 7,
+			name, e->Realname, group, e->Note, SmGetAuthTypeStr(e->AuthType),
+			num, time);
+	}
+
+	LvInsertEnd(b, hWnd, L_USER);
+
+	FreeRpcEnumUser(&t);
+
+	SmUserListUpdate(hWnd, s);
+}
+
+// ユーザーリストコントロール更新
+void SmUserListUpdate(HWND hWnd, SM_USER *s)
+{
+	bool b = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_USER) == false || LvIsMultiMasked(hWnd, L_USER))
+	{
+		b = false;
+	}
+
+	if (s->SelectMode)
+	{
+		SetText(hWnd, IDOK, _UU("SM_SELECT_USER"));
+		SetText(hWnd, IDCANCEL, _UU("SM_SELECT_NO"));
+		SetText(hWnd, S_TITLE, _UU("SM_PLEASE_SELECT"));
+	}
+
+	SetEnable(hWnd, IDOK, b);
+
+	SetEnable(hWnd, B_STATUS, b);
+	SetEnable(hWnd, B_DELETE, (b && s->SelectedName == false) || s->AllowGroup);
+	SetEnable(hWnd, B_CREATE, s->SelectedName == false);
+}
+
+// ユーザーリストダイアログプロシージャ
+UINT SmUserListProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_USER *s = (SM_USER *)param;
+	NMHDR *n;
+	wchar_t *str;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmUserListInit(hWnd, s);
+
+		if (s->CreateNow)
+		{
+			// すぐに作成
+			if (IsEnable(hWnd, B_CREATE))
+			{
+				Command(hWnd, B_CREATE);
+			}
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			if (s->SelectMode == false)
+			{
+				// プロパティ
+				str = LvGetSelectedStr(hWnd, L_USER, 0);
+				if (str != NULL)
+				{
+					char name[MAX_SIZE];
+					UniToStr(name, sizeof(name), str);
+
+					if (SmEditUserDlg(hWnd, s->Hub, name))
+					{
+						SmUserListRefresh(hWnd, s);
+					}
+
+					Free(str);
+				}
+			}
+			else
+			{
+				// ユーザーを選択した
+				str = LvGetSelectedStr(hWnd, L_USER, 0);
+				if (str != NULL)
+				{
+					char name[MAX_SIZE];
+					UniToStr(name, sizeof(name), str);
+
+					s->SelectedName = CopyStr(name);
+
+					EndDialog(hWnd, true);
+
+					Free(str);
+				}
+			}
+			break;
+
+		case B_CREATE:
+			// 新規作成
+			if (SmCreateUserDlg(hWnd, s->Hub))
+			{
+				SmUserListRefresh(hWnd, s);
+			}
+			break;
+
+		case B_DELETE:
+			if (s->AllowGroup)
+			{
+				// グループ選択
+				EndDialog(hWnd, INFINITE);
+			}
+			else
+			{
+				// 削除
+				str = LvGetSelectedStr(hWnd, L_USER, 0);
+				if (str != NULL)
+				{
+					RPC_DELETE_USER t;
+					char name[MAX_SIZE];
+					UniToStr(name, sizeof(name), str);
+
+					Zero(&t, sizeof(t));
+					StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+					StrCpy(t.Name, sizeof(t.Name), name);
+
+					if (MsgBoxEx(hWnd, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION,
+						_UU("SM_USER_DELETE_MSG"), str) == IDYES)
+					{
+						if (CALL(hWnd, ScDeleteUser(s->Rpc, &t)))
+						{
+							SmUserListRefresh(hWnd, s);
+						}
+					}
+
+					Free(str);
+				}
+			}
+			break;
+
+		case B_STATUS:
+			// ユーザー情報表示
+			str = LvGetSelectedStr(hWnd, L_USER, 0);
+			if (str != NULL)
+			{
+				char name[MAX_SIZE];
+				wchar_t tmp[MAX_SIZE];
+				SM_USER_INFO info;
+				UniToStr(name, sizeof(name), str);
+
+				UniFormat(tmp, sizeof(tmp), _UU("SM_USERINFO_CAPTION"), name);
+
+				Zero(&info, sizeof(info));
+				info.p = s->p;
+				info.Rpc = s->Rpc;
+				info.Hub = s->Hub;
+				info.Username = name;
+
+				SmStatusDlg(hWnd, s->p, &info, false, true, tmp, ICO_USER, NULL, SmRefreshUserInfo);
+
+				Free(str);
+			}
+			break;
+			break;
+
+		case B_REFRESH:
+			// 更新
+			SmUserListRefresh(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_USER:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				// コントロール更新
+				SmUserListUpdate(hWnd, s);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_USER);
+
+	return 0;
+}
+
+// ユーザーリストダイアログ (選択)
+char *SmSelectUserDlg(HWND hWnd, SM_HUB *s, char *default_name)
+{
+	return SmSelectUserDlgEx(hWnd, s, default_name, false);
+}
+char *SmSelectUserDlgEx(HWND hWnd, SM_HUB *s, char *default_name, bool allow_group)
+{
+	UINT ret;
+	SM_USER user;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&user, sizeof(user));
+	user.Hub = s;
+	user.p = s->p;
+	user.Rpc = s->Rpc;
+	user.GroupName = NULL;
+	user.SelectedName = default_name;
+	user.SelectMode = true;
+	user.AllowGroup = allow_group;
+
+	ret = Dialog(hWnd, D_SM_USER, SmUserListProc, &user);
+
+	if (ret == 0)
+	{
+		return NULL;
+	}
+	else if (ret == INFINITE)
+	{
+		// グループの選択
+		return SmSelectGroupDlg(hWnd, s, default_name);
+	}
+	else
+	{
+		return user.SelectedName;
+	}
+}
+
+// ユーザーリストダイアログ (グループ名でフィルタ)
+void SmUserListDlgEx(HWND hWnd, SM_HUB *s, char *groupname, bool create)
+{
+	SM_USER user;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&user, sizeof(user));
+	user.Hub = s;
+	user.p = s->p;
+	user.Rpc = s->Rpc;
+	user.GroupName = groupname;
+	user.CreateNow = create;
+
+	Dialog(hWnd, D_SM_USER, SmUserListProc, &user);
+}
+
+// ユーザーリストダイアログ
+void SmUserListDlg(HWND hWnd, SM_HUB *s)
+{
+	SmUserListDlgEx(hWnd, s, NULL, false);
+}
+
+// 初期化
+void SmHubDlgInit(HWND hWnd, SM_HUB *s)
+{
+	CAPSLIST *caps;
+	bool support_user, support_group, support_accesslist, support_cascade,
+		support_log, support_config_hub, support_secure_nat, support_config_radius;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	FormatText(hWnd, 0, s->HubName);
+	FormatText(hWnd, S_TITLE, s->HubName);
+	SetIcon(hWnd, 0, ICO_HUB);
+	DlgFont(hWnd, S_TITLE, 15, true);
+
+	LvInit(hWnd, L_STATUS);
+	LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 0);
+	LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 0);
+
+	caps = s->p->CapsList;
+
+	support_user = GetCapsInt(caps, "i_max_users_per_hub") == 0 ? false : true;
+	support_group = GetCapsInt(caps, "i_max_groups_per_hub") == 0 ? false : true;
+	support_accesslist = GetCapsInt(caps, "i_max_access_lists") == 0 ? false : true;
+	support_cascade = GetCapsBool(caps, "b_support_cascade");
+	support_log = GetCapsBool(caps, "b_support_config_log");
+	support_config_hub = GetCapsBool(caps, "b_support_config_hub");
+	support_secure_nat = GetCapsBool(caps, "b_support_securenat");
+	support_config_radius = GetCapsBool(caps, "b_support_radius");
+
+	SetEnable(hWnd, B_USER, support_user);
+	SetEnable(hWnd, S_USER, support_user);
+
+	SetEnable(hWnd, B_GROUP, support_group);
+	SetEnable(hWnd, S_GROUP, support_group);
+
+	SetEnable(hWnd, B_ACCESS, support_accesslist);
+	SetEnable(hWnd, S_ACCESS, support_accesslist);
+
+	SetEnable(hWnd, B_PROPERTY, s->p->ServerType != SERVER_TYPE_FARM_MEMBER);
+	SetEnable(hWnd, S_PROPERTY, s->p->ServerType != SERVER_TYPE_FARM_MEMBER);
+
+	SetEnable(hWnd, B_RADIUS, support_config_radius);
+	SetEnable(hWnd, S_RADIUS, support_config_radius);
+
+	SetEnable(hWnd, B_LINK, support_cascade);
+	SetEnable(hWnd, S_LINK, support_cascade);
+
+	SetEnable(hWnd, B_LOG, support_log);
+	SetEnable(hWnd, S_LOG, support_log);
+
+	SetEnable(hWnd, B_CA, support_config_hub);
+	SetEnable(hWnd, S_CA, support_config_hub);
+
+	SetEnable(hWnd, B_SNAT, support_secure_nat);
+	SetEnable(hWnd, S_SNAT, support_secure_nat);
+
+	SetEnable(hWnd, B_CRL, GetCapsBool(caps, "b_support_crl"));
+
+	SetEnable(hWnd, B_LOG_FILE, GetCapsBool(caps, "b_support_read_log"));
+
+	SmHubDlgRefresh(hWnd, s);
+}
+
+// コントロール更新
+void SmHubDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+}
+
+// 内容更新
+void SmHubDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SmRefreshHubStatus(hWnd, s->p, (void *)s->HubName);
+	LvAutoSize(hWnd, L_STATUS);
+
+	SmHubDlgUpdate(hWnd, s);
+}
+
+// HUB 管理ダイアログ
+UINT SmHubDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_HUB *s = (SM_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmHubDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_USER:
+			// ユーザー
+			SmUserListDlg(hWnd, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_GROUP:
+			// グループ
+			SmGroupListDlg(hWnd, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_ACCESS:
+			// アクセスリスト
+			SmAccessListDlg(hWnd, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_PROPERTY:
+			// プロパティ
+			if (SmEditHubDlg(hWnd, s->p, s->HubName))
+			{
+				SmHubDlgRefresh(hWnd, s);
+			}
+			break;
+
+		case B_RADIUS:
+			// Radius
+			SmRadiusDlg(hWnd, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_LINK:
+			// カスケード
+			SmLinkDlg(hWnd, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_SESSION:
+			// セッション
+			SmSessionDlg(hWnd, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_LOG:
+			// ログ
+			Dialog(hWnd, D_SM_LOG, SmLogDlg, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_CA:
+			// CA
+			SmCaDlg(hWnd, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case B_REFRESH:
+			// 更新
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_SNAT:
+			// SecureNAT
+			Dialog(hWnd, D_SM_SNAT, SmSNATDlgProc, s);
+			SmHubDlgRefresh(hWnd, s);
+			break;
+
+		case B_CRL:
+			// 無効な証明書の一覧
+			Dialog(hWnd, D_SM_CRL, SmCrlDlgProc, s);
+			break;
+
+		case B_LOG_FILE:
+			// ログファイル
+			Dialog(hWnd, D_SM_LOG_FILE, SmLogFileDlgProc, s->p);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// HUB の管理
+void SmHubDlg(HWND hWnd, SM_HUB *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_HUB, SmHubDlgProc, s);
+}
+
+// サーバー パスワードの変更
+UINT SmChangeServerPasswordDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *p = (SM_SERVER *)param;
+	char tmp1[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	RPC_SET_PASSWORD t;
+	SETTING *setting;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SetIcon(hWnd, 0, ICO_USER_ADMIN);
+		FormatText(hWnd, 0, p->ServerName);
+		FormatText(hWnd, S_TITLE, p->ServerName);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+			GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+			if (StrCmp(tmp1, tmp2) != 0)
+			{
+				MsgBox(hWnd, MB_ICONSTOP, _UU("SM_CHANGE_PASSWORD_1"));
+				FocusEx(hWnd, E_PASSWORD2);
+				break;
+			}
+			if (StrLen(tmp1) == 0)
+			{
+				if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_CHANGE_PASSWORD_2")) == IDNO)
+				{
+					Focus(hWnd, E_PASSWORD1);
+					break;
+				}
+			}
+			Zero(&t, sizeof(t));
+			Hash(t.HashedPassword, tmp1, StrLen(tmp1), true);
+			Copy(hash, t.HashedPassword, sizeof(hash));
+			if (CALL(hWnd, ScSetServerPassword(p->Rpc, &t)) == false)
+			{
+				break;
+			}
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_CHANGE_PASSWORD_3"));
+
+			// 接続設定のパスワードを変更する
+			setting = SmGetSetting(p->CurrentSetting->Title);
+			if (setting != NULL && sm->TempSetting == NULL)
+			{
+				if (IsZero(setting->HashedPassword, SHA1_SIZE) == false)
+				{
+					Copy(setting->HashedPassword, hash, SHA1_SIZE);
+					SmWriteSettingList();
+				}
+			}
+
+			EndDialog(hWnd, true);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// サーバー ファーム コントローラへの接続状況更新
+bool SmRefreshFarmConnectionInfo(HWND hWnd, SM_SERVER *p, void *param)
+{
+	RPC_FARM_CONNECTION_STATUS t;
+	LVB *b;
+	wchar_t tmp[MAX_SIZE];
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScGetFarmConnectionStatus(p->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	if (t.Online == false)
+	{
+		LvInsertAdd(b, ICO_FARM, NULL, 2, _UU("SM_FC_IP"), _UU("SM_FC_NOT_CONNECTED"));
+
+		LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_PORT"), _UU("SM_FC_NOT_CONNECTED"));
+	}
+	else
+	{
+		IPToStr32(str, sizeof(str), t.Ip);
+		StrToUni(tmp, sizeof(tmp), str);
+		LvInsertAdd(b, ICO_FARM, NULL, 2, _UU("SM_FC_IP"), tmp);
+
+		UniToStru(tmp, t.Port);
+		LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_PORT"), tmp);
+	}
+
+	LvInsertAdd(b,
+		t.Online ? ICO_SERVER_ONLINE_EX : ICO_PROTOCOL_X, NULL, 2,
+		_UU("SM_FC_STATUS"),
+		t.Online ? _UU("SM_FC_ONLINE") : _UU("SM_FC_OFFLINE"));
+
+	if (t.Online == false)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("SM_FC_ERROR_TAG"), _E(t.LastError), t.LastError);
+		LvInsertAdd(b, ICO_STOP, NULL, 2,
+			_UU("SM_FC_LAST_ERROR"), tmp);
+	}
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartedTime), NULL);
+	LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_FC_START_TIME"), tmp);
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.FirstConnectedTime), NULL);
+	LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_FC_FIRST_TIME"), tmp);
+
+	//if (t.Online == false)
+	{
+		GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CurrentConnectedTime), NULL);
+		LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_FC_CURRENT_TIME"), tmp);
+	}
+
+	UniToStru(tmp, t.NumTry);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_NUM_TRY"), tmp);
+
+	UniToStru(tmp, t.NumConnected);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_NUM_CONNECTED"), tmp);
+
+	UniToStru(tmp, t.NumFailed);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_NUM_FAILED"), tmp);
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	return true;
+}
+
+// 初期化
+void SmFarmMemberDlgInit(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_FARM);
+
+	FormatText(hWnd, S_TITLE, p->ServerName);
+
+	// カラム初期化
+	LvInit(hWnd, L_FARM_MEMBER);
+	LvSetStyle(hWnd, L_FARM_MEMBER, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 0, _UU("SM_FM_COLUMN_1"), 90);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 1, _UU("SM_FM_COLUMN_2"), 150);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 2, _UU("SM_FM_COLUMN_3"), 140);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 3, _UU("SM_FM_COLUMN_4"), 60);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 4, _UU("SM_FM_COLUMN_5"), 80);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 5, _UU("SM_FM_COLUMN_6"), 80);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 6, _UU("SM_FM_COLUMN_7"), 80);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 7, _UU("SM_FM_COLUMN_8"), 160);
+	LvInsertColumn(hWnd, L_FARM_MEMBER, 8, _UU("SM_FM_COLUMN_9"), 160);
+
+	SmFarmMemberDlgRefresh(hWnd, p);
+}
+
+// 更新
+void SmFarmMemberDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	SetEnable(hWnd, IDOK, LvIsSelected(hWnd, L_FARM_MEMBER) && (LvIsMultiMasked(hWnd, L_FARM_MEMBER) == false));
+	SetEnable(hWnd, B_CERT, LvIsSelected(hWnd, L_FARM_MEMBER) && (LvIsMultiMasked(hWnd, L_FARM_MEMBER) == false));
+}
+
+// 内容更新
+void SmFarmMemberDlgRefresh(HWND hWnd, SM_SERVER *p)
+{
+	RPC_ENUM_FARM t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScEnumFarmMember(p->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	LvReset(hWnd, L_FARM_MEMBER);
+
+	for (i = 0;i < t.NumFarm;i++)
+	{
+		RPC_ENUM_FARM_ITEM *e = &t.Farms[i];
+		wchar_t tmp1[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		wchar_t tmp3[64];
+		wchar_t tmp4[64];
+		wchar_t tmp5[64];
+		wchar_t tmp6[64];
+		wchar_t tmp7[64];
+		wchar_t tmp8[64];
+
+		GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+		StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+		UniToStru(tmp3, e->Point);
+		UniToStru(tmp4, e->NumSessions);
+		UniToStru(tmp5, e->NumTcpConnections);
+		UniToStru(tmp6, e->NumHubs);
+		UniToStru(tmp7, e->AssignedClientLicense);
+		UniToStru(tmp8, e->AssignedBridgeLicense);
+
+		LvInsert(hWnd, L_FARM_MEMBER, e->Controller ? ICO_FARM : ICO_TOWER, (void *)e->Id, 9,
+			e->Controller ? _UU("SM_FM_CONTROLLER") : _UU("SM_FM_MEMBER"),
+			tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8);
+	}
+
+	FreeRpcEnumFarm(&t);
+
+	SmFarmMemberDlgUpdate(hWnd, p);
+}
+
+// OK ボタン
+void SmFarmMemberDlgOnOk(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+}
+
+// ファーム メンバ証明書の表示
+void SmFarmMemberCert(HWND hWnd, SM_SERVER *p, UINT id)
+{
+	RPC_FARM_INFO t;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || id == 0)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Id = id;
+
+	if (CALL(hWnd, ScGetFarmInfo(p->Rpc, &t)) == false)
+	{
+		return;
+	}
+
+	CertDlg(hWnd, t.ServerCert, NULL, true);
+
+	FreeRpcFarmInfo(&t);
+}
+
+// ファームメンバ情報の更新
+bool SmRefreshFarmMemberInfo(HWND hWnd, SM_SERVER *p, void *param)
+{
+	RPC_FARM_INFO t;
+	UINT id = (UINT)param;
+	LVB *b;
+	UINT i;
+	wchar_t tmp[MAX_SIZE];
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || id == 0)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	t.Id = id;
+
+	if (CALL(hWnd, ScGetFarmInfo(p->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	LvInsertAdd(b, ICO_FARM, NULL, 2, _UU("SM_FMINFO_TYPE"),
+		t.Controller ? _UU("SM_FARM_CONTROLLER") : _UU("SM_FARM_MEMBER"));
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+	LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_FMINFO_CONNECT_TIME"), tmp);
+
+	IPToStr32(str, sizeof(str), t.Ip);
+	StrToUni(tmp, sizeof(tmp), str);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FMINFO_IP"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.Hostname);
+	LvInsertAdd(b, ICO_TOWER, NULL, 2, _UU("SM_FMINFO_HOSTNAME"), tmp);
+
+	UniToStru(tmp, t.Point);
+	LvInsertAdd(b, ICO_TEST, NULL, 2, _UU("SM_FMINFO_POINT"), tmp);
+
+	UniToStru(tmp, t.Weight);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_FMINFO_WEIGHT"), tmp);
+
+	UniToStru(tmp, t.NumPort);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FMINFO_NUM_PORT"), tmp);
+
+	for (i = 0;i < t.NumPort;i++)
+	{
+		wchar_t tmp2[MAX_SIZE];
+		UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_PORT"), i + 1);
+		UniToStru(tmp2, t.Ports[i]);
+		LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, tmp, tmp2);
+	}
+
+	UniToStru(tmp, t.NumFarmHub);
+	LvInsertAdd(b, ICO_HUB_OFFLINE, NULL, 2, _UU("SM_FMINFO_NUM_HUB"), tmp);
+
+	for (i = 0;i < t.NumFarmHub;i++)
+	{
+		wchar_t tmp2[MAX_SIZE];
+		UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_HUB"), i + 1);
+		UniFormat(tmp2, sizeof(tmp2),
+			t.FarmHubs[i].DynamicHub ? _UU("SM_FMINFO_HUB_TAG_2") : _UU("SM_FMINFO_HUB_TAG_1"),
+			t.FarmHubs[i].HubName);
+		LvInsertAdd(b, ICO_HUB, NULL, 2, tmp, tmp2);
+	}
+
+	UniToStru(tmp, t.NumSessions);
+	LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_FMINFO_NUM_SESSION"), tmp);
+
+	UniToStru(tmp, t.NumTcpConnections);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FMINFO_NUN_CONNECTION"), tmp);
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	FreeRpcFarmInfo(&t);
+
+	return true;
+}
+
+// ファームメンバ一覧ダイアログ
+UINT SmFarmMemberDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *p = (SM_SERVER *)param;
+	NMHDR *n;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmFarmMemberDlgInit(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			// ファーム メンバの情報を表示
+			i = LvGetSelected(hWnd, L_FARM_MEMBER);
+			if (i != INFINITE)
+			{
+				SmStatusDlg(hWnd, p, LvGetParam(hWnd, L_FARM_MEMBER, i), false, true,
+					_UU("SM_FMINFO_CAPTION"), ICO_FARM, NULL, SmRefreshFarmMemberInfo);
+			}
+			break;
+
+		case B_CERT:
+			// サーバー証明書の表示
+			i = LvGetSelected(hWnd, L_FARM_MEMBER);
+			if (i != INFINITE)
+			{
+				SmFarmMemberCert(hWnd, p, (UINT)LvGetParam(hWnd, L_FARM_MEMBER, i));
+			}
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case B_REFRESH:
+			// 更新
+			SmFarmMemberDlgRefresh(hWnd, p);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->code)
+		{
+		case LVN_ITEMCHANGED:
+			switch (n->idFrom)
+			{
+			case L_FARM_MEMBER:
+				SmFarmMemberDlgUpdate(hWnd, p);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_FARM_MEMBER);
+
+	return 0;
+}
+
+// 文字列をポートリストに変換
+LIST *SmStrToPortList(char *str)
+{
+	return StrToPortList(str);
+}
+
+// ダイアログ初期化
+void SmFarmDlgInit(HWND hWnd, SM_SERVER *p)
+{
+	RPC_FARM t;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_FARM);
+
+	// 現在の設定を取得
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScGetFarmSetting(p->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	if (t.Weight == 0)
+	{
+		t.Weight = FARM_DEFAULT_WEIGHT;
+	}
+
+	FormatText(hWnd, S_TITLE, p->ServerName);
+	DlgFont(hWnd, S_CURRENT, 11, true);
+
+	SetText(hWnd, S_CURRENT, GetServerTypeStr(t.ServerType));
+
+	switch (t.ServerType)
+	{
+	case SERVER_TYPE_FARM_CONTROLLER:
+		Check(hWnd, R_CONTROLLER, true);
+		break;
+
+	case SERVER_TYPE_FARM_MEMBER:
+		Check(hWnd, R_MEMBER, true);
+		break;
+
+	default:
+		Check(hWnd, R_STANDALONE, true);
+		break;
+	}
+
+	SetInt(hWnd, E_WEIGHT, t.Weight);
+
+	if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		Check(hWnd, R_CONTROLLER_ONLY, t.ControllerOnly);
+	}
+
+	if (t.ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		char tmp[MAX_PUBLIC_PORT_NUM * 8];
+		UINT i;
+		if (t.PublicIp != 0)
+		{
+			IpSet(hWnd, E_IP, t.PublicIp);
+		}
+		StrCpy(tmp, sizeof(tmp), "");
+		if (t.NumPort != 0)
+		{
+			for (i = 0;i < t.NumPort;i++)
+			{
+				Format(tmp, sizeof(tmp), "%s%u", tmp, t.Ports[i]);
+				if (i != (t.NumPort - 1))
+				{
+					StrCat(tmp, sizeof(tmp), ", ");
+				}
+			}
+			SetTextA(hWnd, E_PORT, tmp);
+		}
+		SetTextA(hWnd, E_CONTROLLER, t.ControllerName);
+		SetIntEx(hWnd, E_CONTROLLER_PORT, t.ControllerPort);
+		SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+	}
+	else
+	{
+		// ポート一覧を書き込む
+		RPC_LISTENER_LIST t;
+		char tmp[MAX_PUBLIC_PORT_NUM * 8];
+		Zero(&t, sizeof(t));
+		StrCpy(tmp, sizeof(tmp), "");
+		if (CALL(hWnd, ScEnumListener(p->Rpc, &t)))
+		{
+			UINT i;
+			if (t.NumPort != 0)
+			{
+				for (i = 0;i < t.NumPort;i++)
+				{
+					Format(tmp, sizeof(tmp), "%s%u", tmp, t.Ports[i]);
+					if (i != (t.NumPort - 1))
+					{
+						StrCat(tmp, sizeof(tmp), ", ");
+					}
+				}
+				SetTextA(hWnd, E_PORT, tmp);
+			}
+			FreeRpcListenerList(&t);
+		}
+	}
+
+	SmFarmDlgUpdate(hWnd, p);
+
+	FreeRpcFarm(&t);
+
+	Focus(hWnd, IDOK);
+}
+
+// ダイアログ更新
+void SmFarmDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+	bool ok = true;
+	bool farm_member_control = false;
+	char *s;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (IsChecked(hWnd, R_MEMBER))
+	{
+		LIST *o;
+		UINT i = IpGetFilledNum(hWnd, E_IP);
+		if (i != 0 && i != 4)
+		{
+			ok = false;
+		}
+
+		s = GetTextA(hWnd, E_PORT);
+		o = SmStrToPortList(s);
+		if (o == NULL)
+		{
+			ok = false;
+		}
+		else
+		{
+			ReleaseList(o);
+		}
+		Free(s);
+
+		if (IsEmpty(hWnd, E_CONTROLLER))
+		{
+			ok = false;
+		}
+
+		i = GetInt(hWnd, E_CONTROLLER_PORT);
+		if (i == 0 || i >= 65536)
+		{
+			ok = false;
+		}
+
+		farm_member_control = true;
+	}
+
+	if (IsChecked(hWnd, R_STANDALONE))
+	{
+		Disable(hWnd, S_1);
+		Disable(hWnd, S_2);
+		Disable(hWnd, E_WEIGHT);
+	}
+	else
+	{
+		Enable(hWnd, S_1);
+		Enable(hWnd, S_2);
+		Enable(hWnd, E_WEIGHT);
+	}
+
+	if (IsChecked(hWnd, R_CONTROLLER))
+	{
+		Enable(hWnd, R_CONTROLLER_ONLY);
+	}
+	else
+	{
+		Disable(hWnd, R_CONTROLLER_ONLY);
+	}
+
+	if (IsChecked(hWnd, R_CONTROLLER) || IsChecked(hWnd, R_MEMBER))
+	{
+		if (GetInt(hWnd, E_WEIGHT) == 0)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, S_IP_1, farm_member_control);
+	SetEnable(hWnd, E_IP, farm_member_control);
+	SetEnable(hWnd, S_IP_2, farm_member_control);
+	SetEnable(hWnd, S_PORT_1, farm_member_control);
+	SetEnable(hWnd, E_PORT, farm_member_control);
+	SetEnable(hWnd, S_PORT_2, farm_member_control);
+	SetEnable(hWnd, S_PORT_3, farm_member_control);
+	SetEnable(hWnd, E_CONTROLLER, farm_member_control);
+	SetEnable(hWnd, S_CONTROLLER, farm_member_control);
+	SetEnable(hWnd, E_CONTROLLER_PORT, farm_member_control);
+	SetEnable(hWnd, S_CONTROLLER_PORT, farm_member_control);
+	SetEnable(hWnd, S_PASSWORD, farm_member_control);
+	SetEnable(hWnd, E_PASSWORD, farm_member_control);
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// OK ボタン
+void SmFarmDlgOnOk(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// メッセージ表示
+	if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_OKCANCEL | MB_DEFBUTTON2,
+		_UU("SM_FARM_REBOOT_MSG")) == IDOK)
+	{
+		RPC_FARM t;
+		Zero(&t, sizeof(t));
+		t.ServerType = SERVER_TYPE_STANDALONE;
+		if (IsChecked(hWnd, R_CONTROLLER))
+		{
+			t.ServerType = SERVER_TYPE_FARM_CONTROLLER;
+		}
+		if (IsChecked(hWnd, R_MEMBER))
+		{
+			t.ServerType = SERVER_TYPE_FARM_MEMBER;
+		}
+
+		t.ControllerOnly = IsChecked(hWnd, R_CONTROLLER_ONLY);
+		t.Weight = GetInt(hWnd, E_WEIGHT);
+
+		if (t.ServerType == SERVER_TYPE_FARM_MEMBER)
+		{
+			char *s;
+			char pass[MAX_SIZE];
+			t.PublicIp = IpGet(hWnd, E_IP);
+			s = GetTextA(hWnd, E_PORT);
+			if (s != NULL)
+			{
+				LIST *o = SmStrToPortList(s);
+				if (o != NULL)
+				{
+					UINT i;
+					t.NumPort = LIST_NUM(o);
+					t.Ports = ZeroMalloc(sizeof(UINT) * t.NumPort);
+					for (i = 0;i < t.NumPort;i++)
+					{
+						t.Ports[i] = (UINT)LIST_DATA(o, i);
+					}
+					ReleaseList(o);
+				}
+				Free(s);
+			}
+			GetTxtA(hWnd, E_CONTROLLER, t.ControllerName, sizeof(t.ControllerName));
+			t.ControllerPort = GetInt(hWnd, E_CONTROLLER_PORT);
+			GetTxtA(hWnd, E_PASSWORD, pass, sizeof(pass));
+			if (StrCmp(pass, HIDDEN_PASSWORD) != 0)
+			{
+				Hash(t.MemberPassword, pass, StrLen(pass), true);
+			}
+		}
+
+		// 設定更新
+		if (CALL(hWnd, ScSetFarmSetting(p->Rpc, &t)) == false)
+		{
+			return;
+		}
+
+		FreeRpcFarm(&t);
+
+		EndDialog(hWnd, true);
+	}
+}
+
+// サーバー ファーム ダイアログ プロシージャ
+UINT SmFarmDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *p = (SM_SERVER *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmFarmDlgInit(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_STANDALONE:
+		case R_CONTROLLER:
+		case R_MEMBER:
+		case E_IP:
+		case E_PORT:
+		case E_CONTROLLER:
+		case E_CONTROLLER_PORT:
+		case E_PASSWORD:
+		case R_CONTROLLER_ONLY:
+		case E_WEIGHT:
+			SmFarmDlgUpdate(hWnd, p);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmFarmDlgOnOk(hWnd, p);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case R_MEMBER:
+			if (IsChecked(hWnd, R_MEMBER))
+			{
+				Focus(hWnd, E_IP);
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// サーバー ファーム構成
+bool SmFarmDlg(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	return Dialog(hWnd, D_SM_FARM, SmFarmDlgProc, p);
+}
+
+// コネクション情報の更新
+bool SmRefreshConnectionStatus(HWND hWnd, SM_SERVER *p, void *param)
+{
+	RPC_CONNECTION_INFO t;
+	SM_CONNECTION_INFO *info = (SM_CONNECTION_INFO *)param;
+	LVB *b;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || param == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.Name, sizeof(t.Name), info->ConnectionName);
+	if (CALL(hWnd, ScGetConnectionInfo(p->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	StrToUni(tmp, sizeof(tmp), t.Name);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_CONNINFO_NAME"), tmp);
+
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_TYPE"), SmGetConnectionTypeStr(t.Type));
+
+	StrToUni(tmp, sizeof(tmp), t.Hostname);
+	LvInsertAdd(b, ICO_FARM, NULL, 2, _UU("SM_CONNINFO_HOSTNAME"), tmp);
+
+	UniToStru(tmp, t.Port);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_CONNINFO_PORT"), tmp);
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+	LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_CONNINFO_TIME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.ServerStr);
+	LvInsertAdd(b, ICO_VPNSERVER, NULL, 2, _UU("SM_CONNINFO_SERVER_STR"), tmp);
+
+	UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ServerVer / 100, t.ServerVer % 100);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_SERVER_VER"), tmp);
+
+	UniToStru(tmp, t.ServerBuild);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_SERVER_BUILD"), tmp);
+
+	if (StrLen(t.ClientStr) != 0)
+	{
+		StrToUni(tmp, sizeof(tmp), t.ClientStr);
+		LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_CONNINFO_CLIENT_STR"), tmp);
+
+		UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ClientVer / 100, t.ClientVer % 100);
+		LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_CLIENT_VER"), tmp);
+
+		UniToStru(tmp, t.ClientBuild);
+		LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_CLIENT_BUILD"), tmp);
+	}
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	return true;
+}
+
+// 初期化
+void SmConnectionDlgInit(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_PROTOCOL);
+	FormatText(hWnd, S_TITLE, p->ServerName);
+
+	// カラム初期化
+	LvInit(hWnd, L_LIST);
+	LvSetStyle(hWnd, L_LIST, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_CONN_COLUMN_1"), 90);
+	LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_CONN_COLUMN_2"), 150);
+	LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_CONN_COLUMN_3"), 200);
+	LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_CONN_COLUMN_4"), 80);
+
+	SmConnectionDlgRefresh(hWnd, p);
+	SmConnectionDlgUpdate(hWnd, p);
+}
+
+// 更新
+void SmConnectionDlgRefresh(HWND hWnd, SM_SERVER *p)
+{
+	LVB *b;
+	UINT i;
+	RPC_ENUM_CONNECTION t;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScEnumConnection(p->Rpc, &t)) == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	b = LvInsertStart();
+
+	for (i = 0;i < t.NumConnection;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		wchar_t name[MAX_SIZE];
+		wchar_t datetime[MAX_SIZE];
+		RPC_ENUM_CONNECTION_ITEM *e = &t.Connections[i];
+
+		StrToUni(name, sizeof(name), e->Name);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_HOSTNAME_AND_PORT"), e->Hostname, e->Port);
+		GetDateTimeStrEx64(datetime, sizeof(datetime), SystemToLocal64(e->ConnectedTime), NULL);
+
+		LvInsertAdd(b, ICO_PROTOCOL, NULL, 4, name, tmp, datetime,
+			SmGetConnectionTypeStr(e->Type));
+	}
+
+	LvInsertEnd(b, hWnd, L_LIST);
+
+	FreeRpcEnumConnetion(&t);
+}
+
+// コントロール更新
+void SmConnectionDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+	bool b = false;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_LIST) && (LvIsMultiMasked(hWnd, L_LIST) == false))
+	{
+		b = true;
+	}
+
+	SetEnable(hWnd, IDOK, b);
+	SetEnable(hWnd, B_DISCONNECT, b && p->ServerAdminMode);
+}
+
+// コネクション一覧プロシージャ
+UINT SmConnectionDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *p = (SM_SERVER *)param;
+	NMHDR *n;
+	wchar_t *s;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmConnectionDlgInit(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			// コネクション情報を表示
+			s = LvGetSelectedStr(hWnd, L_LIST, 0);
+			if (s != NULL)
+			{
+				wchar_t caption[MAX_SIZE];
+				SM_CONNECTION_INFO info;
+				UniFormat(caption, sizeof(caption), _UU("SM_CONNINFO_CAPTION"),
+					s);
+				Zero(&info, sizeof(info));
+				info.ConnectionName = CopyUniToStr(s);
+				info.p = p;
+				SmStatusDlg(hWnd, p, &info, false, false, caption, ICO_PROTOCOL,
+					NULL, SmRefreshConnectionStatus);
+				Free(info.ConnectionName);
+				Free(s);
+			}
+			break;
+
+		case B_DISCONNECT:
+			// 切断
+			s = LvGetSelectedStr(hWnd, L_LIST, 0);
+			if (s != NULL)
+			{
+				if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+					_UU("SM_CONN_DISCONNECT_MSG"), s) == IDYES)
+				{
+					char tmp[MAX_SIZE];
+					RPC_DISCONNECT_CONNECTION t;
+
+					UniToStr(tmp, sizeof(tmp), s);
+					Zero(&t, sizeof(t));
+					StrCpy(t.Name, sizeof(t.Name), tmp);
+
+					if (CALL(hWnd, ScDisconnectConnection(p->Rpc, &t)))
+					{
+						SmConnectionDlgRefresh(hWnd, p);
+					}
+				}
+				Free(s);
+			}
+			break;
+
+		case B_REFRESH:
+			// 最新の状態に更新
+			SmConnectionDlgRefresh(hWnd, p);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_LIST:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmConnectionDlgUpdate(hWnd, p);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+	return 0;
+}
+
+// コネクション一覧の表示
+void SmConnectionDlg(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Dialog(hWnd, D_SM_CONNECTION, SmConnectionDlgProc, p);
+}
+
+// コネクション種類文字列の取得
+wchar_t *SmGetConnectionTypeStr(UINT type)
+{
+	return GetConnectionTypeStr(type);
+}
+
+// サーバー情報の更新
+bool SmRefreshServerInfo(HWND hWnd, SM_SERVER *p, void *param)
+{
+	RPC_SERVER_INFO t;
+	LVB *b;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScGetServerInfo(p->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	// 製品名
+	StrToUni(tmp, sizeof(tmp), t.ServerProductName);
+	LvInsertAdd(b, ICO_VPNSERVER, NULL, 2, _UU("SM_INFO_PRODUCT_NAME"), tmp);
+
+	// バージョン
+	StrToUni(tmp, sizeof(tmp), t.ServerVersionString);
+	LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_INFO_VERSION"), tmp);
+
+	// ビルド
+	StrToUni(tmp, sizeof(tmp), t.ServerBuildInfoString);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_INFO_BUILD"), tmp);
+
+	// ホスト名
+	StrToUni(tmp, sizeof(tmp), t.ServerHostName);
+	LvInsertAdd(b, ICO_TOWER, NULL, 2, _UU("SM_INFO_HOSTNAME"), tmp);
+
+	// 種類
+	LvInsertAdd(b, t.ServerType == SERVER_TYPE_STANDALONE ? ICO_SERVER_ONLINE : ICO_FARM, 0,
+		2, _UU("SM_ST_SERVER_TYPE"),
+		GetServerTypeStr(t.ServerType));
+
+	// OS
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsSystemName);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SYSTEM_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsProductName);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_PRODUCT_NAME"), tmp);
+
+	if (t.OsInfo.OsServicePack != 0)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("SM_OS_SP_TAG"), t.OsInfo.OsServicePack);
+		LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SERVICE_PACK"), tmp);
+	}
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVendorName);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VENDER_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVersion);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VERSION"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelName);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_NAME"), tmp);
+
+	StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelVersion);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_VERSION"), tmp);
+
+	SmAddServerCaps(b, p->CapsList);
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	FreeRpcServerInfo(&t);
+
+	return true;
+}
+
+// サーバーの Caps を画面に表示する
+void SmAddServerCaps(LVB *b, CAPSLIST *t)
+{
+	UINT i;
+	// 引数チェック
+	if (b == NULL || t == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(t->CapsList);i++)
+	{
+		CAPS *c = LIST_DATA(t->CapsList, i);
+		wchar_t title[MAX_SIZE];
+		char name[256];
+
+		Format(name, sizeof(name), "CT_%s", c->Name);
+
+		UniStrCpy(title, sizeof(title), _UU(name));
+
+		if (UniIsEmptyStr(title))
+		{
+			UniFormat(title, sizeof(title), L"%S", (StrLen(c->Name) >= 2) ? c->Name + 2 : c->Name);
+		}
+
+		if (StartWith(c->Name, "b_"))
+		{
+			bool icon_pass = c->Value == 0 ? false : true;
+			if (StrCmpi(c->Name, "b_must_install_pcap") == 0)
+			{
+				// WinPcap の項目のみ反転する
+				icon_pass = !icon_pass;
+			}
+			LvInsertAdd(b, icon_pass == false ? ICO_DISCARD : ICO_PASS,
+				NULL, 2, title, c->Value == 0 ? _UU("CAPS_NO") : _UU("CAPS_YES"));
+		}
+		else
+		{
+			wchar_t str[64];
+			UniToStru(str, c->Value);
+			LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, title, str);
+		}
+	}
+}
+
+// サーバー状態の更新
+bool SmRefreshServerStatus(HWND hWnd, SM_SERVER *p, void *param)
+{
+	RPC_SERVER_STATUS t;
+	LVB *b;
+	wchar_t tmp[MAX_SIZE];
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScGetServerStatus(p->Rpc, &t)) == false)
+	{
+		return false;
+	}
+
+	b = LvInsertStart();
+
+	// サーバーの種類
+	LvInsertAdd(b, t.ServerType == SERVER_TYPE_STANDALONE ? ICO_SERVER_ONLINE : ICO_FARM, 0,
+		2, _UU("SM_ST_SERVER_TYPE"),
+		GetServerTypeStr(t.ServerType));
+
+	// TCP コネクション数
+	UniToStru(tmp, t.NumTcpConnections);
+	LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_ST_NUM_TCP"), tmp);
+
+	if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// ローカル TCP コネクション数
+		UniToStru(tmp, t.NumTcpConnectionsLocal);
+		LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_ST_NUM_TCP_LOCAL"), tmp);
+
+		// リモート TCP コネクション数
+		UniToStru(tmp, t.NumTcpConnectionsRemote);
+		LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_ST_NUM_TCP_REMOTE"), tmp);
+	}
+
+	// 仮想 HUB 数
+	UniToStru(tmp, t.NumHubTotal);
+	LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_ST_NUM_HUB_TOTAL"), tmp);
+
+	if (t.ServerType != SERVER_TYPE_STANDALONE)
+	{
+		// スタティック HUB 数
+		UniToStru(tmp, t.NumHubStatic);
+		LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_ST_NUM_HUB_STATIC"), tmp);
+
+		// ダイナミック HUB 数
+		UniToStru(tmp, t.NumHubDynamic);
+		LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_ST_NUM_HUB_DYNAMIC"), tmp);
+	}
+
+	// セッション数
+	UniToStru(tmp, t.NumSessionsTotal);
+	LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_ST_NUM_SESSION_TOTAL"), tmp);
+
+	if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// ローカルセッション数
+		UniToStru(tmp, t.NumSessionsLocal);
+		LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_ST_NUM_SESSION_LOCAL"), tmp);
+
+		// ローカルセッション数
+		UniToStru(tmp, t.NumSessionsRemote);
+		LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_ST_NUM_SESSION_REMOTE"), tmp);
+	}
+
+	// MAC テーブル数
+	UniToStru(tmp, t.NumMacTables);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_ST_NUM_MAC_TABLE"), tmp);
+
+	// IP テーブル数
+	UniToStru(tmp, t.NumIpTables);
+	LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_ST_NUM_IP_TABLE"), tmp);
+
+	// ユーザー数
+	UniToStru(tmp, t.NumUsers);
+	LvInsertAdd(b, ICO_USER, NULL, 2, _UU("SM_ST_NUM_USERS"), tmp);
+
+	// グループ数
+	UniToStru(tmp, t.NumGroups);
+	LvInsertAdd(b, ICO_GROUP, NULL, 2, _UU("SM_ST_NUM_GROUPS"), tmp);
+
+	// 割り当て済みライセンス数
+	UniToStru(tmp, t.AssignedClientLicenses);
+	LvInsertAdd(b, ICO_CERT, NULL, 2, _UU("SM_ST_CLIENT_LICENSE"), tmp);
+	UniToStru(tmp, t.AssignedBridgeLicenses);
+	LvInsertAdd(b, ICO_CERT, NULL, 2, _UU("SM_ST_BRIDGE_LICENSE"), tmp);
+
+	if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		UniToStru(tmp, t.AssignedClientLicensesTotal);
+		LvInsertAdd(b, ICO_CERT, NULL, 2, _UU("SM_ST_CLIENT_LICENSE_EX"), tmp);
+		UniToStru(tmp, t.AssignedBridgeLicensesTotal);
+		LvInsertAdd(b, ICO_CERT, NULL, 2, _UU("SM_ST_BRIDGE_LICENSE_EX"), tmp);
+	}
+
+	// トラフィック
+	SmInsertTrafficInfo(b, &t.Traffic);
+
+	// サーバー起動時刻
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartTime), NULL);
+	LvInsertAdd(b, ICO_NULL, NULL, 2, _UU("SM_ST_START_TIME"), tmp);
+
+	// 現在時刻
+	GetDateTimeStrMilli64(str, sizeof(str), SystemToLocal64(t.CurrentTime));
+	StrToUni(tmp, sizeof(tmp), str);
+	LvInsertAdd(b, ICO_NULL, NULL, 2, _UU("SM_ST_CURRENT_TIME"), tmp);
+
+	// Tick 値
+	UniFormat(tmp, sizeof(tmp), L"%I64u", t.CurrentTick);
+	LvInsertAdd(b, ICO_NULL, NULL, 2, _UU("SM_ST_CURRENT_TICK"), tmp);
+
+	// メモリ情報
+	if (t.MemInfo.TotalMemory != 0)
+	{
+		char vv[128];
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.TotalMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.UsedMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.FreeMemory);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_MEMORY"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.TotalPhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_PHYS"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.UsedPhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_PHYS"), tmp);
+
+		ToStr3(vv, sizeof(vv), t.MemInfo.FreePhys);
+		UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+		LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_PHYS"), tmp);
+	}
+
+	LvInsertEnd(b, hWnd, L_STATUS);
+
+	return true;
+}
+
+// 初期化
+void SmSaveKeyPairDlgInit(HWND hWnd, SM_SAVE_KEY_PAIR *s)
+{
+	UINT current;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	current = MsRegReadInt(REG_CURRENT_USER, SM_REG_KEY, "SavePkcs12");
+
+	if (current == 1)
+	{
+		Check(hWnd, R_PKCS12, true);
+	}
+	else if (current == 2)
+	{
+		Check(hWnd, R_SECURE, true);
+	}
+	else
+	{
+		Check(hWnd, R_X509_AND_KEY, true);
+	}
+
+	SmSaveKeyPairDlgUpdate(hWnd, s);
+}
+
+// 更新
+void SmSaveKeyPairDlgUpdate(HWND hWnd, SM_SAVE_KEY_PAIR *s)
+{
+	SECURE_DEVICE *dev;
+	bool ok = true;
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	dev = GetSecureDevice(SmGetCurrentSecureIdFromReg());
+	if (dev == NULL)
+	{
+		UniStrCpy(tmp, sizeof(tmp), _UU("SEC_CURRENT_NO_DEVICE"));
+	}
+	else
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("SEC_CURRENT_DEVICE"), dev->DeviceName);
+	}
+
+	SetText(hWnd, S_INFO, tmp);
+
+	if (IsChecked(hWnd, R_USE_PASS))
+	{
+		char *s1, *s2;
+		s1 = GetTextA(hWnd, E_PASS1);
+		s2 = GetTextA(hWnd, E_PASS2);
+		if (StrCmp(s1, s2) != 0)
+		{
+			ok = false;
+		}
+		Free(s1);
+		Free(s2);
+	}
+
+	if (IsChecked(hWnd, R_SECURE))
+	{
+		if (dev == NULL)
+		{
+			ok = false;
+		}
+	}
+
+	SetEnable(hWnd, B_SELECT, IsChecked(hWnd, R_SECURE));
+	SetEnable(hWnd, B_SECURE_MANAGER, IsChecked(hWnd, R_SECURE));
+	SetEnable(hWnd, S_INFO, IsChecked(hWnd, R_SECURE));
+
+	SetEnable(hWnd, E_PASS1, IsChecked(hWnd, R_USE_PASS) && (IsChecked(hWnd, R_SECURE) == false));
+	SetEnable(hWnd, E_PASS2, IsChecked(hWnd, R_USE_PASS) && (IsChecked(hWnd, R_SECURE) == false));
+	SetEnable(hWnd, S_PASS1, IsChecked(hWnd, R_USE_PASS) && (IsChecked(hWnd, R_SECURE) == false));
+	SetEnable(hWnd, S_PASS2, IsChecked(hWnd, R_USE_PASS) && (IsChecked(hWnd, R_SECURE) == false));
+	SetEnable(hWnd, R_USE_PASS, (IsChecked(hWnd, R_SECURE) == false));
+	SetEnable(hWnd, S_PASS3, (IsChecked(hWnd, R_SECURE) == false));
+	SetEnable(hWnd, S_PASS4, (IsChecked(hWnd, R_SECURE) == false));
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// OK ボタン
+void SmSaveKeyPairDlgOnOk(HWND hWnd, SM_SAVE_KEY_PAIR *s)
+{
+	UINT pkcs12;
+	char pass[MAX_SIZE];
+	char *password;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	pkcs12 = 0;
+
+	if (IsChecked(hWnd, R_PKCS12))
+	{
+		pkcs12 = 1;
+	}
+	else if (IsChecked(hWnd, R_SECURE))
+	{
+		pkcs12 = 2;
+	}
+	MsRegWriteInt(REG_CURRENT_USER, SM_REG_KEY, "SavePkcs12", pkcs12);
+
+	if (pkcs12 != 2)
+	{
+		GetTxtA(hWnd, E_PASS1, pass, sizeof(pass));
+
+		if (StrLen(pass) != 0)
+		{
+			password = pass;
+		}
+		else
+		{
+			password = NULL;
+		}
+
+		if (pkcs12 == false)
+		{
+			// X509 と KEY に書き込む
+			wchar_t *x509_name, *key_name;
+			x509_name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), NULL, L".cer");
+			if (x509_name == NULL)
+			{
+				// キャンセル
+				return;
+			}
+			else
+			{
+				wchar_t default_key_name[MAX_SIZE];
+				UniReplaceStrEx(default_key_name, sizeof(default_key_name), x509_name,
+					L".cer", L"", false);
+				UniReplaceStrEx(default_key_name, sizeof(default_key_name), default_key_name,
+								L".crt", L"", false);
+				UniStrCat(default_key_name, sizeof(default_key_name), L".key");
+				key_name = SaveDlg(hWnd, _UU("DLG_KEY_FILTER"), _UU("DLG_SAVE_KEY"),
+					default_key_name, L".key");
+				if (key_name == NULL)
+				{
+					// キャンセル
+					Free(x509_name);
+					return;
+				}
+				else
+				{
+					bool ok = true;
+					char filename1[MAX_SIZE];
+					char filename2[MAX_SIZE];
+
+					UniToStr(filename1, sizeof(filename1), x509_name);
+					UniToStr(filename2, sizeof(filename2), key_name);
+
+					// 証明書の保存
+					if (XToFile(s->Cert, filename1, true) == false)
+					{
+						MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
+						ok = false;
+					}
+					else
+					{
+						if (KToFile(s->Key, filename2, true, password) == false)
+						{
+							MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_KEY_SAVE_ERROR"));
+							ok = false;
+						}
+					}
+
+					if (ok)
+					{
+						MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_KEY_PAIR_SAVE_OK"));
+						EndDialog(hWnd, true);
+					}
+
+					Free(key_name);
+				}
+				Free(x509_name);
+			}
+		}
+		else
+		{
+			// PKCS#12 に書き込む
+			wchar_t *name = SaveDlg(hWnd, _UU("DLG_PKCS12_FILTER"), _UU("DLG_SAVE_P12"), NULL, L".p12");
+			if (name == NULL)
+			{
+				// キャンセル
+				return;
+			}
+			else
+			{
+				P12 *p12;
+				char filename[MAX_SIZE];
+				UniToStr(filename, sizeof(filename), name);
+
+				// PKCS#12 に変換
+				p12 = NewP12(s->Cert, s->Key, pass);
+				if (p12 == NULL)
+				{
+					// 失敗
+					MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_KEY_PAIR_SAVE_OK"));
+				}
+				else
+				{
+					// 保存
+					if (P12ToFile(p12, filename) == false)
+					{
+						// 失敗
+						MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_KEY_PAIR_SAVE_OK"));
+					}
+					else
+					{
+						// 成功
+						MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_KEY_PAIR_SAVE_OK"));
+						EndDialog(hWnd, true);
+					}
+					FreeP12(p12);
+				}
+
+				Free(name);
+			}
+		}
+	}
+	else
+	{
+		char default_name[MAX_SIZE];
+		char *object_name;
+		bool ok = false;
+		X *x;
+		K *k;
+		WINUI_SECURE_BATCH batch[] =
+		{
+			{WINUI_SECURE_WRITE_CERT, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+			{WINUI_SECURE_WRITE_KEY, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+		};
+
+		x = s->Cert;
+		k = s->Key;
+
+		// デフォルトの名前を生成する
+		GetPrintNameFromXA(default_name, sizeof(default_name), x);
+		ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+		object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+			_UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_CERT, false, false);
+
+		if (object_name != NULL)
+		{
+			// 書き込みと列挙
+			batch[0].InputX = x;
+			batch[0].Name = object_name;
+			batch[1].InputK = k;
+			batch[1].Name = object_name;
+
+			if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), SmGetCurrentSecureIdFromReg(), 0) == false)
+			{
+				// 失敗
+			}
+			else
+			{
+				ok = true;
+			}
+
+			Free(object_name);
+		}
+
+		if (ok)
+		{
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_NEW_CERT_IMPORT_OK"));
+
+			EndDialog(hWnd, true);
+		}
+	}
+}
+
+// 証明書と秘密鍵の保存ダイアログ
+UINT SmSaveKeyPairDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SAVE_KEY_PAIR *s = (SM_SAVE_KEY_PAIR *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmSaveKeyPairDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_PASS1:
+		case E_PASS2:
+		case R_USE_PASS:
+		case R_SECURE:
+		case R_X509_AND_KEY:
+		case R_PKCS12:
+			SmSaveKeyPairDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmSaveKeyPairDlgOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case R_USE_PASS:
+			if (IsChecked(hWnd, R_USE_PASS))
+			{
+				FocusEx(hWnd, E_PASS1);
+			}
+			break;
+
+		case B_SELECT:
+			SmSelectSecureId(hWnd);
+			SmSaveKeyPairDlgUpdate(hWnd, s);
+			break;
+
+		case B_SECURE_MANAGER:
+			CmSecureManagerEx(hWnd, SmGetCurrentSecureId(hWnd), true);
+			SmSaveKeyPairDlgUpdate(hWnd, s);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 証明書と秘密鍵を保存する
+bool SmSaveKeyPairDlg(HWND hWnd, X *x, K *k)
+{
+	SM_SAVE_KEY_PAIR s;
+	// 引数チェック
+	if (hWnd == NULL || x == NULL || k == NULL)
+	{
+		return false;
+	}
+
+	Zero(&s, sizeof(s));
+	s.Cert = x;
+	s.Key = k;
+
+	return Dialog(hWnd,	D_SM_SAVE_KEY_PAIR, SmSaveKeyPairDlgProc, &s);
+}
+
+// SSL 関係ダイアログで OK がクリックされた
+void SmSslDlgOnOk(HWND hWnd, SM_SSL *s)
+{
+	char *name;
+	RPC_KEEP t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (s->p->ServerAdminMode == false)
+	{
+		EndDialog(hWnd, false);
+		return;
+	}
+
+	name = GetTextA(hWnd, C_CIPHER);
+	if (name == NULL)
+	{
+		return;
+	}
+	else
+	{
+		RPC_STR t;
+		Zero(&t, sizeof(t));
+		t.String = name;
+
+		// 暗号化アルゴリズムの設定
+		if (CALL(hWnd, ScSetServerCipher(s->p->Rpc, &t)) == false)
+		{
+			Focus(hWnd, C_CIPHER);
+			return;
+		}
+		FreeRpcStr(&t);
+	}
+
+	if (s->SetCertAndKey)
+	{
+		// 証明書のセット
+		RPC_KEY_PAIR t;
+		Zero(&t, sizeof(t));
+
+		t.Cert = CloneX(s->Cert);
+		t.Key = CloneK(s->Key);
+
+		if (CALL(hWnd, ScSetServerCert(s->p->Rpc, &t)) == false)
+		{
+			return;
+		}
+		FreeRpcKeyPair(&t);
+
+		MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_CERT_SET_MSG"));
+	}
+
+	Zero(&t, sizeof(t));
+	t.UseKeepConnect = IsChecked(hWnd, R_USE_KEEP_CONNECT);
+	GetTxtA(hWnd, E_HOSTNAME, t.KeepConnectHost, sizeof(t.KeepConnectHost));
+	t.KeepConnectPort = GetInt(hWnd, E_PORT);
+	t.KeepConnectInterval = GetInt(hWnd, E_INTERVAL);
+	t.KeepConnectProtocol = IsChecked(hWnd, R_UDP) ? 1 : 0;
+
+	CALL(hWnd, ScSetKeep(s->p->Rpc, &t));
+
+	if (GetCapsBool(s->p->CapsList, "b_support_syslog"))
+	{
+		if (s->p->ServerAdminMode)
+		{
+			SYSLOG_SETTING set;
+
+			Zero(&set, sizeof(set));
+			GetTxtA(hWnd, E_SYSLOG_HOSTNAME, set.Hostname, sizeof(set.Hostname));
+			set.Port = GetInt(hWnd, E_SYSLOG_PORT);
+			set.SaveType = CbGetSelect(hWnd, C_SYSLOG);
+
+			if (CALL(hWnd, ScSetSysLog(s->p->Rpc, &set)) == false)
+			{
+				return;
+			}
+		}
+	}
+
+	EndDialog(hWnd, true);
+}
+
+// SSL 関係ダイアログ初期化
+void SmSslDlgInit(HWND hWnd, SM_SSL *s)
+{
+	UINT i;
+	TOKEN_LIST *cipher_list;
+	RPC_KEEP t;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	// 暗号化アルゴリズム一覧を設定する
+	cipher_list = GetCipherList();
+	CbSetHeight(hWnd, C_CIPHER, 18);
+	for (i = 0;i < cipher_list->NumTokens;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		char *name = cipher_list->Token[i];
+		StrToUni(tmp, sizeof(tmp), name);
+		CbAddStr(hWnd, C_CIPHER, tmp, 0);
+	}
+
+	if (s->p != NULL)
+	{
+		// サーバーから暗号化アルゴリズム名を取得する
+		RPC_STR t;
+		Zero(&t, sizeof(t));
+		if (CALL(hWnd, ScGetServerCipher(s->p->Rpc, &t)))
+		{
+			wchar_t tmp[MAX_SIZE];
+			StrToUni(tmp, sizeof(tmp), t.String);
+			SetText(hWnd, C_CIPHER, tmp);
+			FreeRpcStr(&t);
+		}
+		else
+		{
+			EndDialog(hWnd, 0);
+			return;
+		}
+	}
+
+	if (s->p != NULL)
+	{
+		wchar_t tmp[MAX_SIZE];
+		// サーバーから SSL 証明書と秘密鍵を取得する
+		RPC_KEY_PAIR t;
+		s->SetCertAndKey = false;
+		Zero(&t, sizeof(t));
+		if (CALL(hWnd, ScGetServerCert(s->p->Rpc, &t)))
+		{
+			// 証明書と鍵のコピー
+			s->Cert = CloneX(t.Cert);
+			s->Key = CloneK(t.Key);
+			FreeRpcKeyPair(&t);
+		}
+		else
+		{
+			EndDialog(hWnd, 0);
+			return;
+		}
+
+		// 証明書情報の表示
+		SmGetCertInfoStr(tmp, sizeof(tmp), s->Cert);
+		SetText(hWnd, S_CERT_INFO, tmp);
+	}
+
+	// パスワード変更
+	SetEnable(hWnd, B_PASSWORD, s->p->ServerAdminMode);
+
+	// ボタンの有効化 / 無効化
+	SetEnable(hWnd, B_IMPORT, s->p->ServerAdminMode);
+	SetEnable(hWnd, B_EXPORT, s->p->ServerAdminMode);
+	SetEnable(hWnd, R_USE_KEEP_CONNECT, s->p->ServerAdminMode);
+
+	if (s->p->ServerAdminMode == false)
+	{
+		Disable(hWnd, C_CIPHER);
+	}
+
+	if (CALL(hWnd, ScGetKeep(s->p->Rpc, &t)))
+	{
+		Check(hWnd, R_USE_KEEP_CONNECT, t.UseKeepConnect);
+		SetTextA(hWnd, E_HOSTNAME, t.KeepConnectHost);
+		SetIntEx(hWnd, E_PORT, t.KeepConnectPort);
+		SetInt(hWnd, E_INTERVAL, t.KeepConnectInterval);
+		Check(hWnd, R_TCP, t.KeepConnectProtocol == 0);
+		Check(hWnd, R_UDP, t.KeepConnectProtocol != 0);
+	}
+
+	CbSetHeight(hWnd, C_SYSLOG, 18);
+	CbReset(hWnd, C_SYSLOG);
+	CbAddStr(hWnd, C_SYSLOG, _UU("SM_SYSLOG_0"), SYSLOG_NONE);
+	CbAddStr(hWnd, C_SYSLOG, _UU("SM_SYSLOG_1"), SYSLOG_SERVER_LOG);
+	CbAddStr(hWnd, C_SYSLOG, _UU("SM_SYSLOG_2"), SYSLOG_SERVER_AND_HUB_SECURITY_LOG);
+	CbAddStr(hWnd, C_SYSLOG, _UU("SM_SYSLOG_3"), SYSLOG_SERVER_AND_HUB_ALL_LOG);
+
+	if (GetCapsBool(s->p->CapsList, "b_support_syslog"))
+	{
+		SYSLOG_SETTING set;
+
+		SetEnable(hWnd, C_SYSLOG, s->p->ServerAdminMode);
+		SetEnable(hWnd, E_SYSLOG_HOSTNAME, s->p->ServerAdminMode);
+		SetEnable(hWnd, E_SYSLOG_PORT, s->p->ServerAdminMode);
+		SetEnable(hWnd, S_01, s->p->ServerAdminMode);
+		SetEnable(hWnd, S_02, s->p->ServerAdminMode);
+
+		Zero(&set, sizeof(set));
+
+		if (CALL(hWnd, ScGetSysLog(s->p->Rpc, &set)))
+		{
+			SetTextA(hWnd, E_SYSLOG_HOSTNAME, set.Hostname);
+			SetInt(hWnd, E_SYSLOG_PORT, set.Port == 0 ? SYSLOG_PORT : set.Port);
+			CbSelect(hWnd, C_SYSLOG, set.SaveType);
+		}
+	}
+	else
+	{
+		Disable(hWnd, C_SYSLOG);
+		Disable(hWnd, E_SYSLOG_HOSTNAME);
+		Disable(hWnd, E_SYSLOG_PORT);
+		Disable(hWnd, S_01);
+		Disable(hWnd, S_02);
+	}
+
+	SmSslDlgUpdate(hWnd, s);
+}
+
+// SSL 関係ダイアログコントロール更新
+void SmSslDlgUpdate(HWND hWnd, SM_SSL *s)
+{
+	bool ok = true;
+	bool b;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+	{
+		UINT i;
+		b = true;
+		if (IsEmpty(hWnd, E_HOSTNAME))
+		{
+			ok = false;
+		}
+		i = GetInt(hWnd, E_PORT);
+		if (i == 0 || i >= 65536)
+		{
+			ok = false;
+		}
+		i = GetInt(hWnd, E_INTERVAL);
+		if (i < 5 || i > 600)
+		{
+			ok = false;
+		}
+	}
+	else
+	{
+		b = false;
+	}
+
+	if (IsEnable(hWnd, C_SYSLOG))
+	{
+		UINT i = CbGetSelect(hWnd, C_SYSLOG);
+
+		SetEnable(hWnd, E_SYSLOG_HOSTNAME, i != SYSLOG_NONE);
+		SetEnable(hWnd, E_SYSLOG_PORT, i != SYSLOG_NONE);
+		SetEnable(hWnd, S_01, i != SYSLOG_NONE);
+		SetEnable(hWnd, S_02, i != SYSLOG_NONE);
+	}
+
+	SetEnable(hWnd, S_HOSTNAME, b);
+	SetEnable(hWnd, E_HOSTNAME, b);
+	SetEnable(hWnd, S_PORT, b);
+	SetEnable(hWnd, E_PORT, b);
+	SetEnable(hWnd, S_INTERVAL, b);
+	SetEnable(hWnd, E_INTERVAL, b);
+	SetEnable(hWnd, S_INTERVAL2, b);
+	SetEnable(hWnd, S_PROTOCOL, b);
+	SetEnable(hWnd, R_TCP, b);
+	SetEnable(hWnd, R_UDP, b);
+	SetEnable(hWnd, S_INFO, b);
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// 証明書情報文字列の取得
+void SmGetCertInfoStr(wchar_t *str, UINT size, X *x)
+{
+	wchar_t subject[MAX_SIZE];
+	wchar_t issuer[MAX_SIZE];
+	wchar_t date[MAX_SIZE];
+	// 引数チェック
+	if (x == NULL || str == NULL)
+	{
+		if (str != NULL)
+		{
+			str[0] = 0;
+		}
+		return;
+	}
+
+	GetPrintNameFromName(subject, sizeof(subject), x->subject_name);
+	GetPrintNameFromName(issuer, sizeof(issuer), x->issuer_name);
+	GetDateStrEx64(date, sizeof(date), x->notAfter, NULL);
+
+	UniFormat(str, size, _UU("CM_CERT_INFO"), subject, issuer, date);
+}
+
+// SSL 関係ダイアログプロシージャ
+UINT SmSslDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SSL *s = (SM_SSL *)param;
+	X *x;
+	K *k;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SmSslDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_USE_KEEP_CONNECT:
+		case E_HOSTNAME:
+		case E_PORT:
+		case E_INTERVAL:
+		case R_TCP:
+		case R_UDP:
+		case C_SYSLOG:
+		case E_SYSLOG_HOSTNAME:
+		case E_SYSLOG_PORT:
+			SmSslDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			// OK ボタン
+			SmSslDlgOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+
+		case B_IMPORT:
+			// インポート
+			if (CmLoadXAndK(hWnd, &x, &k))
+			{
+				wchar_t tmp[MAX_SIZE];
+				FreeX(s->Cert);
+				FreeK(s->Key);
+				s->Cert = x;
+				s->Key = k;
+				s->SetCertAndKey = true;
+				// 証明書情報の表示
+				SmGetCertInfoStr(tmp, sizeof(tmp), s->Cert);
+				SetText(hWnd, S_CERT_INFO, tmp);
+			}
+			break;
+
+		case B_EXPORT:
+			// エクスポート
+			SmSaveKeyPairDlg(hWnd, s->Cert, s->Key);
+			break;
+
+		case B_VIEW:
+			// 証明書の表示
+			CertDlg(hWnd, s->Cert, NULL, true);
+			break;
+
+		case B_PASSWORD:
+			// パスワード変更
+			Dialog(hWnd, D_SM_CHANGE_PASSWORD, SmChangeServerPasswordDlg, s->p);
+			break;
+
+		case R_USE_KEEP_CONNECT:
+			if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+			{
+				FocusEx(hWnd, E_HOSTNAME);
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// SSL 関係ダイアログの表示
+void SmSslDlg(HWND hWnd, SM_SERVER *p)
+{
+	SM_SSL s;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(&s, sizeof(s));
+	s.p = p;
+
+	Dialog(hWnd, D_SM_SSL, SmSslDlgProc, &s);
+
+	// クリーンアップ
+	FreeX(s.Cert);
+	FreeK(s.Key);
+}
+
+// リスナー作成ダイアログプロシージャ
+UINT SmCreateListenerDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UINT port;
+	RPC_LISTENER t;
+	SM_SERVER *p = (SM_SERVER *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		Focus(hWnd, E_PORT);
+		Disable(hWnd, IDOK);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_PORT:
+			port = GetInt(hWnd, E_PORT);
+			if (port == 0 || port >= 65536)
+			{
+				Disable(hWnd, IDOK);
+			}
+			else
+			{
+				Enable(hWnd, IDOK);
+			}
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			port = GetInt(hWnd, E_PORT);
+			Zero(&t, sizeof(t));
+			t.Enable = true;
+			t.Port = port;
+			if (CALL(hWnd, ScCreateListener(p->Rpc, &t)))
+			{
+				EndDialog(hWnd, true);
+			}
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// リスナー作成ダイアログ
+bool SmCreateListenerDlg(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	return Dialog(hWnd, D_SM_CREATE_LISTENER, SmCreateListenerDlgProc, p);
+}
+
+// HUB 編集 OK ボタン
+void SmEditHubOnOk(HWND hWnd, SM_EDIT_HUB *s)
+{
+	RPC_CREATE_HUB t;
+	char pass1[MAX_SIZE];
+	char pass2[MAX_SIZE];
+	char hubname[MAX_HUBNAME_LEN + 1];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	if (s->EditMode)
+	{
+		StrCpy(hubname, sizeof(hubname), s->HubName);
+		StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+	}
+	else
+	{
+		GetTxtA(hWnd, E_HUBNAME, t.HubName, sizeof(t.HubName));
+		StrCpy(hubname, sizeof(hubname), t.HubName);
+	}
+
+	GetTxtA(hWnd, E_PASSWORD1, pass1, sizeof(pass1));
+	GetTxtA(hWnd, E_PASSWORD2, pass2, sizeof(pass2));
+
+	if (s->EditMode == false || StrCmp(pass1, HIDDEN_PASSWORD) != 0)
+	{
+		Hash(t.HashedPassword, pass1, StrLen(pass1), true);
+		HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass1);
+	}
+
+	if (IsChecked(hWnd, R_LIMIT_MAX_SESSION))
+	{
+		t.HubOption.MaxSession = GetInt(hWnd, E_MAX_SESSION);
+	}
+
+	t.Online = IsChecked(hWnd, R_ONLINE);
+
+	if (s->p->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		t.HubType = HUB_TYPE_FARM_STATIC;
+		if (IsChecked(hWnd, R_DYNAMIC))
+		{
+			t.HubType = HUB_TYPE_FARM_DYNAMIC;
+		}
+	}
+
+	t.HubOption.NoEnum = IsChecked(hWnd, R_NO_ENUM);
+
+	if (s->EditMode == false)
+	{
+		if (CALL(hWnd, ScCreateHub(s->p->Rpc, &t)))
+		{
+			MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_EDIT_HUB_CREATER"), hubname);
+			EndDialog(hWnd, true);
+		}
+	}
+	else
+	{
+		if (CALL(hWnd, ScSetHub(s->p->Rpc, &t)))
+		{
+			EndDialog(hWnd, true);
+		}
+	}
+}
+
+// HUB 編集更新
+void SmEditHubUpdate(HWND hWnd, SM_EDIT_HUB *s)
+{
+	bool ok = true;
+	char *s1, *s2;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	s1 = GetTextA(hWnd, E_PASSWORD1);
+	s2 = GetTextA(hWnd, E_PASSWORD2);
+	if (StrCmp(s1, s2) != 0)
+	{
+		ok = false;
+	}
+	Free(s1);
+	Free(s2);
+
+	GetTxtA(hWnd, E_HUBNAME, hubname, sizeof(hubname));
+	Trim(hubname);
+	if (StrLen(hubname) == 0 ||
+		IsSafeStr(hubname) == false)
+	{
+		ok = false;
+	}
+
+	if (IsChecked(hWnd, R_LIMIT_MAX_SESSION))
+	{
+		Enable(hWnd, E_MAX_SESSION);
+		Enable(hWnd, S_MAX_SESSION_1);
+		Enable(hWnd, S_MAX_SESSION_2);
+		if (GetInt(hWnd, E_MAX_SESSION) == 0)
+		{
+			ok = false;
+		}
+	}
+	else
+	{
+		Disable(hWnd, E_MAX_SESSION);
+		Disable(hWnd, S_MAX_SESSION_1);
+		Disable(hWnd, S_MAX_SESSION_2);
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// HUB 編集初期化
+void SmEditHubInit(HWND hWnd, SM_EDIT_HUB *s)
+{
+	RPC_CREATE_HUB t;
+	bool b = false;
+	bool support_extoption = false;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_HUB);
+
+	Zero(&t, sizeof(t));
+
+	if (s->EditMode == false)
+	{
+		// 新規作成
+		SetText(hWnd, 0, _UU("CM_EDIT_HUB_1"));
+		FocusEx(hWnd, E_HUBNAME);
+
+		if (s->p->ServerType == SERVER_TYPE_STANDALONE)
+		{
+			// スタンドアロン モード
+			Disable(hWnd, R_STATIC);
+			Disable(hWnd, R_DYNAMIC);
+			SetText(hWnd, S_FARM_INFO, _UU("CM_EDIT_HUB_STANDALONE"));
+		}
+		else
+		{
+			Check(hWnd, R_STATIC, true);
+		}
+
+		Check(hWnd, R_ONLINE, true);
+
+		Hide(hWnd, B_ACL);
+		Hide(hWnd, S_ACL);
+		Hide(hWnd, S_ACL_2);
+		Hide(hWnd, S_ACL_3);
+		Hide(hWnd, S_MSG_1);
+		Hide(hWnd, S_MSG_4);
+		Hide(hWnd, S_MSG_2);
+		Hide(hWnd, B_MSG);
+	}
+	else
+	{
+		// 編集
+		wchar_t tmp[MAX_SIZE];
+		UniFormat(tmp, sizeof(tmp), _UU("CM_EDIT_HUB_2"), s->HubName);
+		SetText(hWnd, 0, tmp);
+		SetTextA(hWnd, E_HUBNAME, s->HubName);
+		Disable(hWnd, E_HUBNAME);
+
+		if (s->p->ServerType == SERVER_TYPE_STANDALONE)
+		{
+			// スタンドアロン モード
+			Disable(hWnd, R_STATIC);
+			Disable(hWnd, R_DYNAMIC);
+			SetText(hWnd, S_FARM_INFO, _UU("CM_EDIT_HUB_STANDALONE"));
+		}
+
+		if (s->p->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			// コントローラ
+			if (GetCapsBool(s->p->CapsList, "b_cluster_hub_type_fixed"))
+			{
+				Disable(hWnd, R_STATIC);
+				Disable(hWnd, R_DYNAMIC);
+				SetText(hWnd, S_FARM_INFO, _UU("CM_EDIT_HUB_TYPE_FIXED"));
+			}
+		}
+
+		// HUB 情報の取得
+		StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+		if (CALL(hWnd, ScGetHub(s->p->Rpc, &t)) == false)
+		{
+			EndDialog(hWnd, false);
+			return;
+		}
+
+		SetTextA(hWnd, E_PASSWORD1, HIDDEN_PASSWORD);
+		SetTextA(hWnd, E_PASSWORD2, HIDDEN_PASSWORD);
+
+		if (t.HubOption.MaxSession == 0)
+		{
+			Check(hWnd, R_LIMIT_MAX_SESSION, false);
+		}
+		else
+		{
+			Check(hWnd, R_LIMIT_MAX_SESSION, true);
+		}
+
+		Check(hWnd, R_NO_ENUM, t.HubOption.NoEnum);
+
+		SetIntEx(hWnd, E_MAX_SESSION, t.HubOption.MaxSession);
+
+		Check(hWnd, R_ONLINE, t.Online);
+		Check(hWnd, R_OFFLINE, t.Online ? false : true);
+
+		Check(hWnd, R_STATIC, t.HubType == HUB_TYPE_FARM_STATIC);
+		Check(hWnd, R_DYNAMIC, t.HubType == HUB_TYPE_FARM_DYNAMIC);
+
+		SetShow(hWnd, B_ACL, GetCapsBool(s->p->CapsList, "b_support_ac"));
+		SetShow(hWnd, S_ACL, GetCapsBool(s->p->CapsList, "b_support_ac"));
+		SetShow(hWnd, S_ACL_2, GetCapsBool(s->p->CapsList, "b_support_ac"));
+		SetShow(hWnd, S_ACL_3, GetCapsBool(s->p->CapsList, "b_support_ac"));
+
+		SetShow(hWnd, S_MSG_1, GetCapsBool(s->p->CapsList, "b_support_msg"));
+		SetShow(hWnd, S_MSG_4, GetCapsBool(s->p->CapsList, "b_support_msg"));
+		SetShow(hWnd, S_MSG_2, GetCapsBool(s->p->CapsList, "b_support_msg"));
+		SetShow(hWnd, B_MSG, GetCapsBool(s->p->CapsList, "b_support_msg"));
+	}
+
+	// 拡張オプション
+	if (s->EditMode)
+	{
+		support_extoption = GetCapsBool(s->p->CapsList, "b_support_hub_ext_options");
+	}
+
+	SetEnable(hWnd, S_STATIC, support_extoption);
+	SetEnable(hWnd, B_EXTOPTION, support_extoption);
+
+	SetEnable(hWnd, R_NO_ENUM, GetCapsBool(s->p->CapsList, "b_support_hide_hub"));
+
+	SmEditHubUpdate(hWnd, s);
+
+	if (s->EditMode)
+	{
+		Focus(hWnd, IDOK);
+	}
+
+	if (s->EditMode)
+	{
+		if (GetCapsBool(s->p->CapsList, "b_support_hub_admin_option"))
+		{
+			b = true;
+		}
+	}
+
+	SetShow(hWnd, S_AO_1, b);
+	SetShow(hWnd, S_AO_2, b);
+	SetShow(hWnd, S_AO_3, b);
+	SetShow(hWnd, B_ADMINOPTION, b);
+}
+
+// HUB 編集プロシージャ
+UINT SmEditHubProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_HUB *s = (SM_EDIT_HUB *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmEditHubInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_PASSWORD1:
+		case E_PASSWORD2:
+		case E_HUBNAME:
+		case R_LIMIT_MAX_SESSION:
+		case E_MAX_SESSION:
+			SmEditHubUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			SmEditHubOnOk(hWnd, s);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case R_LIMIT_MAX_SESSION:
+			if (IsChecked(hWnd, R_LIMIT_MAX_SESSION))
+			{
+				FocusEx(hWnd, E_MAX_SESSION);
+			}
+			break;
+
+		case B_ADMINOPTION:
+			SmHubAdminOption(hWnd, s);
+			break;
+
+		case B_EXTOPTION:
+			SmHubExtOption(hWnd, s);
+			break;
+
+		case B_ACL:
+			SmHubAc(hWnd, s);
+			break;
+
+		case B_MSG:
+			SmHubMsg(hWnd, s);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// HUB 編集ダイアログ
+bool SmEditHubDlg(HWND hWnd, SM_SERVER *p, char *hubname)
+{
+	SM_EDIT_HUB s;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	Zero(&s, sizeof(s));
+	s.p = p;
+	s.EditMode = true;
+	StrCpy(s.HubName, sizeof(s.HubName), hubname);
+
+	if (p->Bridge == false)
+	{
+		return Dialog(hWnd, D_SM_EDIT_HUB, SmEditHubProc, &s);
+	}
+	else
+	{
+		SmHubExtOption(hWnd, &s);
+		return false;
+	}
+}
+
+// HUB 作成ダイアログ
+bool SmCreateHubDlg(HWND hWnd, SM_SERVER *p)
+{
+	SM_EDIT_HUB s;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	Zero(&s, sizeof(s));
+	s.p = p;
+	s.EditMode = false;
+
+	return Dialog(hWnd, D_SM_EDIT_HUB, SmEditHubProc, &s);
+}
+
+// 仮想 HUB 状態の表示
+bool SmRefreshHubStatus(HWND hWnd, SM_SERVER *p, void *param)
+{
+	RPC_HUB_STATUS t;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || param == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(RPC_HUB_STATUS));
+	StrCpy(t.HubName, sizeof(t.HubName), (char *)param);
+	if (CALL(hWnd, ScGetHubStatus(p->Rpc, &t)))
+	{
+		wchar_t *s;
+		wchar_t tmp[MAX_SIZE];
+		LVB *b = LvInsertStart();
+
+		// HUB 名
+		s = CopyStrToUni((char *)param);
+		LvInsertAdd(b, ICO_HUB, 0, 2, _UU("SM_HUB_STATUS_HUBNAME"), s);
+		Free(s);
+
+		// オンライン
+		LvInsertAdd(b, t.Online ? ICO_PROTOCOL : ICO_PROTOCOL_X, 0, 2, _UU("SM_HUB_STATUS_ONLINE"),
+			t.Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"));
+
+		// HUB の種類
+		LvInsertAdd(b, t.HubType == HUB_TYPE_STANDALONE ? ICO_TOWER : ICO_FARM, 0, 2, _UU("SM_HUB_TYPE"),
+			GetHubTypeStr(t.HubType));
+
+		if (t.HubType == HUB_TYPE_STANDALONE)
+		{
+			// SecureNAT の有効/無効
+			LvInsertAdd(b, ICO_ROUTER, NULL, 2, _UU("SM_HUB_SECURE_NAT"),
+				t.SecureNATEnabled ? _UU("SM_HUB_SECURE_NAT_YES") : _UU("SM_HUB_SECURE_NAT_NO"));
+		}
+
+		// その他の値
+		UniToStru(tmp, t.NumSessions);
+		LvInsertAdd(b, ICO_PROTOCOL, 0, 2, _UU("SM_HUB_NUM_SESSIONS"), tmp);
+		if (t.NumSessionsClient != 0 || t.NumSessionsBridge != 0)
+		{
+			UniToStru(tmp, t.NumSessionsClient);
+			LvInsertAdd(b, ICO_PROTOCOL, 0, 2, _UU("SM_HUB_NUM_SESSIONS_CLIENT"), tmp);
+			UniToStru(tmp, t.NumSessionsBridge);
+			LvInsertAdd(b, ICO_PROTOCOL, 0, 2, _UU("SM_HUB_NUM_SESSIONS_BRIDGE"), tmp);
+		}
+
+		UniToStru(tmp, t.NumAccessLists);
+		LvInsertAdd(b, ICO_DISCARD, 0, 2, _UU("SM_HUB_NUM_ACCESSES"), tmp);
+
+		if (p->ServerType != SERVER_TYPE_FARM_MEMBER)
+		{
+			UniToStru(tmp, t.NumUsers);
+			LvInsertAdd(b, ICO_USER, 0, 2, _UU("SM_HUB_NUM_USERS"), tmp);
+			UniToStru(tmp, t.NumGroups);
+			LvInsertAdd(b, ICO_GROUP, 0, 2, _UU("SM_HUB_NUM_GROUPS"), tmp);
+		}
+
+		UniToStru(tmp, t.NumMacTables);
+		LvInsertAdd(b, ICO_MACHINE, 0, 2, _UU("SM_HUB_NUM_MAC_TABLES"), tmp);
+		UniToStru(tmp, t.NumIpTables);
+		LvInsertAdd(b, ICO_MACHINE, 0, 2, _UU("SM_HUB_NUM_IP_TABLES"), tmp);
+
+		// 利用状況
+		UniToStru(tmp, t.NumLogin);
+		LvInsertAdd(b, ICO_KEY, NULL, 2, _UU("SM_HUB_NUM_LOGIN"), tmp);
+
+		if (t.LastLoginTime != 0)
+		{
+			GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastLoginTime));
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+		}
+		LvInsertAdd(b, ICO_DATETIME, NULL, 2, _UU("SM_HUB_LAST_LOGIN_TIME"), tmp);
+
+		if (t.LastCommTime != 0)
+		{
+			GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastCommTime));
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+		}
+		LvInsertAdd(b, ICO_DATETIME, NULL, 2, _UU("SM_HUB_LAST_COMM_TIME"), tmp);
+
+		if (t.CreatedTime != 0)
+		{
+			GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime));
+		}
+		else
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+		}
+		LvInsertAdd(b, ICO_DATETIME, NULL, 2, _UU("SM_HUB_CREATED_TIME"), tmp);
+
+		// トラフィック情報
+		SmInsertTrafficInfo(b, &t.Traffic);
+
+		LvInsertEnd(b, hWnd, L_STATUS);
+	}
+	else
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// トラフィック情報を LVB に追加
+void SmInsertTrafficInfo(LVB *b, TRAFFIC *t)
+{
+	wchar_t tmp[MAX_SIZE];
+	char vv[128];
+	// 引数チェック
+	if (b == NULL || t == NULL)
+	{
+		return;
+	}
+
+	// 送信情報
+	ToStr3(vv, sizeof(vv), t->Send.UnicastCount);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+	LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_SEND_UCAST_NUM"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Send.UnicastBytes);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+	LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_SEND_UCAST_SIZE"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Send.BroadcastCount);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+	LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_SEND_BCAST_NUM"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Send.BroadcastBytes);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+	LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_SEND_BCAST_SIZE"), tmp);
+
+	// 受信情報
+	ToStr3(vv, sizeof(vv), t->Recv.UnicastCount);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+	LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_RECV_UCAST_NUM"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Recv.UnicastBytes);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+	LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_RECV_UCAST_SIZE"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Recv.BroadcastCount);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+	LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_RECV_BCAST_NUM"), tmp);
+
+	ToStr3(vv, sizeof(vv), t->Recv.BroadcastBytes);
+	UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+	LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_RECV_BCAST_SIZE"), tmp);
+}
+
+// ステータス表示ダイアログプロシージャ
+UINT SmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_STATUS *s = (SM_STATUS *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		LvInitEx(hWnd, L_STATUS, s->NoImage);
+		LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+		SetIcon(hWnd, 0, s->Icon);
+		SetIcon(hWnd, S_ICON, s->Icon);
+		SetText(hWnd, 0, s->Caption);
+		SetText(hWnd, S_TITLE, s->Caption);
+		DlgFont(hWnd, S_TITLE, 15, true);
+		if (s->InitProc != NULL)
+		{
+			s->InitProc(hWnd, s->p, s->Param);
+		}
+		else
+		{
+			// カラム初期化
+			LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 0);
+			LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 0);
+		}
+		if (s->RefreshProc(hWnd, s->p, s->Param) == false)
+		{
+			Close(hWnd);
+		}
+		LvAutoSize(hWnd, L_STATUS);
+		Focus(hWnd, L_STATUS);
+
+		if (s->show_refresh_button == false)
+		{
+			Hide(hWnd, IDOK);
+		}
+
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			// 更新
+			if (s->RefreshProc(hWnd, s->p, s->Param) == false)
+			{
+				Close(hWnd);
+			}
+			LvAutoSize(hWnd, L_STATUS);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_STATUS);
+
+	return 0;
+}
+
+// ステータス表示ダイアログ
+void SmStatusDlg(HWND hWnd, SM_SERVER *p, void *param, bool no_image, bool show_refresh_button, wchar_t *caption, UINT icon,
+				 SM_STATUS_INIT_PROC *init, SM_STATUS_REFRESH_PROC *refresh)
+{
+	SM_STATUS s;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || refresh == NULL)
+	{
+		return;
+	}
+
+	if (icon == 0)
+	{
+		icon = ICO_INFORMATION;
+	}
+	if (caption == NULL)
+	{
+		caption = _UU("SM_INFORMATION");
+	}
+
+	Zero(&s, sizeof(s));
+	s.show_refresh_button = show_refresh_button;
+	s.p = p;
+	s.NoImage = no_image;
+	s.Param = param;
+	s.Icon = icon;
+	s.Caption = caption;
+	s.InitProc = init;
+	s.RefreshProc = refresh;
+
+	Dialog(hWnd, D_SM_STATUS, SmStatusDlgProc, &s);
+}
+
+// サーバー管理ダイアログ更新
+void SmServerDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+	bool hub_selected = false;
+	bool hub_selected_online = false;
+	bool hub_selected_offline = false;
+	bool hub_have_admin_right = false;
+	bool listener_selected = false;
+	bool listener_selected_enabled = false;
+	bool listener_selected_disabled = false;
+	bool two_or_more_listener = false;
+	bool bridge;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	bridge = GetCapsBool(p->CapsList, "b_bridge");
+
+	hub_selected = LvIsSelected(hWnd, L_HUB);
+
+	if (hub_selected)
+	{
+		if (p->ServerAdminMode)
+		{
+			hub_have_admin_right = true;
+		}
+		i = LvGetSelected(hWnd, L_HUB);
+		if (i != INFINITE)
+		{
+			wchar_t *s = LvGetStr(hWnd, L_HUB, i, 1);
+			if (p->ServerAdminMode == false)
+			{
+				char *hubname = LvGetStrA(hWnd, L_HUB, i, 0);
+				if (hubname != NULL)
+				{
+					if (StrCmpi(hubname, p->HubName) == 0)
+					{
+						hub_have_admin_right = true;
+					}
+					Free(hubname);
+				}
+			}
+			hub_selected_online = (UniStrCmpi(s, _UU("SM_HUB_ONLINE")) == 0);
+			hub_selected_offline = hub_selected_online ? false : true;
+			Free(s);
+		}
+	}
+
+	listener_selected = LvIsSelected(hWnd, L_LISTENER);
+	if (listener_selected)
+	{
+		wchar_t *s = LvGetSelectedStr(hWnd, L_LISTENER, 1);
+		if (UniStrCmpi(s, _UU("CM_LISTENER_OFFLINE")) == 0)
+		{
+			listener_selected_disabled = true;
+		}
+		else
+		{
+			listener_selected_enabled = true;
+		}
+		Free(s);
+	}
+
+	if (LvNum(hWnd, L_LISTENER) >= 2)
+	{
+		two_or_more_listener = true;
+	}
+
+	SetEnable(hWnd, IDOK, bridge || (hub_selected && hub_have_admin_right));
+	SetEnable(hWnd, B_ONLINE, bridge == false && hub_selected_offline && hub_have_admin_right && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+	SetEnable(hWnd, B_OFFLINE, bridge == false && hub_selected_online && hub_have_admin_right && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+	SetEnable(hWnd, B_HUB_STATUS, hub_selected && hub_have_admin_right);
+	SetEnable(hWnd, B_DELETE, bridge == false && hub_selected && p->ServerAdminMode && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+	SetEnable(hWnd, B_EDIT, hub_selected && hub_have_admin_right && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+	SetEnable(hWnd, B_CREATE, bridge == false && p->ServerAdminMode && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+
+	SetEnable(hWnd, B_CREATE_LISTENER, p->ServerAdminMode);
+	SetEnable(hWnd, B_DELETE_LISTENER, p->ServerAdminMode && listener_selected && two_or_more_listener);
+	SetEnable(hWnd, B_START, p->ServerAdminMode && listener_selected_disabled);
+	SetEnable(hWnd, B_STOP, p->ServerAdminMode && listener_selected_enabled);
+	SetEnable(hWnd, B_FARM, GetCapsBool(p->CapsList, "b_support_cluster") && p->ServerAdminMode);
+	SetEnable(hWnd, B_FARM_STATUS, GetCapsBool(p->CapsList, "b_support_cluster") && p->ServerType != SERVER_TYPE_STANDALONE);
+}
+
+// サーバー管理ダイアログ初期化
+void SmServerDlgInit(HWND hWnd, SM_SERVER *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// カラム初期化
+	LvInit(hWnd, L_HUB);
+	LvSetStyle(hWnd, L_HUB, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_HUB, 0, _UU("SM_HUB_COLUMN_1"), 150);
+	LvInsertColumn(hWnd, L_HUB, 1, _UU("SM_HUB_COLUMN_2"), 80);
+	LvInsertColumn(hWnd, L_HUB, 2, _UU("SM_HUB_COLUMN_3"), 80);
+	LvInsertColumn(hWnd, L_HUB, 3, _UU("SM_HUB_COLUMN_4"), 80);
+	LvInsertColumn(hWnd, L_HUB, 4, _UU("SM_HUB_COLUMN_5"), 80);
+	LvInsertColumn(hWnd, L_HUB, 5, _UU("SM_HUB_COLUMN_6"), 80);
+	LvInsertColumn(hWnd, L_HUB, 6, _UU("SM_HUB_COLUMN_7"), 80);
+	LvInsertColumn(hWnd, L_HUB, 7, _UU("SM_HUB_COLUMN_8"), 80);
+	LvInsertColumn(hWnd, L_HUB, 8, _UU("SM_HUB_COLUMN_9"), 80);
+	LvInsertColumn(hWnd, L_HUB, 9, _UU("SM_HUB_COLUMN_10"), 120);
+	LvInsertColumn(hWnd, L_HUB, 10, _UU("SM_HUB_COLUMN_11"), 120);
+
+	LvInit(hWnd, L_LISTENER);
+	LvSetStyle(hWnd, L_LISTENER, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_LISTENER, 0, _UU("CM_LISTENER_COLUMN_1"), 90);
+	LvInsertColumn(hWnd, L_LISTENER, 1, _UU("CM_LISTENER_COLUMN_2"), 80);
+
+	SmServerDlgRefresh(hWnd, p);
+
+	if (p->ServerAdminMode == false)
+	{
+		// 仮想 HUB 管理モードの場合は唯一の HUB を選択する
+		wchar_t *s = CopyStrToUni(p->HubName);
+		LvSelect(hWnd, L_HUB, LvSearchStr(hWnd, L_HUB, 0, s));
+		Free(s);
+	}
+	else
+	{
+		// サーバー全体の管理モードの場合
+		UINT num_hubs = LvNum(hWnd, L_HUB);
+
+		if (num_hubs == 1)
+		{
+			// 仮想 HUB が 1 個の場合は必ずその仮想 HUB を選択する
+			LvSelect(hWnd, L_HUB, 0);
+		}
+		else
+		{
+			// 仮想 HUB が複数個ある場合は前回最後に選択した仮想 HUB を選択する
+			char tmp[MAX_SIZE];
+			char *hubname;
+
+			Format(tmp, sizeof(tmp), "%s:%u:%s", p->CurrentSetting->ClientOption.Hostname,
+				p->CurrentSetting->ClientOption.Port,
+				p->CurrentSetting->ServerAdminMode ? "" : p->CurrentSetting->HubName);
+
+			hubname = MsRegReadStr(REG_CURRENT_USER, SM_LASTHUB_REG_KEY, tmp);
+
+			if (IsEmptyStr(hubname) == false)
+			{
+				LvSelect(hWnd, L_HUB, LvSearchStrA(hWnd, L_HUB, 0, hubname));
+			}
+
+			Free(hubname);
+		}
+	}
+
+	Focus(hWnd, L_HUB);
+
+	SmServerDlgUpdate(hWnd, p);
+
+	if (GetCapsBool(p->CapsList, "b_bridge"))
+	{
+		Disable(hWnd, L_HUB);
+	}
+
+	// ローカルブリッジボタン等はサーバーの Admin の場合に有効にする
+	SetEnable(hWnd, B_BRIDGE, GetCapsBool(p->CapsList, "b_local_bridge") && p->ServerAdminMode);
+	SetEnable(hWnd, B_CONNECTION, p->ServerAdminMode);
+
+	// Config R/W ボタン
+	SetEnable(hWnd, B_CONFIG, GetCapsBool(p->CapsList, "b_support_config_rw") && p->ServerAdminMode);
+
+	// レイヤ 3 ボタン
+	SetEnable(hWnd, B_L3, GetCapsBool(p->CapsList, "b_support_layer3") && p->ServerAdminMode);
+
+	// ライセンスボタン
+	SetShow(hWnd, B_LICENSE, GetCapsBool(p->CapsList, "b_support_license") && p->ServerAdminMode);
+	SetShow(hWnd, S_LICENSE, GetCapsBool(p->CapsList, "b_support_license") && p->ServerAdminMode);
+	SetShow(hWnd, S_BETA, GetCapsBool(p->CapsList, "b_beta_version") && (IsShow(hWnd, B_LICENSE) == false));
+
+	DlgFont(hWnd, S_BETA, 12, false);
+}
+
+// サーバー管理ダイアログ更新
+void SmServerDlgRefresh(HWND hWnd, SM_SERVER *p)
+{
+	RPC_ENUM_HUB t;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// 仮想 HUB リスト更新
+	Zero(&t, sizeof(t));
+	if (CALL(hWnd, ScEnumHub(p->Rpc, &t)))
+	{
+		LVB *b = LvInsertStart();
+		for (i = 0;i < t.NumHub;i++)
+		{
+			RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+			wchar_t name[MAX_HUBNAME_LEN + 1];
+			wchar_t s1[64], s2[64], s3[64], s4[64], s5[64];
+			wchar_t s6[64], s7[128], s8[128];
+			UniToStru(s1, e->NumUsers);
+			UniToStru(s2, e->NumGroups);
+			UniToStru(s3, e->NumSessions);
+			UniToStru(s4, e->NumMacTables);
+			UniToStru(s5, e->NumIpTables);
+
+			UniToStru(s6, e->NumLogin);
+
+			if (e->LastLoginTime != 0)
+			{
+				GetDateTimeStr64Uni(s7, sizeof(s7), SystemToLocal64(e->LastLoginTime));
+			}
+			else
+			{
+				UniStrCpy(s7, sizeof(s7), _UU("COMMON_UNKNOWN"));
+			}
+
+			if (e->LastCommTime != 0)
+			{
+				GetDateTimeStr64Uni(s8, sizeof(s8), SystemToLocal64(e->LastCommTime));
+			}
+			else
+			{
+				UniStrCpy(s8, sizeof(s8), _UU("COMMON_UNKNOWN"));
+			}
+
+			StrToUni(name, sizeof(name), e->HubName);
+
+			LvInsertAdd(b,
+				e->Online ? ICO_HUB : ICO_HUB_OFFLINE,
+				NULL,
+				11,
+				name,
+				e->Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"),
+				GetHubTypeStr(e->HubType),
+				s1, s2, s3, s4, s5, s6, s7, s8);
+		}
+		LvInsertEnd(b, hWnd, L_HUB);
+		FreeRpcEnumHub(&t);
+	}
+
+	// リスナーリスト更新
+	if (p != NULL)
+	{
+		RPC_LISTENER_LIST t;
+		Zero(&t, sizeof(RPC_LISTENER_LIST));
+		if (CALL(hWnd, ScEnumListener(p->Rpc, &t)))
+		{
+			LVB *b = LvInsertStart();
+			for (i = 0;i < t.NumPort;i++)
+			{
+				wchar_t tmp[MAX_SIZE];
+				wchar_t *status;
+				UINT icon;
+				UniFormat(tmp, sizeof(tmp), _UU("CM_LISTENER_TCP_PORT"), t.Ports[i]);
+
+				status = _UU("CM_LISTENER_ONLINE");
+				icon = ICO_PROTOCOL;
+				if (t.Errors[i])
+				{
+					status = _UU("CM_LISTENER_ERROR");
+					icon = ICO_PROTOCOL_X;
+				}
+				else if (t.Enables[i] == false)
+				{
+					status = _UU("CM_LISTENER_OFFLINE");
+					icon = ICO_PROTOCOL_OFFLINE;
+				}
+
+				LvInsertAdd(b, icon, (void *)t.Ports[i], 2, tmp, status);
+			}
+			LvInsertEnd(b, hWnd, L_LISTENER);
+			FreeRpcListenerList(&t);
+		}
+	}
+
+	SmServerDlgUpdate(hWnd, p);
+}
+
+// サーバー管理ダイアログプロシージャ
+UINT SmServerDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_SERVER *p = (SM_SERVER *)param;
+	wchar_t *s;
+	wchar_t tmp[MAX_SIZE];
+	NMHDR *n;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		FormatText(hWnd, 0, p->Title);
+
+		if (p->Bridge == false)
+		{
+			FormatText(hWnd, S_TITLE, p->ServerName);
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("SM_SERVER_BRIDGE_TITLE"), p->ServerName);
+			SetText(hWnd, S_TITLE, tmp);
+
+			SetText(hWnd, S_VHUB_BRIDGE, _UU("SM_S_VHUB_BRIDGE"));
+		}
+
+		DlgFont(hWnd, S_TITLE, 16, 1);
+
+		SetIcon(hWnd, 0, p->Bridge == false ? ICO_VPNSERVER : ICO_BRIDGE);
+
+		SmServerDlgInit(hWnd, p);
+
+		SetTimer(hWnd, 1, 50, NULL);
+
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			// 管理
+			if (IsEnable(hWnd, IDOK))
+			{
+				if (p->Bridge == false)
+				{
+					s = LvGetSelectedStr(hWnd, L_HUB, 0);
+				}
+				else
+				{
+					s = CopyUniStr(L"BRIDGE");
+				}
+				if (s != NULL)
+				{
+					char hubname[MAX_HUBNAME_LEN + 1];
+					SM_HUB hub;
+					Zero(&hub, sizeof(hub));
+					UniToStr(hubname, sizeof(hubname), s);
+					hub.p = p;
+					hub.Rpc = p->Rpc;
+					hub.HubName = hubname;
+					SmHubDlg(hWnd, &hub);
+					//SmServerDlgRefresh(hWnd, p);
+					Free(s);
+				}
+			}
+			break;
+
+		case B_ONLINE:
+			// オンラインにする
+			s = LvGetSelectedStr(hWnd, L_HUB, 0);
+			if (s != NULL)
+			{
+				RPC_SET_HUB_ONLINE t;
+				Zero(&t, sizeof(t));
+				UniToStr(t.HubName, sizeof(t.HubName), s);
+				t.Online = true;
+				if (CALL(hWnd, ScSetHubOnline(p->Rpc, &t)))
+				{
+					SmServerDlgRefresh(hWnd, p);
+				}
+				Free(s);
+			}
+			break;
+
+		case B_OFFLINE:
+			// オフラインにする
+			s = LvGetSelectedStr(hWnd, L_HUB, 0);
+			if (s != NULL)
+			{
+				RPC_SET_HUB_ONLINE t;
+				Zero(&t, sizeof(t));
+				// 確認メッセージ
+				if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+					_UU("CM_OFFLINE_MSG"), s) == IDYES)
+				{
+					UniToStr(t.HubName, sizeof(t.HubName), s);
+					t.Online = false;
+					if (CALL(hWnd, ScSetHubOnline(p->Rpc, &t)))
+					{
+						SmServerDlgRefresh(hWnd, p);
+					}
+				}
+				Free(s);
+			}
+			break;
+
+		case B_HUB_STATUS:
+			// HUB の状態
+			s = LvGetSelectedStr(hWnd, L_HUB, 0);
+			if (s != NULL)
+			{
+				wchar_t tmp[MAX_SIZE];
+				char *hubname = CopyUniToStr(s);
+				UniFormat(tmp, sizeof(tmp), _UU("SM_HUB_STATUS_CAPTION"), s);
+				SmStatusDlg(hWnd, p, hubname, false, true, tmp, ICO_HUB,
+					NULL, SmRefreshHubStatus);
+				Free(hubname);
+				Free(s);
+			}
+			break;
+
+		case B_CREATE:
+			// HUB の作成
+			if (SmCreateHubDlg(hWnd, p))
+			{
+				SmServerDlgRefresh(hWnd, p);
+			}
+			break;
+
+		case B_EDIT:
+			// HUB の編集
+			s = LvGetSelectedStr(hWnd, L_HUB, 0);
+			if (s != NULL)
+			{
+				char *name = CopyUniToStr(s);
+				if (SmEditHubDlg(hWnd, p, name))
+				{
+					SmServerDlgRefresh(hWnd, p);
+				}
+				Free(name);
+				Free(s);
+			}
+			break;
+
+		case B_DELETE:
+			// HUB の削除
+			s = LvGetSelectedStr(hWnd, L_HUB, 0);
+			if (s != NULL)
+			{
+				char *name = CopyUniToStr(s);
+				RPC_DELETE_HUB t;
+				Zero(&t, sizeof(t));
+				StrCpy(t.HubName, sizeof(t.HubName), name);
+				if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_HUB_MSG"), name) == IDYES)
+				{
+					if (CALL(hWnd, ScDeleteHub(p->Rpc, &t)))
+					{
+						SmServerDlgRefresh(hWnd, p);
+						MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_HUB_DELETED_MSG"), name);
+					}
+				}
+				Free(name);
+				Free(s);
+			}
+			break;
+
+		case B_CREATE_LISTENER:
+			// リスナー作成
+			if (SmCreateListenerDlg(hWnd, p))
+			{
+				SmServerDlgRefresh(hWnd, p);
+			}
+			break;
+
+		case B_DELETE_LISTENER:
+			// リスナー削除
+			i = LvGetSelected(hWnd, L_LISTENER);
+			if (i != INFINITE)
+			{
+				UINT port = (UINT)LvGetParam(hWnd, L_LISTENER, i);
+				if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_LISTENER_MSG"), port) == IDYES)
+				{
+					RPC_LISTENER t;
+					Zero(&t, sizeof(t));
+					t.Enable = false;
+					t.Port = port;
+
+					if (CALL(hWnd, ScDeleteListener(p->Rpc, &t)))
+					{
+						SmServerDlgRefresh(hWnd, p);
+					}
+				}
+			}
+			break;
+
+		case B_START:
+			// 開始
+			i = LvGetSelected(hWnd, L_LISTENER);
+			if (i != INFINITE)
+			{
+				UINT port = (UINT)LvGetParam(hWnd, L_LISTENER, i);
+				RPC_LISTENER t;
+				Zero(&t, sizeof(t));
+				t.Enable = true;
+				t.Port = port;
+
+				if (CALL(hWnd, ScEnableListener(p->Rpc, &t)))
+				{
+					SmServerDlgRefresh(hWnd, p);
+				}
+			}
+			break;
+
+		case B_STOP:
+			// 停止
+			i = LvGetSelected(hWnd, L_LISTENER);
+			if (i != INFINITE)
+			{
+				UINT port = (UINT)LvGetParam(hWnd, L_LISTENER, i);
+				if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_STOP_LISTENER_MSG"), port) == IDYES)
+				{
+					RPC_LISTENER t;
+					Zero(&t, sizeof(t));
+					t.Enable = false;
+					t.Port = port;
+
+					if (CALL(hWnd, ScEnableListener(p->Rpc, &t)))
+					{
+						SmServerDlgRefresh(hWnd, p);
+					}
+				}
+			}
+			break;
+
+		case B_SSL:
+			// SSL 関係
+			SmSslDlg(hWnd, p);
+			break;
+
+		case B_STATUS:
+			// サーバー状態
+			SmStatusDlg(hWnd, p, p, false, true, _UU("SM_SERVER_STATUS"), ICO_VPNSERVER,
+				NULL, SmRefreshServerStatus);
+			break;
+
+		case B_INFO:
+			// サーバー情報
+			SmStatusDlg(hWnd, p, p, false, false, _UU("SM_INFO_TITLE"), ICO_VPNSERVER,
+				NULL, SmRefreshServerInfo);
+			break;
+
+		case B_BRIDGE:
+			// ローカルブリッジ設定
+			SmBridgeDlg(hWnd, p);
+			SmServerDlgRefresh(hWnd, p);
+			break;
+
+		case B_FARM:
+			// サーバーファーム
+			if (SmFarmDlg(hWnd, p))
+			{
+				// サーバー ファーム構成が変更された場合はダイアログを閉じる
+				Close(hWnd);
+			}
+			break;
+
+		case B_FARM_STATUS:
+			// サーバー ファーム 状態
+			if (p->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+			{
+				Dialog(hWnd, D_SM_FARM_MEMBER, SmFarmMemberDlgProc, p);
+			}
+			else if (p->ServerType == SERVER_TYPE_FARM_MEMBER)
+			{
+				SmStatusDlg(hWnd, p, NULL, false, true, _UU("SM_FC_STATUS_CAPTION"),
+					ICO_FARM, NULL, SmRefreshFarmConnectionInfo);
+			}
+			break;
+
+		case B_CONNECTION:
+			// TCP コネクション一覧
+			SmConnectionDlg(hWnd, p);
+			break;
+
+		case B_REFRESH:
+			// 最新の状態に更新
+			SmServerDlgRefresh(hWnd, p);
+			break;
+
+		case B_CONFIG:
+			// config 編集
+			SmConfig(hWnd, p);
+			break;
+
+		case B_L3:
+			// L3 スイッチ
+			SmL3(hWnd, p);
+			break;
+
+		case B_LICENSE:
+			// ライセンスの追加と削除
+			SmLicense(hWnd, p);
+			SmServerDlgUpdate(hWnd, p);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		{
+			// 最後に選択されていた HUB を保存する
+			char *hubname = NULL;
+			char tmp[MAX_SIZE];
+
+
+			Format(tmp, sizeof(tmp), "%s:%u:%s", p->CurrentSetting->ClientOption.Hostname,
+				p->CurrentSetting->ClientOption.Port,
+				p->CurrentSetting->ServerAdminMode ? "" : p->CurrentSetting->HubName);
+
+			if (LvIsSingleSelected(hWnd, L_HUB))
+			{
+				hubname = LvGetSelectedStrA(hWnd, L_HUB, 0);
+			}
+
+			if (IsEmptyStr(hubname) == false)
+			{
+				MsRegWriteStr(REG_CURRENT_USER, SM_LASTHUB_REG_KEY, tmp, hubname);
+			}
+			else
+			{
+				MsRegDeleteValue(REG_CURRENT_USER, SM_LASTHUB_REG_KEY, tmp);
+			}
+
+			Free(hubname);
+
+			EndDialog(hWnd, false);
+		}
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_HUB:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmServerDlgUpdate(hWnd, p);
+				break;
+			}
+			break;
+		case L_LISTENER:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				SmServerDlgUpdate(hWnd, p);
+				break;
+			}
+			break;
+		}
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			if (p->EmptyPassword && p->ServerAdminMode)
+			{
+				// パスワードが空の場合は変更を推奨する
+				if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_PASSWORD_MSG")) == IDYES)
+				{
+					Dialog(hWnd, D_SM_CHANGE_PASSWORD, SmChangeServerPasswordDlg, p);
+				}
+			}
+
+			if (p->ServerAdminMode)
+			{
+				// ライセンスキーが登録されていない場合は登録を促す
+				RPC_LICENSE_STATUS t;
+
+				Zero(&t, sizeof(t));
+				if (p->Bridge == false && GetCapsBool(p->CapsList, "b_support_license"))
+				{
+					if (ScGetLicenseStatus(p->Rpc, &t) == ERR_NO_ERROR)
+					{
+						if (t.EditionId == LICENSE_EDITION_VPN3_NO_LICENSE || (t.NeedSubscription && t.SubscriptionExpires == 0))
+						{
+							// 有効なライセンスキーが 1 つも登録されていない
+
+							if (MsgBox(hWnd, MB_YESNO | MB_ICONINFORMATION,
+								_UU("SM_SETUP_NO_LICENSE_KEY")) == IDYES)
+							{
+								SmLicense(hWnd, p);
+							}
+						}
+					}
+				}
+			}
+
+			SetTimer(hWnd, 2, 150, NULL);
+			break;
+
+		case 2:
+			// セットアップ
+			KillTimer(hWnd, 2);
+
+			if (SmSetupIsNew(p))
+			{
+				if (SmSetup(hWnd, p))
+				{
+					SmServerDlgRefresh(hWnd, p);
+				}
+			}
+
+			SetTimer(hWnd, 3, 150, NULL);
+			break;
+
+		case 3:
+			// 管理者向けメッセージ
+			KillTimer(hWnd, 3);
+
+			if (UniIsEmptyStr(p->AdminMsg) == false)
+			{
+				wchar_t tmp[MAX_SIZE];
+
+				UniFormat(tmp, sizeof(tmp), _UU("SM_SERVER_ADMIN_MSG"), p->ServerName);
+				OnceMsg(hWnd, tmp, p->AdminMsg, true, ICO_VPNSERVER);
+			}
+			break;
+		}
+		break;
+	}
+
+	LvStandardHandler(hWnd, msg, wParam, lParam, L_HUB);
+
+	return 0;
+}
+
+// 接続
+void SmConnect(HWND hWnd, SETTING *s)
+{
+	bool ok;
+	RPC *rpc;
+	char *pass;
+	bool empty_password = false;
+	bool first_bad_password = false;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// コントロールの無効化
+	Disable(hWnd, L_SETTING);
+	Disable(hWnd, B_NEW_SETTING);
+	Disable(hWnd, B_EDIT_SETTING);
+	Disable(hWnd, B_DELETE);
+	Disable(hWnd, IDOK);
+	Disable(hWnd, B_ABOUT);
+	Disable(hWnd, IDCANCEL);
+	Disable(hWnd, B_SECURE_MANAGER);
+	Disable(hWnd, B_SELECT_SECURE);
+
+	ok = true;
+
+	if (IsZero(s->HashedPassword, SHA1_SIZE))
+	{
+		// パスワード入力画面
+ENTER_PASSWORD:
+		pass = SmPassword(hWnd, s->ClientOption.Hostname);
+		if (pass != NULL)
+		{
+			Hash(s->HashedPassword, pass, StrLen(pass), true);
+			Free(pass);
+			ok = true;
+		}
+		else
+		{
+			ok = false;
+		}
+	}
+
+	if (ok)
+	{
+		UINT err = ERR_INTERNAL_ERROR;
+		// 接続
+		rpc = AdminConnectEx2(sm->Cedar, &s->ClientOption, s->ServerAdminMode ? "" : s->HubName, s->HashedPassword, &err, NULL,
+			hWnd);
+		if (rpc == NULL)
+		{
+			// エラー発生
+			if (err != ERR_ACCESS_DENIED || first_bad_password)
+			{
+				MsgBox(hWnd, MB_ICONSTOP, _E(err));
+			}
+			if (err == ERR_ACCESS_DENIED)
+			{
+				// パスワード間違い
+				first_bad_password = true;
+				goto ENTER_PASSWORD;
+			}
+			else
+			{
+				// その他のエラー
+			}
+		}
+		else
+		{
+			UCHAR test[SHA1_SIZE];
+			SM_SERVER p;
+			RPC_SERVER_STATUS status;
+			RPC_SERVER_INFO info;
+			SETTING *setting;
+			RPC_MSG msg;
+
+			Hash(test, "", 0, true);
+
+			if (Cmp(test, s->HashedPassword, SHA1_SIZE) == 0)
+			{
+				empty_password = true;
+			}
+
+			if (sm->TempSetting == NULL)
+			{
+				setting = SmGetSetting(s->Title);
+				if (setting != NULL)
+				{
+					if (IsZero(setting->HashedPassword, SHA1_SIZE) == false)
+					{
+						Copy(setting->HashedPassword, s->HashedPassword, SHA1_SIZE);
+						SmWriteSettingList();
+					}
+				}
+			}
+
+			rpc->ServerAdminMode = s->ServerAdminMode;
+			if (s->ServerAdminMode == false)
+			{
+				StrCpy(rpc->HubName, sizeof(rpc->HubName), s->HubName);
+			}
+
+			Zero(&p, sizeof(p));
+			p.CurrentSetting = s;
+			p.Rpc = rpc;
+			p.EmptyPassword = empty_password;
+			p.ServerAdminMode = rpc->ServerAdminMode;
+			StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption.Hostname);
+			if (p.ServerAdminMode == false)
+			{
+				StrCpy(p.HubName, sizeof(p.HubName), rpc->HubName);
+			}
+			UniStrCpy(p.Title, sizeof(p.Title), s->Title);
+
+			// サーバーの種類の取得
+			Zero(&status, sizeof(status));
+			ScGetServerStatus(rpc, &status);
+
+			p.ServerType = status.ServerType;
+
+			Zero(&info, sizeof(info));
+			ScGetServerInfo(rpc, &info);
+
+			Copy(&p.ServerInfo, &info, sizeof(RPC_SERVER_INFO));
+			Copy(&p.ServerStatus, &status, sizeof(RPC_SERVER_STATUS));
+
+			// Admin Msg の取得
+			Zero(&msg, sizeof(msg));
+			if (ScGetAdminMsg(rpc, &msg) == ERR_NO_ERROR)
+			{
+				p.AdminMsg = UniCopyStr(msg.Msg);
+				FreeRpcMsg(&msg);
+			}
+
+			// Caps の取得
+			p.CapsList = ScGetCapsEx(p.Rpc);
+
+			p.Bridge = GetCapsBool(p.CapsList, "b_bridge");
+
+			if (GetCapsBool(p.CapsList, "b_support_policy_ver_3"))
+			{
+				p.PolicyVer = 3;
+			}
+			else
+			{
+				p.PolicyVer = 2;
+			}
+
+			// サーバー管理画面
+			Dialog(hWnd, D_SM_SERVER, SmServerDlgProc, &p);
+
+			// 切断
+			AdminDisconnect(rpc);
+
+			// Caps の解放
+			FreeCapsList(p.CapsList);
+
+			Free(p.AdminMsg);
+			p.AdminMsg = NULL;
+
+			FreeRpcServerInfo(&info);
+		}
+	}
+
+	// コントロールの有効化
+	Enable(hWnd, L_SETTING);
+	Enable(hWnd, B_NEW_SETTING);
+	Enable(hWnd, B_EDIT_SETTING);
+	Enable(hWnd, B_DELETE);
+	Enable(hWnd, IDOK);
+	Enable(hWnd, B_ABOUT);
+	Enable(hWnd, IDCANCEL);
+	Enable(hWnd, B_SECURE_MANAGER);
+	Enable(hWnd, B_SELECT_SECURE);
+}
+
+// パスワード入力ダイアログ
+char *SmPassword(HWND hWnd, char *server_name)
+{
+	char *ret;
+	UI_PASSWORD_DLG p;
+	// 引数チェック
+	if (server_name == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&p, sizeof(p));
+	p.AdminMode = true;
+	StrCpy(p.ServerName, sizeof(p.ServerName), server_name);
+
+	if (PasswordDlg(hWnd, &p) == false)
+	{
+		return NULL;
+	}
+
+	ret = CopyStr(p.Password);
+
+	return ret;
+}
+
+// 設定の編集ダイアログ初期化
+void SmEditSettingDlgInit(HWND hWnd, SM_EDIT_SETTING *p)
+{
+	SETTING *s;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	p->Inited = false;
+
+	s = p->Setting;
+
+	// タイトル
+	if (p->EditMode == false)
+	{
+		SetText(hWnd, 0, _UU("SM_EDIT_CAPTION_1"));
+	}
+	else
+	{
+		wchar_t tmp[MAX_SIZE];
+		UniFormat(tmp, sizeof(tmp), _UU("SM_EDIT_CAPTION_2"), s->Title);
+		SetText(hWnd, 0, tmp);
+	}
+
+	// 接続設定名
+	SetText(hWnd, E_ACCOUNT_NAME, s->Title);
+
+	// ホスト名
+	SetTextA(hWnd, E_HOSTNAME, s->ClientOption.Hostname);
+
+	// ポート番号
+	CbSetHeight(hWnd, C_PORT, 18);
+	CbAddStr(hWnd, C_PORT, _UU("CM_PORT_4"), 0);
+	CbAddStr(hWnd, C_PORT, _UU("CM_PORT_1"), 0);
+	CbAddStr(hWnd, C_PORT, _UU("CM_PORT_2"), 0);
+	CbAddStr(hWnd, C_PORT, _UU("CM_PORT_3"), 0);
+	SetIntEx(hWnd, C_PORT, s->ClientOption.Port);
+
+	// プロキシ設定
+	Check(hWnd, R_DIRECT_TCP, s->ClientOption.ProxyType == PROXY_DIRECT);
+	Check(hWnd, R_HTTPS, s->ClientOption.ProxyType == PROXY_HTTP);
+	Check(hWnd, R_SOCKS, s->ClientOption.ProxyType == PROXY_SOCKS);
+
+	// 管理モード設定
+	Check(hWnd, R_SERVER_ADMIN, s->ServerAdminMode);
+	Check(hWnd, R_HUB_ADMIN, s->ServerAdminMode == false ? true : false);
+	CbSetHeight(hWnd, C_HUBNAME, 18);
+	SetTextA(hWnd, C_HUBNAME, s->HubName);
+
+	// パスワード
+	if (IsZero(s->HashedPassword, SHA1_SIZE))
+	{
+		Check(hWnd, R_NO_SAVE, true);
+	}
+	else
+	{
+		UCHAR test[SHA1_SIZE];
+
+		Hash(test, "", 0, true);
+		if (Cmp(test, s->HashedPassword, SHA1_SIZE) != 0)
+		{
+			SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+		}
+	}
+
+	if (p->EditMode == false)
+	{
+		FocusEx(hWnd, E_ACCOUNT_NAME);
+	}
+	else
+	{
+		FocusEx(hWnd, E_HOSTNAME);
+	}
+
+	p->Inited = true;
+
+	// 仮想 HUB の列挙を開始
+	CmEnumHubStart(hWnd, &s->ClientOption);
+
+	SmEditSettingDlgUpdate(hWnd, p);
+}
+
+// 設定の編集ダイアログ更新
+void SmEditSettingDlgUpdate(HWND hWnd, SM_EDIT_SETTING *p)
+{
+	bool ok = true;
+	UINT delete_hub_list = 0;
+	SETTING *s;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || p->Inited == false)
+	{
+		return;
+	}
+
+	s = p->Setting;
+
+	GetTxt(hWnd, E_ACCOUNT_NAME, s->Title, sizeof(s->Title));
+	UniTrim(s->Title);
+
+	if (UniStrLen(s->Title) == 0)
+	{
+		ok = false;
+	}
+
+	if (IsChecked(hWnd, R_LOCALHOST))
+	{
+		SetTextA(hWnd, E_HOSTNAME, "localhost");
+		Disable(hWnd, E_HOSTNAME);
+	}
+	else
+	{
+		Enable(hWnd, E_HOSTNAME);
+	}
+
+	GetTxtA(hWnd, E_HOSTNAME, tmp, sizeof(tmp));
+	Trim(tmp);
+
+	if (StrCmpi(tmp, s->ClientOption.Hostname) != 0)
+	{
+		delete_hub_list++;
+	}
+
+	StrCpy(s->ClientOption.Hostname, sizeof(s->ClientOption.Hostname), tmp);
+
+	if (StrLen(s->ClientOption.Hostname) == 0)
+	{
+		ok = false;
+	}
+
+	s->ClientOption.Port = GetInt(hWnd, C_PORT);
+	if (s->ClientOption.Port == 0)
+	{
+		ok = false;
+	}
+
+	if (IsChecked(hWnd, R_DIRECT_TCP))
+	{
+		s->ClientOption.ProxyType = PROXY_DIRECT;
+	}
+	else if (IsChecked(hWnd, R_HTTPS))
+	{
+		s->ClientOption.ProxyType = PROXY_HTTP;
+	}
+	else
+	{
+		s->ClientOption.ProxyType = PROXY_SOCKS;
+	}
+
+	SetEnable(hWnd, B_PROXY_CONFIG, s->ClientOption.ProxyType != PROXY_DIRECT);
+
+	if (s->ClientOption.ProxyType != PROXY_DIRECT)
+	{
+		if (StrLen(s->ClientOption.ProxyName) == 0)
+		{
+			ok = false;
+		}
+		if (s->ClientOption.ProxyPort == 0)
+		{
+			ok = false;
+		}
+	}
+
+	s->ServerAdminMode = IsChecked(hWnd, R_SERVER_ADMIN);
+
+	SetEnable(hWnd, C_HUBNAME, s->ServerAdminMode == false ? true : false);
+	SetEnable(hWnd, S_HUBNAME, s->ServerAdminMode == false ? true : false);
+
+	GetTxtA(hWnd, C_HUBNAME, s->HubName, sizeof(s->HubName));
+	Trim(s->HubName);
+	if (StrLen(s->HubName) == 0)
+	{
+		if (s->ServerAdminMode == false)
+		{
+			ok = false;
+		}
+	}
+
+	if (IsChecked(hWnd, R_NO_SAVE))
+	{
+		Zero(s->HashedPassword, SHA1_SIZE);
+		SetTextA(hWnd, E_PASSWORD, "");
+		Disable(hWnd, E_PASSWORD);
+		Disable(hWnd, S_PASSWORD);
+	}
+	else
+	{
+		char tmp[MAX_PASSWORD_LEN + 1];
+		Enable(hWnd, E_PASSWORD);
+		Enable(hWnd, S_PASSWORD);
+		GetTxtA(hWnd, E_PASSWORD, tmp, sizeof(tmp));
+		if (StrCmp(tmp, HIDDEN_PASSWORD) != 0)
+		{
+			Hash(s->HashedPassword, tmp, StrLen(tmp), true);
+		}
+	}
+
+	if (delete_hub_list)
+	{
+		CbReset(hWnd, C_HUBNAME);
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// 設定の編集ダイアログ OK ボタン
+void SmEditSettingDlgOnOk(HWND hWnd, SM_EDIT_SETTING *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (p->EditMode == false)
+	{
+		// 新規登録
+		SETTING *s = ZeroMalloc(sizeof(SETTING));
+		Copy(s, p->Setting, sizeof(SETTING));
+		if (SmAddSetting(s) == false)
+		{
+			MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SM_SETTING_EXISTS"), s->Title);
+			Free(s);
+			FocusEx(hWnd, E_ACCOUNT_NAME);
+			return;
+		}
+		EndDialog(hWnd, true);
+	}
+	else
+	{
+		// 更新登録
+		SETTING *t = SmGetSetting(p->Setting->Title);
+		if (t != NULL && t != p->OldSetting)
+		{
+			MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SM_SETTING_EXISTS"), p->Setting->Title);
+			FocusEx(hWnd, E_ACCOUNT_NAME);
+			return;
+		}
+
+		Copy(p->OldSetting, p->Setting, sizeof(SETTING));
+		Sort(sm->SettingList);
+		SmWriteSettingList();
+
+		EndDialog(hWnd, true);
+	}
+}
+
+// 設定の追加 / 編集ダイアログ
+UINT SmEditSettingDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SM_EDIT_SETTING *p = (SM_EDIT_SETTING *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SmEditSettingDlgInit(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_LOCALHOST:
+		case E_ACCOUNT_NAME:
+		case E_HOSTNAME:
+		case C_PORT:
+		case R_DIRECT_TCP:
+		case R_HTTPS:
+		case R_SOCKS:
+		case R_SERVER_ADMIN:
+		case R_HUB_ADMIN:
+		case C_HUBNAME:
+		case E_PASSWORD:
+		case R_NO_SAVE:
+			SmEditSettingDlgUpdate(hWnd, p);
+			break;
+		}
+
+		if (LOWORD(wParam) == R_LOCALHOST)
+		{
+			FocusEx(hWnd, E_HOSTNAME);
+		}
+
+		switch (LOWORD(wParam))
+		{
+		case E_HOSTNAME:
+			if (HIWORD(wParam) == EN_KILLFOCUS)
+			{
+				CmEnumHubStart(hWnd, &p->Setting->ClientOption);
+			}
+			break;
+		case C_PORT:
+			if (HIWORD(wParam) == CBN_KILLFOCUS)
+			{
+				CmEnumHubStart(hWnd, &p->Setting->ClientOption);
+			}
+			break;
+		case R_DIRECT_TCP:
+		case R_HTTPS:
+		case R_SOCKS:
+			if (HIWORD(wParam) == BN_CLICKED)
+			{
+				CmEnumHubStart(hWnd, &p->Setting->ClientOption);
+			}
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			SmEditSettingDlgOnOk(hWnd, p);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case B_PROXY_CONFIG:
+			// プロキシ設定
+			if (CmProxyDlg(hWnd, &p->Setting->ClientOption))
+			{
+				UINT n = GetInt(hWnd, C_PORT);
+				if (p->Setting->ClientOption.ProxyType == PROXY_HTTP &&
+					n != 443)
+				{
+					// HTTP プロキシ経由の設定になっていて接続先が 443 番ポート
+					// 以外のポートである場合は警告を表示する
+					if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_HTTP_PROXY_WARNING"), n) == IDYES)
+					{
+						// ポート番号を 443 に変更する
+						SetText(hWnd, C_PORT, _UU("CM_PORT_2"));
+					}
+				}
+				SmEditSettingDlgUpdate(hWnd, p);
+				CmEnumHubStart(hWnd, &p->Setting->ClientOption);
+			}
+			break;
+
+		case R_NO_SAVE:
+			if (IsChecked(hWnd, R_NO_SAVE) == false)
+			{
+				FocusEx(hWnd, E_PASSWORD);
+			}
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 設定の追加ダイアログを表示
+bool SmAddSettingDlg(HWND hWnd, wchar_t *new_name, UINT new_name_size)
+{
+	SM_EDIT_SETTING p;
+	SETTING s;
+	UINT i;
+	bool ret;
+	// 引数チェック
+	if (hWnd == NULL || new_name == NULL)
+	{
+		return false;
+	}
+
+	Zero(&p, sizeof(p));
+	Zero(&s, sizeof(s));
+
+	s.ClientOption.Port = 443;
+
+	p.EditMode = false;
+	p.Setting = &s;
+
+	for (i = 1;;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		if (i == 1)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_1"));
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_2"), i);
+		}
+
+		if (SmGetSetting(tmp) == NULL)
+		{
+			UniStrCpy(s.Title, sizeof(s.Title), tmp);
+			Hash(s.HashedPassword, "", 0, true);
+			s.ServerAdminMode = true;
+			break;
+		}
+	}
+
+	ret = Dialog(hWnd, D_SM_EDIT_SETTING, SmEditSettingDlgProc, &p);
+
+	if (ret)
+	{
+		UniStrCpy(new_name, new_name_size, s.Title);
+	}
+
+	return ret;
+}
+
+// 設定の編集ダイアログを表示
+bool SmEditSettingDlg(HWND hWnd)
+{
+	SM_EDIT_SETTING p;
+	SETTING s, *setting;
+	UINT i;
+	wchar_t *name;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	i = LvGetSelected(hWnd, L_SETTING);
+	if (i == INFINITE)
+	{
+		return false;
+	}
+
+	name = LvGetStr(hWnd, L_SETTING, i, 0);
+
+	setting = SmGetSetting(name);
+	if (setting == NULL)
+	{
+		Free(name);
+		return false;
+	}
+
+	Free(name);
+
+	Copy(&s, setting, sizeof(SETTING));
+
+	Zero(&p, sizeof(p));
+
+	p.EditMode = true;
+	p.OldSetting = setting;
+	p.Setting = &s;
+
+	return Dialog(hWnd, D_SM_EDIT_SETTING, SmEditSettingDlgProc, &p);
+}
+
+// 設定の更新
+bool SmCheckNewName(SETTING *s, wchar_t *new_title)
+{
+	UINT i;
+	// 引数チェック
+	if (new_title == NULL)
+	{
+		return false;
+	}
+	if (s != NULL)
+	{
+		if (IsInList(sm->SettingList, s) == false)
+		{
+			return false;
+		}
+	}
+
+	// 他に同一の名前が無いかどうかチェック
+	for (i = 0;i < LIST_NUM(sm->SettingList);i++)
+	{
+		SETTING *t = LIST_DATA(sm->SettingList, i);
+
+		if (s != t)
+		{
+			if (UniStrCmpi(t->Title, new_title) == 0)
+			{
+				return false;
+			}
+		}
+	}
+
+	return true;
+}
+
+// 設定の削除
+void SmDeleteSetting(wchar_t *title)
+{
+	SETTING *s;
+	// 引数チェック
+	if (title == NULL)
+	{
+		return;
+	}
+
+	s = SmGetSetting(title);
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Delete(sm->SettingList, s);
+	Free(s);
+	Sort(sm->SettingList);
+
+	SmWriteSettingList();
+}
+
+// 設定の追加
+bool SmAddSetting(SETTING *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	if (SmGetSetting(s->Title) != NULL)
+	{
+		return false;
+	}
+
+	Insert(sm->SettingList, s);
+
+	SmWriteSettingList();
+
+	return true;
+}
+
+// 設定の取得
+SETTING *SmGetSetting(wchar_t *title)
+{
+	SETTING s;
+	// 引数チェック
+	if (title == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&s, sizeof(SETTING));
+	UniStrCpy(s.Title, sizeof(s.Title), title);
+
+	return (SETTING *)Search(sm->SettingList, &s);
+}
+
+// 接続設定の比較
+int SmCompareSetting(void *p1, void *p2)
+{
+	SETTING *s1, *s2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(SETTING **)p1;
+	s2 = *(SETTING **)p2;
+	if (s1 == NULL || s2 == NULL)
+	{
+		return 0;
+	}
+
+	return UniStrCmpi(s1->Title, s2->Title);
+}
+
+// 設定リストの初期化
+void SmInitSettingList()
+{
+	sm->SettingList = NewList(SmCompareSetting);
+
+	SmLoadSettingList();
+
+	SmInitDefaultSettingList();
+}
+
+// 設定リストの解放
+void SmFreeSettingList()
+{
+	UINT i;
+
+	// 書き込み
+	SmWriteSettingList();
+
+	for (i = 0;i < LIST_NUM(sm->SettingList);i++)
+	{
+		SETTING *s = LIST_DATA(sm->SettingList, i);
+		Free(s);
+	}
+	ReleaseList(sm->SettingList);
+
+	sm->SettingList = NULL;
+}
+
+// 設定リストの書き込み
+void SmWriteSettingList()
+{
+	TOKEN_LIST *t;
+	UINT i;
+
+	t = MsRegEnumValue(REG_CURRENT_USER, SM_SETTING_REG_KEY);
+	if (t != NULL)
+	{
+		// 既存のすべての値を削除する
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			char *name = t->Token[i];
+			MsRegDeleteValue(REG_CURRENT_USER, SM_SETTING_REG_KEY, name);
+		}
+
+		FreeToken(t);
+	}
+
+	for (i = 0;i < LIST_NUM(sm->SettingList);i++)
+	{
+		char name[MAX_SIZE];
+		SETTING *s = LIST_DATA(sm->SettingList, i);
+
+		// 書き込む
+		Format(name, sizeof(name), "Setting%u", i + 1);
+		MsRegWriteBin(REG_CURRENT_USER, SM_SETTING_REG_KEY, name, s, sizeof(SETTING));
+	}
+}
+
+// 接続リストの読み込み
+void SmLoadSettingList()
+{
+	TOKEN_LIST *t;
+	UINT i;
+	char *key_name = SM_SETTING_REG_KEY;
+
+	t = MsRegEnumValue(REG_CURRENT_USER, key_name);
+	if (t == NULL)
+	{
+		key_name = SM_SETTING_REG_KEY_OLD;
+		t = MsRegEnumValue(REG_CURRENT_USER, key_name);
+		if (t == NULL)
+		{
+			return;
+		}
+	}
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *name = t->Token[i];
+		BUF *b = MsRegReadBin(REG_CURRENT_USER, key_name, name);
+		if (b != NULL)
+		{
+			if (b->Size == sizeof(SETTING))
+			{
+				SETTING *s = ZeroMalloc(sizeof(SETTING));
+				Copy(s, b->Buf, sizeof(SETTING));
+
+				Add(sm->SettingList, s);
+			}
+			FreeBuf(b);
+		}
+	}
+
+	FreeToken(t);
+
+	Sort(sm->SettingList);
+}
+
+// デフォルトの設定リストの初期化
+void SmInitDefaultSettingList()
+{
+	if (LIST_NUM(sm->SettingList) == 0)
+	{
+		bool b = false;
+		LIST *pl = MsGetProcessList();
+
+		if (pl != NULL)
+		{
+			UINT i;
+			for (i = 0;i < LIST_NUM(pl);i++)
+			{
+				MS_PROCESS *p = LIST_DATA(pl, i);
+
+				if (InStr(p->ExeFilename, "utvpnserver.exe") || InStr(p->ExeFilename, "utvpnserver_x64.exe") ||
+					InStr(p->ExeFilename, "utvpnserver_ia64.exe") ||
+					InStr(p->ExeFilename, "utvpnbridge.exe") || InStr(p->ExeFilename, "utvpnbridge_x64.exe") ||
+					InStr(p->ExeFilename, "utvpnbridge_ia64.exe"))
+				{
+					b = true;
+				}
+			}
+		}
+
+		MsFreeProcessList(pl);
+
+		if (b == false)
+		{
+			if (MsIsServiceRunning(_SS("SVC_UTVPNSERVER_NAME")))
+			{
+				b = true;
+			}
+		}
+
+		if (b)
+		{
+			SETTING *s = ZeroMalloc(sizeof(SETTING));
+
+			UniStrCpy(s->Title, sizeof(s->Title), _UU("SM_LOCALHOST"));
+			s->ServerAdminMode = true;
+			Hash(s->HashedPassword, "", 0, true);
+			UniStrCpy(s->ClientOption.AccountName, sizeof(s->ClientOption.AccountName), s->Title);
+			StrCpy(s->ClientOption.Hostname, sizeof(s->ClientOption.Hostname), "localhost");
+			s->ClientOption.Port = 5555;
+
+			Add(sm->SettingList, s);
+		}
+	}
+}
+
+// メインダイアログ初期化
+void SmMainDlgInit(HWND hWnd)
+{
+	wchar_t *last_select;
+	UINT i = INFINITE;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, ICO_VPNSERVER);
+
+	LvInit(hWnd, L_SETTING);
+	LvSetStyle(hWnd, L_SETTING, LVS_EX_GRIDLINES);
+	LvInsertColumn(hWnd, L_SETTING, 0, _UU("SM_MAIN_COLUMN_1"), 146);
+	LvInsertColumn(hWnd, L_SETTING, 1, _UU("SM_MAIN_COLUMN_2"), 130);
+	LvInsertColumn(hWnd, L_SETTING, 2, _UU("SM_MAIN_COLUMN_3"), 130);
+
+	SmRefreshSetting(hWnd);
+
+	last_select = MsRegReadStrW(REG_CURRENT_USER, SM_REG_KEY, "Last Select");
+	if (UniIsEmptyStr(last_select) == false)
+	{
+		i = LvSearchStr(hWnd, L_SETTING, 0, last_select);
+	}
+	Free(last_select);
+
+	if (i == INFINITE)
+	{
+		LvSelect(hWnd, L_SETTING, 0);
+	}
+	else
+	{
+		LvSelect(hWnd, L_SETTING, i);
+	}
+
+	Focus(hWnd, L_SETTING);
+
+	SmMainDlgUpdate(hWnd);
+}
+
+// 設定一覧の更新
+void SmRefreshSetting(HWND hWnd)
+{
+	SmRefreshSettingEx(hWnd, NULL);
+}
+void SmRefreshSettingEx(HWND hWnd, wchar_t *select_name)
+{
+	LVB *b;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	b = LvInsertStart();
+
+	for (i = 0;i < LIST_NUM(sm->SettingList);i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		SETTING *s = LIST_DATA(sm->SettingList, i);
+
+		if (s->ServerAdminMode)
+		{
+			UniStrCpy(tmp, sizeof(tmp), _UU("SM_MODE_SERVER"));
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("SM_MODE_HUB"), s->HubName);
+		}
+
+		StrToUni(tmp2, sizeof(tmp2), s->ClientOption.Hostname);
+
+		LvInsertAdd(b,
+			(s->ServerAdminMode ? ICO_SERVER_ONLINE : ICO_HUB),
+			NULL,
+			3,
+			s->Title,
+			tmp2,
+			tmp);
+	}
+
+	LvInsertEnd(b, hWnd, L_SETTING);
+
+	if (UniIsEmptyStr(select_name) == false)
+	{
+		LvSelect(hWnd, L_SETTING, LvSearchStr(hWnd, L_SETTING, 0, select_name));
+	}
+}
+
+// メインダイアログ更新
+void SmMainDlgUpdate(HWND hWnd)
+{
+	bool ok = true;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_SETTING) == false)
+	{
+		ok = false;
+	}
+	if (LvIsMultiMasked(hWnd, L_SETTING))
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+	SetEnable(hWnd, B_EDIT_SETTING, ok);
+	SetEnable(hWnd, B_DELETE, ok);
+}
+
+// メインウインドウプロシージャ
+UINT SmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	NMHDR *n;
+	NMLVDISPINFOW *info;
+	NMLVKEYDOWN *key;
+	wchar_t *tmp;
+	UINT i;
+	wchar_t new_name[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		ShowSplashEx(hWnd, "UT-VPN Server", 1300, SM_SPLASH_BORDER_COLOR);
+		SmMainDlgInit(hWnd);
+		SetTimer(hWnd, 4, 100, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 4:
+			KillTimer(hWnd, 4);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			// 接続
+			i = LvGetSelected(hWnd, L_SETTING);
+			if (i != INFINITE)
+			{
+				tmp = LvGetStr(hWnd, L_SETTING, i, 0);
+				if (tmp != NULL)
+				{
+					SETTING *setting = SmGetSetting(tmp);
+					if (setting != NULL)
+					{
+						SETTING s;
+
+						// レジストリに最後の選択として記録
+						MsRegWriteStrW(REG_CURRENT_USER, SM_REG_KEY, "Last Select", tmp);
+
+						// 設定コピー
+						Copy(&s, setting, sizeof(SETTING));
+						SmConnect(hWnd, &s);
+					}
+					Free(tmp);
+				}
+			}
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case B_NEW_SETTING:
+			// 追加
+			if (SmAddSettingDlg(hWnd, new_name, sizeof(new_name)))
+			{
+				SmRefreshSettingEx(hWnd, new_name);
+			}
+			break;
+
+		case B_EDIT_SETTING:
+			// 編集
+			if (SmEditSettingDlg(hWnd))
+			{
+				SmWriteSettingList();
+				SmRefreshSetting(hWnd);
+			}
+
+			break;
+
+		case B_DELETE:
+			// 削除
+			i = LvGetSelected(hWnd, L_SETTING);
+			if (i != INFINITE)
+			{
+				tmp = LvGetStr(hWnd, L_SETTING, i, 0);
+				if (tmp != NULL)
+				{
+					if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+						_UU("SM_SETTING_DELETE_MSG"), tmp) == IDYES)
+					{
+						SmDeleteSetting(tmp);
+						SmWriteSettingList();
+						SmRefreshSetting(hWnd);
+					}
+					Free(tmp);
+				}
+			}
+			break;
+
+		case B_ABOUT:
+			// バージョン情報
+			ShowSplashEx(hWnd, "UT-VPN Server", 0, SM_SPLASH_BORDER_COLOR);
+			break;
+
+		case B_SECURE_MANAGER:
+			// スマートカードマネージャ
+			SmSecureManager(hWnd);
+			break;
+
+		case B_SELECT_SECURE:
+			// スマートカード選択
+			SmSelectSecureId(hWnd);
+			break;
+		}
+
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_SETTING:
+			switch (n->code)
+			{
+			case NM_DBLCLK:
+				Command(hWnd, IDOK);
+				break;
+
+			case LVN_KEYDOWN:
+				key = (NMLVKEYDOWN *)n;
+				if (key != NULL)
+				{
+					UINT code = key->wVKey;
+					switch (code)
+					{
+					case VK_F2:
+						if (LvIsSelected(hWnd, L_SETTING))
+						{
+							LvRename(hWnd, L_SETTING, LvGetSelected(hWnd, L_SETTING));
+						}
+						break;
+
+					case VK_DELETE:
+						Command(hWnd, B_DELETE);
+						break;
+
+					case VK_RETURN:
+						Command(hWnd, IDOK);
+						break;
+					}
+				}
+				break;
+
+			case LVN_ENDLABELEDITW:
+				// 名前の変更
+				info = (NMLVDISPINFOW *)n;
+				if (info->item.pszText != NULL)
+				{
+					wchar_t *new_name = info->item.pszText;
+					wchar_t *old_name = LvGetStr(hWnd, L_SETTING, info->item.iItem, 0);
+
+					if (old_name != NULL)
+					{
+						if (UniStrCmp(new_name, old_name) != 0 && UniStrLen(new_name) != 0)
+						{
+							// 名前変更の実行
+							SETTING *s = SmGetSetting(old_name);
+							if (s != NULL)
+							{
+								if (SmGetSetting(new_name) != NULL)
+								{
+									MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SM_SETTING_EXISTS"),
+										new_name);
+								}
+								else
+								{
+									UniStrCpy(s->Title, sizeof(s->Title), new_name);
+									Sort(sm->SettingList);
+									SmWriteSettingList();
+									LvSetItem(hWnd, L_SETTING, info->item.iItem, 0, new_name);
+								}
+							}
+						}
+
+						Free(old_name);
+					}
+				}
+				break;
+
+			case LVN_ITEMCHANGED:
+				SmMainDlgUpdate(hWnd);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	LvSortHander(hWnd, msg, wParam, lParam, L_SETTING);
+
+	return 0;
+}
+
+// メインウインドウ
+void SmMainDlg()
+{
+	Dialog(NULL, D_SM_MAIN, SmMainDlgProc, NULL);
+}
+
+// Server Manager メイン処理
+void MainSM()
+{
+	if (sm->TempSetting == NULL)
+	{
+		// メインウインドウを開く
+		SmMainDlg();
+	}
+	else
+	{
+		SmConnect(sm->hParentWnd, sm->TempSetting);
+	}
+}
+
+// 初期化
+void InitSM()
+{
+	if (sm != NULL)
+	{
+		// すでに初期化されている
+		return;
+	}
+
+	sm = ZeroMalloc(sizeof(SM));
+
+	InitWinUi(_UU("SM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+	sm->Cedar = NewCedar(NULL, NULL);
+
+	SmInitSettingList();
+
+	InitCM();
+
+	// コマンドラインを解釈する
+	SmParseCommandLine();
+}
+
+// コマンドラインを解釈する
+void SmParseCommandLine()
+{
+	LIST *o;
+	CONSOLE *c = NewLocalConsole(NULL, NULL);
+	wchar_t *cmdline;
+	PARAM args[] =
+	{
+		{"[vpnserver]", NULL, NULL, NULL, NULL,},
+		{"HUB", NULL, NULL, NULL, NULL,},
+		{"PASSWORD", NULL, NULL, NULL, NULL,},
+		{"TITLE", NULL, NULL, NULL, NULL,},
+		{"HWND", NULL, NULL, NULL, NULL,},
+	};
+	if (c == NULL)
+	{
+		return;
+	}
+	
+	cmdline = GetCommandLineUniStr();
+
+	if (UniIsEmptyStr(cmdline) == false)
+	{
+		o = ParseCommandList(c, "vpnsmgr", cmdline, args, sizeof(args) / sizeof(args[0]));
+		if (o != NULL)
+		{
+			char *host;
+			UINT port;
+
+			if (ParseHostPort(GetParamStr(o, "[vpnserver]"), &host, &port, 443))
+			{
+				char *hub = GetParamStr(o, "HUB");
+				char *password = GetParamStr(o, "PASSWORD");
+				char *title = GetParamStr(o, "TITLE");
+				char *hwndstr = GetParamStr(o, "HWND");
+
+				if (hub == NULL || StrCmpi(hub, "\"") == 0)
+				{
+					hub = CopyStr("");
+				}
+				if (password == NULL)
+				{
+					password = CopyStr("");
+				}
+				if (title == NULL)
+				{
+					title = CopyStr(host);
+				}
+
+				if (IsEmptyStr(host) == false)
+				{
+					SETTING *s = ZeroMalloc(sizeof(SETTING));
+					BUF *b;
+					CLIENT_OPTION *o;
+
+					StrToUni(s->Title, sizeof(s->Title), title);
+
+					if (IsEmptyStr(hub))
+					{
+						s->ServerAdminMode = true;
+					}
+					else
+					{
+						s->ServerAdminMode = false;
+						StrCpy(s->HubName, sizeof(s->HubName), hub);
+					}
+
+					b = StrToBin(password);
+					if (b == NULL || b->Size != SHA1_SIZE)
+					{
+						Hash(s->HashedPassword, password, StrLen(password), true);
+					}
+					else
+					{
+						Copy(s->HashedPassword, b->Buf, SHA1_SIZE);
+					}
+					FreeBuf(b);
+
+					o = &s->ClientOption;
+
+					UniStrCpy(o->AccountName, sizeof(o->AccountName), s->Title);
+					StrCpy(o->Hostname, sizeof(o->Hostname), host);
+					o->Port = port;
+					o->ProxyType = PROXY_DIRECT;
+					StrCpy(o->DeviceName, sizeof(o->DeviceName), "DUMMY");
+
+					sm->TempSetting = s;
+
+					if (IsEmptyStr(hwndstr) == false)
+					{
+						sm->hParentWnd = (HWND)ToInt64(hwndstr);
+					}
+				}
+
+				Free(hwndstr);
+				Free(title);
+				Free(hub);
+				Free(password);
+				Free(host);
+			}
+		}
+	}
+
+	Free(cmdline);
+
+	c->Free(c);
+}
+
+// 解放
+void FreeSM()
+{
+	if (sm == NULL)
+	{
+		// 初期化されていない
+		return;
+	}
+
+	FreeCM();
+
+	SmFreeSettingList();
+
+	ReleaseCedar(sm->Cedar);
+
+	FreeWinUi();
+
+	if (sm->TempSetting != NULL)
+	{
+		Free(sm->TempSetting);
+	}
+
+	Free(sm);
+	sm = NULL;
+}
+
+// Server Manager の実行
+void SMExec()
+{
+	InitSM();
+	MainSM();
+	FreeSM();
+}
+
+#endif	// WIN32
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SM.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SM.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SM.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,88 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// SM.h
+// SM.c のヘッダ
+
+#ifndef	SM_H
+#define	SM_H
+
+void SMExec();
+
+#endif	// SM_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SMInner.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SMInner.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SMInner.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,703 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// SMInner.h
+// SM.c の内部向けヘッダ
+
+// 定数
+#define	SM_REG_KEY			"Software\\SoftEther Corporation\\UT-VPN\\Server Manager"
+#define	SM_CERT_REG_KEY		"Software\\SoftEther Corporation\\UT-VPN\\Server Manager\\Cert Tool"
+#define	SM_SETTING_REG_KEY	"Software\\SoftEther Corporation\\UT-VPN\\Server Manager\\Settings"
+#define	SM_LASTHUB_REG_KEY	"Software\\SoftEther Corporation\\UT-VPN\\Server Manager\\Last HUB Name"
+
+// 定数 (古い値)
+#define	SM_SETTING_REG_KEY_OLD	"Software\\SoftEther Corporation\\PacketiX VPN\\Server Manager\\Settings_Dummy"
+
+// スプラッシュスクリーンの枠線の色
+#define	SM_SPLASH_BORDER_COLOR	(RGB(72, 72, 72))
+
+// 接続設定
+typedef struct SETTING
+{
+	wchar_t Title[MAX_SIZE];	// 設定名
+	bool ServerAdminMode;		// サーバー管理モード
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	UCHAR HashedPassword[SHA1_SIZE];	// パスワード
+	CLIENT_OPTION ClientOption;	// クライアントオプション
+	UCHAR Reserved[10240 - sizeof(bool) * 7];	// 予約領域
+} SETTING;
+
+// 構造体宣言
+typedef struct SM
+{
+	CEDAR *Cedar;				// Cedar
+	LIST *SettingList;			// 設定リスト
+	SETTING *TempSetting;		// 仮設定
+	HWND hParentWnd;			// 親ウインドウハンドル
+} SM;
+
+// 接続設定編集
+typedef struct SM_EDIT_SETTING
+{
+	bool EditMode;				// 編集モード
+	SETTING *OldSetting;		// 以前の設定へのポインタ
+	SETTING *Setting;			// 設定へのポインタ
+	bool Inited;				// 初期済みフラグ
+} SM_EDIT_SETTING;
+
+// サーバー管理ダイアログ
+typedef struct SM_SERVER
+{
+	RPC *Rpc;					// RPC
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	wchar_t Title[MAX_SIZE];	// タイトル
+	bool ServerAdminMode;		// サーバー管理モード
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+	UINT ServerType;			// サーバーの種類
+	bool Bridge;				// VPN Bridge 製品
+	UINT PolicyVer;				// ポリシーバージョン
+	RPC_SERVER_STATUS ServerStatus;	// サーバー状態
+	RPC_SERVER_INFO ServerInfo;		// サーバー情報
+	CAPSLIST *CapsList;			// Caps リスト
+	bool EmptyPassword;			// 空のパスワード
+	SETTING *CurrentSetting;	// 現在の接続設定
+	wchar_t *AdminMsg;			// 管理者向けメッセージ
+} SM_SERVER;
+
+typedef void (SM_STATUS_INIT_PROC)(HWND hWnd, SM_SERVER *p, void *param);
+typedef bool (SM_STATUS_REFRESH_PROC)(HWND hWnd, SM_SERVER *p, void *param);
+
+// 情報表示ダイアログ
+typedef struct SM_STATUS
+{
+	SM_SERVER *p;				// P へのポインタ
+	void *Param;				// パラメータ
+	UINT Icon;					// アイコン
+	wchar_t *Caption;			// タイトル
+	bool show_refresh_button;	// 更新ボタンの表示
+	bool NoImage;				// イメージ無し
+	SM_STATUS_INIT_PROC *InitProc;
+	SM_STATUS_REFRESH_PROC *RefreshProc;
+} SM_STATUS;
+
+// 仮想 HUB 編集ダイアログ
+typedef struct SM_EDIT_HUB
+{
+	SM_SERVER *p;				// P
+	bool EditMode;				// 編集モード
+	char HubName[MAX_HUBNAME_LEN + 1];	// HUB 名
+} SM_EDIT_HUB;
+
+// SSL 関係
+typedef struct SM_SSL
+{
+	SM_SERVER *p;				// P
+	X *Cert;					// 証明書
+	K *Key;						// 秘密鍵
+	bool SetCertAndKey;			// キーをセットする
+} SM_SSL;
+
+// 証明書保存
+typedef struct SM_SAVE_KEY_PAIR
+{
+	X *Cert;					// 証明書
+	K *Key;						// 秘密鍵
+	char *Pass;					// パスフレーズ
+} SM_SAVE_KEY_PAIR;
+
+// コネクション情報
+typedef struct SM_CONNECTION_INFO
+{
+	SM_SERVER *p;				// P
+	char *ConnectionName;		// コネクション名
+} SM_CONNECTION_INFO;
+
+// HUB の管理
+typedef struct SM_HUB
+{
+	SM_SERVER *p;				// P
+	RPC *Rpc;					// RPC
+	char *HubName;				// HUB 名
+} SM_HUB;
+
+// ユーザーリスト表示
+typedef struct SM_USER
+{
+	SM_SERVER *p;				// P
+	RPC *Rpc;					// RPC
+	SM_HUB *Hub;				// HUB
+	char *GroupName;			// グループ名でフィルタ
+	bool SelectMode;			// 選択モード
+	char *SelectedName;			// 選択されたユーザー名
+	bool AllowGroup;			// グループの選択を許可
+	bool CreateNow;				// すぐにユーザーを作成
+} SM_USER;
+
+// ユーザーの編集
+typedef struct SM_EDIT_USER
+{
+	bool Inited;				// 初期化済みフラグ
+	bool EditMode;				// 編集モード
+	SM_SERVER *p;				// P
+	RPC *Rpc;					// RPC
+	SM_HUB *Hub;				// HUB
+	RPC_SET_USER SetUser;		// ユーザー設定
+} SM_EDIT_USER;
+
+// ユーザー情報
+typedef struct SM_USER_INFO
+{
+	SM_SERVER *p;				// P
+	RPC *Rpc;					// RPC
+	SM_HUB *Hub;				// HUB
+	char *Username;				// Username
+} SM_USER_INFO;
+
+// ポリシー
+typedef struct SM_POLICY
+{
+	bool Inited;				// 初期化
+	POLICY *Policy;				// ポリシー
+	wchar_t *Caption;			// タイトル
+	bool CascadeMode;			// カスケードモード
+	UINT Ver;					// バージョン
+} SM_POLICY;
+
+// グループリスト表示
+typedef struct SM_GROUP
+{
+	SM_SERVER *p;				// P
+	RPC *Rpc;					// RPC
+	SM_HUB *Hub;				// HUB
+	bool SelectMode;			// 選択モード
+	char *SelectedGroupName;	// 選択されたグループ名
+} SM_GROUP;
+
+// グループの編集
+typedef struct SM_EDIT_GROUP
+{
+	bool Inited;				// 初期化フラグ
+	bool EditMode;				// 編集モード
+	SM_SERVER *p;				// P
+	RPC *Rpc;					// RPC
+	SM_HUB *Hub;				// HUB
+	RPC_SET_GROUP SetGroup;		// グループ設定
+} SM_EDIT_GROUP;
+
+// アクセスリスト一覧
+typedef struct SM_ACCESS_LIST
+{
+	RPC *Rpc;					// RPC
+	SM_HUB *Hub;				// HUB
+	LIST *AccessList;			// アクセスリスト
+} SM_ACCESS_LIST;
+
+// アクセスリストの編集
+typedef struct SM_EDIT_ACCESS
+{
+	SM_HUB *Hub;				// HUB
+	bool Inited;				// 初期化フラグ
+	bool EditMode;				// 編集モード
+	SM_ACCESS_LIST *AccessList;	// アクセスリスト
+	ACCESS *Access;				// アクセスリスト項目
+} SM_EDIT_ACCESS;
+
+// アクセスリストの状態表示
+typedef struct SM_LINK
+{
+	SM_HUB *Hub;				// HUB
+	wchar_t *AccountName;		// アカウント名
+} SM_LINK;
+
+// セッション ステータス
+typedef struct SM_SESSION_STATUS
+{
+	SM_HUB *Hub;				// HUB
+	char *SessionName;			// セッション名
+} SM_SESSION_STATUS;
+
+// アドレステーブル
+typedef struct SM_TABLE
+{
+	SM_HUB *Hub;				// HUB
+	RPC *Rpc;					// RPC
+	char *SessionName;			// セッション名
+} SM_TABLE;
+
+// 証明書ツール
+typedef struct SM_CERT
+{
+	X *x;						// 生成された証明書
+	K *k;						// 生成された秘密鍵
+	X *root_x;					// ルート証明書
+	K *root_k;					// ルート証明書の秘密鍵
+	bool do_not_save;			// ファイルに保存しない
+	char *default_cn;			// デフォルトの CN
+} SM_CERT;
+
+// config 編集
+typedef struct SM_CONFIG
+{
+	SM_SERVER *s;				// SM_SERVER
+	RPC_CONFIG Config;			// Config 本体
+} SM_CONFIG;
+
+// hub_admin_option 編集
+typedef struct SM_EDIT_AO
+{
+	SM_EDIT_HUB *e;
+	bool CanChange;
+	RPC_ADMIN_OPTION CurrentOptions;
+	RPC_ADMIN_OPTION DefaultOptions;
+	bool NewMode;
+	char Name[MAX_ADMIN_OPTION_NAME_LEN + 1];
+	UINT Value;
+	bool ExtOption;
+} SM_EDIT_AO;
+
+// スイッチ編集
+typedef struct SM_L3SW
+{
+	SM_SERVER *s;
+	char *SwitchName;
+	bool Enable;
+} SM_L3SW;
+
+// スマートカードから証明書と秘密鍵の指定
+typedef struct SM_SECURE_KEYPAIR
+{
+	UINT Id;
+	bool UseCert;
+	bool UseKey;
+	char CertName[MAX_SIZE];
+	char KeyName[MAX_SIZE];
+	bool Flag;
+	UINT BitmapId;
+} SM_SECURE_KEYPAIR;
+
+// CRL 編集
+typedef struct SM_EDIT_CRL
+{
+	SM_HUB *s;
+	bool NewCrl;
+	UINT Key;
+} SM_EDIT_CRL;
+
+// AC リスト編集
+typedef struct SM_EDIT_AC_LIST
+{
+	SM_EDIT_HUB *s;
+	LIST *AcList;
+} SM_EDIT_AC_LIST;
+
+// AC 編集
+typedef struct SM_EDIT_AC
+{
+	SM_EDIT_AC_LIST *e;
+	UINT id;
+} SM_EDIT_AC;
+
+// ログファイルダウンロード
+typedef struct SM_READ_LOG_FILE
+{
+	HWND hWnd;
+	SM_SERVER *s;
+	char *server_name;
+	char *filepath;
+	UINT totalsize;
+	bool cancel_flag;
+	BUF *Buffer;
+} SM_READ_LOG_FILE;
+
+// セットアップダイアログ
+typedef struct SM_SETUP
+{
+	SM_SERVER *s;
+	RPC *Rpc;
+	bool IsBridge;
+	bool UseRemote;			// リモートアクセス VPN
+	bool UseSite;			// 拠点間接続 VPN
+	bool UseSiteEdge;		// 各拠点に設置する VPN Server / Bridge
+	char HubName[MAX_HUBNAME_LEN + 1];	// 仮想 HUB 名
+	bool Flag1;
+	bool Flag2;
+} SM_SETUP;
+
+
+// 関数プロトタイプ
+void InitSM();
+void SmParseCommandLine();
+void MainSM();
+void FreeSM();
+void SmMainDlg();
+UINT SmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmMainDlgInit(HWND hWnd);
+void SmMainDlgUpdate(HWND hWnd);
+void SmInitSettingList();
+void SmFreeSettingList();
+void SmWriteSettingList();
+void SmLoadSettingList();
+void SmInitDefaultSettingList();
+int SmCompareSetting(void *p1, void *p2);
+SETTING *SmGetSetting(wchar_t *title);
+bool SmAddSetting(SETTING *s);
+void SmDeleteSetting(wchar_t *title);
+bool SmCheckNewName(SETTING *s, wchar_t *new_title);
+void SmRefreshSetting(HWND hWnd);
+void SmRefreshSettingEx(HWND hWnd, wchar_t *select_name);
+bool SmAddSettingDlg(HWND hWnd, wchar_t *new_name, UINT new_name_size);
+bool SmEditSettingDlg(HWND hWnd);
+UINT SmEditSettingDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditSettingDlgInit(HWND hWnd, SM_EDIT_SETTING *p);
+void SmEditSettingDlgUpdate(HWND hWnd, SM_EDIT_SETTING *p);
+void SmEditSettingDlgOnOk(HWND hWnd, SM_EDIT_SETTING *p);
+void SmConnect(HWND hWnd, SETTING *s);
+char *SmPassword(HWND hWnd, char *server_name);
+UINT SmServerDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmServerDlgInit(HWND hWnd, SM_SERVER *p);
+void SmServerDlgUpdate(HWND hWnd, SM_SERVER *p);
+void SmServerDlgRefresh(HWND hWnd, SM_SERVER *p);
+void SmStatusDlg(HWND hWnd, SM_SERVER *p, void *param, bool no_image, bool show_refresh_button, wchar_t *caption, UINT icon,
+				 SM_STATUS_INIT_PROC *init, SM_STATUS_REFRESH_PROC *refresh);
+UINT SmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool SmRefreshHubStatus(HWND hWnd, SM_SERVER *p, void *param);
+void SmInsertTrafficInfo(LVB *b, TRAFFIC *t);
+bool SmCreateHubDlg(HWND hWnd, SM_SERVER *p);
+bool SmEditHubDlg(HWND hWnd, SM_SERVER *p, char *hubname);
+UINT SmEditHubProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditHubInit(HWND hWnd, SM_EDIT_HUB *s);
+void SmEditHubUpdate(HWND hWnd, SM_EDIT_HUB *s);
+void SmEditHubOnOk(HWND hWnd, SM_EDIT_HUB *s);
+bool SmCreateListenerDlg(HWND hWnd, SM_SERVER *p);
+UINT SmCreateListenerDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSslDlg(HWND hWnd, SM_SERVER *p);
+UINT SmSslDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSslDlgInit(HWND hWnd, SM_SSL *s);
+void SmSslDlgOnOk(HWND hWnd, SM_SSL *s);
+void SmSslDlgUpdate(HWND hWnd, SM_SSL *s);
+void SmGetCertInfoStr(wchar_t *str, UINT size, X *x);
+bool SmSaveKeyPairDlg(HWND hWnd, X *x, K *k);
+UINT SmSaveKeyPairDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSaveKeyPairDlgInit(HWND hWnd, SM_SAVE_KEY_PAIR *s);
+void SmSaveKeyPairDlgUpdate(HWND hWnd, SM_SAVE_KEY_PAIR *s);
+void SmSaveKeyPairDlgOnOk(HWND hWnd, SM_SAVE_KEY_PAIR *s);
+bool SmRefreshServerStatus(HWND hWnd, SM_SERVER *p, void *param);
+bool SmRefreshServerInfo(HWND hWnd, SM_SERVER *p, void *param);
+void SmPrintNodeInfo(LVB *b, NODE_INFO *info);
+wchar_t *SmGetConnectionTypeStr(UINT type);
+void SmConnectionDlg(HWND hWnd, SM_SERVER *p);
+UINT SmConnectionDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmConnectionDlgInit(HWND hWnd, SM_SERVER *p);
+void SmConnectionDlgRefresh(HWND hWnd, SM_SERVER *p);
+void SmConnectionDlgUpdate(HWND hWnd, SM_SERVER *p);
+bool SmRefreshConnectionStatus(HWND hWnd, SM_SERVER *p, void *param);
+bool SmFarmDlg(HWND hWnd, SM_SERVER *p);
+UINT SmFarmDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmFarmDlgInit(HWND hWnd, SM_SERVER *p);
+void SmFarmDlgUpdate(HWND hWnd, SM_SERVER *p);
+void SmFarmDlgOnOk(HWND hWnd, SM_SERVER *p);
+LIST *SmStrToPortList(char *str);
+UINT SmFarmMemberDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmFarmMemberDlgInit(HWND hWnd, SM_SERVER *p);
+void SmFarmMemberDlgUpdate(HWND hWnd, SM_SERVER *p);
+void SmFarmMemberDlgRefresh(HWND hWnd, SM_SERVER *p);
+void SmFarmMemberDlgOnOk(HWND hWnd, SM_SERVER *p);
+void SmFarmMemberCert(HWND hWnd, SM_SERVER *p, UINT id);
+bool SmRefreshFarmMemberInfo(HWND hWnd, SM_SERVER *p, void *param);
+bool SmRefreshFarmConnectionInfo(HWND hWnd, SM_SERVER *p, void *param);
+UINT SmChangeServerPasswordDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubDlg(HWND hWnd, SM_HUB *s);
+UINT SmHubDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubDlgInit(HWND hWnd, SM_HUB *s);
+void SmHubDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmHubDlgRefresh(HWND hWnd, SM_HUB *s);
+void SmUserListDlg(HWND hWnd, SM_HUB *s);
+UINT SmUserListProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmUserListInit(HWND hWnd, SM_USER *s);
+void SmUserListRefresh(HWND hWnd, SM_USER *s);
+void SmUserListUpdate(HWND hWnd, SM_USER *s);
+wchar_t *SmGetAuthTypeStr(UINT id);
+bool SmCreateUserDlg(HWND hWnd, SM_HUB *s);
+UINT SmEditUserDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditUserDlgInit(HWND hWnd, SM_EDIT_USER *s);
+void SmEditUserDlgUpdate(HWND hWnd, SM_EDIT_USER *s);
+void SmEditUserDlgOk(HWND hWnd, SM_EDIT_USER *s);
+bool SmPolicyDlg(HWND hWnd, POLICY *p, wchar_t *caption);
+bool SmPolicyDlgEx(HWND hWnd, POLICY *p, wchar_t *caption, bool cascade_mode);
+bool SmPolicyDlgEx2(HWND hWnd, POLICY *p, wchar_t *caption, bool cascade_mode, UINT ver);
+UINT SmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmPolicyDlgInit(HWND hWnd, SM_POLICY *s);
+void SmPolicyDlgUpdate(HWND hWnd, SM_POLICY *s);
+void SmPolicyDlgOk(HWND hWnd, SM_POLICY *s);
+bool SmEditUserDlg(HWND hWnd, SM_HUB *s, char *username);
+bool SmRefreshUserInfo(HWND hWnd, SM_SERVER *s, void *param);
+void SmGroupListDlg(HWND hWnd, SM_HUB *s);
+char *SmSelectGroupDlg(HWND hWnd, SM_HUB *s, char *default_name);
+UINT SmGroupListDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmGroupListDlgInit(HWND hWnd, SM_GROUP *s);
+void SmGroupListDlgUpdate(HWND hWnd, SM_GROUP *s);
+void SmGroupListDlgRefresh(HWND hWnd, SM_GROUP *s);
+bool SmCreateGroupDlg(HWND hWnd, SM_GROUP *s);
+bool SmEditGroupDlg(HWND hWnd, SM_GROUP *s, char *name);
+UINT SmEditGroupDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditGroupDlgInit(HWND hWnd, SM_EDIT_GROUP *g);
+void SmEditGroupDlgUpdate(HWND hWnd, SM_EDIT_GROUP *g);
+void SmEditGroupDlgOnOk(HWND hWnd, SM_EDIT_GROUP *g);
+void SmUserListDlgEx(HWND hWnd, SM_HUB *s, char *groupname, bool create);
+void SmAccessListDlg(HWND hWnd, SM_HUB *s);
+UINT SmAccessListProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmAccessListInit(HWND hWnd, SM_ACCESS_LIST *s);
+void SmAccessListUpdate(HWND hWnd, SM_ACCESS_LIST *s);
+void SmAccessListRefresh(HWND hWnd, SM_ACCESS_LIST *s);
+bool SmAddAccess(HWND hWnd, SM_ACCESS_LIST *s, bool ipv6);
+bool SmEditAccess(HWND hWnd, SM_ACCESS_LIST *s, ACCESS *a);
+UINT SmEditAccessDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditAccessInit(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmEditAccessUpdate(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmEditAccessOnOk(HWND hWnd, SM_EDIT_ACCESS *s);
+UINT SmSimulationDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSimulationUpdate(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmSimulationInit(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmSimulationOnOk(HWND hWnd, SM_EDIT_ACCESS *s);
+char *SmSelectUserDlg(HWND hWnd, SM_HUB *s, char *default_name);
+char *SmSelectUserDlgEx(HWND hWnd, SM_HUB *s, char *default_name, bool allow_group);
+void SmRadiusDlg(HWND hWnd, SM_HUB *s);
+UINT SmRadiusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmRadiusDlgInit(HWND hWnd, SM_HUB *s);
+void SmRadiusDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmRadiusDlgOnOk(HWND hWnd, SM_HUB *s);
+void SmLinkDlg(HWND hWnd, SM_HUB *s);
+void SmLinkDlgEx(HWND hWnd, SM_HUB *s, bool createNow);
+UINT SmLinkDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLinkDlgInit(HWND hWnd, SM_HUB *s);
+void SmLinkDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmLinkDlgRefresh(HWND hWnd, SM_HUB *s);
+bool SmLinkCreate(HWND hWnd, SM_HUB *s);
+bool SmLinkCreateEx(HWND hWnd, SM_HUB *s, bool connectNow);
+bool SmLinkEdit(HWND hWnd, SM_HUB *s, wchar_t *name);
+bool SmRefreshLinkStatus(HWND hWnd, SM_SERVER *s, void *param);
+UINT SmLogDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLogDlgInit(HWND hWnd, SM_HUB *s);
+void SmLogDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmLogDlgOnOk(HWND hWnd, SM_HUB *s);
+void SmCaDlg(HWND hWnd, SM_HUB *s);
+UINT SmCaDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmCaDlgInit(HWND hWnd, SM_HUB *s);
+void SmCaDlgRefresh(HWND hWnd, SM_HUB *s);
+void SmCaDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmCaDlgOnOk(HWND hWnd, SM_HUB *s);
+bool SmCaDlgAdd(HWND hWnd, SM_HUB *s);
+void SmSessionDlg(HWND hWnd, SM_HUB *s);
+UINT SmSessionDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSessionDlgInit(HWND hWnd, SM_HUB *s);
+void SmSessionDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmSessionDlgRefresh(HWND hWnd, SM_HUB *s);
+bool SmRefreshSessionStatus(HWND hWnd, SM_SERVER *s, void *param);
+void SmMacTableDlg(HWND hWnd, SM_HUB *s, char *session_name);
+UINT SmMacTableDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmMacTableDlgInit(HWND hWnd, SM_TABLE *s);
+void SmMacTableDlgUpdate(HWND hWnd, SM_TABLE *s);
+void SmMacTableDlgRefresh(HWND hWnd, SM_TABLE *s);
+void SmIpTableDlg(HWND hWnd, SM_HUB *s, char *session_name);
+UINT SmIpTableDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmIpTableDlgInit(HWND hWnd, SM_TABLE *s);
+void SmIpTableDlgUpdate(HWND hWnd, SM_TABLE *s);
+void SmIpTableDlgRefresh(HWND hWnd, SM_TABLE *s);
+bool SmCreateCert(HWND hWnd, X **x, K **k, bool do_not_save, char *default_cn);
+UINT SmCreateCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmCreateCertDlgInit(HWND hWnd, SM_CERT *s);
+void SmCreateCertDlgUpdate(HWND hWnd, SM_CERT *s);
+void SmCreateCertDlgOnOk(HWND hWnd, SM_CERT *s);
+UINT SmSNATDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSNATDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmBridgeDlg(HWND hWnd, SM_SERVER *s);
+void SmInstallWinPcap(HWND hWnd, SM_SERVER *s);
+UINT SmBridgeDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmBridgeDlgInit(HWND hWnd, SM_SERVER *s);
+void SmBridgeDlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmBridgeDlgRefresh(HWND hWnd, SM_SERVER *s);
+void SmBridgeDlgOnOk(HWND hWnd, SM_SERVER *s);
+void SmAddServerCaps(LVB *b, CAPSLIST *t);
+void SmConfig(HWND hWnd, SM_SERVER *s);
+UINT SmConfigDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmConfigDlgInit(HWND hWnd, SM_CONFIG *c);
+void SmHubAdminOption(HWND hWnd, SM_EDIT_HUB *e);
+void SmHubExtOption(HWND hWnd, SM_EDIT_HUB *e);
+UINT SmHubAdminOptionDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubAdminOptionDlgUpdate(HWND hWnd, SM_EDIT_AO *a);
+void SmHubAdminOptionDlgInit(HWND hWnd, SM_EDIT_AO *a);
+void SmHubAdminOptionDlgOk(HWND hWnd, SM_EDIT_AO *a);
+UINT SmHubAdminOptionValueDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubAdminOptionValueDlgUpdate(HWND hWnd, SM_EDIT_AO *a);
+void SmL3(HWND hWnd, SM_SERVER *s);
+UINT SmL3Dlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3DlgInit(HWND hWnd, SM_SERVER *s);
+void SmL3DlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmL3DlgRefresh(HWND hWnd, SM_SERVER *s);
+UINT SmL3AddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3AddDlgUpdate(HWND hWnd, SM_SERVER *s);
+UINT SmL3SwDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3SwDlgInit(HWND hWnd, SM_L3SW *w);
+void SmL3SwDlgUpdate(HWND hWnd, SM_L3SW *w);
+void SmL3SwDlgRefresh(HWND hWnd, SM_L3SW *w);
+UINT SmL3SwIfDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3SwIfDlgInit(HWND hWnd, SM_L3SW *w);
+void SmL3SwIfDlgUpdate(HWND hWnd, SM_L3SW *w);
+UINT SmL3SwTableDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3SwTableDlgInit(HWND hWnd, SM_L3SW *w);
+void SmL3SwTableDlgUpdate(HWND hWnd, SM_L3SW *w);
+bool SmL3IsSwActive(SM_SERVER *s, char *name);
+UINT SmGetCurrentSecureId(HWND hWnd);
+UINT SmGetCurrentSecureIdFromReg();
+UINT SmSelectSecureId(HWND hWnd);
+void SmWriteSelectSecureIdReg(UINT id);
+bool SmSelectKeyPair(HWND hWnd, char *cert_name, UINT cert_name_size, char *key_name, UINT key_name_size);
+bool SmSelectKeyPairEx(HWND hWnd, char *cert_name, UINT cert_name_size, char *key_name, UINT key_name_size, UINT bitmap_id);
+UINT SmSelectKeyPairDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSelectKeyPairDlgInit(HWND hWnd, SM_SECURE_KEYPAIR *k);
+void SmSelectKeyPairDlgUpdate(HWND hWnd, SM_SECURE_KEYPAIR *k);
+void SmSelectKeyPairDlgRefresh(HWND hWnd, SM_SECURE_KEYPAIR *k);
+void SmSecureManager(HWND hWnd);
+UINT SmCrlDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmCrlDlgInit(HWND hWnd, SM_HUB *s);
+void SmCrlDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmCrlDlgRefresh(HWND hWnd, SM_HUB *s);
+UINT SmEditCrlDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditCrlDlgInit(HWND hWnd, SM_EDIT_CRL *c);
+void SmEditCrlDlgUpdate(HWND hWnd, SM_EDIT_CRL *c);
+void SmEditCrlDlgOnOk(HWND hWnd, SM_EDIT_CRL *c);
+void SmEditCrlDlgOnLoad(HWND hWnd, SM_EDIT_CRL *c);
+void SmEditCrlDlgSetName(HWND hWnd, NAME *name);
+void SmEditCrlDlgSetSerial(HWND hWnd, X_SERIAL *serial);
+void SmEditCrlDlgSetHash(HWND hWnd, UCHAR *hash_md5, UCHAR *hash_sha1);
+void SmHubAc(HWND hWnd, SM_EDIT_HUB *s);
+UINT SmHubAcDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubAcDlgInit(HWND hWnd, SM_EDIT_AC_LIST *p);
+void SmHubAcDlgUpdate(HWND hWnd, SM_EDIT_AC_LIST *p);
+void SmHubAcDlgRefresh(HWND hWnd, SM_EDIT_AC_LIST *p);
+UINT SmHubEditAcDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubEditAcDlgInit(HWND hWnd, SM_EDIT_AC *p);
+void SmHubEditAcDlgUpdate(HWND hWnd, SM_EDIT_AC *p);
+void SmHubEditAcDlgOnOk(HWND hWnd, SM_EDIT_AC *p);
+UINT SmLogFileDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLogFileDlgInit(HWND hWnd, SM_SERVER *p);
+void SmLogFileDlgRefresh(HWND hWnd, SM_SERVER *p);
+void SmLogFileDlgUpdate(HWND hWnd, SM_SERVER *p);
+void SmLogFileStartDownload(HWND hWnd, SM_SERVER *s, char *server_name, char *filepath, UINT totalsize);
+UINT SmReadLogFile(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool SmReadLogFileProc(DOWNLOAD_PROGRESS *g);
+UINT SmSaveLogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLicense(HWND hWnd, SM_SERVER *s);
+UINT SmLicenseDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLicenseDlgInit(HWND hWnd, SM_SERVER *s);
+void SmLicenseDlgRefresh(HWND hWnd, SM_SERVER *s);
+void SmLicenseDlgUpdate(HWND hWnd, SM_SERVER *s);
+bool SmLicenseAdd(HWND hWnd, SM_SERVER *s);
+UINT SmLicenseAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLicenseAddDlgInit(HWND hWnd, SM_SERVER *s);
+void SmLicenseAddDlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmLicenseAddDlgShiftTextItem(HWND hWnd, UINT id1, UINT id2, UINT *next_focus);
+void SmLicenseAddDlgGetText(HWND hWnd, char *str, UINT size);
+void SmLicenseAddDlgOnOk(HWND hWnd, SM_SERVER *s);
+bool SmSetup(HWND hWnd, SM_SERVER *s);
+UINT SmSetupDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSetupDlgInit(HWND hWnd, SM_SETUP *s);
+void SmSetupDlgUpdate(HWND hWnd, SM_SETUP *s);
+void SmSetupDlgOnOk(HWND hWnd, SM_SETUP *s);
+UINT SmSetupHubDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSetupHubDlgUpdate(HWND hWnd, SM_SETUP *s);
+bool SmSetupInit(HWND hWnd, SM_SETUP *s);
+bool SmSetupDeleteAllHub(HWND hWnd, SM_SETUP *s);
+bool SmSetupDeleteAllLocalBridge(HWND hWnd, SM_SETUP *s);
+bool SmSetupDeleteAllLayer3(HWND hWnd, SM_SETUP *s);
+bool SmSetupDeleteAllObjectInBridgeHub(HWND hWnd, SM_SETUP *s);
+void SmSetupStep(HWND hWnd, SM_SETUP *s);
+UINT SmSetupStepDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSetupStepDlgInit(HWND hWnd, SM_SETUP *s);
+void SmSetupOnClose(HWND hWnd, SM_SETUP *s);
+bool SmSetupIsNew(SM_SERVER *s);
+void SmVLan(HWND hWnd, SM_SERVER *s);
+UINT SmVLanDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmVLanDlgInit(HWND hWnd, SM_SERVER *s);
+void SmVLanDlgRefresh(HWND hWnd, SM_SERVER *s);
+void SmVLanDlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmHubMsg(HWND hWnd, SM_EDIT_HUB *s);
+UINT SmHubMsgDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubMsgDlgInit(HWND hWnd, SM_EDIT_HUB *s);
+void SmHubMsgDlgUpdate(HWND hWnd, SM_EDIT_HUB *s);
+void SmHubMsgDlgOnOk(HWND hWnd, SM_EDIT_HUB *s);
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Sam.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Sam.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Sam.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,347 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Sam.c
+// セキュリティアカウントマネージャ
+
+// Windows NT の SAM を真似してかっこいい名前を付けてみたが、
+// 実装してみると結局大した処理はしていない。
+
+#include "CedarPch.h"
+
+// パスワードの暗号化
+void SecurePassword(void *secure_password, void *password, void *random)
+{
+	BUF *b;
+	// 引数チェック
+	if (secure_password == NULL || password == NULL || random == NULL)
+	{
+		return;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, password, SHA1_SIZE);
+	WriteBuf(b, random, SHA1_SIZE);
+	Hash(secure_password, b->Buf, b->Size, true);
+
+	FreeBuf(b);
+}
+
+// 160bit 乱数の生成
+void GenRamdom(void *random)
+{
+	// 引数チェック
+	if (random == NULL)
+	{
+		return;
+	}
+
+	Rand(random, SHA1_SIZE);
+}
+
+// ユーザーの匿名認証
+bool SamAuthUserByAnonymous(HUB *h, char *username)
+{
+	bool b = false;
+	// 引数チェック
+	if (h == NULL || username == NULL)
+	{
+		return false;
+	}
+
+	AcLock(h);
+	{
+		USER *u = AcGetUser(h, username);
+		if (u)
+		{
+			Lock(u->lock);
+			{
+				if (u->AuthType == AUTHTYPE_ANONYMOUS)
+				{
+					b = true;
+				}
+			}
+			Unlock(u->lock);
+		}
+		ReleaseUser(u);
+	}
+	AcUnlock(h);
+
+	return b;
+}
+
+// 指定した証明書を署名したルート証明書をリストから取得する
+X *GetIssuerFromList(LIST *cert_list, X *cert)
+{
+	UINT i;
+	X *ret = NULL;
+	// 引数チェック
+	if (cert_list == NULL || cert == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(cert_list);i++)
+	{
+		X *x = LIST_DATA(cert_list, i);
+		// 名前の比較
+		if (CheckXDateNow(x))
+		{
+			if (CompareName(x->subject_name, cert->issuer_name))
+			{
+				// ルート証明書の公開鍵を取得
+				K *k = GetKFromX(x);
+
+				if (k != NULL)
+				{
+					// 署名のチェック
+					if (CheckSignature(cert, k))
+					{
+						ret = x;
+					}
+					FreeK(k);
+				}
+			}
+		}
+		if (CompareX(x, cert))
+		{
+			// 完全同一
+			ret = x;
+		}
+	}
+
+	return ret;
+}
+
+// ユーザーに適用されるべきポリシーを取得
+POLICY *SamGetUserPolicy(HUB *h, char *username)
+{
+	POLICY *ret = NULL;
+	// 引数チェック
+	if (h == NULL || username == NULL)
+	{
+		return NULL;
+	}
+
+	AcLock(h);
+	{
+		USER *u;
+		u = AcGetUser(h, username);
+		if (u)
+		{
+			USERGROUP *g = NULL;
+			Lock(u->lock);
+			{
+				if (u->Policy != NULL)
+				{
+					ret = ClonePolicy(u->Policy);
+				}
+
+				g = u->Group;
+
+				if (g != NULL)
+				{
+					AddRef(g->ref);
+				}
+			}
+			Unlock(u->lock);
+
+			ReleaseUser(u);
+			u = NULL;
+
+			if (ret == NULL)
+			{
+				if (g != NULL)
+				{
+					Lock(g->lock);
+					{
+						ret = ClonePolicy(g->Policy);
+					}
+					Unlock(g->lock);
+				}
+			}
+
+			if (g != NULL)
+			{
+				ReleaseGroup(g);
+			}
+		}
+	}
+	AcUnlock(h);
+
+	return ret;
+}
+
+// ユーザーのパスワード認証
+bool SamAuthUserByPassword(HUB *h, char *username, void *random, void *secure_password)
+{
+	bool b = false;
+	UCHAR secure_password_check[SHA1_SIZE];
+	// 引数チェック
+	if (h == NULL || username == NULL || secure_password == NULL)
+	{
+		return false;
+	}
+
+	if (StrCmpi(username, ADMINISTRATOR_USERNAME) == 0)
+	{
+		// Administrator モード
+		SecurePassword(secure_password_check, h->SecurePassword, random);
+		if (Cmp(secure_password_check, secure_password, SHA1_SIZE) == 0)
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	AcLock(h);
+	{
+		USER *u;
+		u = AcGetUser(h, username);
+		if (u)
+		{
+			Lock(u->lock);
+			{
+				if (u->AuthType == AUTHTYPE_PASSWORD)
+				{
+					AUTHPASSWORD *auth = (AUTHPASSWORD *)u->AuthData;
+					SecurePassword(secure_password_check, auth->HashedKey, random);
+					if (Cmp(secure_password_check, secure_password, SHA1_SIZE) == 0)
+					{
+						b = true;
+					}
+				}
+			}
+			Unlock(u->lock);
+			ReleaseUser(u);
+		}
+	}
+	AcUnlock(h);
+
+	return b;
+}
+
+// ユーザーが存在することを確認
+bool SamIsUser(HUB *h, char *username)
+{
+	bool b;
+	// 引数チェック
+	if (h == NULL || username == NULL)
+	{
+		return false;
+	}
+
+	AcLock(h);
+	{
+		b = AcIsUser(h, username);
+	}
+	AcUnlock(h);
+
+	return b;
+}
+
+// ユーザーが使用する認証の種類を取得
+UINT SamGetUserAuthType(HUB *h, char *username)
+{
+	UINT authtype;
+	// 引数チェック
+	if (h == NULL || username == NULL)
+	{
+		return INFINITE;
+	}
+
+	AcLock(h);
+	{
+		USER *u = AcGetUser(h, username);
+		if (u == NULL)
+		{
+			authtype = INFINITE;
+		}
+		else
+		{
+			authtype = u->AuthType;
+			ReleaseUser(u);
+		}
+	}
+	AcUnlock(h);
+
+	return authtype;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Sam.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Sam.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Sam.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,97 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Sam.h
+// Sam.c のヘッダ
+
+#ifndef	SAM_H
+#define	SAM_H
+
+
+// 関数プロトタイプ
+bool SamIsUser(HUB *h, char *username);
+UINT SamGetUserAuthType(HUB *h, char *username);
+bool SamAuthUserByPassword(HUB *h, char *username, void *random, void *secure_password);
+bool SamAuthUserByAnonymous(HUB *h, char *username);
+POLICY *SamGetUserPolicy(HUB *h, char *username);
+
+void GenRamdom(void *random);
+void SecurePassword(void *secure_password, void *password, void *random);
+X *GetIssuerFromList(LIST *cert_list, X *cert);
+
+#endif	// SAM_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SecureNAT.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SecureNAT.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SecureNAT.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,189 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// SecureNAT.c
+// SecureNAT コード
+
+#include "CedarPch.h"
+
+// SecureNAT サーバー側スレッド
+void SnSecureNATThread(THREAD *t, void *param)
+{
+	SNAT *s;
+	CONNECTION *c;
+	SESSION *se;
+	POLICY *policy;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	s = (SNAT *)param;
+	// サーバーコネクションの作成
+	c = NewServerConnection(s->Cedar, NULL, t);
+	c->Protocol = CONNECTION_HUB_SECURE_NAT;
+
+	// デフォルトポリシーの適用
+	policy = ClonePolicy(GetDefaultPolicy());
+
+	// サーバーセッションの作成
+	se = NewServerSession(s->Cedar, c, s->Hub, SNAT_USER_NAME, policy);
+	se->SecureNATMode = true;
+	se->SecureNAT = s;
+	c->Session = se;
+	ReleaseConnection(c);
+
+	HLog(se->Hub, "LH_NAT_START", se->Name);
+
+	// ユーザー名
+	se->Username = CopyStr(SNAT_USER_NAME_PRINT);
+
+	s->Session = se;
+	AddRef(se->ref);
+
+	// 初期化完了を通知
+	NoticeThreadInit(t);
+
+	ReleaseCancel(s->Nat->Virtual->Cancel);
+	s->Nat->Virtual->Cancel = se->Cancel1;
+	AddRef(se->Cancel1->ref);
+
+	// セッションのメイン関数
+	Debug("SecureNAT Start.\n");
+	SessionMain(se);
+	Debug("SecureNAT Stop.\n");
+
+	HLog(se->Hub, "LH_NAT_STOP");
+
+	ReleaseSession(se);
+}
+
+// SecureNAT の解放
+void SnFreeSecureNAT(SNAT *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// セッション停止
+	StopSession(s->Session);
+	ReleaseSession(s->Session);
+
+	// 仮想マシン解放
+	Virtual_Free(s->Nat->Virtual);
+
+	// NAT 解放
+	NiFreeNat(s->Nat);
+
+	DeleteLock(s->lock);
+
+	Free(s);
+}
+
+// 新しい SecureNAT の作成
+SNAT *SnNewSecureNAT(HUB *h, VH_OPTION *o)
+{
+	SNAT *s;
+	THREAD *t;
+	// 引数チェック
+	if (h == NULL || o == NULL)
+	{
+		return NULL;
+	}
+
+	s = ZeroMalloc(sizeof(SNAT));
+	s->Cedar = h->Cedar;
+	s->Hub = h;
+	s->lock = NewLock();
+
+	// NAT の作成
+	s->Nat = NiNewNatEx(s, o);
+
+	// 仮想マシン初期化
+	VirtualInit(s->Nat->Virtual);
+
+	// スレッド作成
+	t = NewThread(SnSecureNATThread, s);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+
+	return s;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SecureNAT.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SecureNAT.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/SecureNAT.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,101 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// SecureNAT.h
+// SecureNAT.c のヘッダ
+
+#ifndef	SECURENAT_H
+#define	SECURENAT_H
+
+struct SNAT
+{
+	LOCK *lock;						// ロック
+	CEDAR *Cedar;					// Cedar
+	HUB *Hub;						// HUB
+	SESSION *Session;				// セッション
+	POLICY *Policy;					// ポリシー
+	NAT *Nat;						// NAT
+};
+
+
+SNAT *SnNewSecureNAT(HUB *h, VH_OPTION *o);
+void SnFreeSecureNAT(SNAT *s);
+void SnSecureNATThread(THREAD *t, void *param);
+
+
+#endif	// SECURENAT_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Server.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Server.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Server.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,9239 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Server.c
+// サーバーマネージャ
+
+#include "CedarPch.h"
+
+static SERVER *server = NULL;
+static LOCK *server_lock = NULL;
+char *SERVER_CONFIG_FILE_NAME = "@vpn_server.config";
+char *BRIDGE_CONFIG_FILE_NAME = "@vpn_bridge.config";
+
+static bool server_reset_setting = false;
+
+// VPN Server に登録されているユーザーオブジェクト数が多すぎるかどうか取得
+bool SiTooManyUserObjectsInServer(SERVER *s, bool oneMore)
+{
+	LICENSE_STATUS st;
+	UINT num;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	num = SiGetServerNumUserObjects(s);
+
+	Zero(&st, sizeof(st));
+
+	LiParseCurrentLicenseStatus(s->LicenseSystem, &st);
+
+	if (st.NumUserLicense == INFINITE)
+	{
+		return false;
+	}
+
+	if (oneMore)
+	{
+		st.NumUserLicense++;
+	}
+
+	if (st.NumUserLicense <= num)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// VPN Server に登録されているユーザーオブジェクト数を取得
+UINT SiGetServerNumUserObjects(SERVER *s)
+{
+	CEDAR *c;
+	UINT ret = 0;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	c = s->Cedar;
+
+	LockList(c->HubList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(c->HubList);i++)
+		{
+			HUB *h = LIST_DATA(c->HubList, i);
+
+			if (h->HubDb != NULL)
+			{
+				ret += LIST_NUM(h->HubDb->UserList);
+			}
+		}
+	}
+	UnlockList(c->HubList);
+
+	return ret;
+}
+
+
+typedef struct SI_DEBUG_PROC_LIST
+{
+	UINT Id;
+	char *Description;
+	char *Args;
+	SI_DEBUG_PROC *Proc;
+} SI_DEBUG_PROC_LIST;
+
+// デバッグ機能
+UINT SiDebug(SERVER *s, RPC_TEST *ret, UINT i, char *str)
+{
+	SI_DEBUG_PROC_LIST proc_list[] =
+	{
+		{1, "Hello World", "<test string>", SiDebugProcHelloWorld},
+		{2, "Terminate process now", "", SiDebugProcExit},
+		{3, "Write memory dumpfile", "", SiDebugProcDump},
+		{4, "Restore process priority", "", SiDebugProcRestorePriority},
+		{5, "Set the process priority high", "", SiDebugProcSetHighPriority},
+		{6, "Get the .exe filename of the process", "", SiDebugProcGetExeFileName},
+		{7, "Crash the process", "", SiDebugProcCrash},
+	};
+	UINT num_proc_list = sizeof(proc_list) / sizeof(proc_list[0]);
+	UINT j;
+	UINT ret_value = ERR_NO_ERROR;
+	// 引数チェック
+	if (s == NULL || ret == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	if (i == 0)
+	{
+		char tmp[MAX_SIZE];
+		Zero(ret, sizeof(RPC_TEST));
+
+		StrCat(ret->StrValue, sizeof(ret->StrValue),
+			"\n--- Debug Functions List --\n");
+
+		for (j = 0;j < num_proc_list;j++)
+		{
+			SI_DEBUG_PROC_LIST *p = &proc_list[j];
+
+			if (IsEmptyStr(p->Args) == false)
+			{
+				Format(tmp, sizeof(tmp),
+					" %u: %s - Usage: %u /ARGS:\"%s\"\n",
+					p->Id, p->Description, p->Id, p->Args);
+			}
+			else
+			{
+				Format(tmp, sizeof(tmp),
+					" %u: %s - Usage: %u\n",
+					p->Id, p->Description, p->Id);
+			}
+
+			StrCat(ret->StrValue, sizeof(ret->StrValue), tmp);
+		}
+	}
+	else
+	{
+		ret_value = ERR_NOT_SUPPORTED;
+
+		for (j = 0;j < num_proc_list;j++)
+		{
+			SI_DEBUG_PROC_LIST *p = &proc_list[j];
+
+			if (p->Id == i)
+			{
+				ret_value = p->Proc(s, str, ret->StrValue, sizeof(ret->StrValue));
+
+				if (ret_value == ERR_NO_ERROR && IsEmptyStr(ret->StrValue))
+				{
+					StrCpy(ret->StrValue, sizeof(ret->StrValue), "Ok.");
+				}
+				break;
+			}
+		}
+	}
+
+	return ret_value;
+}
+UINT SiDebugProcHelloWorld(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
+{
+	// 引数チェック
+	if (s == NULL || in_str == NULL || ret_str == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	Format(ret_str, ret_str_size, "Hello World %s\n", in_str);
+
+	return ERR_NO_ERROR;
+}
+UINT SiDebugProcExit(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
+{
+	// 引数チェック
+	if (s == NULL || in_str == NULL || ret_str == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	_exit(1);
+
+	return ERR_NO_ERROR;
+}
+UINT SiDebugProcDump(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
+{
+	// 引数チェック
+	if (s == NULL || in_str == NULL || ret_str == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+#ifdef	OS_WIN32
+	MsWriteMinidump(NULL, NULL);
+#else	// OS_WIN32
+	return ERR_NOT_SUPPORTED;
+#endif	// OS_WIN32
+
+	return ERR_NO_ERROR;
+}
+UINT SiDebugProcRestorePriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
+{
+	// 引数チェック
+	if (s == NULL || in_str == NULL || ret_str == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	OSRestorePriority();
+
+	return ERR_NO_ERROR;
+}
+UINT SiDebugProcSetHighPriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
+{
+	// 引数チェック
+	if (s == NULL || in_str == NULL || ret_str == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	OSSetHighPriority();
+
+	return ERR_NO_ERROR;
+}
+UINT SiDebugProcGetExeFileName(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
+{
+	// 引数チェック
+	if (s == NULL || in_str == NULL || ret_str == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	GetExeName(ret_str, ret_str_size);
+
+	return ERR_NO_ERROR;
+}
+UINT SiDebugProcCrash(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size)
+{
+	// 引数チェック
+	if (s == NULL || in_str == NULL || ret_str == NULL)
+	{
+		return ERR_INVALID_PARAMETER;
+	}
+
+	CrashNow();
+
+	return ERR_NO_ERROR;
+}
+
+// デバッグログの書き込み
+void SiDebugLog(SERVER *s, char *msg)
+{
+	// 引数チェック
+	if (s == NULL || msg == NULL)
+	{
+		return;
+	}
+
+	if (s->DebugLog != NULL)
+	{
+		WriteTinyLog(s->DebugLog, msg);
+	}
+}
+
+// デッドロック検査メイン
+void SiCheckDeadLockMain(SERVER *s, UINT timeout)
+{
+	CEDAR *cedar;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Debug("SiCheckDeadLockMain Start.\n");
+
+	cedar = s->Cedar;
+
+	if (s->ServerListenerList != NULL)
+	{
+		CheckDeadLock(s->ServerListenerList->lock, timeout, "s->ServerListenerList->lock");
+	}
+
+	CheckDeadLock(s->lock, timeout, "s->lock");
+
+	if (s->FarmMemberList != NULL)
+	{
+		CheckDeadLock(s->FarmMemberList->lock, timeout, "s->FarmMemberList->lock");
+	}
+
+	if (s->HubCreateHistoryList != NULL)
+	{
+		CheckDeadLock(s->HubCreateHistoryList->lock, timeout, "s->HubCreateHistoryList->lock");
+	}
+
+	CheckDeadLock(s->CapsCacheLock, timeout, "s->CapsCacheLock");
+
+	CheckDeadLock(s->TasksFromFarmControllerLock, timeout, "s->TasksFromFarmControllerLock");
+
+	if (cedar != NULL)
+	{
+		if (cedar->HubList != NULL)
+		{
+			CheckDeadLock(cedar->HubList->lock, timeout, "cedar->HubList->lock");
+		}
+
+		if (cedar->ListenerList != NULL)
+		{
+			UINT i;
+			LIST *o = NewListFast(NULL);
+
+			CheckDeadLock(cedar->ListenerList->lock, timeout, "cedar->ListenerList->lock");
+
+			LockList(cedar->ListenerList);
+			{
+				for (i = 0;i < LIST_NUM(cedar->ListenerList);i++)
+				{
+					LISTENER *r = LIST_DATA(cedar->ListenerList, i);
+
+					AddRef(r->ref);
+
+					Add(o, r);
+				}
+			}
+			UnlockList(cedar->ListenerList);
+
+			for (i = 0;i < LIST_NUM(o);i++)
+			{
+				LISTENER *r = LIST_DATA(o, i);
+
+				ReleaseListener(r);
+			}
+
+			ReleaseList(o);
+		}
+
+		if (cedar->ConnectionList != NULL)
+		{
+			CheckDeadLock(cedar->ConnectionList->lock, timeout, "cedar->ConnectionList->lock");
+		}
+
+		if (cedar->CaList != NULL)
+		{
+			CheckDeadLock(cedar->CaList->lock, timeout, "cedar->CaList->lock");
+		}
+
+		if (cedar->TrafficLock != NULL)
+		{
+			CheckDeadLock(cedar->TrafficLock, timeout, "cedar->TrafficLock");
+		}
+
+		if (cedar->TrafficDiffList != NULL)
+		{
+			CheckDeadLock(cedar->TrafficDiffList->lock, timeout, "cedar->TrafficDiffList->lock");
+		}
+
+		if (cedar->LocalBridgeList != NULL)
+		{
+			CheckDeadLock(cedar->LocalBridgeList->lock, timeout, "cedar->LocalBridgeList->lock");
+		}
+
+		if (cedar->L3SwList != NULL)
+		{
+			CheckDeadLock(cedar->L3SwList->lock, timeout, "cedar->L3SwList->lock");
+		}
+	}
+
+	Debug("SiCheckDeadLockMain Finish.\n");
+}
+
+// デッドロックチェックスレッド
+void SiDeadLockCheckThread(THREAD *t, void *param)
+{
+	SERVER *s = (SERVER *)param;
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		Wait(s->DeadLockWaitEvent, SERVER_DEADLOCK_CHECK_SPAN);
+
+		if (s->HaltDeadLockThread)
+		{
+			break;
+		}
+
+		SiCheckDeadLockMain(s, SERVER_DEADLOCK_CHECK_TIMEOUT);
+	}
+}
+
+// デッドロックチェックの初期化
+void SiInitDeadLockCheck(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+	if (s->DisableDeadLockCheck)
+	{
+		return;
+	}
+
+	s->HaltDeadLockThread = false;
+	s->DeadLockWaitEvent = NewEvent();
+	s->DeadLockCheckThread = NewThread(SiDeadLockCheckThread, s);
+}
+
+// デッドロックチェックの解放
+void SiFreeDeadLockCheck(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (s->DeadLockCheckThread == NULL)
+	{
+		return;
+	}
+
+	s->HaltDeadLockThread = true;
+	Set(s->DeadLockWaitEvent);
+
+	WaitThread(s->DeadLockCheckThread, INFINITE);
+
+	ReleaseThread(s->DeadLockCheckThread);
+	s->DeadLockCheckThread = NULL;
+
+	ReleaseEvent(s->DeadLockWaitEvent);
+	s->DeadLockWaitEvent = NULL;
+
+	s->HaltDeadLockThread = false;
+}
+
+// 指定した仮想 HUB が作成履歴に登録されているかどうか調べる
+bool SiIsHubRegistedOnCreateHistory(SERVER *s, char *name)
+{
+	UINT i;
+	bool ret = false;
+	// 引数チェック
+	if (s == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	SiDeleteOldHubCreateHistory(s);
+
+	LockList(s->HubCreateHistoryList);
+	{
+		for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
+		{
+			SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
+
+			if (StrCmpi(h->HubName, name) == 0)
+			{
+				ret = true;
+				break;
+			}
+		}
+	}
+	UnlockList(s->HubCreateHistoryList);
+
+	return ret;
+}
+
+// 仮想 HUB 作成履歴の削除
+void SiDelHubCreateHistory(SERVER *s, char *name)
+{
+	UINT i;
+	// 引数チェック
+	if (s == NULL || name == NULL)
+	{
+		return;
+	}
+
+	LockList(s->HubCreateHistoryList);
+	{
+		SERVER_HUB_CREATE_HISTORY *hh = NULL;
+		for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
+		{
+			SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
+
+			if (StrCmpi(h->HubName, name) == 0)
+			{
+				Delete(s->HubCreateHistoryList, h);
+				Free(h);
+				break;
+			}
+		}
+	}
+	UnlockList(s->HubCreateHistoryList);
+
+	SiDeleteOldHubCreateHistory(s);
+}
+
+// 仮想 HUB 作成履歴への登録
+void SiAddHubCreateHistory(SERVER *s, char *name)
+{
+	UINT i;
+	// 引数チェック
+	if (s == NULL || name == NULL)
+	{
+		return;
+	}
+
+	LockList(s->HubCreateHistoryList);
+	{
+		SERVER_HUB_CREATE_HISTORY *hh = NULL;
+		for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
+		{
+			SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
+
+			if (StrCmpi(h->HubName, name) == 0)
+			{
+				hh = h;
+				break;
+			}
+		}
+
+		if (hh == NULL)
+		{
+			hh = ZeroMalloc(sizeof(SERVER_HUB_CREATE_HISTORY));
+			StrCpy(hh->HubName, sizeof(hh->HubName), name);
+
+			Add(s->HubCreateHistoryList, hh);
+		}
+
+		hh->CreatedTime = Tick64();
+	}
+	UnlockList(s->HubCreateHistoryList);
+
+	SiDeleteOldHubCreateHistory(s);
+}
+
+// 古くなった仮想 HUB 作成履歴の削除
+void SiDeleteOldHubCreateHistory(SERVER *s)
+{
+	UINT i;
+	LIST *o;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	LockList(s->HubCreateHistoryList);
+	{
+		o = NewListFast(NULL);
+
+		for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
+		{
+			SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
+
+			if ((h->CreatedTime + ((UINT64)TICKET_EXPIRES)) <= Tick64())
+			{
+				// 有効期限切れ
+				Add(o, h);
+			}
+		}
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(o, i);
+
+			Delete(s->HubCreateHistoryList, h);
+
+			Free(h);
+		}
+
+		ReleaseList(o);
+	}
+	UnlockList(s->HubCreateHistoryList);
+}
+
+// 仮想 HUB 作成履歴の初期化
+void SiInitHubCreateHistory(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	s->HubCreateHistoryList = NewList(NULL);
+}
+
+// 仮想 HUB 作成履歴の解放
+void SiFreeHubCreateHistory(SERVER *s)
+{
+	UINT i;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(s->HubCreateHistoryList);i++)
+	{
+		SERVER_HUB_CREATE_HISTORY *h = LIST_DATA(s->HubCreateHistoryList, i);
+
+		Free(h);
+	}
+
+	ReleaseList(s->HubCreateHistoryList);
+
+	s->HubCreateHistoryList = NULL;
+}
+
+// Admin Pack のインストーラ作成キットで作成した VPN Client が
+// 接続可能なサーバーかどうか判別
+bool IsAdminPackSupportedServerProduct(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return true;
+	}
+
+	return true;
+
+#if	0
+	// SoftEther UT-VPN ではこの制限はなくなった
+	if (SearchStrEx(name, "home", 0, false) != INFINITE)
+	{
+		return false;
+	}
+
+	if (SearchStrEx(name, "soho", 0, false) != INFINITE)
+	{
+		return false;
+	}
+
+	if (SearchStrEx(name, "small business", 0, false) != INFINITE)
+	{
+		return false;
+	}
+
+	if (SearchStrEx(name, "standard", 0, false) != INFINITE)
+	{
+		return false;
+	}
+
+	return true;
+#endif
+}
+
+
+// Server スナップショットの初期化
+void InitServerSnapshot(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (s->Cedar->Bridge)
+	{
+		return;
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return;
+	}
+
+	s->SnapshotLogger = NewLog(CE_SNAPSHOT_DIR_NAME, CE_SNAPSHOT_PREFIX, LOG_SWITCH_MONTH);
+	s->LastSnapshotTime = SystemTime64();
+	s->HaltSnapshot = false;
+	s->SnapshotHaltEvent = NewEvent();
+	s->SnapshotThread = NewThread(ServerSnapshotThread, s);
+	s->SnapshotInited = true;
+}
+
+// Server スナップショットの解放
+void FreeServerSnapshot(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+	if (s->SnapshotInited == false)
+	{
+		return;
+	}
+
+	s->HaltSnapshot = true;
+	Set(s->SnapshotHaltEvent);
+
+	WaitThread(s->SnapshotThread, INFINITE);
+	ReleaseThread(s->SnapshotThread);
+
+	FreeLog(s->SnapshotLogger);
+	ReleaseEvent(s->SnapshotHaltEvent);
+}
+
+// スナップショットをバッファに書き出す
+BUF *ServerSnapshotToBuf(SERVER_SNAPSHOT *t)
+{
+	BUF *b = NewBuf();
+	char tmp[MAX_SIZE * 3];
+	char tmp2[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	UCHAR hash2[SHA1_SIZE];
+	UINT i;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	WriteBufLine(b, "------------------------------------------------------");
+	WriteBufLine(b, "[RECORD_INFO]");
+
+	GetDateTimeStr64(tmp2, sizeof(tmp2), SystemToLocal64(t->DateTime));
+	Format(tmp, sizeof(tmp), "DATETIME: %s", tmp2);
+	WriteBufLine(b, tmp);
+
+	IPToStr(tmp2, sizeof(tmp2), &t->ServerIp);
+	Format(tmp, sizeof(tmp), "SERVER_IP: %s", tmp2);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "SERVER_HOSTNAME: %s", t->ServerHostname);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "SERVER_PRODUCT: %s", t->ServerProduct);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "SERVER_VERSION: %s", t->ServerVersion);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "SERVER_BUILD: %s", t->ServerBuild);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "SERVER_OS: %s", t->ServerOs);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "SERVER_LICENSE_ID: %I64u", t->ServerLicenseId);
+	WriteBufLine(b, tmp);
+
+	if (t->ServerLicenseExpires != 0)
+	{
+		GetDateTimeStr64(tmp2, sizeof(tmp2), SystemToLocal64(t->ServerLicenseExpires));
+	}
+	else
+	{
+		StrCpy(tmp2, sizeof(tmp2), "None");
+	}
+	Format(tmp, sizeof(tmp), "SERVER_LICENSE_EXPIRES: %s", tmp2);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "SERVER_TYPE: %u", t->ServerType);
+	WriteBufLine(b, tmp);
+
+	GetDateTimeStr64(tmp2, sizeof(tmp), SystemToLocal64(t->ServerStartupDatetime));
+	Format(tmp, sizeof(tmp), "SERVER_STARTUP_DATETIME: %s", tmp2);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "NUMBER_OF_CLUSTER_NODES: %u", t->NumClusterNodes);
+	WriteBufLine(b, tmp);
+
+	Format(tmp, sizeof(tmp), "NUMBER_OF_HUBS: %u", LIST_NUM(t->HubList));
+	WriteBufLine(b, tmp);
+
+	for (i = 0;i < LIST_NUM(t->HubList);i++)
+	{
+		HUB_SNAPSHOT *h = LIST_DATA(t->HubList, i);
+		Format(tmp, sizeof(tmp), "[HUB%u]", i);
+		WriteBufLine(b, tmp);
+
+		Format(tmp, sizeof(tmp), "HUB_NAME: %s", h->HubName);
+		WriteBufLine(b, tmp);
+
+		Format(tmp, sizeof(tmp), "HUB_STATUS: %s",
+			h->HubStatus ? "Online" : "Offline");
+		WriteBufLine(b, tmp);
+
+		Format(tmp, sizeof(tmp), "HUB_MAX_SESSIONS_CLIENT: %u",
+			h->HubMaxSessionsClient);
+		WriteBufLine(b, tmp);
+
+		Format(tmp, sizeof(tmp), "HUB_MAX_SESSIONS_BRIDGE: %u",
+			h->HubMaxSessionsBridge);
+		WriteBufLine(b, tmp);
+	}
+
+	// ハッシュ計算
+	HashSha1(hash, b->Buf, b->Size);
+	HashSha1(hash2, hash, sizeof(hash));
+
+	WriteBufLine(b, "[DIGITAL_SIGNATURE]");
+	BinToStr(tmp2, sizeof(tmp2), hash2, sizeof(hash2));
+	Format(tmp, sizeof(tmp), "SIGNATURE: %s", tmp2);
+	WriteBufLine(b, tmp);
+
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// スナップショットのログを書き込む
+void WriteServerSnapshotLog(SERVER *s, SERVER_SNAPSHOT *t)
+{
+	BUF *b;
+	LOG *g;
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return;
+	}
+
+	b = ServerSnapshotToBuf(t);
+	if (b == NULL)
+	{
+		return;
+	}
+
+	g = s->SnapshotLogger;
+
+	WriteMultiLineLog(g, b);
+
+	FreeBuf(b);
+}
+
+// Server スナップショットスレッド
+void ServerSnapshotThread(THREAD *t, void *param)
+{
+	SERVER *s;
+	UINT64 last_check_license = 0;
+	LICENSE_STATUS license;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	s = (SERVER *)param;
+
+	Zero(&license, sizeof(license));
+
+	while (true)
+	{
+		UINT64 now;
+		if (s->HaltSnapshot)
+		{
+			break;
+		}
+
+		if (last_check_license == 0 || (last_check_license + (UINT64)(CE_SNAPSHOT_POLLING_INTERVAL_LICENSE)) <= Tick64())
+		{
+			last_check_license = Tick64();
+
+			LiParseCurrentLicenseStatus(s->LicenseSystem, &license);
+		}
+
+		if (license.CarrierEdition)
+		{
+			now = SystemTime64();
+
+			if ((s->LastSnapshotTime / CE_SNAPSHOT_INTERVAL) !=
+				(now / CE_SNAPSHOT_INTERVAL))
+			{
+				SERVER_SNAPSHOT t;
+				if (MakeServerSnapshot(s, 0, &t))
+				{
+					s->LastSnapshotTime = now;
+					WriteServerSnapshotLog(s, &t);
+
+					FreeSnapshot(&t);
+				}
+			}
+		}
+
+		Wait(s->SnapshotHaltEvent, CE_SNAPSHOT_POLLING_INTERVAL);
+	}
+}
+
+// Server のスナップショットの保存
+bool MakeServerSnapshot(SERVER *s, UINT64 now, SERVER_SNAPSHOT *t)
+{
+	LICENSE_STATUS license;
+	OS_INFO *os = GetOsInfo();
+	CEDAR *cedar;
+	HUB **hubs;
+	UINT i, num_hubs;
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return false;
+	}
+	if (now == 0)
+	{
+		now = SystemTime64();
+	}
+
+	cedar = s->Cedar;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		return false;
+	}
+
+	Zero(&license, sizeof(license));
+	LiParseCurrentLicenseStatus(s->LicenseSystem, &license);
+
+	if (license.CarrierEdition == false)
+	{
+		return false;
+	}
+
+	now = (now / CE_SNAPSHOT_INTERVAL) * CE_SNAPSHOT_INTERVAL;
+
+	t->DateTime = now;
+	GetMachineIp(&t->ServerIp);
+	GetMachineName(t->ServerHostname, sizeof(t->ServerHostname));
+	StrCpy(t->ServerProduct, sizeof(t->ServerProduct), license.EditionStr);
+	t->ServerLicenseId = license.SystemId;
+	t->ServerLicenseExpires = license.Expires;
+	t->ServerType = s->ServerType;
+	if (t->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		LockList(s->FarmMemberList);
+		{
+			t->NumClusterNodes = LIST_NUM(s->FarmMemberList);
+		}
+		UnlockList(s->FarmMemberList);
+	}
+
+	StrCpy(t->ServerVersion, sizeof(t->ServerVersion), s->Cedar->VerString);
+	StrCpy(t->ServerBuild, sizeof(t->ServerBuild), s->Cedar->BuildInfo);
+	Format(t->ServerOs, sizeof(t->ServerOs),
+		"%s %s %s",
+		os->OsVendorName, os->OsProductName, os->OsVersion);
+
+	t->ServerStartupDatetime = s->StartTime;
+
+	LockList(cedar->HubList);
+	{
+		num_hubs = LIST_NUM(cedar->HubList);
+		hubs = ZeroMalloc(sizeof(HUB *) * num_hubs);
+
+		for (i = 0;i < num_hubs;i++)
+		{
+			HUB *h = LIST_DATA(cedar->HubList, i);
+			hubs[i] = h;
+
+			AddRef(h->ref);
+		}
+	}
+	UnlockList(cedar->HubList);
+
+	t->HubList = NewListFast(NULL);
+
+	for (i = 0;i < num_hubs;i++)
+	{
+		HUB *h = hubs[i];
+		UINT client, bridge;
+		HUB_SNAPSHOT *sn;
+
+		client = GetHubAdminOption(h, "max_sessions_client");
+		bridge = GetHubAdminOption(h, "max_sessions_bridge");
+
+		sn = ZeroMalloc(sizeof(HUB_SNAPSHOT));
+		sn->HubMaxSessionsClient = client;
+		sn->HubMaxSessionsBridge = bridge;
+		StrCpy(sn->HubName, sizeof(sn->HubName), h->Name);
+		sn->HubStatus = h->Offline ? false : true;
+
+		Insert(t->HubList, sn);
+
+		ReleaseHub(h);
+	}
+
+	Free(hubs);
+
+	return true;
+}
+
+// スナップショットの解放
+void FreeSnapshot(SERVER_SNAPSHOT *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(t->HubList);i++)
+	{
+		HUB_SNAPSHOT *h = LIST_DATA(t->HubList, i);
+
+		Free(h);
+	}
+
+	ReleaseList(t->HubList);
+
+	Zero(t, sizeof(SERVER_SNAPSHOT));
+}
+
+// サーバーの現在のライセンスステータスを取得する
+void SiGetServerLicenseStatus(SERVER *s, LICENSE_STATUS *st)
+{
+	// 引数チェック
+	if (s == NULL || st == NULL)
+	{
+		return;
+	}
+
+	if (s->LicenseSystem == NULL || s->LicenseSystem->Status == NULL)
+	{
+		Zero(st, sizeof(LICENSE_STATUS));
+		return;
+	}
+
+	Copy(st, s->LicenseSystem->Status, sizeof(LICENSE_STATUS));
+}
+
+// サーバー製品名を取得する
+void GetServerProductName(SERVER *s, char *name, UINT size)
+{
+	char *cpu;
+	// 引数チェック
+	if (s == NULL || name == NULL)
+	{
+		return;
+	}
+
+	GetServerProductNameInternal(s, name, size);
+
+#ifdef	CPU_64
+	cpu = " (64 bit)";
+#else	// CPU_64
+	cpu = " (32 bit)";
+#endif	// CPU_64
+
+	StrCat(name, size, cpu);
+}
+void GetServerProductNameInternal(SERVER *s, char *name, UINT size)
+{
+	// 引数チェック
+	if (s == NULL || name == NULL)
+	{
+		return;
+	}
+
+#ifdef	BETA_NUMBER
+	if (s->Cedar->Bridge)
+	{
+		StrCpy(name, size, CEDAR_BRIDGE_STR);
+	}
+	else
+	{
+		StrCpy(name, size, CEDAR_BETA_SERVER);
+	}
+	return;
+#else	// BETA_NUMBER
+	if (s->Cedar->Bridge)
+	{
+		StrCpy(name, size, CEDAR_BRIDGE_STR);
+	}
+	else
+	{
+		LICENSE_STATUS st;
+
+		LiParseCurrentLicenseStatus(s->LicenseSystem, &st);
+
+		StrCpy(name, size, st.EditionStr);
+	}
+#endif	// BETA_NUMBER
+}
+
+// ログファイル列挙を結合する
+void AdjoinEnumLogFile(LIST *o, LIST *src)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || src == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(src);i++)
+	{
+		LOG_FILE *f = LIST_DATA(src, i);
+
+		Insert(o, Clone(f, sizeof(LOG_FILE)));
+	}
+}
+
+// 指定した名前のログファイルが列挙リストに入っているかどうか確認する
+bool CheckLogFileNameFromEnumList(LIST *o, char *name, char *server_name)
+{
+	LOG_FILE t;
+	// 引数チェック
+	if (o == NULL || name == NULL || server_name == NULL)
+	{
+		return false;
+	}
+
+	Zero(&t, sizeof(t));
+	StrCpy(t.Path, sizeof(t.Path), name);
+	StrCpy(t.ServerName, sizeof(t.ServerName), server_name);
+
+	if (Search(o, &t) == NULL)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ログファイル列挙を解放する
+void FreeEnumLogFile(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		LOG_FILE *f = LIST_DATA(o, i);
+
+		Free(f);
+	}
+
+	ReleaseList(o);
+}
+
+// 仮想 HUB に関連するログファイルを列挙する (サーバー管理者の場合はすべて列挙する)
+LIST *EnumLogFile(char *hubname)
+{
+	char exe_dir[MAX_PATH];
+	char tmp[MAX_PATH];
+	LIST *o = NewListFast(CmpLogFile);
+	DIRLIST *dir;
+
+	if (StrLen(hubname) == 0)
+	{
+		hubname = NULL;
+	}
+
+	GetExeDir(exe_dir, sizeof(exe_dir));
+
+	// server_log の下を列挙する
+	if (hubname == NULL)
+	{
+		EnumLogFileDir(o, "server_log");
+	}
+
+	// packet_log の下を列挙する
+	Format(tmp, sizeof(tmp), "%s/packet_log", exe_dir);
+	dir = EnumDir(tmp);
+	if (dir != NULL)
+	{
+		UINT i;
+		for (i = 0;i < dir->NumFiles;i++)
+		{
+			DIRENT *e = dir->File[i];
+
+			if (e->Folder)
+			{
+				char dir_name[MAX_PATH];
+
+				if (hubname == NULL || StrCmpi(hubname, e->FileName) == 0)
+				{
+					Format(dir_name, sizeof(dir_name), "packet_log/%s", e->FileName);
+					EnumLogFileDir(o, dir_name);
+				}
+			}
+		}
+
+		FreeDir(dir);
+	}
+
+	// security_log の下を列挙する
+	Format(tmp, sizeof(tmp), "%s/security_log", exe_dir);
+	dir = EnumDir(tmp);
+	if (dir != NULL)
+	{
+		UINT i;
+		for (i = 0;i < dir->NumFiles;i++)
+		{
+			DIRENT *e = dir->File[i];
+
+			if (e->Folder)
+			{
+				char dir_name[MAX_PATH];
+
+				if (hubname == NULL || StrCmpi(hubname, e->FileName) == 0)
+				{
+					Format(dir_name, sizeof(dir_name), "security_log/%s", e->FileName);
+					EnumLogFileDir(o, dir_name);
+				}
+			}
+		}
+
+		FreeDir(dir);
+	}
+
+	return o;
+}
+
+// 指定した名前のディレクトリのログファイルを列挙する
+void EnumLogFileDir(LIST *o, char *dirname)
+{
+	UINT i;
+	char exe_dir[MAX_PATH];
+	char dir_full_path[MAX_PATH];
+	DIRLIST *dir;
+	// 引数チェック
+	if (o == NULL || dirname == NULL)
+	{
+		return;
+	}
+
+	GetExeDir(exe_dir, sizeof(exe_dir));
+	Format(dir_full_path, sizeof(dir_full_path), "%s/%s", exe_dir, dirname);
+
+	dir = EnumDir(dir_full_path);
+	if (dir == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < dir->NumFiles;i++)
+	{
+		DIRENT *e = dir->File[i];
+
+		if (e->Folder == false && e->FileSize > 0)
+		{
+			char full_path[MAX_PATH];
+			char file_path[MAX_PATH];
+
+			Format(file_path, sizeof(file_path), "%s/%s", dirname, e->FileName);
+			Format(full_path, sizeof(full_path), "%s/%s", exe_dir, file_path);
+
+			if (EndWith(file_path, ".log"))
+			{
+				LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+				StrCpy(f->Path, sizeof(f->Path), file_path);
+				f->FileSize = (UINT)(MIN(e->FileSize, 0xffffffffUL));
+				f->UpdatedTime = e->UpdateDate;
+
+				GetMachineName(f->ServerName, sizeof(f->ServerName));
+
+				Insert(o, f);
+			}
+		}
+	}
+
+	FreeDir(dir);
+}
+
+// ログファイルリストエントリ比較
+int CmpLogFile(void *p1, void *p2)
+{
+	LOG_FILE *f1, *f2;
+	UINT i;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	f1 = *(LOG_FILE **)p1;
+	f2 = *(LOG_FILE **)p2;
+	if (f1 == NULL || f2 == NULL)
+	{
+		return 0;
+	}
+
+	i = StrCmpi(f1->Path, f2->Path);
+	if (i != 0)
+	{
+		return i;
+	}
+
+	return StrCmpi(f1->ServerName, f2->ServerName);
+}
+
+// サーバーの Caps を取得する
+UINT GetServerCapsInt(SERVER *s, char *name)
+{
+	CAPSLIST t;
+	UINT ret;
+	// 引数チェック
+	if (s == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	Zero(&t, sizeof(t));
+	GetServerCaps(s, &t);
+
+	ret = GetCapsInt(&t, name);
+
+	return ret;
+}
+bool GetServerCapsBool(SERVER *s, char *name)
+{
+	return (GetServerCapsInt(s, name) == 0) ? false : true;
+}
+
+// サーバーの Caps キャッシュの初期化
+void InitServerCapsCache(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	s->CapsCacheLock = NewLock();
+	s->CapsListCache = NULL;
+}
+
+// サーバーの Caps キャッシュの解放
+void FreeServerCapsCache(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (s->CapsListCache != NULL)
+	{
+		FreeCapsList(s->CapsListCache);
+		s->CapsListCache = NULL;
+	}
+	DeleteLock(s->CapsCacheLock);
+}
+
+// サーバーの Caps キャッシュの廃棄
+void DestroyServerCapsCache(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Lock(s->CapsCacheLock);
+	{
+		if (s->CapsListCache != NULL)
+		{
+			FreeCapsList(s->CapsListCache);
+			s->CapsListCache = NULL;
+		}
+	}
+	Unlock(s->CapsCacheLock);
+}
+
+// このサーバーの Caps リストを取得する
+void GetServerCaps(SERVER *s, CAPSLIST *t)
+{
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return;
+	}
+
+	Lock(s->CapsCacheLock);
+	{
+		if (s->CapsListCache == NULL)
+		{
+			s->CapsListCache = ZeroMalloc(sizeof(CAPSLIST));
+			GetServerCapsMain(s, s->CapsListCache);
+		}
+
+		Copy(t, s->CapsListCache, sizeof(s->CapsListCache));
+	}
+	Unlock(s->CapsCacheLock);
+}
+
+// サーバーの Caps 取得メイン
+void GetServerCapsMain(SERVER *s, CAPSLIST *t)
+{
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return;
+	}
+
+	// 初期化
+	InitCapsList(t);
+
+	// 最大 Ethernet パケットサイズ
+	AddCapsInt(t, "i_max_packet_size", MAX_PACKET_SIZE);
+
+	if (s->Cedar->Bridge == false)
+	{
+		LICENSE_STATUS st;
+		UINT max_sessions, max_clients, max_bridges, max_user_creations;
+
+		LiParseCurrentLicenseStatus(s->LicenseSystem, &st);
+
+		max_clients = st.NumClientLicense;
+		max_bridges = st.NumBridgeLicense;
+		max_sessions = st.MaxSessions;
+		max_user_creations = st.NumUserLicense;
+
+		// 最大仮想 HUB 数
+		AddCapsInt(t, "i_max_hubs", st.MaxHubs);
+
+		// 最大同時接続セッション数
+		AddCapsInt(t, "i_max_sessions", max_sessions);
+
+		// 最大作成可能ユーザー数
+		AddCapsInt(t, "i_max_user_creation", max_user_creations);
+
+		// 最大クライアント数
+		AddCapsInt(t, "i_max_clients", max_clients);
+
+		// 最大ブリッジ数
+		AddCapsInt(t, "i_max_bridges", max_bridges);
+
+		if (s->ServerType != SERVER_TYPE_FARM_MEMBER)
+		{
+			// 登録可能な最大ユーザー数 / 仮想 HUB
+			AddCapsInt(t, "i_max_users_per_hub", MAX_USERS);
+
+			// 登録可能な最大グループ数 / 仮想 HUB
+			AddCapsInt(t, "i_max_groups_per_hub", MAX_GROUPS);
+
+			// 登録可能な最大アクセスリスト数 / 仮想 HUB
+			AddCapsInt(t, "i_max_access_lists", MAX_ACCESSLISTS);
+		}
+		else
+		{
+			// 登録可能な最大ユーザー数 / 仮想 HUB
+			AddCapsInt(t, "i_max_users_per_hub", 0);
+
+			// 登録可能な最大グループ数 / 仮想 HUB
+			AddCapsInt(t, "i_max_groups_per_hub", 0);
+
+			// 登録可能な最大アクセスリスト数 / 仮想 HUB
+			AddCapsInt(t, "i_max_access_lists", 0);
+		}
+
+		// 多重ログインに関するポリシー
+		AddCapsBool(t, "b_support_limit_multilogin", true);
+
+		// QoS / VoIP
+		AddCapsBool(t, "b_support_qos", true);
+	}
+	else
+	{
+		// 最大仮想 HUB 数
+		AddCapsInt(t, "i_max_hubs", 0);
+
+		// 最大同時接続セッション数
+		AddCapsInt(t, "i_max_sessions", 0);
+
+		// 最大クライアント数
+		AddCapsInt(t, "i_max_clients", 0);
+
+		// 最大ブリッジ数
+		AddCapsInt(t, "i_max_bridges", 0);
+
+		// 登録可能な最大ユーザー数 / 仮想 HUB
+		AddCapsInt(t, "i_max_users_per_hub", 0);
+
+		// 登録可能な最大グループ数 / 仮想 HUB
+		AddCapsInt(t, "i_max_groups_per_hub", 0);
+
+		// 登録可能な最大アクセスリスト数 / 仮想 HUB
+		AddCapsInt(t, "i_max_access_lists", 0);
+
+		// QoS / VoIP
+		AddCapsBool(t, "b_support_qos", true);
+
+		// syslog
+		AddCapsBool(t, "b_support_syslog", true);
+	}
+
+	// syslog は使用不可
+	AddCapsBool(t, "b_support_syslog", false);
+
+	// クラスタ内仮想 HUB の種類の変更が禁止されている
+	AddCapsBool(t, "b_cluster_hub_type_fixed", true);
+
+	// MAC アドレステーブル最大サイズ / 仮想 HUB
+	AddCapsInt(t, "i_max_mac_tables", MAX_MAC_TABLES);
+
+	// IP アドレステーブル最大サイズ / 仮想 HUB
+	AddCapsInt(t, "i_max_ip_tables", MAX_IP_TABLES);
+
+	// SecureNAT 機能が使用できる
+	AddCapsBool(t, "b_support_securenat", true);
+
+	if (s->ServerType != SERVER_TYPE_STANDALONE)
+	{
+		AddCapsBool(t, "b_virtual_nat_disabled", true);
+	}
+
+	// NAT テーブル最大サイズ / 仮想 HUB
+	AddCapsInt(t, "i_max_secnat_tables", NAT_MAX_SESSIONS);
+
+	// カスケード接続
+	if (s->ServerType == SERVER_TYPE_STANDALONE)
+	{
+		AddCapsBool(t, "b_support_cascade", true);
+	}
+	else
+	{
+		AddCapsBool(t, "b_support_cascade", false);
+	}
+
+	if (s->Cedar->Bridge)
+	{
+		// ブリッジ モード
+		AddCapsBool(t, "b_bridge", true);
+	}
+	else if (s->ServerType == SERVER_TYPE_STANDALONE)
+	{
+		// スタンドアロン モード
+		AddCapsBool(t, "b_standalone", true);
+	}
+	else if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// クラスタ コントローラ モード
+		AddCapsBool(t, "b_cluster_controller", true);
+	}
+	else
+	{
+		// クラスタ メンバ モード
+		AddCapsBool(t, "b_cluster_member", true);
+	}
+
+	// 仮想 HUB の設定変更が可能である
+	AddCapsBool(t, "b_support_config_hub", s->ServerType != SERVER_TYPE_FARM_MEMBER &&
+		s->Cedar->Bridge == false);
+
+	// VPN クライアントが接続可能である
+	AddCapsBool(t, "b_vpn_client_connect", s->Cedar->Bridge == false ? true : false);
+
+	// 外部認証サーバーは使用不可
+	AddCapsBool(t, "b_support_radius", false);
+
+	// ローカル ブリッジ機能が使用できる
+	AddCapsBool(t, "b_local_bridge", IsBridgeSupported());
+
+	if (OS_IS_WINDOWS(GetOsInfo()->OsType))
+	{
+		// パケットキャプチャドライバが未インストール
+		AddCapsBool(t, "b_must_install_pcap", IsEthSupported() == false ? true : false);
+	}
+	else
+	{
+		// Linux 版ではドライバはインストール済みとする
+		AddCapsBool(t, "b_must_install_pcap", false);
+	}
+
+	if (IsBridgeSupported())
+	{
+		// tun/tap が使用可能 (Linux のみ)
+		AddCapsBool(t, "b_tap_supported", GetOsInfo()->OsType == OSTYPE_LINUX ? true : false);
+	}
+
+	// カスケード接続
+	if (s->ServerType == SERVER_TYPE_STANDALONE)
+	{
+		AddCapsBool(t, "b_support_cascade", true);
+	}
+	else
+	{
+		AddCapsBool(t, "b_support_cascade", false);
+	}
+
+	// カスケード接続時のサーバー認証が使用できる
+	AddCapsBool(t, "b_support_cascade_cert", true);
+
+	// ログファイル設定の変更ができる
+	AddCapsBool(t, "b_support_config_log", s->ServerType != SERVER_TYPE_FARM_MEMBER);
+
+	// ログファイルの自動削除が使用可能である
+	AddCapsBool(t, "b_support_autodelete", true);
+
+	// config 操作が使用可能である
+	AddCapsBool(t, "b_support_config_rw", true);
+
+	// 仮想 HUB ごとの属性が設定可能である
+	AddCapsBool(t, "b_support_hub_admin_option", true);
+
+	// カスケード接続でクライアント証明書が設定可能である
+	AddCapsBool(t, "b_support_cascade_client_cert", true);
+
+	// 仮想 HUB を隠すことができる
+	AddCapsBool(t, "b_support_hide_hub", true);
+
+	// 統合管理
+	AddCapsBool(t, "b_support_cluster_admin", true);
+
+	if (s->Cedar->Bridge == false)
+	{
+		LICENSE_STATUS status;
+		// 仮想レイヤ 3 スイッチ機能が使える
+		AddCapsBool(t, "b_support_layer3", true);
+
+		AddCapsInt(t, "i_max_l3_sw", MAX_NUM_L3_SWITCH);
+		AddCapsInt(t, "i_max_l3_if", MAX_NUM_L3_IF);
+		AddCapsInt(t, "i_max_l3_table", MAX_NUM_L3_TABLE);
+
+		LiParseCurrentLicenseStatus(s->LicenseSystem, &status);
+
+		if (status.AllowEnterpriseFunction || s->ServerType != SERVER_TYPE_STANDALONE)
+		{
+			// クラスタの一部として動作できる
+			AddCapsBool(t, "b_support_cluster", true);
+		}
+		else
+		{
+			// クラスタとして動作できない
+			AddCapsBool(t, "b_support_cluster", false);
+		}
+	}
+	else
+	{
+		AddCapsBool(t, "b_support_layer3", false);
+
+		AddCapsInt(t, "i_max_l3_sw", 0);
+		AddCapsInt(t, "i_max_l3_if", 0);
+		AddCapsInt(t, "i_max_l3_table", 0);
+
+		AddCapsBool(t, "b_support_cluster", false);
+	}
+
+	if (s->ServerType != SERVER_TYPE_FARM_MEMBER && s->Cedar->Bridge == false)
+	{
+		// CRL をサポート
+		AddCapsBool(t, "b_support_crl", true);
+	}
+
+	// AC は非サポート
+	AddCapsBool(t, "b_support_ac", false);
+
+	// ログ ファイルのダウンロードをサポート
+	AddCapsBool(t, "b_support_read_log", true);
+
+	// カスケード接続の名前の変更が可能である
+	AddCapsBool(t, "b_support_rename_cascade", true);
+
+	// ライセンス管理は不可能
+	AddCapsBool(t, "b_support_license", false);
+
+	if (s->Cedar->Beta)
+	{
+		// ベータ版
+		AddCapsBool(t, "b_beta_version", true);
+	}
+
+	// ローカルブリッジにネットワーク接続の名前表示をサポート
+#ifdef	OS_WIN32
+	if (IsBridgeSupported() && IsNt() && GetOsInfo()->OsType >= OSTYPE_WINDOWS_2000_PROFESSIONAL)
+	{
+		AddCapsBool(t, "b_support_network_connection_name", true);
+	}
+#else	// OS_WIN32
+	if (IsBridgeSupported() && EthIsInterfaceDescriptionSupportedUnix())
+	{
+		AddCapsBool(t, "b_support_network_connection_name", true);
+	}
+#endif	// OS_WIN32
+
+	// MAC アドレスフィルタリングをサポート
+	AddCapsBool(t, "b_support_check_mac", true);
+
+	// TCP コネクションの状態チェックをサポート
+	AddCapsBool(t, "b_support_check_tcp_state", true);
+
+	// Radius 認証は使用不可
+	AddCapsBool(t, "b_support_radius_retry_interval_and_several_servers", false);
+
+	// MAC アドレステーブルでタグ付き VLAN の ID を管理できる
+	AddCapsBool(t, "b_support_vlan", true);
+
+	// 仮想 HUB 拡張オプションをサポート
+	if ((s->Cedar->Bridge == false) &&
+		(s->ServerType == SERVER_TYPE_STANDALONE || s->ServerType == SERVER_TYPE_FARM_CONTROLLER))
+	{
+		AddCapsBool(t, "b_support_hub_ext_options", true);
+	}
+	else
+	{
+		AddCapsBool(t, "b_support_hub_ext_options", false);
+	}
+
+	// セキュリティポリシー バージョン 3.0 をサポート
+	AddCapsBool(t, "b_support_policy_ver_3", true);
+
+	// IPv6 アクセスリストをサポート
+	AddCapsBool(t, "b_support_ipv6_acl", true);
+
+	// アクセスリストで遅延・ジッタ・パケットロスの設定をサポート
+	AddCapsBool(t, "b_support_ex_acl", true);
+
+	// アクセスリストでグループ名による指定をサポート
+	AddCapsBool(t, "b_support_acl_group", true);
+
+	// IPv6 接続元 IP 制限リストをサポート
+	AddCapsBool(t, "b_support_ipv6_ac", true);
+
+	// タグ付き VLAN パケット透過設定ツールをサポート
+	AddCapsBool(t, "b_support_eth_vlan", (OS_IS_WINDOWS_NT(GetOsType()) && GET_KETA(GetOsType(), 100) >= 2));
+
+	// 仮想 HUB への VPN 接続時のメッセージ表示機能をサポート
+	AddCapsBool(t, "b_support_msg", true);
+
+	// VPN3
+	AddCapsBool(t, "b_vpn3", true);
+
+	// オープンソース版
+	AddCapsBool(t, "b_gpl", true);
+}
+
+// SYSLOG_SETTING
+void InRpcSysLogSetting(SYSLOG_SETTING *t, PACK *p)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(SYSLOG_SETTING));
+	t->SaveType = PackGetInt(p, "SaveType");
+	t->Port = PackGetInt(p, "Port");
+	PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));
+}
+void OutRpcSysLogSetting(PACK *p, SYSLOG_SETTING *t)
+{
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackAddInt(p, "SaveType", t->SaveType);
+	PackAddInt(p, "Port", t->Port);
+	PackAddStr(p, "Hostname", t->Hostname);
+}
+
+// CAPSLIST
+void InitCapsList(CAPSLIST *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(CAPSLIST));
+	t->CapsList = NewListFast(NULL);
+}
+void InRpcCapsList(CAPSLIST *t, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(CAPSLIST));
+	t->CapsList = NewListFast(CompareCaps);
+
+	for (i = 0;i < LIST_NUM(p->elements);i++)
+	{
+		ELEMENT *e = LIST_DATA(p->elements, i);
+
+		if (StartWith(e->name, "caps_") && e->type == VALUE_INT && e->num_value == 1)
+		{
+			CAPS *c = NewCaps(e->name + 5, e->values[0]->IntValue);
+			Insert(t->CapsList, c);
+		}
+	}
+}
+void OutRpcCapsList(PACK *p, CAPSLIST *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(t->CapsList);i++)
+	{
+		char tmp[MAX_SIZE];
+		CAPS *c = LIST_DATA(t->CapsList, i);
+
+		Format(tmp, sizeof(tmp), "caps_%s", c->Name);
+		PackAddInt(p, tmp, c->Value);
+	}
+}
+void FreeRpcCapsList(CAPSLIST *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(t->CapsList);i++)
+	{
+		CAPS *c = LIST_DATA(t->CapsList, i);
+
+		FreeCaps(c);
+	}
+
+	ReleaseList(t->CapsList);
+}
+
+// Caps リストに bool 型を追加
+void AddCapsBool(CAPSLIST *caps, char *name, bool b)
+{
+	CAPS *c;
+	// 引数チェック
+	if (caps == NULL || name == NULL)
+	{
+		return;
+	}
+
+	c = NewCaps(name, b == false ? 0 : 1);
+	AddCaps(caps, c);
+}
+
+// Caps リストに int 型を追加
+void AddCapsInt(CAPSLIST *caps, char *name, UINT i)
+{
+	CAPS *c;
+	// 引数チェック
+	if (caps == NULL || name == NULL)
+	{
+		return;
+	}
+
+	c = NewCaps(name, i);
+	AddCaps(caps, c);
+}
+
+// Caps リストから int 型を取得
+UINT GetCapsInt(CAPSLIST *caps, char *name)
+{
+	CAPS *c;
+	// 引数チェック
+	if (caps == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	c = GetCaps(caps, name);
+	if (c == NULL)
+	{
+		return 0;
+	}
+
+	return c->Value;
+}
+
+// Caps リストから bool 型を取得
+bool GetCapsBool(CAPSLIST *caps, char *name)
+{
+	CAPS *c;
+	// 引数チェック
+	if (caps == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	c = GetCaps(caps, name);
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	return c->Value == 0 ? false : true;
+}
+
+// Caps リストの解放
+void FreeCapsList(CAPSLIST *caps)
+{
+	UINT i;
+	// 引数チェック
+	if (caps == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(caps->CapsList);i++)
+	{
+		CAPS *c = LIST_DATA(caps->CapsList, i);
+
+		FreeCaps(c);
+	}
+
+	ReleaseList(caps->CapsList);
+	Free(caps);
+}
+
+// Caps の取得
+CAPS *GetCaps(CAPSLIST *caps, char *name)
+{
+	UINT i;
+	// 引数チェック
+	if (caps == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(caps->CapsList);i++)
+	{
+		CAPS *c = LIST_DATA(caps->CapsList, i);
+
+		if (StrCmpi(c->Name, name) == 0)
+		{
+			return c;
+		}
+	}
+
+	return NULL;
+}
+
+// Caps の追加
+void AddCaps(CAPSLIST *caps, CAPS *c)
+{
+	// 引数チェック
+	if (caps == NULL || c == NULL)
+	{
+		return;
+	}
+
+	Insert(caps->CapsList, c);
+}
+
+// Caps の比較
+int CompareCaps(void *p1, void *p2)
+{
+	CAPS *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(CAPS **)p1;
+	c2 = *(CAPS **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(c1->Name, c2->Name);
+}
+
+// Caps リストの作成
+CAPSLIST *NewCapsList()
+{
+	CAPSLIST *caps = ZeroMalloc(sizeof(CAPSLIST));
+
+	caps->CapsList = NewListFast(CompareCaps);
+
+	return caps;
+}
+
+// Caps の解放
+void FreeCaps(CAPS *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	Free(c->Name);
+	Free(c);
+}
+
+// Caps の作成
+CAPS *NewCaps(char *name, UINT value)
+{
+	CAPS *c;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	c = ZeroMalloc(sizeof(CAPS));
+	c->Name = CopyStr(name);
+	c->Value = value;
+
+	return c;
+}
+
+// 現在の接続数と重みから得点を計算する
+UINT SiCalcPoint(SERVER *s, UINT num, UINT weight)
+{
+	UINT server_max_sessions = SERVER_MAX_SESSIONS;
+	if (s == NULL)
+	{
+		return 0;
+	}
+	if (weight == 0)
+	{
+		weight = 100;
+	}
+
+	server_max_sessions = GetServerCapsInt(s, "i_max_sessions");
+
+	return (UINT)(((double)server_max_sessions -
+		MIN((double)num * 100.0 / (double)weight, (double)server_max_sessions))
+		* (double)FARM_BASE_POINT / (double)server_max_sessions);
+}
+
+// サーバー得点の取得
+UINT SiGetPoint(SERVER *s)
+{
+	UINT num_session;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	num_session = Count(s->Cedar->CurrentSessions);
+
+	return SiCalcPoint(s, num_session, s->Weight);
+}
+
+// デフォルトの証明書を生成する
+void SiGenerateDefualtCert(X **server_x, K **server_k)
+{
+	X *x;
+	K *private_key, *public_key;
+	NAME *name;
+	char tmp[MAX_SIZE];
+	wchar_t cn[MAX_SIZE];
+	// 引数チェック
+	if (server_x == NULL || server_k == NULL)
+	{
+		return;
+	}
+
+	// 鍵ペアの作成
+	RsaGen(&private_key, &public_key, 1024);
+
+	// ホスト名の取得
+	StrCpy(tmp, sizeof(tmp), "server.softether.vpn");
+	GetMachineName(tmp, sizeof(tmp));
+
+	StrToUni(cn, sizeof(cn), tmp);
+	name = NewName(cn, L"Default Random Certification", L"VPN Server",
+		L"JP", NULL, NULL);
+	x = NewRootX(public_key, private_key, name, MAX(GetDaysUntil2038(), SERVER_DEFAULT_CERT_DAYS), NULL);
+
+	*server_x = x;
+	*server_k = private_key;
+
+	FreeName(name);
+
+	FreeK(public_key);
+}
+
+// サーバー証明書をデフォルトにする
+void SiInitDefaultServerCert(SERVER *s)
+{
+	X *x = NULL;
+	K *k = NULL;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// サーバー証明書と秘密鍵を生成する
+	SiGenerateDefualtCert(&x, &k);
+
+	// 設定する
+	SetCedarCert(s->Cedar, x, k);
+
+	FreeX(x);
+	FreeK(k);
+}
+
+// 暗号化アルゴリズム名をデフォルトにする
+void SiInitCipherName(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	SetCedarCipherList(s->Cedar, SERVER_DEFAULT_CIPHER_NAME);
+}
+
+// リスナーリストを初期化する
+void SiInitListenerList(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	SiLockListenerList(s);
+	{
+		// デフォルト ポートとして 443, 992, 5555 の 3 つのポートを登録する
+		SiAddListener(s, 443, true);
+		SiAddListener(s, 992, true);
+		SiAddListener(s, 5555, true);
+	}
+	SiUnlockListenerList(s);
+}
+
+// リスナーを削除する
+bool SiDeleteListener(SERVER *s, UINT port)
+{
+	SERVER_LISTENER *e;
+	// 引数チェック
+	if (s == NULL || port == 0)
+	{
+		return false;
+	}
+
+	e = SiGetListener(s, port);
+	if (e == NULL)
+	{
+		return false;
+	}
+
+	// まだ動作中であれば停止する
+	SiDisableListener(s, port);
+
+	if (e->Listener != NULL)
+	{
+		ReleaseListener(e->Listener);
+	}
+
+	Delete(s->ServerListenerList, e);
+	Free(e);
+
+	return true;
+}
+
+// SERVER_LISTENER を比較する
+int CompareServerListener(void *p1, void *p2)
+{
+	SERVER_LISTENER *s1, *s2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(SERVER_LISTENER **)p1;
+	s2 = *(SERVER_LISTENER **)p2;
+	if (s1 == NULL || s2 == NULL)
+	{
+		return 0;
+	}
+
+	if (s1->Port > s2->Port)
+	{
+		return 1;
+	}
+	else if (s1->Port < s2->Port)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// リスナーを停止する
+bool SiDisableListener(SERVER *s, UINT port)
+{
+	SERVER_LISTENER *e;
+	// 引数チェック
+	if (s == NULL || port == 0)
+	{
+		return false;
+	}
+
+	// リスナーを取得する
+	e = SiGetListener(s, port);
+	if (e == NULL)
+	{
+		return false;
+	}
+
+	if (e->Enabled == false || e->Listener == NULL)
+	{
+		// 停止中である
+		return true;
+	}
+
+	// リスナーを停止する
+	StopListener(e->Listener);
+
+	// リスナーを解放する
+	ReleaseListener(e->Listener);
+	e->Listener = NULL;
+
+	e->Enabled = false;
+
+	return true;
+}
+
+// リスナーを開始する
+bool SiEnableListener(SERVER *s, UINT port)
+{
+	SERVER_LISTENER *e;
+	// 引数チェック
+	if (s == NULL || port == 0)
+	{
+		return false;
+	}
+
+	// リスナーを取得する
+	e = SiGetListener(s, port);
+	if (e == NULL)
+	{
+		return false;
+	}
+
+	if (e->Enabled)
+	{
+		// すでに開始されている
+		return true;
+	}
+
+	// リスナーを作成する
+	e->Listener = NewListener(s->Cedar, LISTENER_TCP, e->Port);
+	if (e->Listener == NULL)
+	{
+		// 失敗
+		return false;
+	}
+
+	e->Enabled = true;
+
+	return true;
+}
+
+// リスナーを取得する
+SERVER_LISTENER *SiGetListener(SERVER *s, UINT port)
+{
+	UINT i;
+	// 引数チェック
+	if (s == NULL || port == 0)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+	{
+		SERVER_LISTENER *e = LIST_DATA(s->ServerListenerList, i);
+		if (e->Port == port)
+		{
+			return e;
+		}
+	}
+
+	return NULL;
+}
+
+// リスナーを追加する
+bool SiAddListener(SERVER *s, UINT port, bool enabled)
+{
+	SERVER_LISTENER *e;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || port == 0)
+	{
+		return false;
+	}
+
+	// 既存のリスナーが存在していないかどうかチェックする
+	for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+	{
+		e = LIST_DATA(s->ServerListenerList, i);
+		if (e->Port == port)
+		{
+			// すでに存在する
+			return false;
+		}
+	}
+
+	// 新しいリスナーを初期化して登録する
+	e = ZeroMalloc(sizeof(SERVER_LISTENER));
+	e->Enabled = enabled;
+	e->Port = port;
+
+	if (e->Enabled)
+	{
+		// リスナーを作成する
+		e->Listener = NewListener(s->Cedar, LISTENER_TCP, e->Port);
+	}
+
+	Insert(s->ServerListenerList, e);
+
+	return true;
+}
+
+// リスナーリストをロックする
+void SiLockListenerList(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	LockList(s->ServerListenerList);
+}
+
+// リスナーリストのロックを解除する
+void SiUnlockListenerList(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	UnlockList(s->ServerListenerList);
+}
+
+// Bridge の初期化
+void SiInitBridge(SERVER *s)
+{
+	HUB *h;
+	HUB_OPTION o;
+	HUB_LOG g;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Zero(&o, sizeof(o));
+	o.MaxSession = 0;
+
+	h = NewHub(s->Cedar, SERVER_DEFAULT_BRIDGE_NAME, &o);
+	AddHub(s->Cedar, h);
+
+	h->Offline = true;
+	SetHubOnline(h);
+
+	// ログ設定
+	SiSetDefaultLogSetting(&g);
+	SetHubLogSetting(h, &g);
+
+	ReleaseHub(h);
+}
+
+// デフォルトの仮想 HUB を作成する
+void SiInitDefaultHubList(SERVER *s)
+{
+	HUB *h;
+	HUB_OPTION o;
+	HUB_LOG g;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Zero(&o, sizeof(o));
+	o.MaxSession = 0;
+	o.VlanTypeId = MAC_PROTO_TAGVLAN;
+	o.NoIPv6DefaultRouterInRAWhenIPv6 = true;
+	o.ManageOnlyPrivateIP = true;
+	o.ManageOnlyLocalUnicastIPv6 = true;
+	o.NoMacAddressLog = true;
+
+	h = NewHub(s->Cedar, s->Cedar->Bridge == false ? SERVER_DEFAULT_HUB_NAME : SERVER_DEFAULT_BRIDGE_NAME, &o);
+	h->CreatedTime = SystemTime64();
+	AddHub(s->Cedar, h);
+
+	if (s->Cedar->Bridge)
+	{
+		// パスワードを乱数にする
+		Rand(h->HashedPassword, sizeof(h->HashedPassword));
+		Rand(h->SecurePassword, sizeof(h->SecurePassword));
+	}
+
+	h->Offline = true;
+	SetHubOnline(h);
+
+	// ログ設定
+	SiSetDefaultLogSetting(&g);
+	SetHubLogSetting(h, &g);
+
+	{
+		UINT i;
+		for (i = 0;i < 0;i++)
+		{
+			char tmp[MAX_SIZE];
+			USER *u;
+			sprintf(tmp, "user%u", i);
+			AcLock(h);
+			u = NewUser(tmp, L"test", L"", AUTHTYPE_ANONYMOUS, NULL);
+			AcAddUser(h, u);
+			ReleaseUser(u);
+			AcUnlock(h);
+		}
+	}
+
+	ReleaseHub(h);
+}
+
+// ログ設定をデフォルトにする
+void SiSetDefaultLogSetting(HUB_LOG *g)
+{
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	Zero(g, sizeof(HUB_LOG));
+	g->SaveSecurityLog = true;
+	g->SecurityLogSwitchType = LOG_SWITCH_DAY;
+	g->SavePacketLog = false;
+	g->PacketLogSwitchType = LOG_SWITCH_DAY;
+	g->PacketLogConfig[PACKET_LOG_TCP_CONN] =
+		g->PacketLogConfig[PACKET_LOG_DHCP] = PACKET_LOG_HEADER;
+}
+
+// テスト
+void SiTest(SERVER *s)
+{
+#if	0
+	USER *u;
+	USERGROUP *g;
+	HUB *h;
+	LINK *k;
+	CLIENT_OPTION o;
+	CLIENT_AUTH a;
+	ACCESS *ac;
+	X *x;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	h = GetHub(s->Cedar, SERVER_DEFAULT_HUB_NAME);
+	if (h == NULL)
+	{
+		return;
+	}
+
+	// ユーザーを作成する
+	g = NewGroup("test_group", L"テスト グループ", L"テストです。");
+	AcAddGroup(h, g);
+
+	u = NewUser("test", L"テスト", L"はむです", AUTHTYPE_ANONYMOUS, NULL);
+	AcAddUser(h, u);
+	JoinUserToGroup(u, g);
+	ReleaseUser(u);
+
+	u = NewUser("anonymous", L"匿名ユーザー", L"ソフトイーサ株式会社", AUTHTYPE_ANONYMOUS, NULL);
+	AcAddUser(h, u);
+	JoinUserToGroup(u, g);
+	ReleaseUser(u);
+
+	u = NewUser("password", L"パスワードユーザー", L"ソフトイーサ株式会社", AUTHTYPE_PASSWORD, NewPasswordAuthData("password", "microsoft"));
+	AcAddUser(h, u);
+	ReleaseUser(u);
+
+	x = FileToX("mayaqua.cer");
+	u = NewUser("usercert", L"ユーザー証明書テストユーザー", L"ソフトイーサ株式会社", AUTHTYPE_USERCERT, NewUserCertAuthData(x));
+	AcAddUser(h, u);
+	ReleaseUser(u);
+	FreeX(x);
+
+	u = NewUser("rootcert", L"ルート証明書テストユーザー", L"ソフトイーサ株式会社", AUTHTYPE_ROOTCERT, NewRootCertAuthData(NULL, NULL));
+	AcAddUser(h, u);
+	ReleaseUser(u);
+
+	u = NewUser("*", L"*", L"すべて", AUTHTYPE_RADIUS, NewRadiusAuthData(L""));
+	AcAddUser(h, u);
+	ReleaseUser(u);
+
+	ReleaseGroup(g);
+
+	// Radius サーバーを設定する
+	SetRadiusServer(h, "dc.sec.softether.co.jp", RADIUS_DEFAULT_PORT, "microsoft");
+
+	// HUB 間リンクを作成する
+	Zero(&o, sizeof(o));
+	UniStrCpy(o.AccountName, sizeof(o.AccountName), L"テスト リンク");
+	o.MaxConnection = 8;
+	o.NumRetry = INFINITE;
+	o.UseEncrypt = true;
+	StrCpy(o.HubName, sizeof(o.HubName), "TEST_HUB");
+	o.Port = 443;
+	StrCpy(o.Hostname, sizeof(o.Hostname), "ts.softether.co.jp");
+
+	Zero(&a, sizeof(a));
+	a.AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+	StrCpy(a.Username, sizeof(a.Username), "anonymous_test");
+
+	k = NewLink(s->Cedar, h, &o, &a, GetDefaultPolicy());
+	StartLink(k);
+
+	ReleaseLink(k);
+
+	// 証明書を追加する
+	x = FileToX("root.cer");
+	AddRootCert(h, x);
+	FreeX(x);
+
+	// アクセスリストを追加する
+	ac = ZeroMalloc(sizeof(ACCESS));
+	ac->Id = 1;
+	UniStrCpy(ac->Note, sizeof(ac->Note), L"アクセスリストのテスト");
+	ac->Active = true;
+	ac->Priority = 3;
+	ac->Discard = true;
+	ac->SrcIpAddress = 0x12345678;
+	ac->SrcSubnetMask = 0xffffffff;
+	ac->DestIpAddress = 0x36547894;
+	ac->DestSubnetMask = 0xffffffff;
+	ac->Protocol = IP_PROTO_TCP;
+	StrCpy(ac->SrcUsername, 0, "yagi");
+	StrCpy(ac->DestUsername, 0, "neko");
+	AddAccessList(h, ac);
+	Free(ac);
+
+	ReleaseHub(h);
+#endif
+}
+
+// 初期コンフィグレーションを設定する
+void SiLoadInitialConfiguration(SERVER *s)
+{
+	RPC_KEEP k;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// 自動保存間隔関係
+	s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;
+
+	s->Weight = FARM_DEFAULT_WEIGHT;
+
+	// KEEP 関係
+	Zero(&k, sizeof(k));
+	k.UseKeepConnect = true;
+	k.KeepConnectPort = 80;
+	StrCpy(k.KeepConnectHost, sizeof(k.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);
+	k.KeepConnectInterval = KEEP_INTERVAL_DEFAULT * 1000;
+	k.KeepConnectProtocol = CONNECTION_UDP;
+
+	Lock(s->Keep->lock);
+	{
+		KEEP *keep = s->Keep;
+		keep->Enable = k.UseKeepConnect;
+		keep->Server = true;
+		StrCpy(keep->ServerName, sizeof(keep->ServerName), k.KeepConnectHost);
+		keep->ServerPort = k.KeepConnectPort;
+		keep->UdpMode = k.KeepConnectProtocol;
+		keep->Interval = k.KeepConnectInterval;
+	}
+	Unlock(s->Keep->lock);
+
+	// パスワードを初期化する
+	Hash(s->HashedPassword, "", 0, true);
+
+	// 暗号化アルゴリズム名をデフォルトにする
+	SiInitCipherName(s);
+
+	// サーバー証明書をデフォルトにする
+	SiInitDefaultServerCert(s);
+
+	// リスナーリストをデフォルト設定する
+	SiInitListenerList(s);
+
+	// デフォルト HUB の作成
+	SiInitDefaultHubList(s);
+
+	s->Eraser = NewEraser(s->Logger, 0);
+}
+
+// コンフィグレーションファイルを読み込む (メイン)
+bool SiLoadConfigurationFileMain(SERVER *s, FOLDER *root)
+{
+	// 引数チェック
+	if (s == NULL || root == NULL)
+	{
+		return false;
+	}
+
+	return SiLoadConfigurationCfg(s, root);
+}
+
+// コンフィグレーションファイルを読み込む
+bool SiLoadConfigurationFile(SERVER *s)
+{
+	// 引数チェック
+	bool ret = false;
+	FOLDER *root;
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	s->CfgRw = NewCfgRw(&root,
+		s->Cedar->Bridge == false ? SERVER_CONFIG_FILE_NAME : BRIDGE_CONFIG_FILE_NAME);
+
+	if (server_reset_setting)
+	{
+		CfgDeleteFolder(root);
+		root = NULL;
+		server_reset_setting = false;
+	}
+
+	if (root == NULL)
+	{
+		return false;
+	}
+
+	ret = SiLoadConfigurationFileMain(s, root);
+
+	CfgDeleteFolder(root);
+
+	return ret;
+}
+
+// コンフィグレーション初期化
+void SiInitConfiguration(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// Ethernet 初期化
+	InitEth();
+
+	s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;
+
+	SLog(s->Cedar, "LS_LOAD_CONFIG_1");
+	if (SiLoadConfigurationFile(s) == false)
+	{
+		SLog(s->Cedar, "LS_LOAD_CONFIG_3");
+		SiLoadInitialConfiguration(s);
+
+		server_reset_setting = false;
+	}
+	else
+	{
+		SLog(s->Cedar, "LS_LOAD_CONFIG_2");
+	}
+
+	// Linux における arp_filter
+	if (GetOsInfo()->OsType == OSTYPE_LINUX)
+	{
+		if (s->NoLinuxArpFilter == false)
+		{
+			SetLinuxArpFilter();
+		}
+	}
+
+	// 保存スレッド作成
+	SLog(s->Cedar, "LS_INIT_SAVE_THREAD", s->AutoSaveConfigSpan / 1000);
+	s->SaveHaltEvent = NewEvent();
+	s->SaveThread = NewThread(SiSaverThread, s);
+}
+
+// サーバー設定を CFG から読み込む
+bool SiLoadConfigurationCfg(SERVER *s, FOLDER *root)
+{
+	FOLDER *f1, *f2, *f3, *f4, *f5, *f6;
+	// 引数チェック
+	if (s == NULL || root == NULL)
+	{
+		return false;
+	}
+
+	f1 = CfgGetFolder(root, "ServerConfiguration");
+	f2 = CfgGetFolder(root, "VirtualHUB");
+	f3 = CfgGetFolder(root, "ListenerList");
+	f4 = CfgGetFolder(root, "LocalBridgeList");
+	f5 = CfgGetFolder(root, "VirtualLayer3SwitchList");
+	f6 = CfgGetFolder(root, "LicenseManager");
+
+	if (f1 == NULL)
+	{
+		SLog(s->Cedar, "LS_BAD_CONFIG");
+		return false;
+	}
+
+	s->ConfigRevision = CfgGetInt(root, "ConfigRevision");
+
+	if (s->Cedar->Bridge == false && f6 != NULL)
+	{
+		if (GetServerCapsBool(s, "b_support_license"))
+		{
+			SiLoadLicenseManager(s, f6);
+		}
+	}
+
+	DestroyServerCapsCache(s);
+
+	SiLoadServerCfg(s, f1);
+
+	if (s->ServerType != SERVER_TYPE_FARM_MEMBER)
+	{
+		SiLoadHubs(s, f2);
+	}
+
+	SiLoadListeners(s, f3);
+
+	if (f4 != NULL)
+	{
+		SiLoadLocalBridges(s, f4);
+	}
+
+	if (s->Cedar->Bridge == false && f5 != NULL)
+	{
+		SiLoadL3Switchs(s, f5);
+	}
+
+	return true;
+}
+
+// リスナー設定を書き出す
+void SiWriteListenerCfg(FOLDER *f, SERVER_LISTENER *r)
+{
+	// 引数チェック
+	if (f == NULL || r == NULL)
+	{
+		return;
+	}
+
+	CfgAddBool(f, "Enabled", r->Enabled);
+	CfgAddInt(f, "Port", r->Port);
+}
+
+// リスナー設定を読み込む
+void SiLoadListenerCfg(SERVER *s, FOLDER *f)
+{
+	bool enable;
+	UINT port;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	enable = CfgGetBool(f, "Enabled");
+	port = CfgGetInt(f, "Port");
+
+	if (port == 0)
+	{
+		return;
+	}
+
+	SiAddListener(s, port, enable);
+}
+
+// リスナー一覧を読み込む
+void SiLoadListeners(SERVER *s, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		FOLDER *ff = CfgGetFolder(f, t->Token[i]);
+		if (ff != NULL)
+		{
+			SiLoadListenerCfg(s, ff);
+		}
+	}
+	FreeToken(t);
+}
+
+// リスナー一覧を書き出す
+void SiWriteListeners(FOLDER *f, SERVER *s)
+{
+	// 引数チェック
+	if (f == NULL || s == NULL)
+	{
+		return;
+	}
+
+	LockList(s->ServerListenerList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+		{
+			SERVER_LISTENER *r = LIST_DATA(s->ServerListenerList, i);
+			char name[MAX_SIZE];
+			Format(name, sizeof(name), "Listener%u", i);
+			SiWriteListenerCfg(CfgCreateFolder(f, name), r);
+		}
+	}
+	UnlockList(s->ServerListenerList);
+}
+
+// ブリッジを書き出す
+void SiWriteLocalBridgeCfg(FOLDER *f, LOCALBRIDGE *br)
+{
+	// 引数チェック
+	if (f == NULL || br == NULL)
+	{
+		return;
+	}
+
+	CfgAddStr(f, "DeviceName", br->DeviceName);
+	CfgAddStr(f, "HubName", br->HubName);
+	CfgAddBool(f, "NoPromiscuousMode", br->Local);
+	CfgAddBool(f, "MonitorMode", br->Monitor);
+	CfgAddBool(f, "FullBroadcastMode", br->FullBroadcast);
+
+	if (OS_IS_UNIX(GetOsInfo()->OsType))
+	{
+		CfgAddBool(f, "TapMode", br->TapMode);
+
+		if (br->TapMode)
+		{
+			char tmp[MAX_SIZE];
+			MacToStr(tmp, sizeof(tmp), br->TapMacAddress);
+			CfgAddStr(f, "TapMacAddress", tmp);
+		}
+	}
+}
+
+// ブリッジ一覧を書き出す
+void SiWriteLocalBridges(FOLDER *f, SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	LockList(s->Cedar->LocalBridgeList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(s->Cedar->LocalBridgeList);i++)
+		{
+			LOCALBRIDGE *br = LIST_DATA(s->Cedar->LocalBridgeList, i);
+			char name[MAX_SIZE];
+
+			Format(name, sizeof(name), "LocalBridge%u", i);
+			SiWriteLocalBridgeCfg(CfgCreateFolder(f, name), br);
+		}
+	}
+	UnlockList(s->Cedar->LocalBridgeList);
+}
+
+// ブリッジを読み込む
+void SiLoadLocalBridgeCfg(SERVER *s, FOLDER *f)
+{
+	char hub[MAX_SIZE];
+	char nic[MAX_SIZE];
+	bool tapmode = false;
+	UCHAR tapaddr[6];
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	Zero(hub, sizeof(hub));
+	Zero(nic, sizeof(nic));
+
+	CfgGetStr(f, "HubName", hub, sizeof(hub));
+	CfgGetStr(f, "DeviceName", nic, sizeof(nic));
+
+	if (IsEmptyStr(hub) || IsEmptyStr(nic))
+	{
+		return;
+	}
+
+	if (OS_IS_UNIX(GetOsInfo()->OsType))
+	{
+		if (CfgGetBool(f, "TapMode"))
+		{
+			char tmp[MAX_SIZE];
+			tapmode = true;
+			Zero(tapaddr, sizeof(tapaddr));
+			if (CfgGetStr(f, "TapMacAddress", tmp, sizeof(tmp)))
+			{
+				BUF *b;
+				b = StrToBin(tmp);
+				if (b != NULL && b->Size == 6)
+				{
+					Copy(tapaddr, b->Buf, sizeof(tapaddr));
+				}
+				FreeBuf(b);
+			}
+		}
+	}
+
+	AddLocalBridge(s->Cedar, hub, nic, CfgGetBool(f, "NoPromiscuousMode"), CfgGetBool(f, "MonitorMode"),
+		tapmode, tapaddr, CfgGetBool(f, "FullBroadcastMode"));
+}
+
+// ブリッジ一覧を読み込む
+void SiLoadLocalBridges(SERVER *s, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *name = t->Token[i];
+
+		SiLoadLocalBridgeCfg(s, CfgGetFolder(f, name));
+	}
+
+	FreeToken(t);
+}
+
+// サーバーの設定リビジョンをインクリメントする
+void IncrementServerConfigRevision(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	s->ConfigRevision++;
+}
+
+// サーバー設定を CFG に書き出す
+FOLDER *SiWriteConfigurationToCfg(SERVER *s)
+{
+	FOLDER *root;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	root = CfgCreateFolder(NULL, TAG_ROOT);
+
+	CfgAddInt(root, "ConfigRevision", s->ConfigRevision);
+
+	SiWriteListeners(CfgCreateFolder(root, "ListenerList"), s);
+
+	SiWriteLocalBridges(CfgCreateFolder(root, "LocalBridgeList"), s);
+
+	SiWriteServerCfg(CfgCreateFolder(root, "ServerConfiguration"), s);
+
+	if (s->UpdatedServerType != SERVER_TYPE_FARM_MEMBER)
+	{
+		SiWriteHubs(CfgCreateFolder(root, "VirtualHUB"), s);
+	}
+
+	if (s->Cedar->Bridge == false)
+	{
+		SiWriteL3Switchs(CfgCreateFolder(root, "VirtualLayer3SwitchList"), s);
+
+		if (GetServerCapsBool(s, "b_support_license"))
+		{
+			SiWriteLicenseManager(CfgCreateFolder(root, "LicenseManager"), s);
+		}
+	}
+
+	return root;
+}
+
+// ポリシーの読み込み
+void SiLoadPolicyCfg(POLICY *p, FOLDER *f)
+{
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+
+	Zero(p, sizeof(POLICY));
+
+	// Ver 2
+	p->Access = CfgGetBool(f, "Access");
+	p->DHCPFilter = CfgGetBool(f, "DHCPFilter");
+	p->DHCPNoServer = CfgGetBool(f, "DHCPNoServer");
+	p->DHCPForce = CfgGetBool(f, "DHCPForce");
+	p->NoBridge = CfgGetBool(f, "NoBridge");
+	p->NoRouting = CfgGetBool(f, "NoRouting");
+	p->CheckMac = CfgGetBool(f, "CheckMac");
+	p->CheckIP = CfgGetBool(f, "CheckIP");
+	p->ArpDhcpOnly = CfgGetBool(f, "ArpDhcpOnly");
+	p->PrivacyFilter = CfgGetBool(f, "PrivacyFilter");
+	p->NoServer = CfgGetBool(f, "NoServer");
+	p->NoBroadcastLimiter = CfgGetBool(f, "NoBroadcastLimiter");
+	p->MonitorPort = CfgGetBool(f, "MonitorPort");
+	p->MaxConnection = CfgGetInt(f, "MaxConnection");
+	p->TimeOut = CfgGetInt(f, "TimeOut");
+	p->MaxMac = CfgGetInt(f, "MaxMac");
+	p->MaxIP = CfgGetInt(f, "MaxIP");
+	p->MaxUpload = CfgGetInt(f, "MaxUpload");
+	p->MaxDownload = CfgGetInt(f, "MaxDownload");
+	p->FixPassword = CfgGetBool(f, "FixPassword");
+	p->MultiLogins = CfgGetInt(f, "MultiLogins");
+	p->NoQoS = CfgGetBool(f, "NoQoS");
+
+	// Ver 3
+	p->RSandRAFilter = CfgGetBool(f, "RSandRAFilter");
+	p->RAFilter = CfgGetBool(f, "RAFilter");
+	p->DHCPv6Filter = CfgGetBool(f, "DHCPv6Filter");
+	p->DHCPv6NoServer = CfgGetBool(f, "DHCPv6NoServer");
+	p->NoRoutingV6 = CfgGetBool(f, "NoRoutingV6");
+	p->CheckIPv6 = CfgGetBool(f, "CheckIPv6");
+	p->NoServerV6 = CfgGetBool(f, "NoServerV6");
+	p->MaxIPv6 = CfgGetInt(f, "MaxIPv6");
+	p->NoSavePassword = CfgGetBool(f, "NoSavePassword");
+	p->AutoDisconnect = CfgGetInt(f, "AutoDisconnect");
+	p->FilterIPv4 = CfgGetBool(f, "FilterIPv4");
+	p->FilterIPv6 = CfgGetBool(f, "FilterIPv6");
+	p->FilterNonIP = CfgGetBool(f, "FilterNonIP");
+	p->NoIPv6DefaultRouterInRA = CfgGetBool(f, "NoIPv6DefaultRouterInRA");
+	p->NoIPv6DefaultRouterInRAWhenIPv6 = CfgGetBool(f, "NoIPv6DefaultRouterInRAWhenIPv6");
+	p->VLanId = CfgGetInt(f, "VLanId");
+}
+
+// ポリシーの書き込み
+void SiWritePolicyCfg(FOLDER *f, POLICY *p, bool cascade_mode)
+{
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// Ver 2.0
+	if (cascade_mode == false)
+	{
+		CfgAddBool(f, "Access", p->Access);
+	}
+
+	CfgAddBool(f, "DHCPFilter", p->DHCPFilter);
+	CfgAddBool(f, "DHCPNoServer", p->DHCPNoServer);
+	CfgAddBool(f, "DHCPForce", p->DHCPForce);
+
+	if (cascade_mode == false)
+	{
+		CfgAddBool(f, "NoBridge", p->NoBridge);
+		CfgAddBool(f, "NoRouting", p->NoRouting);
+	}
+
+	CfgAddBool(f, "CheckMac", p->CheckMac);
+	CfgAddBool(f, "CheckIP", p->CheckIP);
+	CfgAddBool(f, "ArpDhcpOnly", p->ArpDhcpOnly);
+
+	if (cascade_mode == false)
+	{
+		CfgAddBool(f, "PrivacyFilter", p->PrivacyFilter);
+	}
+
+	CfgAddBool(f, "NoServer", p->NoServer);
+	CfgAddBool(f, "NoBroadcastLimiter", p->NoBroadcastLimiter);
+
+	if (cascade_mode == false)
+	{
+		CfgAddBool(f, "MonitorPort", p->MonitorPort);
+		CfgAddInt(f, "MaxConnection", p->MaxConnection);
+		CfgAddInt(f, "TimeOut", p->TimeOut);
+	}
+
+	CfgAddInt(f, "MaxMac", p->MaxMac);
+	CfgAddInt(f, "MaxIP", p->MaxIP);
+	CfgAddInt(f, "MaxUpload", p->MaxUpload);
+	CfgAddInt(f, "MaxDownload", p->MaxDownload);
+
+	if (cascade_mode == false)
+	{
+		CfgAddBool(f, "FixPassword", p->FixPassword);
+		CfgAddInt(f, "MultiLogins", p->MultiLogins);
+		CfgAddBool(f, "NoQoS", p->NoQoS);
+	}
+
+	// Ver 3.0
+	CfgAddBool(f, "RSandRAFilter", p->RSandRAFilter);
+	CfgAddBool(f, "RAFilter", p->RAFilter);
+	CfgAddBool(f, "DHCPv6Filter", p->DHCPv6Filter);
+	CfgAddBool(f, "DHCPv6NoServer", p->DHCPv6NoServer);
+
+	if (cascade_mode == false)
+	{
+		CfgAddBool(f, "NoRoutingV6", p->NoRoutingV6);
+	}
+
+	CfgAddBool(f, "CheckIPv6", p->CheckIPv6);
+	CfgAddBool(f, "NoServerV6", p->NoServerV6);
+	CfgAddInt(f, "MaxIPv6", p->MaxIPv6);
+
+	if (cascade_mode == false)
+	{
+		CfgAddBool(f, "NoSavePassword", p->NoSavePassword);
+		CfgAddInt(f, "AutoDisconnect", p->AutoDisconnect);
+	}
+
+	CfgAddBool(f, "FilterIPv4", p->FilterIPv4);
+	CfgAddBool(f, "FilterIPv6", p->FilterIPv6);
+	CfgAddBool(f, "FilterNonIP", p->FilterNonIP);
+	CfgAddBool(f, "NoIPv6DefaultRouterInRA", p->NoIPv6DefaultRouterInRA);
+	CfgAddBool(f, "NoIPv6DefaultRouterInRAWhenIPv6", p->NoIPv6DefaultRouterInRAWhenIPv6);
+	CfgAddInt(f, "VLanId", p->VLanId);
+}
+
+// 仮想 HUB のリンク情報の書き込み
+void SiWriteHubLinkCfg(FOLDER *f, LINK *k)
+{
+	// 引数チェック
+	if (f == NULL || k == NULL)
+	{
+		return;
+	}
+
+	Lock(k->lock);
+	{
+		// オンライン
+		CfgAddBool(f, "Online", k->Offline ? false : true);
+
+		// クライアントオプション
+		CiWriteClientOption(CfgCreateFolder(f, "ClientOption"), k->Option);
+
+		// クライアント認証データ
+		CiWriteClientAuth(CfgCreateFolder(f, "ClientAuth"), k->Auth);
+
+		// ポリシー
+		if (k->Policy != NULL)
+		{
+			SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), k->Policy, true);
+		}
+
+		CfgAddBool(f, "CheckServerCert", k->CheckServerCert);
+
+		if (k->ServerCert != NULL)
+		{
+			BUF *b = XToBuf(k->ServerCert, false);
+			CfgAddBuf(f, "ServerCert", b);
+			FreeBuf(b);
+		}
+	}
+	Unlock(k->lock);
+}
+
+// リンク情報の読み込み
+void SiLoadHubLinkCfg(FOLDER *f, HUB *h)
+{
+	bool online;
+	CLIENT_OPTION *o;
+	CLIENT_AUTH *a;
+	FOLDER *pf;
+	POLICY p;
+	LINK *k;
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	pf = CfgGetFolder(f, "Policy");
+	if (pf == NULL)
+	{
+		return;
+	}
+
+	SiLoadPolicyCfg(&p, pf);
+
+	online = CfgGetBool(f, "Online");
+
+	o = CiLoadClientOption(CfgGetFolder(f, "ClientOption"));
+	a = CiLoadClientAuth(CfgGetFolder(f, "ClientAuth"));
+	if (o == NULL || a == NULL)
+	{
+		Free(o);
+		CiFreeClientAuth(a);
+		return;
+	}
+
+	k = NewLink(h->Cedar, h, o, a, &p);
+	if (k != NULL)
+	{
+		BUF *b;
+		k->CheckServerCert = CfgGetBool(f, "CheckServerCert");
+		b = CfgGetBuf(f, "ServerCert");
+		if (b != NULL)
+		{
+			k->ServerCert = BufToX(b, false);
+			FreeBuf(b);
+		}
+
+		if (online)
+		{
+			k->Offline = true;
+			SetLinkOnline(k);
+		}
+		else
+		{
+			k->Offline = false;
+			SetLinkOffline(k);
+		}
+		ReleaseLink(k);
+	}
+
+	Free(o);
+	CiFreeClientAuth(a);
+}
+
+// 仮想 HUB の SecureNAT の書き込み
+void SiWriteSecureNAT(HUB *h, FOLDER *f)
+{
+	// 引数チェック
+	if (h == NULL || f == NULL)
+	{
+		return;
+	}
+
+	CfgAddBool(f, "Disabled", h->EnableSecureNAT ? false : true);
+
+	NiWriteVhOptionEx(h->SecureNATOption, f);
+}
+
+// 仮想 HUB の管理オプションの読み込み
+void SiLoadHubAdminOptions(HUB *h, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (h == NULL || f == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumItemToTokenList(f);
+	if (t != NULL)
+	{
+		UINT i;
+
+		LockList(h->AdminOptionList);
+		{
+			DeleteAllHubAdminOption(h, false);
+
+			for (i = 0;i < t->NumTokens;i++)
+			{
+				char *name = t->Token[i];
+				ADMIN_OPTION *a;
+				UINT value = CfgGetInt(f, name);;
+
+				Trim(name);
+
+				a = ZeroMalloc(sizeof(ADMIN_OPTION));
+				StrCpy(a->Name, sizeof(a->Name), name);
+				a->Value = value;
+
+				Insert(h->AdminOptionList, a);
+			}
+
+			AddHubAdminOptionsDefaults(h, false);
+		}
+		UnlockList(h->AdminOptionList);
+
+		FreeToken(t);
+	}
+}
+
+// 仮想 HUB の管理オプションの書き込み
+void SiWriteHubAdminOptions(FOLDER *f, HUB *h)
+{
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->AdminOptionList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
+		{
+			ADMIN_OPTION *a = LIST_DATA(h->AdminOptionList, i);
+
+			CfgAddInt(f, a->Name, a->Value);
+		}
+	}
+	UnlockList(h->AdminOptionList);
+}
+
+// 仮想 HUB のリンクリストの書き込み
+void SiWriteHubLinks(FOLDER *f, HUB *h)
+{
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->LinkList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(h->LinkList);i++)
+		{
+			LINK *k = LIST_DATA(h->LinkList, i);
+			char name[MAX_SIZE];
+			Format(name, sizeof(name), "Cascade%u", i);
+			SiWriteHubLinkCfg(CfgCreateFolder(f, name), k);
+		}
+	}
+	UnlockList(h->LinkList);
+}
+
+// リンクリストの読み込み
+void SiLoadHubLinks(HUB *h, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	// 引数チェック
+	if (h == NULL || f == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *name = t->Token[i];
+		SiLoadHubLinkCfg(CfgGetFolder(f, name), h);
+	}
+
+	FreeToken(t);
+}
+
+// アクセスリスト項目の書き込み
+void SiWriteHubAccessCfg(FOLDER *f, ACCESS *a)
+{
+	// 引数チェック
+	if (f == NULL || a == NULL)
+	{
+		return;
+	}
+
+	CfgAddUniStr(f, "Note", a->Note);
+	CfgAddBool(f, "Active", a->Active);
+	CfgAddInt(f, "Priority", a->Priority);
+	CfgAddBool(f, "Discard", a->Discard);
+	CfgAddBool(f, "IsIPv6", a->IsIPv6);
+
+	if (a->IsIPv6 == false)
+	{
+		CfgAddIp32(f, "SrcIpAddress", a->SrcIpAddress);
+		CfgAddIp32(f, "SrcSubnetMask", a->SrcSubnetMask);
+		CfgAddIp32(f, "DestIpAddress", a->DestIpAddress);
+		CfgAddIp32(f, "DestSubnetMask", a->DestSubnetMask);
+	}
+	else
+	{
+		CfgAddIp6Addr(f, "SrcIpAddress6", &a->SrcIpAddress6);
+		CfgAddIp6Addr(f, "SrcSubnetMask6", &a->SrcSubnetMask6);
+		CfgAddIp6Addr(f, "DestIpAddress6", &a->DestIpAddress6);
+		CfgAddIp6Addr(f, "DestSubnetMask6", &a->DestSubnetMask6);
+	}
+
+	CfgAddInt(f, "Protocol", a->Protocol);
+	CfgAddInt(f, "SrcPortStart", a->SrcPortStart);
+	CfgAddInt(f, "SrcPortEnd", a->SrcPortEnd);
+	CfgAddInt(f, "DestPortStart", a->DestPortStart);
+	CfgAddInt(f, "DestPortEnd", a->DestPortEnd);
+	CfgAddStr(f, "SrcUsername", a->SrcUsername);
+	CfgAddStr(f, "DestUsername", a->DestUsername);
+	CfgAddBool(f, "CheckSrcMac", a->CheckSrcMac);
+
+	if (a->CheckSrcMac)
+	{
+		char tmp[MAX_PATH];
+
+		MacToStr(tmp, sizeof(tmp), a->SrcMacAddress);
+		CfgAddStr(f, "SrcMacAddress", tmp);
+
+		MacToStr(tmp, sizeof(tmp), a->SrcMacMask);
+		CfgAddStr(f, "SrcMacMask", tmp);
+	}
+
+	CfgAddBool(f, "CheckDstMac", a->CheckDstMac);
+
+	if (a->CheckDstMac)
+	{
+		char tmp[MAX_PATH];
+
+		MacToStr(tmp, sizeof(tmp), a->DstMacAddress);
+		CfgAddStr(f, "DstMacAddress", tmp);
+
+		MacToStr(tmp, sizeof(tmp), a->DstMacMask);
+		CfgAddStr(f, "DstMacMask", tmp);
+	}
+
+	CfgAddBool(f, "CheckTcpState", a->CheckTcpState);
+	CfgAddBool(f, "Established", a->Established);
+
+	CfgAddInt(f, "Delay", a->Delay);
+	CfgAddInt(f, "Jitter", a->Jitter);
+	CfgAddInt(f, "Loss", a->Loss);
+}
+
+// アクセスリスト項目の読み込み
+void SiLoadHubAccessCfg(HUB *h, FOLDER *f)
+{
+	ACCESS a;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (h == NULL || f == NULL)
+	{
+		return;
+	}
+
+	Zero(&a, sizeof(a));
+
+	CfgGetUniStr(f, "Note", a.Note, sizeof(a.Note));
+	a.Active = CfgGetBool(f, "Active");
+	a.Priority = CfgGetInt(f, "Priority");
+	a.Discard = CfgGetBool(f, "Discard");
+	a.IsIPv6 = CfgGetBool(f, "IsIPv6");
+
+	if (a.IsIPv6 == false)
+	{
+		a.SrcIpAddress = CfgGetIp32(f, "SrcIpAddress");
+		a.SrcSubnetMask = CfgGetIp32(f, "SrcSubnetMask");
+		a.DestIpAddress = CfgGetIp32(f, "DestIpAddress");
+		a.DestSubnetMask = CfgGetIp32(f, "DestSubnetMask");
+	}
+	else
+	{
+		CfgGetIp6Addr(f, "SrcIpAddress6", &a.SrcIpAddress6);
+		CfgGetIp6Addr(f, "SrcSubnetMask6", &a.SrcSubnetMask6);
+		CfgGetIp6Addr(f, "DestIpAddress6", &a.DestIpAddress6);
+		CfgGetIp6Addr(f, "DestSubnetMask6", &a.DestSubnetMask6);
+	}
+
+	a.Protocol = CfgGetInt(f, "Protocol");
+	a.SrcPortStart = CfgGetInt(f, "SrcPortStart");
+	a.SrcPortEnd = CfgGetInt(f, "SrcPortEnd");
+	a.DestPortStart = CfgGetInt(f, "DestPortStart");
+	a.DestPortEnd = CfgGetInt(f, "DestPortEnd");
+	CfgGetStr(f, "SrcUsername", a.SrcUsername, sizeof(a.SrcUsername));
+	CfgGetStr(f, "DestUsername", a.DestUsername, sizeof(a.DestUsername));
+	a.CheckSrcMac = CfgGetBool(f, "CheckSrcMac");
+
+	if (CfgGetByte(f, "SrcMacAddress", a.SrcMacAddress, sizeof(a.SrcMacAddress)) == 0)
+	{
+		CfgGetStr(f, "SrcMacAddress", tmp, sizeof(tmp));
+		if (StrToMac(a.SrcMacAddress, tmp) == false)
+		{
+			a.CheckSrcMac = false;
+		}
+	}
+
+	if (CfgGetByte(f, "SrcMacMask", a.SrcMacMask, sizeof(a.SrcMacMask)) == 0)
+	{
+		CfgGetStr(f, "SrcMacMask", tmp, sizeof(tmp));
+		if (StrToMac(a.SrcMacMask, tmp) == false)
+		{
+			a.CheckSrcMac = false;
+		}
+	}
+
+	a.CheckDstMac = CfgGetBool(f, "CheckDstMac");
+
+	if (CfgGetByte(f, "DstMacAddress", a.DstMacAddress, sizeof(a.DstMacAddress)) == 0)
+	{
+		CfgGetStr(f, "DstMacAddress", tmp, sizeof(tmp));
+		if (StrToMac(a.DstMacAddress, tmp) == false)
+		{
+			a.CheckDstMac = false;
+		}
+	}
+
+	if (CfgGetByte(f, "DstMacMask", a.DstMacMask, sizeof(a.DstMacMask)) == 0)
+	{
+		CfgGetStr(f, "DstMacMask", tmp, sizeof(tmp));
+		if (StrToMac(a.DstMacMask, tmp) == false)
+		{
+			a.CheckDstMac = false;
+		}
+	}
+
+	a.CheckTcpState = CfgGetBool(f, "CheckTcpState");
+	a.Established = CfgGetBool(f, "Established");
+	a.Delay = MAKESURE(CfgGetInt(f, "Delay"), 0, HUB_ACCESSLIST_DELAY_MAX);
+	a.Jitter = MAKESURE(CfgGetInt(f, "Jitter"), 0, HUB_ACCESSLIST_JITTER_MAX);
+	a.Loss = MAKESURE(CfgGetInt(f, "Loss"), 0, HUB_ACCESSLIST_LOSS_MAX);
+
+	AddAccessList(h, &a);
+}
+
+// アクセスリストの書き込み
+void SiWriteHubAccessLists(FOLDER *f, HUB *h)
+{
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->AccessList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(h->AccessList);i++)
+		{
+			ACCESS *a = LIST_DATA(h->AccessList, i);
+			char name[MAX_SIZE];
+			ToStr(name, a->Id);
+			SiWriteHubAccessCfg(CfgCreateFolder(f, name), a);
+		}
+	}
+	UnlockList(h->AccessList);
+}
+
+// アクセスリストの読み込み
+void SiLoadHubAccessLists(HUB *h, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *name = t->Token[i];
+		UINT id = ToInt(name);
+		SiLoadHubAccessCfg(h, CfgGetFolder(f, name));
+	}
+
+	FreeToken(t);
+}
+
+// HUB_OPTION の読み込み
+void SiLoadHubOptionCfg(FOLDER *f, HUB_OPTION *o)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (f == NULL || o == NULL)
+	{
+		return;
+	}
+
+	o->MaxSession = CfgGetInt(f, "MaxSession");
+	o->NoArpPolling = CfgGetBool(f, "NoArpPolling");
+	o->NoIPv6AddrPolling = CfgGetBool(f, "NoIPv6AddrPolling");
+	o->NoIpTable = CfgGetBool(f, "NoIpTable");
+	o->NoEnum = CfgGetBool(f, "NoEnum");
+	o->FilterPPPoE = CfgGetBool(f, "FilterPPPoE");
+	o->FilterOSPF = CfgGetBool(f, "FilterOSPF");
+	o->FilterIPv4 = CfgGetBool(f, "FilterIPv4");
+	o->FilterIPv6 = CfgGetBool(f, "FilterIPv6");
+	o->FilterNonIP = CfgGetBool(f, "FilterNonIP");
+	o->FilterBPDU = CfgGetBool(f, "FilterBPDU");
+	o->NoIPv4PacketLog = CfgGetBool(f, "NoIPv4PacketLog");
+	o->NoIPv6PacketLog = CfgGetBool(f, "NoIPv6PacketLog");
+	o->NoIPv6DefaultRouterInRAWhenIPv6 = CfgGetBool(f, "NoIPv6DefaultRouterInRAWhenIPv6");
+	o->DisableIPParsing = CfgGetBool(f, "DisableIPParsing");
+	o->YieldAfterStorePacket = CfgGetBool(f, "YieldAfterStorePacket");
+	o->NoSpinLockForPacketDelay = CfgGetBool(f, "NoSpinLockForPacketDelay");
+	o->BroadcastStormDetectionThreshold = CfgGetInt(f, "BroadcastStormDetectionThreshold");
+	o->ClientMinimumRequiredBuild = CfgGetInt(f, "ClientMinimumRequiredBuild");
+	o->RequiredClientId = CfgGetInt(f, "RequiredClientId");
+	o->NoManageVlanId = CfgGetBool(f, "NoManageVlanId");
+	o->VlanTypeId = 0;
+	if (CfgGetStr(f, "VlanTypeId", tmp, sizeof(tmp)))
+	{
+		o->VlanTypeId = HexToInt(tmp);
+	}
+	if (o->VlanTypeId == 0)
+	{
+		o->VlanTypeId = MAC_PROTO_TAGVLAN;
+	}
+	o->FixForDLinkBPDU = CfgGetBool(f, "FixForDLinkBPDU");
+	o->NoLookBPDUBridgeId = CfgGetBool(f, "NoLookBPDUBridgeId");
+
+	// デフォルトで有効
+	if (CfgIsItem(f, "ManageOnlyPrivateIP"))
+	{
+		o->ManageOnlyPrivateIP = CfgGetBool(f, "ManageOnlyPrivateIP");
+	}
+	else
+	{
+		o->ManageOnlyPrivateIP = true;
+	}
+	if (CfgIsItem(f, "ManageOnlyLocalUnicastIPv6"))
+	{
+		o->ManageOnlyLocalUnicastIPv6 = CfgGetBool(f, "ManageOnlyLocalUnicastIPv6");
+	}
+	else
+	{
+		o->ManageOnlyLocalUnicastIPv6 = true;
+	}
+	if (CfgIsItem(f, "NoMacAddressLog"))
+	{
+		o->NoMacAddressLog = CfgGetBool(f, "NoMacAddressLog");
+	}
+	else
+	{
+		o->NoMacAddressLog = true;
+	}
+}
+
+// HUB_OPTION の書き込み
+void SiWriteHubOptionCfg(FOLDER *f, HUB_OPTION *o)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (f == NULL || o == NULL)
+	{
+		return;
+	}
+
+	CfgAddInt(f, "MaxSession", o->MaxSession);
+	CfgAddBool(f, "NoArpPolling", o->NoArpPolling);
+	CfgAddBool(f, "NoIPv6AddrPolling", o->NoIPv6AddrPolling);
+	CfgAddBool(f, "NoIpTable", o->NoIpTable);
+	CfgAddBool(f, "NoEnum", o->NoEnum);
+	CfgAddBool(f, "FilterPPPoE", o->FilterPPPoE);
+	CfgAddBool(f, "FilterOSPF", o->FilterOSPF);
+	CfgAddBool(f, "FilterIPv4", o->FilterIPv4);
+	CfgAddBool(f, "FilterIPv6", o->FilterIPv6);
+	CfgAddBool(f, "FilterNonIP", o->FilterNonIP);
+	CfgAddBool(f, "NoIPv4PacketLog", o->NoIPv4PacketLog);
+	CfgAddBool(f, "NoIPv6PacketLog", o->NoIPv6PacketLog);
+	CfgAddBool(f, "FilterBPDU", o->FilterBPDU);
+	CfgAddBool(f, "NoIPv6DefaultRouterInRAWhenIPv6", o->NoIPv6DefaultRouterInRAWhenIPv6);
+	CfgAddBool(f, "NoMacAddressLog", o->NoMacAddressLog);
+	CfgAddBool(f, "ManageOnlyPrivateIP", o->ManageOnlyPrivateIP);
+	CfgAddBool(f, "ManageOnlyLocalUnicastIPv6", o->ManageOnlyLocalUnicastIPv6);
+	CfgAddBool(f, "DisableIPParsing", o->DisableIPParsing);
+	CfgAddBool(f, "YieldAfterStorePacket", o->YieldAfterStorePacket);
+	CfgAddBool(f, "NoSpinLockForPacketDelay", o->NoSpinLockForPacketDelay);
+	CfgAddInt(f, "BroadcastStormDetectionThreshold", o->BroadcastStormDetectionThreshold);
+	CfgAddInt(f, "ClientMinimumRequiredBuild", o->ClientMinimumRequiredBuild);
+	CfgAddInt(f, "RequiredClientId", o->RequiredClientId);
+	CfgAddBool(f, "NoManageVlanId", o->NoManageVlanId);
+	Format(tmp, sizeof(tmp), "0x%x", o->VlanTypeId);
+	CfgAddStr(f, "VlanTypeId", tmp);
+	if (o->FixForDLinkBPDU)
+	{
+		CfgAddBool(f, "FixForDLinkBPDU", o->FixForDLinkBPDU);
+	}
+	CfgAddBool(f, "NoLookBPDUBridgeId", o->NoLookBPDUBridgeId);
+}
+
+// ユーザーの書き込み
+void SiWriteUserCfg(FOLDER *f, USER *u)
+{
+	AUTHPASSWORD *password;
+	// 引数チェック
+	if (f == NULL || u == NULL)
+	{
+		return;
+	}
+
+	Lock(u->lock);
+	{
+		CfgAddUniStr(f, "RealName", u->RealName);
+		CfgAddUniStr(f, "Note", u->Note);
+		if (u->Group != NULL)
+		{
+			CfgAddStr(f, "GroupName", u->GroupName);
+		}
+		CfgAddInt64(f, "CreatedTime", u->CreatedTime);
+		CfgAddInt64(f, "UpdatedTime", u->UpdatedTime);
+		CfgAddInt64(f, "ExpireTime", u->ExpireTime);
+		CfgAddInt64(f, "LastLoginTime", u->LastLoginTime);
+		CfgAddInt(f, "NumLogin", u->NumLogin);
+		if (u->Policy != NULL)
+		{
+			SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), u->Policy, false);
+		}
+		SiWriteTraffic(f, "Traffic", u->Traffic);
+
+		CfgAddInt(f, "AuthType", u->AuthType);
+		if (u->AuthData != NULL)
+		{
+			switch (u->AuthType)
+			{
+			case AUTHTYPE_ANONYMOUS:
+				break;
+
+			case AUTHTYPE_PASSWORD:
+				password = (AUTHPASSWORD *)u->AuthData;
+				CfgAddByte(f, "AuthPassword", password->HashedKey, sizeof(password->HashedKey));
+				break;
+			}
+		}
+	}
+	Unlock(u->lock);
+}
+
+// ユーザーの読み込み
+void SiLoadUserCfg(HUB *h, FOLDER *f)
+{
+	char *username;
+	wchar_t realname[MAX_SIZE];
+	wchar_t note[MAX_SIZE];
+	char groupname[MAX_SIZE];
+	FOLDER *pf;
+	UINT64 created_time;
+	UINT64 updated_time;
+	UINT64 expire_time;
+	UINT64 last_login_time;
+	UINT num_login;
+	POLICY p;
+	TRAFFIC t;
+	UINT authtype;
+	void *authdata;
+	X_SERIAL *serial = NULL;
+	UCHAR hashed_password[SHA1_SIZE];
+	USER *u;
+	USERGROUP *g;
+	// 引数チェック
+	if (h == NULL || f == NULL)
+	{
+		return;
+	}
+
+	username = f->Name;
+	CfgGetUniStr(f, "RealName", realname, sizeof(realname));
+	CfgGetUniStr(f, "Note", note, sizeof(note));
+	CfgGetStr(f, "GroupName", groupname, sizeof(groupname));
+
+	created_time = CfgGetInt64(f, "CreatedTime");
+	updated_time = CfgGetInt64(f, "UpdatedTime");
+	expire_time = CfgGetInt64(f, "ExpireTime");
+	last_login_time = CfgGetInt64(f, "LastLoginTime");
+	num_login = CfgGetInt(f, "NumLogin");
+	pf = CfgGetFolder(f, "Policy");
+	if (pf != NULL)
+	{
+		SiLoadPolicyCfg(&p, pf);
+	}
+	SiLoadTraffic(f, "Traffic", &t);
+
+	authtype = CfgGetInt(f, "AuthType");
+	authdata = NULL;
+
+	switch (authtype)
+	{
+	case AUTHTYPE_PASSWORD:
+		// 通常のパスワード認証
+		CfgGetByte(f, "AuthPassword", hashed_password, sizeof(hashed_password));
+		authdata = NewPasswordAuthDataRaw(hashed_password);
+		break;
+
+	default:
+		// それ以外の認証方法が指定された
+		authtype = AUTHTYPE_ANONYMOUS;
+		authdata = NULL;
+		break;
+	}
+
+	// ユーザーの追加
+	AcLock(h);
+	{
+		if (StrLen(groupname) > 0)
+		{
+			g = AcGetGroup(h, groupname);
+		}
+		else
+		{
+			g = NULL;
+		}
+
+		u = NewUser(username, realname, note, authtype, authdata);
+		if (u != NULL)
+		{
+			if (g != NULL)
+			{
+				JoinUserToGroup(u, g);
+			}
+
+			SetUserTraffic(u, &t);
+
+			if (pf != NULL)
+			{
+				SetUserPolicy(u, &p);
+			}
+
+			Lock(u->lock);
+			{
+				u->CreatedTime = created_time;
+				u->UpdatedTime = updated_time;
+				u->ExpireTime = expire_time;
+				u->LastLoginTime = last_login_time;
+				u->NumLogin = num_login;
+			}
+			Unlock(u->lock);
+
+			AcAddUser(h, u);
+
+			ReleaseUser(u);
+		}
+
+		if (g != NULL)
+		{
+			ReleaseGroup(g);
+		}
+	}
+	AcUnlock(h);
+
+	if (serial != NULL)
+	{
+		FreeXSerial(serial);
+	}
+}
+
+// ユーザーリストの書き込み
+void SiWriteUserList(FOLDER *f, LIST *o)
+{
+	// 引数チェック
+	if (f == NULL || o == NULL)
+	{
+		return;
+	}
+
+	LockList(o);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			USER *u = LIST_DATA(o, i);
+			SiWriteUserCfg(CfgCreateFolder(f, u->Name), u);
+		}
+	}
+	UnlockList(o);
+}
+
+// ユーザーリストの読み込み
+void SiLoadUserList(HUB *h, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	char *name;
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		FOLDER *ff;
+		name = t->Token[i];
+		ff = CfgGetFolder(f, name);
+		SiLoadUserCfg(h, ff);
+	}
+
+	FreeToken(t);
+}
+
+// グループ情報の書き込み
+void SiWriteGroupCfg(FOLDER *f, USERGROUP *g)
+{
+	// 引数チェック
+	if (f == NULL || g == NULL)
+	{
+		return;
+	}
+
+	Lock(g->lock);
+	{
+		CfgAddUniStr(f, "RealName", g->RealName);
+		CfgAddUniStr(f, "Note", g->Note);
+		if (g->Policy != NULL)
+		{
+			SiWritePolicyCfg(CfgCreateFolder(f, "Policy"), g->Policy, false);
+		}
+		SiWriteTraffic(f, "Traffic", g->Traffic);
+	}
+	Unlock(g->lock);
+}
+
+// グループ情報の読み込み
+void SiLoadGroupCfg(HUB *h, FOLDER *f)
+{
+	wchar_t realname[MAX_SIZE];
+	wchar_t note[MAX_SIZE];
+	char *name;
+	FOLDER *pf;
+	POLICY p;
+	TRAFFIC t;
+	USERGROUP *g;
+	// 引数チェック
+	if (h == NULL || f == NULL)
+	{
+		return;
+	}
+
+	name = f->Name;
+
+	CfgGetUniStr(f, "RealName", realname, sizeof(realname));
+	CfgGetUniStr(f, "Note", note, sizeof(note));
+
+	pf = CfgGetFolder(f, "Policy");
+	if (pf != NULL)
+	{
+		SiLoadPolicyCfg(&p, pf);
+	}
+
+	SiLoadTraffic(f, "Traffic", &t);
+
+	g = NewGroup(name, realname, note);
+	if (g == NULL)
+	{
+		return;
+	}
+
+	if (pf != NULL)
+	{
+		SetGroupPolicy(g, &p);
+	}
+
+	SetGroupTraffic(g, &t);
+
+	AcLock(h);
+	{
+		AcAddGroup(h, g);
+	}
+	AcUnlock(h);
+
+	ReleaseGroup(g);
+}
+
+// グループリストの書き込み
+void SiWriteGroupList(FOLDER *f, LIST *o)
+{
+	// 引数チェック
+	if (f == NULL || o == NULL)
+	{
+		return;
+	}
+
+	LockList(o);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			USERGROUP *g = LIST_DATA(o, i);
+			SiWriteGroupCfg(CfgCreateFolder(f, g->Name), g);
+		}
+	}
+	UnlockList(o);
+}
+
+// グループリストの読み込み
+void SiLoadGroupList(HUB *h, FOLDER *f)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	char *name;
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	t = CfgEnumFolderToTokenList(f);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		name = t->Token[i];
+		SiLoadGroupCfg(h, CfgGetFolder(f, name));
+	}
+
+	FreeToken(t);
+}
+
+// 無効な証明書リストの書き込み
+void SiWriteCrlList(FOLDER *f, LIST *o)
+{
+	// 引数チェック
+	if (f == NULL || o == NULL)
+	{
+		return;
+	}
+
+	LockList(o);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			char name[MAX_SIZE];
+			CRL *crl = LIST_DATA(o, i);
+			FOLDER *ff;
+			NAME *n;
+
+			Format(name, sizeof(name), "Crl%u", i);
+
+			ff = CfgCreateFolder(f, name);
+			n = crl->Name;
+
+			if (UniIsEmptyStr(n->CommonName) == false)
+			{
+				CfgAddUniStr(ff, "CommonName", n->CommonName);
+			}
+
+			if (UniIsEmptyStr(n->Organization) == false)
+			{
+				CfgAddUniStr(ff, "Organization", n->Organization);
+			}
+
+			if (UniIsEmptyStr(n->Unit) == false)
+			{
+				CfgAddUniStr(ff, "Unit", n->Unit);
+			}
+
+			if (UniIsEmptyStr(n->Country) == false)
+			{
+				CfgAddUniStr(ff, "Country", n->Country);
+			}
+
+			if (UniIsEmptyStr(n->State) == false)
+			{
+				CfgAddUniStr(ff, "State", n->State);
+			}
+
+			if (UniIsEmptyStr(n->Local) == false)
+			{
+				CfgAddUniStr(ff, "Local", n->Local);
+			}
+
+			if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
+			{
+				char tmp[MAX_SIZE];
+
+				BinToStr(tmp, sizeof(tmp), crl->DigestMD5, MD5_SIZE);
+				CfgAddStr(ff, "DigestMD5", tmp);
+			}
+
+			if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
+			{
+				char tmp[MAX_SIZE];
+
+				BinToStr(tmp, sizeof(tmp), crl->DigestSHA1, SHA1_SIZE);
+				CfgAddStr(ff, "DigestSHA1", tmp);
+			}
+
+			if (crl->Serial != NULL)
+			{
+				char tmp[MAX_SIZE];
+
+				BinToStr(tmp, sizeof(tmp), crl->Serial->data, crl->Serial->size);
+				CfgAddStr(ff, "Serial", tmp);
+			}
+		}
+	}
+	UnlockList(o);
+}
+
+// 無効な証明書リストの読み込み
+void SiLoadCrlList(LIST *o, FOLDER *f)
+{
+	// 引数チェック
+	if (o == NULL || f == NULL)
+	{
+		return;
+	}
+
+	LockList(o);
+	{
+		UINT i;
+		TOKEN_LIST *t;
+
+		t = CfgEnumFolderToTokenList(f);
+
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			CRL *crl;
+			FOLDER *ff = CfgGetFolder(f, t->Token[i]);
+			wchar_t cn[MAX_SIZE], org[MAX_SIZE], u[MAX_SIZE], c[MAX_SIZE],
+				st[MAX_SIZE], l[MAX_SIZE];
+			char tmp[MAX_SIZE];
+
+			if (ff != NULL)
+			{
+				BUF *b;
+
+				crl = ZeroMalloc(sizeof(CRL));
+
+				CfgGetUniStr(ff, "CommonName", cn, sizeof(cn));
+				CfgGetUniStr(ff, "Organization", org, sizeof(org));
+				CfgGetUniStr(ff, "Unit", u, sizeof(u));
+				CfgGetUniStr(ff, "Country", c, sizeof(c));
+				CfgGetUniStr(ff, "State", st, sizeof(st));
+				CfgGetUniStr(ff, "Local", l, sizeof(l));
+
+				crl->Name = NewName(cn, org, u, c, st, l);
+
+				if (CfgGetStr(ff, "Serial", tmp, sizeof(tmp)))
+				{
+					b = StrToBin(tmp);
+
+					if (b != NULL)
+					{
+						if (b->Size >= 1)
+						{
+							crl->Serial = NewXSerial(b->Buf, b->Size);
+						}
+
+						FreeBuf(b);
+					}
+				}
+
+				if (CfgGetStr(ff, "DigestMD5", tmp, sizeof(tmp)))
+				{
+					b = StrToBin(tmp);
+
+					if (b != NULL)
+					{
+						if (b->Size == MD5_SIZE)
+						{
+							Copy(crl->DigestMD5, b->Buf, MD5_SIZE);
+						}
+
+						FreeBuf(b);
+					}
+				}
+
+				if (CfgGetStr(ff, "DigestSHA1", tmp, sizeof(tmp)))
+				{
+					b = StrToBin(tmp);
+
+					if (b != NULL)
+					{
+						if (b->Size == SHA1_SIZE)
+						{
+							Copy(crl->DigestSHA1, b->Buf, SHA1_SIZE);
+						}
+
+						FreeBuf(b);
+					}
+				}
+
+				Insert(o, crl);
+			}
+		}
+
+		FreeToken(t);
+	}
+	UnlockList(o);
+}
+
+// 証明書リストの書き込み
+void SiWriteCertList(FOLDER *f, LIST *o)
+{
+	// 引数チェック
+	if (f == NULL || o == NULL)
+	{
+		return;
+	}
+
+	LockList(o);
+	{
+		UINT i;
+		X *x;
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			char name[MAX_SIZE];
+			BUF *b;
+			x = LIST_DATA(o, i);
+			Format(name, sizeof(name), "Cert%u", i);
+			b = XToBuf(x, false);
+			if (b != NULL)
+			{
+				CfgAddBuf(CfgCreateFolder(f, name), "X509", b);
+				FreeBuf(b);
+			}
+		}
+	}
+	UnlockList(o);
+}
+
+// 証明書リストの読み込み
+void SiLoadCertList(LIST *o, FOLDER *f)
+{
+	// 引数チェック
+	if (o == NULL || f == NULL)
+	{
+		return;
+	}
+
+	LockList(o);
+	{
+		UINT i;
+		TOKEN_LIST *t;
+
+		t = CfgEnumFolderToTokenList(f);
+
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			FOLDER *ff = CfgGetFolder(f, t->Token[i]);
+			BUF *b;
+
+			b = CfgGetBuf(ff, "X509");
+			if (b != NULL)
+			{
+				X *x = BufToX(b, false);
+				if (x != NULL)
+				{
+					Insert(o, x);
+				}
+				FreeBuf(b);
+			}
+		}
+
+		FreeToken(t);
+	}
+	UnlockList(o);
+}
+
+// データベースの書き込み
+void SiWriteHubDb(FOLDER *f, HUBDB *db)
+{
+	// 引数チェック
+	if (f == NULL || db == NULL)
+	{
+		return;
+	}
+
+	SiWriteUserList(CfgCreateFolder(f, "UserList"), db->UserList);
+	SiWriteGroupList(CfgCreateFolder(f, "GroupList"), db->GroupList);
+	SiWriteCertList(CfgCreateFolder(f, "CertList"), db->RootCertList);
+	SiWriteCrlList(CfgCreateFolder(f, "CrlList"), db->CrlList);
+}
+
+// データベースの読み込み
+void SiLoadHubDb(HUB *h, FOLDER *f)
+{
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	SiLoadGroupList(h, CfgGetFolder(f, "GroupList"));
+	SiLoadUserList(h, CfgGetFolder(f, "UserList"));
+
+	if (h->HubDb != NULL)
+	{
+		SiLoadCertList(h->HubDb->RootCertList, CfgGetFolder(f, "CertList"));
+		SiLoadCrlList(h->HubDb->CrlList, CfgGetFolder(f, "CrlList"));
+	}
+}
+
+// 仮想 HUB 設定の書き込み
+void SiWriteHubCfg(FOLDER *f, HUB *h)
+{
+	// 引数チェック
+	if (f == NULL || h == NULL)
+	{
+		return;
+	}
+
+	// パスワード
+	CfgAddByte(f, "HashedPassword", h->HashedPassword, sizeof(h->HashedPassword));
+	CfgAddByte(f, "SecurePassword", h->SecurePassword, sizeof(h->SecurePassword));
+
+	// Online / Offline フラグ
+	if (h->Cedar->Bridge == false)
+	{
+		CfgAddBool(f, "Online", (h->Offline && (h->HubIsOnlineButHalting == false)) ? false : true);
+	}
+
+	// トラフィック情報
+	SiWriteTraffic(f, "Traffic", h->Traffic);
+
+	// HUB オプション
+	SiWriteHubOptionCfg(CfgCreateFolder(f, "Option"), h->Option);
+
+	// メッセージ
+	{
+		FOLDER *folder = CfgCreateFolder(f, "Message");
+
+		if (IsEmptyUniStr(h->Msg) == false)
+		{
+			CfgAddUniStr(folder, "MessageText", h->Msg);
+		}
+	}
+
+	// HUB_LOG
+	SiWriteHubLogCfg(CfgCreateFolder(f, "LogSetting"), &h->LogSetting);
+
+	if (h->Type == HUB_TYPE_STANDALONE)
+	{
+		// リンクリスト
+		SiWriteHubLinks(CfgCreateFolder(f, "CascadeList"), h);
+	}
+
+	if (h->Type != HUB_TYPE_FARM_STATIC)
+	{
+		if (GetServerCapsBool(h->Cedar->Server, "b_support_securenat"))
+		{
+			// SecureNAT
+			SiWriteSecureNAT(h, CfgCreateFolder(f, "SecureNAT"));
+		}
+	}
+
+	// アクセスリスト
+	SiWriteHubAccessLists(CfgCreateFolder(f, "AccessList"), h);
+
+	// 管理オプション
+	SiWriteHubAdminOptions(CfgCreateFolder(f, "AdminOption"), h);
+
+	// HUB の種類
+	CfgAddInt(f, "Type", h->Type);
+
+	// データベース
+	if (h->Cedar->Bridge == false)
+	{
+		SiWriteHubDb(CfgCreateFolder(f, "SecurityAccountDatabase"), h->HubDb);
+	}
+
+	// 利用状況
+	CfgAddInt64(f, "LastCommTime", h->LastCommTime);
+	CfgAddInt64(f, "LastLoginTime", h->LastLoginTime);
+	CfgAddInt64(f, "CreatedTime", h->CreatedTime);
+	CfgAddInt(f, "NumLogin", h->NumLogin);
+}
+
+// ログオプションの読み込み
+void SiLoadHubLogCfg(HUB_LOG *g, FOLDER *f)
+{
+	// 引数チェック
+	if (f == NULL || g == NULL)
+	{
+		return;
+	}
+
+	Zero(g, sizeof(HUB_LOG));
+	g->SaveSecurityLog = CfgGetBool(f, "SaveSecurityLog");
+	g->SecurityLogSwitchType = CfgGetInt(f, "SecurityLogSwitchType");
+	g->SavePacketLog = CfgGetBool(f, "SavePacketLog");
+	g->PacketLogSwitchType = CfgGetInt(f, "PacketLogSwitchType");
+
+	g->PacketLogConfig[PACKET_LOG_TCP_CONN] = CfgGetInt(f, "PACKET_LOG_TCP_CONN");
+	g->PacketLogConfig[PACKET_LOG_TCP] = CfgGetInt(f, "PACKET_LOG_TCP");
+	g->PacketLogConfig[PACKET_LOG_DHCP] = CfgGetInt(f, "PACKET_LOG_DHCP");
+	g->PacketLogConfig[PACKET_LOG_UDP] = CfgGetInt(f, "PACKET_LOG_UDP");
+	g->PacketLogConfig[PACKET_LOG_ICMP] = CfgGetInt(f, "PACKET_LOG_ICMP");
+	g->PacketLogConfig[PACKET_LOG_IP] = CfgGetInt(f, "PACKET_LOG_IP");
+	g->PacketLogConfig[PACKET_LOG_ARP] = CfgGetInt(f, "PACKET_LOG_ARP");
+	g->PacketLogConfig[PACKET_LOG_ETHERNET] = CfgGetInt(f, "PACKET_LOG_ETHERNET");
+}
+
+// ログオプションの書き込み
+void SiWriteHubLogCfg(FOLDER *f, HUB_LOG *g)
+{
+	SiWriteHubLogCfgEx(f, g, false);
+}
+void SiWriteHubLogCfgEx(FOLDER *f, HUB_LOG *g, bool el_mode)
+{
+	// 引数チェック
+	if (f == NULL || g == NULL)
+	{
+		return;
+	}
+
+	if (el_mode == false)
+	{
+		CfgAddBool(f, "SaveSecurityLog", g->SaveSecurityLog);
+		CfgAddInt(f, "SecurityLogSwitchType", g->SecurityLogSwitchType);
+		CfgAddBool(f, "SavePacketLog", g->SavePacketLog);
+	}
+
+	CfgAddInt(f, "PacketLogSwitchType", g->PacketLogSwitchType);
+
+	CfgAddInt(f, "PACKET_LOG_TCP_CONN", g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+	CfgAddInt(f, "PACKET_LOG_TCP", g->PacketLogConfig[PACKET_LOG_TCP]);
+	CfgAddInt(f, "PACKET_LOG_DHCP", g->PacketLogConfig[PACKET_LOG_DHCP]);
+	CfgAddInt(f, "PACKET_LOG_UDP", g->PacketLogConfig[PACKET_LOG_UDP]);
+	CfgAddInt(f, "PACKET_LOG_ICMP", g->PacketLogConfig[PACKET_LOG_ICMP]);
+	CfgAddInt(f, "PACKET_LOG_IP", g->PacketLogConfig[PACKET_LOG_IP]);
+	CfgAddInt(f, "PACKET_LOG_ARP", g->PacketLogConfig[PACKET_LOG_ARP]);
+	CfgAddInt(f, "PACKET_LOG_ETHERNET", g->PacketLogConfig[PACKET_LOG_ETHERNET]);
+}
+
+// 仮想 HUB 設定の読み込み
+void SiLoadHubCfg(SERVER *s, FOLDER *f, char *name)
+{
+	HUB *h;
+	CEDAR *c;
+	HUB_OPTION o;
+	bool online;
+	UINT hub_old_type = 0;
+	// 引数チェック
+	if (s == NULL || f == NULL || name == NULL)
+	{
+		return;
+	}
+
+	c = s->Cedar;
+
+	// オプションの取得
+	Zero(&o, sizeof(o));
+	SiLoadHubOptionCfg(CfgGetFolder(f, "Option"), &o);
+
+	// HUB の作成
+	h = NewHub(c, name, &o);
+	if (h != NULL)
+	{
+		HUB_LOG g;
+
+		// パスワード
+		if (CfgGetByte(f, "HashedPassword", h->HashedPassword, sizeof(h->HashedPassword)) != sizeof(h->HashedPassword))
+		{
+			Hash(h->HashedPassword, "", 0, true);
+		}
+		if (CfgGetByte(f, "SecurePassword", h->SecurePassword, sizeof(h->SecurePassword)) != sizeof(h->SecurePassword))
+		{
+			HashPassword(h->SecurePassword, ADMINISTRATOR_USERNAME, "");
+		}
+
+		// ログ設定
+		Zero(&g, sizeof(g));
+		SiLoadHubLogCfg(&g, CfgGetFolder(f, "LogSetting"));
+		SetHubLogSetting(h, &g);
+
+		// Online / Offline フラグ
+		if (h->Cedar->Bridge == false)
+		{
+			online = CfgGetBool(f, "Online");
+		}
+		else
+		{
+			online = true;
+		}
+
+		// トラフィック情報
+		SiLoadTraffic(f, "Traffic", h->Traffic);
+
+		// アクセスリスト
+		SiLoadHubAccessLists(h, CfgGetFolder(f, "AccessList"));
+
+		// HUB の種類
+		hub_old_type = h->Type = CfgGetInt(f, "Type");
+		if (s->ServerType == SERVER_TYPE_STANDALONE)
+		{
+			if (h->Type != HUB_TYPE_STANDALONE)
+			{
+				// サーバーがスタンドアロンの場合は HUB の種類をスタンドアロンに変換する
+				h->Type = HUB_TYPE_STANDALONE;
+			}
+		}
+		else
+		{
+			if (h->Type == HUB_TYPE_STANDALONE)
+			{
+				// サーバーがファームコントローラの場合は HUB の種類をファーム対応にする
+				h->Type = HUB_TYPE_FARM_DYNAMIC;
+			}
+		}
+
+		// メッセージ
+		{
+			FOLDER *folder = CfgGetFolder(f, "Message");
+			if (folder != NULL)
+			{
+				wchar_t *tmp = Malloc(sizeof(wchar_t) * (HUB_MAXMSG_LEN + 1));
+				if (CfgGetUniStr(folder, "MessageText", tmp, sizeof(wchar_t) * (HUB_MAXMSG_LEN + 1)))
+				{
+					SetHubMsg(h, tmp);
+				}
+				Free(tmp);
+			}
+		}
+
+		// リンクリスト
+		if (h->Type == HUB_TYPE_STANDALONE)
+		{
+			// リンクリストはスタンドアロン HUB の場合しか使用しない
+			SiLoadHubLinks(h, CfgGetFolder(f, "CascadeList"));
+		}
+
+		// SecureNAT
+		if (GetServerCapsBool(h->Cedar->Server, "b_support_securenat"))
+		{
+			if (h->Type == HUB_TYPE_STANDALONE || h->Type == HUB_TYPE_FARM_DYNAMIC)
+			{
+				// SecureNAT はスタンドアロン HUB かダイナミック HUB の場合しか使用しない
+				SiLoadSecureNAT(h, CfgGetFolder(f, "SecureNAT"));
+
+				if (h->Type != HUB_TYPE_STANDALONE && h->Cedar != NULL && h->Cedar->Server != NULL &&
+					h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+				{
+					NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption,
+						hub_old_type == HUB_TYPE_STANDALONE);
+				}
+
+			}
+		}
+
+		// 管理オプション
+		SiLoadHubAdminOptions(h, CfgGetFolder(f, "AdminOption"));
+
+		// データベース
+		if (h->Cedar->Bridge == false)
+		{
+			SiLoadHubDb(h, CfgGetFolder(f, "SecurityAccountDatabase"));
+		}
+
+		// 利用状況
+		h->LastCommTime = CfgGetInt64(f, "LastCommTime");
+		if (h->LastCommTime == 0)
+		{
+			h->LastCommTime = SystemTime64();
+		}
+		h->LastLoginTime = CfgGetInt64(f, "LastLoginTime");
+		if (h->LastLoginTime == 0)
+		{
+			h->LastLoginTime = SystemTime64();
+		}
+		h->CreatedTime = CfgGetInt64(f, "CreatedTime");
+		h->NumLogin = CfgGetInt(f, "NumLogin");
+
+		// HUB の動作開始
+		AddHub(c, h);
+
+		if (online)
+		{
+			h->Offline = true;
+			SetHubOnline(h);
+		}
+		else
+		{
+			h->Offline = false;
+			SetHubOffline(h);
+		}
+
+		WaitLogFlush(h->SecurityLogger);
+		WaitLogFlush(h->PacketLogger);
+
+		ReleaseHub(h);
+	}
+}
+
+// SecureNAT 設定の読み込み
+void SiLoadSecureNAT(HUB *h, FOLDER *f)
+{
+	VH_OPTION o;
+	// 引数チェック
+	if (h == NULL || f == NULL)
+	{
+		return;
+	}
+
+	// VH_OPTION を読み込む
+	NiLoadVhOptionEx(&o, f);
+
+	// VH_OPTION をセット
+	Copy(h->SecureNATOption, &o, sizeof(VH_OPTION));
+
+	EnableSecureNAT(h, CfgGetBool(f, "Disabled") ? false : true);
+}
+
+// 仮想レイヤ 3 スイッチ設定の読み込み
+void SiLoadL3SwitchCfg(L3SW *sw, FOLDER *f)
+{
+	UINT i;
+	FOLDER *if_folder, *table_folder;
+	TOKEN_LIST *t;
+	bool active = false;
+	// 引数チェック
+	if (sw == NULL || f == NULL)
+	{
+		return;
+	}
+
+	active = CfgGetBool(f, "Active");
+
+	// インターフェイスリスト
+	if_folder = CfgGetFolder(f, "InterfaceList");
+	if (if_folder != NULL)
+	{
+		t = CfgEnumFolderToTokenList(if_folder);
+		if (t != NULL)
+		{
+			for (i = 0;i < t->NumTokens;i++)
+			{
+				FOLDER *ff = CfgGetFolder(if_folder, t->Token[i]);
+				char name[MAX_HUBNAME_LEN + 1];
+				UINT ip, subnet;
+
+				CfgGetStr(ff, "HubName", name, sizeof(name));
+				ip = CfgGetIp32(ff, "IpAddress");
+				subnet = CfgGetIp32(ff, "SubnetMask");
+
+				L3AddIf(sw, name, ip, subnet);
+			}
+			FreeToken(t);
+		}
+	}
+
+	// ルーティングテーブル
+	table_folder = CfgGetFolder(f, "RoutingTable");
+	if (table_folder != NULL)
+	{
+		t = CfgEnumFolderToTokenList(table_folder);
+		if (t != NULL)
+		{
+			for (i = 0;i < t->NumTokens;i++)
+			{
+				FOLDER *ff = CfgGetFolder(table_folder, t->Token[i]);
+				L3TABLE tbl;
+
+				Zero(&tbl, sizeof(tbl));
+				tbl.NetworkAddress = CfgGetIp32(ff, "NetworkAddress");
+				tbl.SubnetMask = CfgGetIp32(ff, "SubnetMask");
+				tbl.GatewayAddress = CfgGetIp32(ff, "GatewayAddress");
+				tbl.Metric = CfgGetInt(ff, "Metric");
+
+				L3AddTable(sw, &tbl);
+			}
+			FreeToken(t);
+		}
+	}
+
+	if (active)
+	{
+		L3SwStart(sw);
+	}
+}
+
+// 仮想レイヤ 3 スイッチ設定の書き込み
+void SiWriteL3SwitchCfg(FOLDER *f, L3SW *sw)
+{
+	UINT i;
+	FOLDER *if_folder, *table_folder;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (f == NULL || sw == NULL)
+	{
+		return;
+	}
+
+	// 動作フラグ
+	CfgAddBool(f, "Active", sw->Active);
+
+	// インターフェイスリスト
+	if_folder = CfgCreateFolder(f, "InterfaceList");
+	for (i = 0;i < LIST_NUM(sw->IfList);i++)
+	{
+		L3IF *e = LIST_DATA(sw->IfList, i);
+		FOLDER *ff;
+
+		Format(tmp, sizeof(tmp), "Interface%u", i);
+		ff = CfgCreateFolder(if_folder, tmp);
+
+		CfgAddStr(ff, "HubName", e->HubName);
+		CfgAddIp32(ff, "IpAddress", e->IpAddress);
+		CfgAddIp32(ff, "SubnetMask", e->SubnetMask);
+	}
+
+	// ルーティングテーブル
+	table_folder = CfgCreateFolder(f, "RoutingTable");
+	for (i = 0;i < LIST_NUM(sw->TableList);i++)
+	{
+		L3TABLE *e = LIST_DATA(sw->TableList, i);
+		FOLDER *ff;
+
+		Format(tmp, sizeof(tmp), "Entry%u", i);
+		ff = CfgCreateFolder(table_folder, tmp);
+
+		CfgAddIp32(ff, "NetworkAddress", e->NetworkAddress);
+		CfgAddIp32(ff, "SubnetMask", e->SubnetMask);
+		CfgAddIp32(ff, "GatewayAddress", e->GatewayAddress);
+		CfgAddInt(ff, "Metric", e->Metric);
+	}
+}
+
+// 仮想レイヤ 3 スイッチ一覧の読み込み
+void SiLoadL3Switchs(SERVER *s, FOLDER *f)
+{
+	UINT i;
+	TOKEN_LIST *t;
+	CEDAR *c;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+	c = s->Cedar;
+
+	t = CfgEnumFolderToTokenList(f);
+	if (t != NULL)
+	{
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			char *name = t->Token[i];
+			L3SW *sw = L3AddSw(c, name);
+
+			SiLoadL3SwitchCfg(sw, CfgGetFolder(f, name));
+
+			ReleaseL3Sw(sw);
+		}
+	}
+	FreeToken(t);
+}
+
+// 仮想レイヤ 3 スイッチ一覧の書き込み
+void SiWriteL3Switchs(FOLDER *f, SERVER *s)
+{
+	UINT i;
+	FOLDER *folder;
+	CEDAR *c;
+	// 引数チェック
+	if (f == NULL || s == NULL)
+	{
+		return;
+	}
+	c = s->Cedar;
+
+	LockList(c->L3SwList);
+	{
+		for (i = 0;i < LIST_NUM(c->L3SwList);i++)
+		{
+			L3SW *sw = LIST_DATA(c->L3SwList, i);
+
+			Lock(sw->lock);
+			{
+				folder = CfgCreateFolder(f, sw->Name);
+
+				SiWriteL3SwitchCfg(folder, sw);
+			}
+			Unlock(sw->lock);
+		}
+	}
+	UnlockList(c->L3SwList);
+}
+
+// ライセンス一覧の書き込み
+void SiWriteLicenseManager(FOLDER *f, SERVER *s)
+{
+	LICENSE_SYSTEM *ss;
+	// 引数チェック
+	if (f == NULL || s == NULL)
+	{
+		return;
+	}
+
+	ss = s->LicenseSystem;
+	if (s == NULL)
+	{
+		return;
+	}
+
+	LockList(ss->LicenseList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(ss->LicenseList);i++)
+		{
+			LICENSE *e = LIST_DATA(ss->LicenseList, i);
+			char name[MAX_SIZE];
+			FOLDER *ff;
+
+			Format(name, sizeof(name), "License%u", i);
+			ff = CfgCreateFolder(f, name);
+			CfgAddStr(ff, "LicenseKey", e->LicenseKeyStr);
+			CfgAddInt(ff, "LicenseType", e->ProductId);
+		}
+	}
+	UnlockList(ss->LicenseList);
+}
+
+// ライセンス一覧の読み込み
+void SiLoadLicenseManager(SERVER *s, FOLDER *f)
+{
+	UINT i;
+	TOKEN_LIST *t;
+	CEDAR *c;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+	c = s->Cedar;
+
+	t = CfgEnumFolderToTokenList(f);
+	if (t != NULL)
+	{
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			char *str = t->Token[i];
+			FOLDER *ff = CfgGetFolder(f, str);
+
+			if (ff != NULL)
+			{
+				UINT product_id = CfgGetInt(ff, "LicenseType");
+				char key[MAX_SIZE];
+
+				if (CfgGetStr(ff, "LicenseKey", key, sizeof(key)))
+				{
+					// ライセンス登録
+					//LiInputLicenseKeyEx(c, s->LicenseSystem, key, product_id, NULL);
+				}
+			}
+		}
+	}
+	FreeToken(t);
+
+	DestroyServerCapsCache(s);
+}
+
+// 仮想 HUB 一覧の書き込み
+void SiWriteHubs(FOLDER *f, SERVER *s)
+{
+	UINT i;
+	FOLDER *hub_folder;
+	CEDAR *c;
+	UINT num;
+	HUB **hubs;
+	// 引数チェック
+	if (f == NULL || s == NULL)
+	{
+		return;
+	}
+	c = s->Cedar;
+
+	LockList(c->HubList);
+	{
+		hubs = ToArray(c->HubList);
+		num = LIST_NUM(c->HubList);
+
+		for (i = 0;i < num;i++)
+		{
+			AddRef(hubs[i]->ref);
+		}
+	}
+	UnlockList(c->HubList);
+
+	for (i = 0;i < num;i++)
+	{
+		HUB *h = hubs[i];
+
+		Lock(h->lock);
+		{
+			hub_folder = CfgCreateFolder(f, h->Name);
+			SiWriteHubCfg(hub_folder, h);
+		}
+		Unlock(h->lock);
+
+		ReleaseHub(h);
+
+		if ((i % 30) == 1)
+		{
+			YieldCpu();
+		}
+	}
+
+	Free(hubs);
+}
+
+// 仮想 HUB 一覧の読み込み
+void SiLoadHubs(SERVER *s, FOLDER *f)
+{
+	UINT i;
+	FOLDER *hub_folder;
+	CEDAR *c;
+	TOKEN_LIST *t;
+	bool b = false;
+	// 引数チェック
+	if (f == NULL || s == NULL)
+	{
+		return;
+	}
+	c = s->Cedar;
+
+	t = CfgEnumFolderToTokenList(f);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *name = t->Token[i];
+		if (s->Cedar->Bridge)
+		{
+			if (StrCmpi(name, SERVER_DEFAULT_BRIDGE_NAME) == 0)
+			{
+				// Bridge の場合は "BRIDGE" という名前の仮想 HUB の設定
+				// しか読み込まない
+				b = true;
+			}
+			else
+			{
+				continue;
+			}
+		}
+		hub_folder = CfgGetFolder(f, name);
+		if (hub_folder != NULL)
+		{
+			SiLoadHubCfg(s, hub_folder, name);
+		}
+	}
+	FreeToken(t);
+
+	if (s->Cedar->Bridge && b == false)
+	{
+		// "BRIDGE" という名前の仮想 HUB の設定が存在しない場合は新たに作成する
+		SiInitDefaultHubList(s);
+	}
+}
+
+// サーバー固有の設定の読み込み
+void SiLoadServerCfg(SERVER *s, FOLDER *f)
+{
+	BUF *b;
+	CEDAR *c;
+	char tmp[MAX_SIZE];
+	X *x = NULL;
+	K *k = NULL;
+	bool cluster_allowed = false;
+	UINT num_connections_per_ip = 0;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	// 保存間隔関係
+	s->AutoSaveConfigSpan = CfgGetInt(f, "AutoSaveConfigSpan") * 1000;
+	if (s->AutoSaveConfigSpan == 0)
+	{
+		s->AutoSaveConfigSpan = SERVER_FILE_SAVE_INTERVAL_DEFAULT;
+	}
+	else
+	{
+		s->AutoSaveConfigSpan = MAKESURE(s->AutoSaveConfigSpan, SERVER_FILE_SAVE_INTERVAL_MIN, SERVER_FILE_SAVE_INTERVAL_MAX);
+	}
+
+	c = s->Cedar;
+	Lock(c->lock);
+	{
+		{
+			RPC_KEEP k;
+
+			// キープアライブ関係
+			Zero(&k, sizeof(k));
+			k.UseKeepConnect = CfgGetBool(f, "UseKeepConnect");
+			CfgGetStr(f, "KeepConnectHost", k.KeepConnectHost, sizeof(k.KeepConnectHost));
+			k.KeepConnectPort = CfgGetInt(f, "KeepConnectPort");
+			k.KeepConnectProtocol = CfgGetInt(f, "KeepConnectProtocol");
+			k.KeepConnectInterval = CfgGetInt(f, "KeepConnectInterval") * 1000;
+			if (k.KeepConnectPort == 0)
+			{
+				k.KeepConnectPort = 80;
+			}
+			if (StrLen(k.KeepConnectHost) == 0)
+			{
+				StrCpy(k.KeepConnectHost, sizeof(k.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);
+			}
+			if (k.KeepConnectInterval == 0)
+			{
+				k.KeepConnectInterval = KEEP_INTERVAL_DEFAULT * 1000;
+			}
+			if (k.KeepConnectInterval < 5000)
+			{
+				k.KeepConnectInterval = 5000;
+			}
+			if (k.KeepConnectInterval > 600000)
+			{
+				k.KeepConnectInterval = 600000;
+			}
+
+			Lock(s->Keep->lock);
+			{
+				KEEP *keep = s->Keep;
+				keep->Enable = k.UseKeepConnect;
+				keep->Server = true;
+				StrCpy(keep->ServerName, sizeof(keep->ServerName), k.KeepConnectHost);
+				keep->ServerPort = k.KeepConnectPort;
+				keep->UdpMode = k.KeepConnectProtocol;
+				keep->Interval = k.KeepConnectInterval;
+			}
+			Unlock(s->Keep->lock);
+		}
+
+		// IPv6 リスナーを無効にするかどうか
+		s->Cedar->DisableIPv6Listener = CfgGetBool(f, "DisableIPv6Listener");
+
+		// DeadLock
+		s->DisableDeadLockCheck = CfgGetBool(f, "DisableDeadLockCheck");
+
+		// 自動ファイル削除器
+		s->Eraser = NewEraser(s->Logger, CfgGetInt64(f, "AutoDeleteCheckDiskFreeSpaceMin"));
+
+		// NoLinuxArpFilter
+		s->NoLinuxArpFilter = CfgGetBool(f, "NoLinuxArpFilter");
+
+		// NoHighPriorityProcess
+		s->NoHighPriorityProcess = CfgGetBool(f, "NoHighPriorityProcess");
+
+		// NoDebugDump
+		s->NoDebugDump = CfgGetBool(f, "NoDebugDump");
+		if (s->NoDebugDump)
+		{
+#ifdef	OS_WIN32
+			MsSetEnableMinidump(false);
+#endif	// OS_WIN32
+		}
+
+		// クライアントにシグネチャを送信させない
+		s->NoSendSignature = CfgGetBool(f, "NoSendSignature");
+
+		// デバッグログ
+		s->SaveDebugLog = CfgGetBool(f, "SaveDebugLog");
+		if (s->SaveDebugLog)
+		{
+			s->DebugLog = NewTinyLog();
+		}
+
+		// サーバー証明書
+		b = CfgGetBuf(f, "ServerCert");
+		if (b != NULL)
+		{
+			x = BufToX(b, false);
+			FreeBuf(b);
+		}
+
+		// サーバー秘密鍵
+		b = CfgGetBuf(f, "ServerKey");
+		if (b != NULL)
+		{
+			k = BufToK(b, true, false, NULL);
+			FreeBuf(b);
+		}
+
+		if (x == NULL || k == NULL || CheckXandK(x, k) == false)
+		{
+			FreeX(x);
+			FreeK(k);
+			SiGenerateDefualtCert(&x, &k);
+
+			SetCedarCert(c, x, k);
+
+			FreeX(x);
+			FreeK(k);
+		}
+		else
+		{
+			SetCedarCert(c, x, k);
+
+			FreeX(x);
+			FreeK(k);
+		}
+
+		// 暗号化名
+		if (CfgGetStr(f, "CipherName", tmp, sizeof(tmp)))
+		{
+			StrUpper(tmp);
+			if (CheckCipherListName(tmp))
+			{
+				SetCedarCipherList(c, tmp);
+			}
+		}
+
+		// トラフィック情報
+		Lock(c->TrafficLock);
+		{
+			SiLoadTraffic(f, "ServerTraffic", c->Traffic);
+		}
+		Unlock(c->TrafficLock);
+
+		// 現在のライセンスでクラスタモードが許可されているかどうかを取得する
+		cluster_allowed = false;
+		if (s->Cedar->Bridge == false)
+		{
+			LICENSE_STATUS status;
+
+			LiParseCurrentLicenseStatus(s->LicenseSystem, &status);
+
+			if (status.AllowEnterpriseFunction)
+			{
+				cluster_allowed = true;
+			}
+		}
+
+		// サーバーの種類
+		s->UpdatedServerType = s->ServerType = 
+			cluster_allowed ? CfgGetInt(f, "ServerType") : SERVER_TYPE_STANDALONE;
+
+		// パスワード
+		if (CfgGetByte(f, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword)) != sizeof(s->HashedPassword))
+		{
+			Hash(s->HashedPassword, "", 0, true);
+		}
+
+		if (s->ServerType != SERVER_TYPE_STANDALONE)
+		{
+			// サーバーの性能基準比
+			s->Weight = CfgGetInt(f, "ClusterMemberWeight");
+			if (s->Weight == 0)
+			{
+				s->Weight = FARM_DEFAULT_WEIGHT;
+			}
+		}
+		else
+		{
+			s->Weight = FARM_DEFAULT_WEIGHT;
+		}
+
+		if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			s->ControllerOnly = CfgGetBool(f, "ControllerOnly");
+		}
+
+		if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+		{
+			char tmp[6 * MAX_PUBLIC_PORT_NUM + 1];
+			// ファームメンバの場合の設定項目の読み込み
+			CfgGetStr(f, "ControllerName", s->ControllerName, sizeof(s->ControllerName));
+			s->ControllerPort = CfgGetInt(f, "ControllerPort");
+			CfgGetByte(f, "MemberPassword", s->MemberPassword, SHA1_SIZE);
+			s->PublicIp = CfgGetIp32(f, "PublicIp");
+			if (CfgGetStr(f, "PublicPorts", tmp, sizeof(tmp)))
+			{
+				TOKEN_LIST *t = ParseToken(tmp, ", ");
+				UINT i;
+				s->NumPublicPort = t->NumTokens;
+				s->PublicPorts = ZeroMalloc(s->NumPublicPort * sizeof(UINT));
+				for (i = 0;i < s->NumPublicPort;i++)
+				{
+					s->PublicPorts[i] = ToInt(t->Token[i]);
+				}
+				FreeToken(t);
+			}
+		}
+	}
+	Unlock(c->lock);
+}
+
+// サーバー固有の設定の書き込み
+void SiWriteServerCfg(FOLDER *f, SERVER *s)
+{
+	BUF *b;
+	CEDAR *c;
+	// 引数チェック
+	if (f == NULL || s == NULL)
+	{
+		return;
+	}
+
+	CfgAddInt(f, "AutoSaveConfigSpan", s->AutoSaveConfigSpan / 1000);
+
+	c = s->Cedar;
+
+	Lock(c->lock);
+	{
+		Lock(s->Keep->lock);
+		{
+			KEEP *k = s->Keep;
+			CfgAddBool(f, "UseKeepConnect", k->Enable);
+			CfgAddStr(f, "KeepConnectHost", k->ServerName);
+			CfgAddInt(f, "KeepConnectPort", k->ServerPort);
+			CfgAddInt(f, "KeepConnectProtocol", k->UdpMode);
+			CfgAddInt(f, "KeepConnectInterval", k->Interval / 1000);
+		}
+		Unlock(s->Keep->lock);
+
+		// IPv6 リスナー無効化設定
+		CfgAddBool(f, "DisableIPv6Listener", s->Cedar->DisableIPv6Listener);
+
+		// DeadLock
+		CfgAddBool(f, "DisableDeadLockCheck", s->DisableDeadLockCheck);
+
+		// 自動ファイル削除器関係
+		CfgAddInt64(f, "AutoDeleteCheckDiskFreeSpaceMin", s->Eraser->MinFreeSpace);
+
+		// NoLinuxArpFilter
+		if (GetOsInfo()->OsType == OSTYPE_LINUX)
+		{
+			CfgAddBool(f, "NoLinuxArpFilter", s->NoLinuxArpFilter);
+		}
+
+		// NoHighPriorityProcess
+		CfgAddBool(f, "NoHighPriorityProcess", s->NoHighPriorityProcess);
+
+#ifdef	OS_WIN32
+		CfgAddBool(f, "NoDebugDump", s->NoDebugDump);
+#endif	// OS_WIN32
+
+		// デバッグログ
+		CfgAddBool(f, "SaveDebugLog", s->SaveDebugLog);
+
+		// クライアントにシグネチャを送信させない
+		CfgAddBool(f, "NoSendSignature", s->NoSendSignature);
+
+		// サーバー証明書
+		b = XToBuf(c->ServerX, false);
+		CfgAddBuf(f, "ServerCert", b);
+		FreeBuf(b);
+
+		// サーバー秘密鍵
+		b = KToBuf(c->ServerK, false, NULL);
+		CfgAddBuf(f, "ServerKey", b);
+		FreeBuf(b);
+
+		// トラフィック情報
+		Lock(c->TrafficLock);
+		{
+			SiWriteTraffic(f, "ServerTraffic", c->Traffic);
+		}
+		Unlock(c->TrafficLock);
+
+		// サーバーの種類
+		if (s->Cedar->Bridge == false)
+		{
+			CfgAddInt(f, "ServerType", s->UpdatedServerType);
+		}
+
+		// 暗号化
+		CfgAddStr(f, "CipherName", s->Cedar->CipherList);
+
+		// パスワード
+		CfgAddByte(f, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));
+
+		if (s->UpdatedServerType == SERVER_TYPE_FARM_MEMBER)
+		{
+			char tmp[6 * MAX_PUBLIC_PORT_NUM + 1];
+			UINT i;
+			// ファームメンバの場合の設定項目
+			CfgAddStr(f, "ControllerName", s->ControllerName);
+			CfgAddInt(f, "ControllerPort", s->ControllerPort);
+			CfgAddByte(f, "MemberPassword", s->MemberPassword, SHA1_SIZE);
+			CfgAddIp32(f, "PublicIp", s->PublicIp);
+			tmp[0] = 0;
+			for (i = 0;i < s->NumPublicPort;i++)
+			{
+				char tmp2[MAX_SIZE];
+				ToStr(tmp2, s->PublicPorts[i]);
+				StrCat(tmp, sizeof(tmp), tmp2);
+				StrCat(tmp, sizeof(tmp), ",");
+			}
+			if (StrLen(tmp) >= 1)
+			{
+				if (tmp[StrLen(tmp) - 1] == ',')
+				{
+					tmp[StrLen(tmp) - 1] = 0;
+				}
+			}
+			CfgAddStr(f, "PublicPorts", tmp);
+		}
+
+		if (s->UpdatedServerType != SERVER_TYPE_STANDALONE)
+		{
+			CfgAddInt(f, "ClusterMemberWeight", s->Weight);
+		}
+
+		if (s->UpdatedServerType == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			CfgAddBool(f, "ControllerOnly", s->ControllerOnly);
+		}
+	}
+	Unlock(c->lock);
+}
+
+// トラフィック情報の読み込み
+void SiLoadTraffic(FOLDER *parent, char *name, TRAFFIC *t)
+{
+	FOLDER *f;
+	// 引数チェック
+	if (t != NULL)
+	{
+		Zero(t, sizeof(TRAFFIC));
+	}
+	if (parent == NULL || name == NULL || t == NULL)
+	{
+		return;
+	}
+
+	f = CfgGetFolder(parent, name);
+
+	if (f == NULL)
+	{
+		return;
+	}
+
+	SiLoadTrafficInner(f, "SendTraffic", &t->Send);
+	SiLoadTrafficInner(f, "RecvTraffic", &t->Recv);
+}
+void SiLoadTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e)
+{
+	FOLDER *f;
+	// 引数チェック
+	if (e != NULL)
+	{
+		Zero(e, sizeof(TRAFFIC_ENTRY));
+	}
+	if (parent == NULL || name == NULL || e == NULL)
+	{
+		return;
+	}
+
+	f = CfgGetFolder(parent, name);
+	if (f == NULL)
+	{
+		return;
+	}
+
+	e->BroadcastCount = CfgGetInt64(f, "BroadcastCount");
+	e->BroadcastBytes = CfgGetInt64(f, "BroadcastBytes");
+	e->UnicastCount = CfgGetInt64(f, "UnicastCount");
+	e->UnicastBytes = CfgGetInt64(f, "UnicastBytes");
+}
+
+// トラフィック情報の書き込み
+void SiWriteTraffic(FOLDER *parent, char *name, TRAFFIC *t)
+{
+	FOLDER *f;
+	// 引数チェック
+	if (parent == NULL || name == NULL || t == NULL)
+	{
+		return;
+	}
+
+	f = CfgCreateFolder(parent, name);
+
+	SiWriteTrafficInner(f, "SendTraffic", &t->Send);
+	SiWriteTrafficInner(f, "RecvTraffic", &t->Recv);
+}
+void SiWriteTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e)
+{
+	FOLDER *f;
+	// 引数チェック
+	if (parent == NULL || name == NULL || e == NULL)
+	{
+		return;
+	}
+
+	f = CfgCreateFolder(parent, name);
+	CfgAddInt64(f, "BroadcastCount", e->BroadcastCount);
+	CfgAddInt64(f, "BroadcastBytes", e->BroadcastBytes);
+	CfgAddInt64(f, "UnicastCount", e->UnicastCount);
+	CfgAddInt64(f, "UnicastBytes", e->UnicastBytes);
+}
+
+// 設定ファイル書き込み用スレッド
+void SiSaverThread(THREAD *thread, void *param)
+{
+	SERVER *s = (SERVER *)param;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	while (s->Halt == false)
+	{
+		// 設定ファイル保存
+		SiWriteConfigurationFile(s);
+
+		Wait(s->SaveHaltEvent, s->AutoSaveConfigSpan);
+	}
+}
+
+// 設定ファイルに書き込む
+UINT SiWriteConfigurationFile(SERVER *s)
+{
+	UINT ret;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	if (s->CfgRw == NULL)
+	{
+		return 0;
+	}
+
+	Lock(s->SaveCfgLock);
+	{
+		FOLDER *f;
+
+		Debug("save: SiWriteConfigurationToCfg() start.\n");
+		f = SiWriteConfigurationToCfg(s);
+		Debug("save: SiWriteConfigurationToCfg() finished.\n");
+
+		Debug("save: SaveCfgRw() start.\n");
+		ret = SaveCfgRw(s->CfgRw, f);
+		Debug("save: SaveCfgRw() finished.\n");
+
+		Debug("save: CfgDeleteFolder() start.\n");
+		CfgDeleteFolder(f);
+		Debug("save: CfgDeleteFolder() finished.\n");
+	}
+	Unlock(s->SaveCfgLock);
+
+	return ret;
+}
+
+// コンフィグレーション解放
+void SiFreeConfiguration(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// 設定ファイルに書き込む
+	SiWriteConfigurationFile(s);
+
+	// 設定ファイル保存スレッドの終了
+	s->Halt = true;
+	Set(s->SaveHaltEvent);
+	WaitThread(s->SaveThread, INFINITE);
+
+	ReleaseEvent(s->SaveHaltEvent);
+	ReleaseThread(s->SaveThread);
+
+	FreeCfgRw(s->CfgRw);
+	s->CfgRw = NULL;
+
+	// Ethernet 解放
+	FreeEth();
+}
+
+// StXxx 関係関数の初期化
+void StInit()
+{
+	if (server_lock != NULL)
+	{
+		return;
+	}
+
+	server_lock = NewLock();
+}
+
+// StXxx 関係関数の解放
+void StFree()
+{
+	DeleteLock(server_lock);
+	server_lock = NULL;
+}
+
+// サーバーの開始
+void StStartServer(bool bridge)
+{
+	Lock(server_lock);
+	{
+		if (server != NULL)
+		{
+			// すでに開始されている
+			Unlock(server_lock);
+			return;
+		}
+
+		// サーバーの作成
+		server = SiNewServer(bridge);
+	}
+	Unlock(server_lock);
+
+//	StartCedarLog();
+}
+
+// サーバーの取得
+SERVER *StGetServer()
+{
+	if (server == NULL)
+	{
+		return NULL;
+	}
+	return server;
+}
+
+// サーバーの停止
+void StStopServer()
+{
+	Lock(server_lock);
+	{
+		if (server == NULL)
+		{
+			// 開始されていない
+			Unlock(server_lock);
+			return;
+		}
+
+		// サーバーの解放
+		SiReleaseServer(server);
+		server = NULL;
+	}
+	Unlock(server_lock);
+
+	StopCedarLog();
+}
+
+// サーバーの種類の設定
+void SiSetServerType(SERVER *s, UINT type,
+					 UINT ip, UINT num_port, UINT *ports,
+					 char *controller_name, UINT controller_port, UCHAR *password, UINT weight, bool controller_only)
+{
+	bool bridge;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+	if (type == SERVER_TYPE_FARM_MEMBER &&
+		(num_port == 0 || ports == NULL || controller_name == NULL ||
+		controller_port == 0 || password == NULL || num_port > MAX_PUBLIC_PORT_NUM))
+	{
+		return;
+	}
+	if (weight == 0)
+	{
+		weight = FARM_DEFAULT_WEIGHT;
+	}
+
+	bridge = s->Cedar->Bridge;
+
+	Lock(s->lock);
+	{
+		// 種類の更新
+		s->UpdatedServerType = type;
+
+		s->Weight = weight;
+
+		// 値の設定
+		if (type == SERVER_TYPE_FARM_MEMBER)
+		{
+			StrCpy(s->ControllerName, sizeof(s->ControllerName), controller_name);
+			s->ControllerPort = controller_port;
+			if (IsZero(password, SHA1_SIZE) == false)
+			{
+				Copy(s->MemberPassword, password, SHA1_SIZE);
+			}
+			s->PublicIp = ip;
+			s->NumPublicPort = num_port;
+			if (s->PublicPorts != NULL)
+			{
+				Free(s->PublicPorts);
+			}
+			s->PublicPorts = ZeroMalloc(num_port * sizeof(UINT));
+			Copy(s->PublicPorts, ports, num_port * sizeof(UINT));
+		}
+
+		if (type == SERVER_TYPE_FARM_CONTROLLER)
+		{
+			s->ControllerOnly = controller_only;
+		}
+	}
+	Unlock(s->lock);
+
+	// サーバーの再起動
+	SiRebootServer(bridge);
+}
+
+// サーバーの再起動スレッド
+void SiRebootServerThread(THREAD *thread, void *param)
+{
+	// 引数チェック
+	if (thread == NULL)
+	{
+		return;
+	}
+
+	if (server == NULL)
+	{
+		return;
+	}
+
+	// サーバーの停止
+	StStopServer();
+
+	// サーバーの開始
+	StStartServer((bool)param);
+}
+
+// サーバーの再起動
+void SiRebootServer(bool bridge)
+{
+	SiRebootServerEx(bridge, false);
+}
+void SiRebootServerEx(bool bridge, bool reset_setting)
+{
+	THREAD *t;
+
+	server_reset_setting = reset_setting;
+
+	t = NewThread(SiRebootServerThread, (void *)bridge);
+	ReleaseThread(t);
+}
+
+// すべてのリスナーの停止
+void SiStopAllListener(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	SiLockListenerList(s);
+	{
+		UINT i;
+		LIST *o = NewListFast(NULL);
+		for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+		{
+			SERVER_LISTENER *e = LIST_DATA(s->ServerListenerList, i);
+			Add(o, e);
+		}
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			SERVER_LISTENER *e = LIST_DATA(o, i);
+			SiDeleteListener(s, e->Port);
+		}
+
+		ReleaseList(o);
+	}
+	SiUnlockListenerList(s);
+
+	ReleaseList(s->ServerListenerList);
+}
+
+// サーバーのクリーンアップ
+void SiCleanupServer(SERVER *s)
+{
+	UINT i;
+	CEDAR *c;
+	LISTENER **listener_list;
+	UINT num_listener;
+	HUB **hub_list;
+	UINT num_hub;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	SiFreeDeadLockCheck(s);
+
+	FreeServerSnapshot(s);
+
+	c = s->Cedar;
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		// ファームメンバの場合、ファームコントローラへの接続を停止
+		SLog(c, "LS_STOP_FARM_MEMBER");
+		SiStopConnectToController(s->FarmController);
+		s->FarmController = NULL;
+		SLog(c, "LS_STOP_FARM_MEMBER_2");
+	}
+
+	IncrementServerConfigRevision(s);
+
+	SLog(c, "LS_END_2");
+
+	SLog(c, "LS_STOP_ALL_LISTENER");
+	// すべてのリスナーを停止
+	LockList(c->ListenerList);
+	{
+		listener_list = ToArray(c->ListenerList);
+		num_listener = LIST_NUM(c->ListenerList);
+		for (i = 0;i < num_listener;i++)
+		{
+			AddRef(listener_list[i]->ref);
+		}
+	}
+	UnlockList(c->ListenerList);
+
+	for (i = 0;i < num_listener;i++)
+	{
+		StopListener(listener_list[i]);
+		ReleaseListener(listener_list[i]);
+	}
+	Free(listener_list);
+	SLog(c, "LS_STOP_ALL_LISTENER_2");
+
+	SLog(c, "LS_STOP_ALL_HUB");
+	// すべての HUB を停止
+	LockList(c->HubList);
+	{
+		hub_list = ToArray(c->HubList);
+		num_hub = LIST_NUM(c->HubList);
+		for (i = 0;i < num_hub;i++)
+		{
+			AddRef(hub_list[i]->ref);
+		}
+	}
+	UnlockList(c->HubList);
+
+	for (i = 0;i < num_hub;i++)
+	{
+		StopHub(hub_list[i]);
+		ReleaseHub(hub_list[i]);
+	}
+	Free(hub_list);
+	SLog(c, "LS_STOP_ALL_HUB_2");
+
+	// コンフィグレーション解放
+	SiFreeConfiguration(s);
+
+	// Cedar の停止
+	SLog(c, "LS_STOP_CEDAR");
+	StopCedar(s->Cedar);
+	SLog(c, "LS_STOP_CEDAR_2");
+
+	// すべてのリスナーの停止
+	SiStopAllListener(s);
+
+	if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// ファームコントローラの場合
+		UINT i;
+
+		SLog(c, "LS_STOP_FARM_CONTROL");
+
+		// ファームコントロールを停止
+		SiStopFarmControl(s);
+
+		// ファームメンバ情報を解放
+		ReleaseList(s->FarmMemberList);
+		s->FarmMemberList = NULL;
+
+		for (i = 0;i < LIST_NUM(s->Me->HubList);i++)
+		{
+			Free(LIST_DATA(s->Me->HubList, i));
+		}
+		ReleaseList(s->Me->HubList);
+
+		Free(s->Me);
+
+		SLog(c, "LS_STOP_FARM_CONTROL_2");
+	}
+
+	if (s->PublicPorts != NULL)
+	{
+		Free(s->PublicPorts);
+	}
+
+	SLog(s->Cedar, "LS_END_1");
+	SLog(s->Cedar, "L_LINE");
+
+	ReleaseCedar(s->Cedar);
+	DeleteLock(s->lock);
+	DeleteLock(s->SaveCfgLock);
+
+	StopKeep(s->Keep);
+
+	FreeEraser(s->Eraser);
+
+	// ライセンスシステム解放
+	if (s->LicenseSystem != NULL)
+	{
+		LiFreeLicenseSystem(s->LicenseSystem);
+	}
+
+	FreeLog(s->Logger);
+
+	FreeServerCapsCache(s);
+
+	SiFreeHubCreateHistory(s);
+
+	// デバッグログの停止
+	FreeTinyLog(s->DebugLog);
+
+	DeleteLock(s->TasksFromFarmControllerLock);
+
+	Free(s);
+}
+
+// サーバーの解放
+void SiReleaseServer(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (Release(s->ref) == 0)
+	{
+		SiCleanupServer(s);
+	}
+}
+
+// 次に処理をさせるファームメンバーを指定する
+FARM_MEMBER *SiGetNextFarmMember(SERVER *s)
+{
+	UINT i, num;
+	UINT min_point = 0;
+	FARM_MEMBER *ret = NULL;
+	// 引数チェック
+	if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		return NULL;
+	}
+
+	num = LIST_NUM(s->FarmMemberList);
+	if (num == 0)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < num;i++)
+	{
+		UINT num_sessions;
+		UINT max_sessions;
+		FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+		if (s->ControllerOnly)
+		{
+			if (f->Me)
+			{
+				// ControllerOnly のとき自分自身は選定しない
+				continue;
+			}
+		}
+
+		if (f->Me == false)
+		{
+			num_sessions = f->NumSessions;
+			max_sessions = f->MaxSessions;
+		}
+		else
+		{
+			num_sessions = Count(s->Cedar->CurrentSessions);
+			max_sessions = GetServerCapsInt(s, "i_max_sessions");
+		}
+
+		if (max_sessions == 0)
+		{
+			max_sessions = GetServerCapsInt(s, "i_max_sessions");
+		}
+
+		if (num_sessions < max_sessions)
+		{
+			if (f->Point >= min_point)
+			{
+				min_point = f->Point;
+				ret = f;
+			}
+		}
+	}
+
+	return ret;
+}
+
+// HUB 列挙指令受信
+void SiCalledEnumHub(SERVER *s, PACK *p, PACK *req)
+{
+	UINT i;
+	CEDAR *c;
+	LICENSE_STATUS st;
+	UINT num = 0;
+	// 引数チェック
+	if (s == NULL || p == NULL || req == NULL)
+	{
+		return;
+	}
+
+	LiParseCurrentLicenseStatus(s->LicenseSystem, &st);
+
+	c = s->Cedar;
+
+	LockList(c->HubList);
+	{
+		UINT num = LIST_NUM(c->HubList);
+		for (i = 0;i < num;i++)
+		{
+			HUB *h = LIST_DATA(c->HubList, i);
+			Lock(h->lock);
+			{
+				PackAddStrEx(p, "HubName", h->Name, i, num);
+				PackAddIntEx(p, "HubType", h->Type, i, num);
+				PackAddIntEx(p, "NumSession", Count(h->NumSessions), i, num);
+
+				PackAddIntEx(p, "NumSessions", LIST_NUM(h->SessionList), i, num);
+				PackAddIntEx(p, "NumSessionsClient", Count(h->NumSessionsClient), i, num);
+				PackAddIntEx(p, "NumSessionsBridge", Count(h->NumSessionsBridge), i, num);
+
+				PackAddIntEx(p, "NumMacTables", LIST_NUM(h->MacTable), i, num);
+
+				PackAddIntEx(p, "NumIpTables", LIST_NUM(h->IpTable), i, num);
+
+				PackAddInt64Ex(p, "LastCommTime", h->LastCommTime, i, num);
+				PackAddInt64Ex(p, "CreatedTime", h->CreatedTime, i, num);
+			}
+			Unlock(h->lock);
+		}
+	}
+	UnlockList(c->HubList);
+
+	PackAddInt(p, "Point", SiGetPoint(s));
+	PackAddInt(p, "NumTcpConnections", Count(s->Cedar->CurrentTcpConnections));
+	PackAddInt(p, "NumTotalSessions", Count(s->Cedar->CurrentSessions));
+	PackAddInt(p, "MaxSessions", GetServerCapsInt(s, "i_max_sessions"));
+
+	PackAddInt(p, "AssignedClientLicense", Count(s->Cedar->AssignedClientLicense));
+	PackAddInt(p, "AssignedBridgeLicense", Count(s->Cedar->AssignedBridgeLicense));
+
+	PackAddData(p, "RandomKey", s->MyRandomKey, SHA1_SIZE);
+	PackAddInt64(p, "SystemId", st.SystemId);
+
+	Lock(c->TrafficLock);
+	{
+		OutRpcTraffic(p, c->Traffic);
+	}
+	Unlock(c->TrafficLock);
+
+	LockList(c->TrafficDiffList);
+	{
+		UINT num = LIST_NUM(c->TrafficDiffList);
+		UINT i;
+
+		for (i = 0;i < num;i++)
+		{
+			TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);
+
+			PackAddIntEx(p, "TdType", d->Type, i, num);
+			PackAddStrEx(p, "TdHubName", d->HubName, i, num);
+			PackAddStrEx(p, "TdName", d->Name, i, num);
+
+			OutRpcTrafficEx(&d->Traffic, p, i, num);
+
+			Free(d->HubName);
+			Free(d->Name);
+			Free(d);
+		}
+
+		DeleteAll(c->TrafficDiffList);
+	}
+	UnlockList(c->TrafficDiffList);
+}
+
+// HUB 削除指令受信
+void SiCalledDeleteHub(SERVER *s, PACK *p)
+{
+	char name[MAX_SIZE];
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (PackGetStr(p, "HubName", name, sizeof(name)) == false)
+	{
+		return;
+	}
+
+	LockHubList(s->Cedar);
+
+	h = GetHub(s->Cedar, name);
+	if (h == NULL)
+	{
+		UnlockHubList(s->Cedar);
+		return;
+	}
+	UnlockHubList(s->Cedar);
+
+	SetHubOffline(h);
+
+	LockHubList(s->Cedar);
+
+	DelHubEx(s->Cedar, h, true);
+
+	UnlockHubList(s->Cedar);
+
+	ReleaseHub(h);
+}
+
+// HUB 更新指令受信
+void SiCalledUpdateHub(SERVER *s, PACK *p)
+{
+	char name[MAX_SIZE];
+	UINT type;
+	HUB_OPTION o;
+	HUB_LOG log;
+	bool save_packet_log;
+	UINT packet_log_switch_type;
+	UINT packet_log_config[NUM_PACKET_LOG];
+	bool save_security_log;
+	bool type_changed = false;
+	UINT security_log_switch_type;
+	UINT i;
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackGetStr(p, "HubName", name, sizeof(name));
+	type = PackGetInt(p, "HubType");
+	Zero(&o, sizeof(o));
+	o.MaxSession = PackGetInt(p, "MaxSession");
+	o.NoArpPolling = PackGetBool(p, "NoArpPolling");
+	o.NoIPv6AddrPolling = PackGetBool(p, "NoIPv6AddrPolling");
+	o.FilterPPPoE = PackGetBool(p, "FilterPPPoE");
+	o.YieldAfterStorePacket = PackGetBool(p, "YieldAfterStorePacket");
+	o.NoSpinLockForPacketDelay = PackGetBool(p, "NoSpinLockForPacketDelay");
+	o.BroadcastStormDetectionThreshold = PackGetInt(p, "BroadcastStormDetectionThreshold");
+	o.ClientMinimumRequiredBuild = PackGetInt(p, "ClientMinimumRequiredBuild");
+	o.FixForDLinkBPDU = PackGetBool(p, "FixForDLinkBPDU");
+	o.NoLookBPDUBridgeId = PackGetBool(p, "NoLookBPDUBridgeId");
+	o.NoManageVlanId = PackGetBool(p, "NoManageVlanId");
+	o.VlanTypeId = PackGetInt(p, "VlanTypeId");
+	if (o.VlanTypeId == 0)
+	{
+		o.VlanTypeId = MAC_PROTO_TAGVLAN;
+	}
+	o.FilterOSPF = PackGetBool(p, "FilterOSPF");
+	o.FilterIPv4 = PackGetBool(p, "FilterIPv4");
+	o.FilterIPv6 = PackGetBool(p, "FilterIPv6");
+	o.FilterNonIP = PackGetBool(p, "FilterNonIP");
+	o.NoIPv4PacketLog = PackGetBool(p, "NoIPv4PacketLog");
+	o.NoIPv6PacketLog = PackGetBool(p, "NoIPv6PacketLog");
+	o.FilterBPDU = PackGetBool(p, "FilterBPDU");
+	o.NoIPv6DefaultRouterInRAWhenIPv6 = PackGetBool(p, "NoIPv6DefaultRouterInRAWhenIPv6");
+	o.NoMacAddressLog = PackGetBool(p, "NoMacAddressLog");
+	o.ManageOnlyPrivateIP = PackGetBool(p, "ManageOnlyPrivateIP");
+	o.ManageOnlyLocalUnicastIPv6 = PackGetBool(p, "ManageOnlyLocalUnicastIPv6");
+	o.DisableIPParsing = PackGetBool(p, "DisableIPParsing");
+	o.NoIpTable = PackGetBool(p, "NoIpTable");
+	o.NoEnum = PackGetBool(p, "NoEnum");
+	save_packet_log = PackGetInt(p, "SavePacketLog");
+	packet_log_switch_type = PackGetInt(p, "PacketLogSwitchType");
+	for (i = 0;i < NUM_PACKET_LOG;i++)
+	{
+		packet_log_config[i] = PackGetIntEx(p, "PacketLogConfig", i);
+	}
+	save_security_log = PackGetInt(p, "SaveSecurityLog");
+	security_log_switch_type = PackGetInt(p, "SecurityLogSwitchType");
+
+	Zero(&log, sizeof(log));
+	log.SavePacketLog = save_packet_log;
+	log.PacketLogSwitchType = packet_log_switch_type;
+	Copy(log.PacketLogConfig, packet_log_config, sizeof(log.PacketLogConfig));
+	log.SaveSecurityLog = save_security_log;
+	log.SecurityLogSwitchType = security_log_switch_type;
+
+	h = GetHub(s->Cedar, name);
+	if (h == NULL)
+	{
+		return;
+	}
+
+	h->FarmMember_MaxSessionClient = PackGetInt(p, "MaxSessionClient");
+	h->FarmMember_MaxSessionBridge = PackGetInt(p, "MaxSessionBridge");
+	h->FarmMember_MaxSessionClientBridgeApply = PackGetBool(p, "MaxSessionClientBridgeApply");
+
+	if (h->FarmMember_MaxSessionClientBridgeApply == false)
+	{
+		h->FarmMember_MaxSessionClient = INFINITE;
+		h->FarmMember_MaxSessionBridge = INFINITE;
+	}
+
+	Lock(h->lock);
+	{
+		Copy(h->Option, &o, sizeof(HUB_OPTION));
+		PackGetData2(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);
+		PackGetData2(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);
+	}
+	Unlock(h->lock);
+
+	SetHubLogSetting(h, &log);
+
+	if (h->Type != type)
+	{
+		h->Type = type;
+		type_changed = true;
+	}
+
+	LockList(h->AccessList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(h->AccessList);i++)
+		{
+			ACCESS *a = LIST_DATA(h->AccessList, i);
+			Free(a);
+		}
+		DeleteAll(h->AccessList);
+	}
+	UnlockList(h->AccessList);
+
+	for (i = 0;i < SiNumAccessFromPack(p);i++)
+	{
+		ACCESS *a = SiPackToAccess(p, i);
+		AddAccessList(h, a);
+		Free(a);
+	}
+
+	if (PackGetBool(p, "EnableSecureNAT"))
+	{
+		VH_OPTION t;
+		bool changed;
+
+		InVhOption(&t, p);
+
+		changed = Cmp(h->SecureNATOption, &t, sizeof(VH_OPTION)) == 0 ? false : true;
+		Copy(h->SecureNATOption, &t, sizeof(VH_OPTION));
+
+		EnableSecureNAT(h, true);
+
+		if (changed)
+		{
+			Lock(h->lock_online);
+			{
+				if (h->SecureNAT != NULL)
+				{
+					SetVirtualHostOption(h->SecureNAT->Nat->Virtual, &t);
+					Debug("SiCalledUpdateHub: SecureNAT Updated.\n");
+				}
+			}
+			Unlock(h->lock_online);
+		}
+	}
+	else
+	{
+		EnableSecureNAT(h, false);
+		Debug("SiCalledUpdateHub: SecureNAT Disabled.\n");
+	}
+
+	if (type_changed)
+	{
+		// HUB の種類が変更されたのですべてのセッションを削除する
+		if (h->Offline == false)
+		{
+			SetHubOffline(h);
+			SetHubOnline(h);
+		}
+	}
+
+	ReleaseHub(h);
+}
+
+// チケットの検査
+bool SiCheckTicket(HUB *h, UCHAR *ticket, char *username, UINT username_size, char *usernamereal, UINT usernamereal_size, POLICY *policy, char *sessionname, UINT sessionname_size, char *groupname, UINT groupname_size)
+{
+	bool ret = false;
+	// 引数チェック
+	if (h == NULL || ticket == NULL || username == NULL || usernamereal == NULL || policy == NULL || sessionname == NULL)
+	{
+		return false;
+	}
+
+	LockList(h->TicketList);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(h->TicketList);i++)
+		{
+			TICKET *t = LIST_DATA(h->TicketList, i);
+			if (Cmp(t->Ticket, ticket, SHA1_SIZE) == 0)
+			{
+				ret = true;
+				StrCpy(username, username_size, t->Username);
+				StrCpy(usernamereal, usernamereal_size, t->UsernameReal);
+				StrCpy(sessionname, sessionname_size, t->SessionName);
+				StrCpy(groupname, groupname_size, t->GroupName);
+				Copy(policy, &t->Policy, sizeof(POLICY));
+				Delete(h->TicketList, t);
+				Free(t);
+				break;
+			}
+		}
+	}
+	UnlockList(h->TicketList);
+
+	return ret;
+}
+
+// MAC アドレス削除指令受信
+void SiCalledDeleteMacTable(SERVER *s, PACK *p)
+{
+	UINT key;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return;
+	}
+	key = PackGetInt(p, "Key");
+
+	LockHubList(s->Cedar);
+	{
+		h = GetHub(s->Cedar, hubname);
+	}
+	UnlockHubList(s->Cedar);
+
+	if (h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->MacTable);
+	{
+		if (IsInList(h->MacTable, (void *)key))
+		{
+			MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)key;
+			Delete(h->MacTable, e);
+			Free(e);
+		}
+	}
+	UnlockList(h->MacTable);
+
+	ReleaseHub(h);
+}
+
+// IP アドレス削除指令受信
+void SiCalledDeleteIpTable(SERVER *s, PACK *p)
+{
+	UINT key;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return;
+	}
+	key = PackGetInt(p, "Key");
+
+	LockHubList(s->Cedar);
+	{
+		h = GetHub(s->Cedar, hubname);
+	}
+	UnlockHubList(s->Cedar);
+
+	if (h == NULL)
+	{
+		return;
+	}
+
+	LockList(h->IpTable);
+	{
+		if (IsInList(h->IpTable, (void *)key))
+		{
+			IP_TABLE_ENTRY *e = (IP_TABLE_ENTRY *)key;
+			Delete(h->IpTable, e);
+			Free(e);
+		}
+	}
+	UnlockList(h->IpTable);
+
+	ReleaseHub(h);
+}
+
+// セッション削除指令受信
+void SiCalledDeleteSession(SERVER *s, PACK *p)
+{
+	char name[MAX_SESSION_NAME_LEN + 1];
+	char hubname[MAX_HUBNAME_LEN + 1];
+	HUB *h;
+	SESSION *sess;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return;
+	}
+	if (PackGetStr(p, "SessionName", name, sizeof(name)) == false)
+	{
+		return;
+	}
+
+	LockHubList(s->Cedar);
+	{
+		h = GetHub(s->Cedar, hubname);
+	}
+	UnlockHubList(s->Cedar);
+
+	if (h == NULL)
+	{
+		return;
+	}
+
+	sess = GetSessionByName(h, name);
+
+	if (sess != NULL)
+	{
+		if (sess->BridgeMode == false && sess->LinkModeServer == false && sess->SecureNATMode == false)
+		{
+			StopSession(sess);
+		}
+		ReleaseSession(sess);
+	}
+
+	ReleaseHub(h);
+}
+
+// ログファイル読み込み指令受信
+PACK *SiCalledReadLogFile(SERVER *s, PACK *p)
+{
+	RPC_READ_LOG_FILE t;
+	PACK *ret;
+	char filepath[MAX_PATH];
+	UINT offset;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	PackGetStr(p, "FilePath", filepath, sizeof(filepath));
+	offset = PackGetInt(p, "Offset");
+
+	Zero(&t, sizeof(t));
+
+	SiReadLocalLogFile(s, filepath, offset, &t);
+
+	ret = NewPack();
+
+	OutRpcReadLogFile(ret, &t);
+	FreeRpcReadLogFile(&t);
+
+	return ret;
+}
+
+// ログファイル列挙指令受信
+PACK *SiCalledEnumLogFileList(SERVER *s, PACK *p)
+{
+	RPC_ENUM_LOG_FILE t;
+	PACK *ret;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	PackGetStr(p, "HubName", hubname, sizeof(hubname));
+
+	Zero(&t, sizeof(t));
+
+	SiEnumLocalLogFileList(s, hubname, &t);
+
+	ret = NewPack();
+
+	OutRpcEnumLogFile(ret, &t);
+	FreeRpcEnumLogFile(&t);
+
+	return ret;
+}
+
+// セッション情報指令受信
+PACK *SiCalledGetSessionStatus(SERVER *s, PACK *p)
+{
+	RPC_SESSION_STATUS t;
+	ADMIN a;
+	PACK *ret;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	InRpcSessionStatus(&t, p);
+
+	Zero(&a, sizeof(a));
+	a.Server = s;
+	a.ServerAdmin = true;
+
+	if (StGetSessionStatus(&a, &t) != ERR_NO_ERROR)
+	{
+		FreeRpcSessionStatus(&t);
+		return NULL;
+	}
+
+	ret = NewPack();
+
+	OutRpcSessionStatus(ret, &t);
+
+	FreeRpcSessionStatus(&t);
+
+	return ret;
+}
+
+// IP テーブル列挙指令
+PACK *SiCalledEnumIpTable(SERVER *s, PACK *p)
+{
+	char hubname[MAX_HUBNAME_LEN + 1];
+	RPC_ENUM_IP_TABLE t;
+	PACK *ret;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NewPack();
+	}
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return NewPack();
+	}
+	Zero(&t, sizeof(t));
+
+	SiEnumIpTable(s, hubname, &t);
+
+	ret = NewPack();
+	OutRpcEnumIpTable(ret, &t);
+	FreeRpcEnumIpTable(&t);
+
+	return ret;
+}
+
+// MAC テーブル列挙指令
+PACK *SiCalledEnumMacTable(SERVER *s, PACK *p)
+{
+	char hubname[MAX_HUBNAME_LEN + 1];
+	RPC_ENUM_MAC_TABLE t;
+	PACK *ret;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NewPack();
+	}
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return NewPack();
+	}
+	Zero(&t, sizeof(t));
+
+	SiEnumMacTable(s, hubname, &t);
+
+	ret = NewPack();
+	OutRpcEnumMacTable(ret, &t);
+	FreeRpcEnumMacTable(&t);
+
+	return ret;
+}
+
+// NAT の状況取得指令
+PACK *SiCalledGetNatStatus(SERVER *s, PACK *p)
+{
+	char hubname[MAX_HUBNAME_LEN + 1];
+	RPC_NAT_STATUS t;
+	PACK *ret;
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NewPack();
+	}
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return NewPack();
+	}
+	Zero(&t, sizeof(t));
+
+	LockHubList(s->Cedar);
+	{
+		h = GetHub(s->Cedar, hubname);
+	}
+	UnlockHubList(s->Cedar);
+
+	if (h != NULL)
+	{
+		Lock(h->lock_online);
+		{
+			if (h->SecureNAT != NULL)
+			{
+				NtGetStatus(h->SecureNAT->Nat, &t);
+			}
+		}
+		Unlock(h->lock_online);
+	}
+
+	ReleaseHub(h);
+
+	ret = NewPack();
+	OutRpcNatStatus(ret, &t);
+	FreeRpcNatStatus(&t);
+
+	return ret;
+}
+
+// DHCP テーブル列挙指令
+PACK *SiCalledEnumDhcp(SERVER *s, PACK *p)
+{
+	char hubname[MAX_HUBNAME_LEN + 1];
+	RPC_ENUM_DHCP t;
+	PACK *ret;
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NewPack();
+	}
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return NewPack();
+	}
+	Zero(&t, sizeof(t));
+
+	LockHubList(s->Cedar);
+	{
+		h = GetHub(s->Cedar, hubname);
+	}
+	UnlockHubList(s->Cedar);
+
+	if (h != NULL)
+	{
+		Lock(h->lock_online);
+		{
+			if (h->SecureNAT != NULL)
+			{
+				NtEnumDhcpList(h->SecureNAT->Nat, &t);
+			}
+		}
+		Unlock(h->lock_online);
+	}
+
+	ReleaseHub(h);
+
+	ret = NewPack();
+	OutRpcEnumDhcp(ret, &t);
+	FreeRpcEnumDhcp(&t);
+
+	return ret;
+}
+
+// NAT テーブル列挙指令
+PACK *SiCalledEnumNat(SERVER *s, PACK *p)
+{
+	char hubname[MAX_HUBNAME_LEN + 1];
+	RPC_ENUM_NAT t;
+	PACK *ret;
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NewPack();
+	}
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return NewPack();
+	}
+	Zero(&t, sizeof(t));
+
+	LockHubList(s->Cedar);
+	{
+		h = GetHub(s->Cedar, hubname);
+	}
+	UnlockHubList(s->Cedar);
+
+	if (h != NULL)
+	{
+		Lock(h->lock_online);
+		{
+			if (h->SecureNAT != NULL)
+			{
+				NtEnumNatList(h->SecureNAT->Nat, &t);
+			}
+		}
+		Unlock(h->lock_online);
+	}
+
+	ReleaseHub(h);
+
+	ret = NewPack();
+	OutRpcEnumNat(ret, &t);
+	FreeRpcEnumNat(&t);
+
+	return ret;
+}
+
+// セッション列挙指令受信
+PACK *SiCalledEnumSession(SERVER *s, PACK *p)
+{
+	char hubname[MAX_HUBNAME_LEN + 1];
+	RPC_ENUM_SESSION t;
+	PACK *ret;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NewPack();
+	}
+	if (PackGetStr(p, "HubName", hubname, sizeof(hubname)) == false)
+	{
+		return NewPack();
+	}
+	Zero(&t, sizeof(t));
+
+	SiEnumLocalSession(s, hubname, &t);
+
+	ret = NewPack();
+	OutRpcEnumSession(ret, &t);
+	FreeRpcEnumSession(&t);
+
+	return ret;
+}
+
+// チケット作成指令受信
+PACK *SiCalledCreateTicket(SERVER *s, PACK *p)
+{
+	char username[MAX_SIZE];
+	char hubname[MAX_SIZE];
+	char groupname[MAX_SIZE];
+	char realusername[MAX_SIZE];
+	char sessionname[MAX_SESSION_NAME_LEN + 1];
+	POLICY policy;
+	UCHAR ticket[SHA1_SIZE];
+	char ticket_str[MAX_SIZE];
+	HUB *h;
+	UINT i;
+	PACK *ret;
+	TICKET *t;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return NewPack();
+	}
+
+	PackGetStr(p, "UserName", username, sizeof(username));
+	PackGetStr(p, "GroupName", groupname, sizeof(groupname));
+	PackGetStr(p, "HubName", hubname, sizeof(hubname));
+	PackGetStr(p, "RealUserName", realusername, sizeof(realusername));
+	PackGetStr(p, "SessionName", sessionname, sizeof(sessionname));
+
+	InRpcPolicy(&policy, p);
+	if (PackGetDataSize(p, "Ticket") == SHA1_SIZE)
+	{
+		PackGetData(p, "Ticket", ticket);
+	}
+
+	BinToStr(ticket_str, sizeof(ticket_str), ticket, SHA1_SIZE);
+
+	SLog(s->Cedar, "LS_TICKET_2", hubname, username, realusername, sessionname,
+		ticket_str, TICKET_EXPIRES / 1000);
+
+	// HUB を取得
+	h = GetHub(s->Cedar, hubname);
+	if (h == NULL)
+	{
+		return NewPack();
+	}
+
+	LockList(h->TicketList);
+	{
+		LIST *o = NewListFast(NULL);
+		// 古いチケットを破棄
+		for (i = 0;i < LIST_NUM(h->TicketList);i++)
+		{
+			TICKET *t = LIST_DATA(h->TicketList, i);
+			if ((t->CreatedTick + TICKET_EXPIRES) < Tick64())
+			{
+				Add(o, t);
+			}
+		}
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			TICKET *t = LIST_DATA(o, i);
+			Delete(h->TicketList, t);
+			Free(t);
+		}
+		ReleaseList(o);
+
+		// チケットを作成
+		t = ZeroMalloc(sizeof(TICKET));
+		t->CreatedTick = Tick64();
+		Copy(&t->Policy, &policy, sizeof(POLICY));
+		Copy(t->Ticket, ticket, SHA1_SIZE);
+		StrCpy(t->Username, sizeof(t->Username), username);
+		StrCpy(t->UsernameReal, sizeof(t->UsernameReal), realusername);
+		StrCpy(t->GroupName, sizeof(t->GroupName), groupname);
+		StrCpy(t->SessionName, sizeof(t->SessionName), sessionname);
+
+		Add(h->TicketList, t);
+	}
+	UnlockList(h->TicketList);
+
+	ReleaseHub(h);
+
+	ret = NewPack();
+
+	PackAddInt(ret, "Point", SiGetPoint(s));
+
+	return ret;
+}
+
+// HUB 作成指令受信
+void SiCalledCreateHub(SERVER *s, PACK *p)
+{
+	char name[MAX_SIZE];
+	UINT type;
+	HUB_OPTION o;
+	HUB_LOG log;
+	bool save_packet_log;
+	UINT packet_log_switch_type;
+	UINT packet_log_config[NUM_PACKET_LOG];
+	bool save_security_log;
+	UINT security_log_switch_type;
+	UINT i;
+	HUB *h;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	PackGetStr(p, "HubName", name, sizeof(name));
+	type = PackGetInt(p, "HubType");
+	Zero(&o, sizeof(o));
+	o.MaxSession = PackGetInt(p, "MaxSession");
+	save_packet_log = PackGetInt(p, "SavePacketLog");
+	packet_log_switch_type = PackGetInt(p, "PacketLogSwitchType");
+	for (i = 0;i < NUM_PACKET_LOG;i++)
+	{
+		packet_log_config[i] = PackGetIntEx(p, "PacketLogConfig", i);
+	}
+	save_security_log = PackGetInt(p, "SaveSecurityLog");
+	security_log_switch_type = PackGetInt(p, "SecurityLogSwitchType");
+
+	Zero(&log, sizeof(log));
+	log.SavePacketLog = save_packet_log;
+	log.PacketLogSwitchType = packet_log_switch_type;
+	Copy(log.PacketLogConfig, packet_log_config, sizeof(log.PacketLogConfig));
+	log.SaveSecurityLog = save_security_log;
+	log.SecurityLogSwitchType = security_log_switch_type;
+
+	h = NewHub(s->Cedar, name, &o);
+	h->LastCommTime = h->LastLoginTime = h->CreatedTime = 0;
+	SetHubLogSetting(h, &log);
+	h->Type = type;
+	h->FarmMember_MaxSessionClient = PackGetInt(p, "MaxSessionClient");
+	h->FarmMember_MaxSessionBridge = PackGetInt(p, "MaxSessionBridge");
+	h->FarmMember_MaxSessionClientBridgeApply = PackGetBool(p, "MaxSessionClientBridgeApply");
+
+	if (h->FarmMember_MaxSessionClientBridgeApply == false)
+	{
+		h->FarmMember_MaxSessionClient = INFINITE;
+		h->FarmMember_MaxSessionBridge = INFINITE;
+	}
+
+	PackGetData2(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);
+	PackGetData2(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);
+
+	for (i = 0;i < SiNumAccessFromPack(p);i++)
+	{
+		ACCESS *a = SiPackToAccess(p, i);
+		AddAccessList(h, a);
+		Free(a);
+	}
+
+	if (PackGetBool(p, "EnableSecureNAT"))
+	{
+		VH_OPTION t;
+
+		InVhOption(&t, p);
+
+		Copy(h->SecureNATOption, &t, sizeof(VH_OPTION));
+		EnableSecureNAT(h, true);
+
+		Debug("SiCalledCreateHub: SecureNAT Created.\n");
+	}
+
+	AddHub(s->Cedar, h);
+	h->Offline = true;
+	SetHubOnline(h);
+
+	ReleaseHub(h);
+}
+
+// ファームコントロールスレッド
+void SiFarmControlThread(THREAD *thread, void *param)
+{
+	SERVER *s;
+	CEDAR *c;
+	EVENT *e;
+	LIST *o;
+	UINT i;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	s = (SERVER *)param;
+	c = s->Cedar;
+	e = s->FarmControlThreadHaltEvent;
+
+	while (true)
+	{
+		Lock(c->CedarSuperLock);
+
+		// 各ファームメンバーがホストしている HUB 一覧を列挙する
+		Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
+		SiDebugLog(s, tmp);
+
+		LockList(s->FarmMemberList);
+		{
+			UINT i;
+			UINT num;
+			UINT assigned_client_license = 0;
+			UINT assigned_bridge_license = 0;
+
+			Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
+			SiDebugLog(s, tmp);
+
+			num = 0;
+
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+				SiCallEnumHub(s, f);
+				// サーバーファーム全体での合計セッション数を取得する
+				num += f->NumSessions;
+
+				assigned_client_license += f->AssignedClientLicense;
+				assigned_bridge_license += f->AssignedBridgeLicense;
+			}
+
+			s->CurrentTotalNumSessionsOnFarm = num;
+
+			// 割り当て済みライセンス数を更新する
+			s->CurrentAssignedBridgeLicense = assigned_bridge_license;
+			s->CurrentAssignedClientLicense = assigned_client_license;
+
+			Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
+			SiDebugLog(s, tmp);
+		}
+		UnlockList(s->FarmMemberList);
+
+		Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
+		SiDebugLog(s, tmp);
+
+		o = NewListFast(NULL);
+
+		Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
+		SiDebugLog(s, tmp);
+
+		// 各 HUB に対して更新通知を発する
+		LockList(c->HubList);
+		{
+			UINT i;
+			for (i = 0;i < LIST_NUM(c->HubList);i++)
+			{
+				HUB *h = LIST_DATA(c->HubList, i);
+				AddRef(h->ref);
+				Add(o, h);
+			}
+		}
+		UnlockList(c->HubList);
+
+		Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
+		SiDebugLog(s, tmp);
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			HUB *h = LIST_DATA(o, i);
+			SiHubUpdateProc(h);
+			ReleaseHub(h);
+		}
+
+		Format(tmp, sizeof(tmp), "CONTROLLER: %s %u", __FILE__, __LINE__);
+		SiDebugLog(s, tmp);
+
+		ReleaseList(o);
+
+		Unlock(c->CedarSuperLock);
+
+		Wait(e, SERVER_FARM_CONTROL_INTERVAL);
+		if (s->Halt)
+		{
+			break;
+		}
+	}
+}
+
+// ファームコントロールの開始
+void SiStartFarmControl(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		return;
+	}
+
+	s->FarmControlThreadHaltEvent = NewEvent();
+	s->FarmControlThread = NewThread(SiFarmControlThread, s);
+}
+
+// ファームコントロールの終了
+void SiStopFarmControl(SERVER *s)
+{
+	// 引数チェック
+	if (s == NULL || s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		return;
+	}
+
+	Set(s->FarmControlThreadHaltEvent);
+	WaitThread(s->FarmControlThread, INFINITE);
+	ReleaseEvent(s->FarmControlThreadHaltEvent);
+	ReleaseThread(s->FarmControlThread);
+}
+
+// HUB 列挙指令
+void SiCallEnumHub(SERVER *s, FARM_MEMBER *f)
+{
+	CEDAR *c;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	c = s->Cedar;
+
+	if (f->Me)
+	{
+		LICENSE_STATUS st;
+
+		LiParseCurrentLicenseStatus(s->LicenseSystem, &st);
+
+		// ローカルの HUB を列挙する
+		LockList(f->HubList);
+		{
+			// ローカル HUB の場合、まず STATIC HUB リストを一旦
+			// すべて消去して再列挙を行うようにする
+			UINT i;
+			LIST *o = NewListFast(NULL);
+			for (i = 0;i < LIST_NUM(f->HubList);i++)
+			{
+				HUB_LIST *h = LIST_DATA(f->HubList, i);
+				if (h->DynamicHub == false)
+				{
+					Add(o, h);
+				}
+			}
+
+			// STATIC HUB をすべて消去
+			for (i = 0;i < LIST_NUM(o);i++)
+			{
+				HUB_LIST *h = LIST_DATA(o, i);
+				Free(h);
+				Delete(f->HubList, h);
+			}
+			ReleaseList(o);
+
+			// 次に DYNAMIC HUB でユーザーが 1 人もいないものを停止する
+			o = NewListFast(NULL);
+			for (i = 0;i < LIST_NUM(f->HubList);i++)
+			{
+				HUB_LIST *h = LIST_DATA(f->HubList, i);
+				if (h->DynamicHub == true)
+				{
+					LockList(c->HubList);
+					{
+						HUB *hub = GetHub(s->Cedar, h->Name);
+						if (hub != NULL)
+						{
+							if (Count(hub->NumSessions) == 0 || hub->Type != HUB_TYPE_FARM_DYNAMIC)
+							{
+								Add(o, h);
+							}
+							ReleaseHub(hub);
+						}
+					}
+					UnlockList(c->HubList);
+				}
+			}
+
+			for (i = 0;i < LIST_NUM(o);i++)
+			{
+				HUB_LIST *h = LIST_DATA(o, i);
+				Debug("Delete HUB: %s\n", h->Name);
+				Free(h);
+				Delete(f->HubList, h);
+			}
+
+			ReleaseList(o);
+
+			// 列挙結果を設定
+			LockList(c->HubList);
+			{
+				for (i = 0;i < LIST_NUM(c->HubList);i++)
+				{
+					HUB *h = LIST_DATA(c->HubList, i);
+					if (h->Offline == false)
+					{
+						if (h->Type == HUB_TYPE_FARM_STATIC)
+						{
+							HUB_LIST *hh = ZeroMalloc(sizeof(HUB_LIST));
+							hh->FarmMember = f;
+							hh->DynamicHub = false;
+							StrCpy(hh->Name, sizeof(hh->Name), h->Name);
+							Add(f->HubList, hh);
+
+							LockList(h->SessionList);
+							{
+								hh->NumSessions = LIST_NUM(h->SessionList);
+								hh->NumSessionsBridge = Count(h->NumSessionsBridge);
+								hh->NumSessionsClient = Count(h->NumSessionsClient);
+							}
+							UnlockList(h->SessionList);
+
+							LockList(h->MacTable);
+							{
+								hh->NumMacTables = LIST_NUM(h->MacTable);
+							}
+							UnlockList(h->MacTable);
+
+							LockList(h->IpTable);
+							{
+								hh->NumIpTables = LIST_NUM(h->IpTable);
+							}
+							UnlockList(h->IpTable);
+						}
+					}
+				}
+			}
+			UnlockList(c->HubList);
+		}
+		UnlockList(f->HubList);
+
+		// ポイント
+		f->Point = SiGetPoint(s);
+		f->NumSessions = Count(s->Cedar->CurrentSessions);
+		f->MaxSessions = GetServerCapsInt(s, "i_max_sessions");
+		f->NumTcpConnections = Count(s->Cedar->CurrentTcpConnections);
+
+		Lock(s->Cedar->TrafficLock);
+		{
+			Copy(&f->Traffic, s->Cedar->Traffic, sizeof(TRAFFIC));
+		}
+		Unlock(s->Cedar->TrafficLock);
+
+		f->AssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);
+		f->AssignedClientLicense = Count(s->Cedar->AssignedClientLicense);
+
+		Copy(f->RandomKey, s->MyRandomKey, SHA1_SIZE);
+		f->SystemId = st.SystemId;
+
+		Debug("Server %s: Point %u\n", f->hostname, f->Point);
+	}
+	else
+	{
+		// リモートのメンバの HUB を列挙する
+		PACK *p = NewPack();
+		UINT i, num, j;
+		LIST *o = NewListFast(NULL);
+
+		num = 0;
+
+		for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+		{
+			FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+			if (IsZero(f->RandomKey, SHA1_SIZE) == false && f->SystemId != 0)
+			{
+				num++;
+			}
+		}
+
+		j = 0;
+
+		for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+		{
+			FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+			if (IsZero(f->RandomKey, SHA1_SIZE) == false && f->SystemId != 0)
+			{
+				PackAddDataEx(p, "MemberRandomKey", f->RandomKey, SHA1_SIZE, j, num);
+				PackAddInt64Ex(p, "MemberSystemId", f->SystemId, j, num);
+				j++;
+			}
+		}
+		PackAddInt(p, "MemberSystemIdNum", num);
+
+		p = SiCallTask(f, p, "enumhub");
+		if (p != NULL)
+		{
+			LockList(f->HubList);
+			{
+				UINT i;
+				// リスト消去
+				for (i = 0;i < LIST_NUM(f->HubList);i++)
+				{
+					HUB_LIST *hh = LIST_DATA(f->HubList, i);
+					Free(hh);
+				}
+				DeleteAll(f->HubList);
+
+				for (i = 0;i < PackGetIndexCount(p, "HubName");i++)
+				{
+					HUB_LIST *hh = ZeroMalloc(sizeof(HUB_LIST));
+					UINT num;
+					UINT64 LastCommTime;
+
+					PackGetStrEx(p, "HubName", hh->Name, sizeof(hh->Name), i);
+					num = PackGetIntEx(p, "NumSession", i);
+					hh->DynamicHub = ((PackGetIntEx(p, "HubType", i) == HUB_TYPE_FARM_DYNAMIC) ? true : false);
+					hh->FarmMember = f;
+					hh->NumSessions = PackGetIntEx(p, "NumSessions", i);
+					hh->NumSessionsClient = PackGetIntEx(p, "NumSessionsClient", i);
+					hh->NumSessionsBridge = PackGetIntEx(p, "NumSessionsBridge", i);
+					hh->NumIpTables = PackGetIntEx(p, "NumIpTables", i);
+					hh->NumMacTables = PackGetIntEx(p, "NumMacTables", i);
+					LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);
+					Add(f->HubList, hh);
+					Debug("%s\n", hh->Name);
+
+					LockList(c->HubList);
+					{
+						HUB *h = GetHub(c, hh->Name);
+
+						if (h != NULL)
+						{
+							// 仮想 HUB の LastCommTime を更新する
+							Lock(h->lock);
+							{
+								if (h->LastCommTime < LastCommTime)
+								{
+									h->LastCommTime = LastCommTime;
+								}
+							}
+							Unlock(h->lock);
+
+							ReleaseHub(h);
+						}
+					}
+					UnlockList(c->HubList);
+
+					if (hh->DynamicHub && num >= 1)
+					{
+						// すでにユーザーセッションが 1 以上接続されているので
+						// 仮想 HUB 作成履歴リストに登録しておく必要はない
+						// 仮想 HUB 作成履歴リストから削除する
+						SiDelHubCreateHistory(s, hh->Name);
+					}
+
+					if (hh->DynamicHub && num == 0)
+					{
+						// 仮想 HUB 作成履歴リストを確認する
+						// 直近 60 秒以内に作成され、まだ 1 人目のユーザーが接続
+						// していない仮想 HUB の場合は、ユーザーが 1 人もいないという
+						// 理由で削除しない
+						if (SiIsHubRegistedOnCreateHistory(s, hh->Name) == false)
+						{
+							// ダイナミック HUB でユーザーが 1 人もいないので停止する
+							HUB *h;
+							LockList(c->HubList);
+							{
+								h = GetHub(c, hh->Name);
+							}
+							UnlockList(c->HubList);
+
+							if (h != NULL)
+							{
+								Add(o, h);
+							}
+						}
+					}
+				}
+			}
+			UnlockList(f->HubList);
+			f->Point = PackGetInt(p, "Point");
+			Debug("Server %s: Point %u\n", f->hostname, f->Point);
+			f->NumSessions = PackGetInt(p, "NumTotalSessions");
+			if (f->NumSessions == 0)
+			{
+				f->NumSessions = PackGetInt(p, "NumSessions");
+			}
+			f->MaxSessions = PackGetInt(p, "MaxSessions");
+			f->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+			InRpcTraffic(&f->Traffic, p);
+
+			f->AssignedBridgeLicense = PackGetInt(p, "AssignedBridgeLicense");
+			f->AssignedClientLicense = PackGetInt(p, "AssignedClientLicense");
+
+			if (PackGetDataSize(p, "RandomKey") == SHA1_SIZE)
+			{
+				PackGetData(p, "RandomKey", f->RandomKey);
+			}
+
+			f->SystemId = PackGetInt64(p, "SystemId");
+
+			// トラフィック差分情報を適用する
+			num = PackGetIndexCount(p, "TdType");
+			for (i = 0;i < num;i++)
+			{
+				TRAFFIC traffic;
+				UINT type;
+				HUB *h;
+				char name[MAX_SIZE];
+				char hubname[MAX_SIZE];
+
+				type = PackGetIntEx(p, "TdType", i);
+				PackGetStrEx(p, "TdName", name, sizeof(name), i);
+				PackGetStrEx(p, "TdHubName", hubname, sizeof(hubname), i);
+				InRpcTrafficEx(&traffic, p, i);
+
+				LockList(c->HubList);
+				{
+					h = GetHub(c, hubname);
+					if (h != NULL)
+					{
+						if (type == TRAFFIC_DIFF_HUB)
+						{
+							Lock(h->TrafficLock);
+							{
+								AddTraffic(h->Traffic, &traffic);
+							}
+							Unlock(h->TrafficLock);
+						}
+						else
+						{
+							AcLock(h);
+							{
+								USER *u = AcGetUser(h, name);
+								if (u != NULL)
+								{
+									Lock(u->lock);
+									{
+										AddTraffic(u->Traffic, &traffic);
+									}
+									Unlock(u->lock);
+									if (u->Group != NULL)
+									{
+										Lock(u->Group->lock);
+										{
+											AddTraffic(u->Group->Traffic, &traffic);
+										}
+										Unlock(u->Group->lock);
+									}
+									ReleaseUser(u);
+								}
+							}
+							AcUnlock(h);
+						}
+						ReleaseHub(h);
+					}
+					UnlockList(c->HubList);
+				}
+			}
+
+			FreePack(p);
+		}
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			HUB *h = LIST_DATA(o, i);
+			SiCallDeleteHub(s, f, h);
+			Debug("Delete HUB: %s\n", h->Name);
+			ReleaseHub(h);
+		}
+
+		ReleaseList(o);
+	}
+}
+
+// セッション情報取得指令
+bool SiCallGetSessionStatus(SERVER *s, FARM_MEMBER *f, RPC_SESSION_STATUS *t)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return false;
+	}
+
+	p = NewPack();
+	OutRpcSessionStatus(p, t);
+	FreeRpcSessionStatus(t);
+	Zero(t, sizeof(RPC_SESSION_STATUS));
+
+	p = SiCallTask(f, p, "getsessionstatus");
+
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	InRpcSessionStatus(t, p);
+	FreePack(p);
+
+	return true;
+}
+
+// ログファイル読み込み指令
+bool SiCallReadLogFile(SERVER *s, FARM_MEMBER *f, RPC_READ_LOG_FILE *t)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return false;
+	}
+
+	p = NewPack();
+	OutRpcReadLogFile(p, t);
+	FreeRpcReadLogFile(t);
+	Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+	p = SiCallTask(f, p, "readlogfile");
+
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	InRpcReadLogFile(t, p);
+	FreePack(p);
+
+	return true;
+}
+
+// ログファイルリスト列挙指令
+bool SiCallEnumLogFileList(SERVER *s, FARM_MEMBER *f, RPC_ENUM_LOG_FILE *t, char *hubname)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return false;
+	}
+
+	p = NewPack();
+	OutRpcEnumLogFile(p, t);
+	FreeRpcEnumLogFile(t);
+	Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+
+	PackAddStr(p, "HubName", hubname);
+
+	p = SiCallTask(f, p, "enumlogfilelist");
+
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	InRpcEnumLogFile(t, p);
+	FreePack(p);
+
+	return true;
+}
+
+// HUB 削除指令
+void SiCallDeleteHub(SERVER *s, FARM_MEMBER *f, HUB *h)
+{
+	PACK *p;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	if (f->Me == false)
+	{
+		p = NewPack();
+
+		PackAddStr(p, "HubName", h->Name);
+
+		p = SiCallTask(f, p, "deletehub");
+		FreePack(p);
+	}
+
+	LockList(f->HubList);
+	{
+		for (i = 0;i < LIST_NUM(f->HubList);i++)
+		{
+			HUB_LIST *hh = LIST_DATA(f->HubList, i);
+			if (StrCmpi(hh->Name, h->Name) == 0)
+			{
+				Free(hh);
+				Delete(f->HubList, hh);
+			}
+		}
+	}
+	UnlockList(f->HubList);
+}
+
+// HUB 更新指令送信
+void SiCallUpdateHub(SERVER *s, FARM_MEMBER *f, HUB *h)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	if (f->Me == false)
+	{
+		p = NewPack();
+
+		SiPackAddCreateHub(p, h);
+
+		p = SiCallTask(f, p, "updatehub");
+		FreePack(p);
+	}
+}
+
+// チケット作成指令送信
+void SiCallCreateTicket(SERVER *s, FARM_MEMBER *f, char *hubname, char *username, char *realusername, POLICY *policy, UCHAR *ticket, UINT counter, char *groupname)
+{
+	PACK *p;
+	char name[MAX_SESSION_NAME_LEN + 1];
+	char hub_name_upper[MAX_SIZE];
+	char user_name_upper[MAX_USERNAME_LEN + 1];
+	char ticket_str[MAX_SIZE];
+	UINT point;
+	// 引数チェック
+	if (s == NULL || f == NULL || realusername == NULL || hubname == NULL || username == NULL || policy == NULL || ticket == NULL)
+	{
+		return;
+	}
+	if (groupname == NULL)
+	{
+		groupname = "";
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+	PackAddStr(p, "UserName", username);
+	PackAddStr(p, "groupname", groupname);
+	PackAddStr(p, "RealUserName", realusername);
+	OutRpcPolicy(p, policy);
+	PackAddData(p, "Ticket", ticket, SHA1_SIZE);
+
+	BinToStr(ticket_str, sizeof(ticket_str), ticket, SHA1_SIZE);
+
+	StrCpy(hub_name_upper, sizeof(hub_name_upper), hubname);
+	StrUpper(hub_name_upper);
+	StrCpy(user_name_upper, sizeof(user_name_upper), username);
+	StrUpper(user_name_upper);
+	Format(name, sizeof(name), "SID-%s-%u", user_name_upper,
+		counter);
+	PackAddStr(p, "SessionName", name);
+
+	p = SiCallTask(f, p, "createticket");
+
+	SLog(s->Cedar, "LS_TICKET_1", f->hostname, hubname, username, realusername, name, ticket_str);
+
+	point = PackGetInt(p, "Point");
+	if (point != 0)
+	{
+		f->Point = point;
+		f->NumSessions++;
+	}
+
+	FreePack(p);
+}
+
+// MAC アドレス削除指令送信
+void SiCallDeleteMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+	PackAddInt(p, "Key", key);
+
+	p = SiCallTask(f, p, "deletemactable");
+
+	FreePack(p);
+}
+
+// IP アドレス削除指令送信
+void SiCallDeleteIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+	PackAddInt(p, "Key", key);
+
+	p = SiCallTask(f, p, "deleteiptable");
+
+	FreePack(p);
+}
+
+// セッション削除指令送信
+void SiCallDeleteSession(SERVER *s, FARM_MEMBER *f, char *hubname, char *session_name)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL || session_name == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+	PackAddStr(p, "SessionName", session_name);
+
+	p = SiCallTask(f, p, "deletesession");
+
+	FreePack(p);
+}
+
+// IP テーブル列挙指令送信
+void SiCallEnumIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_IP_TABLE *t)
+{
+	PACK *p;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL || t == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+
+	p = SiCallTask(f, p, "enumiptable");
+
+	Zero(t, sizeof(RPC_ENUM_IP_TABLE));
+	InRpcEnumIpTable(t, p);
+
+	for (i = 0;i < t->NumIpTable;i++)
+	{
+		t->IpTables[i].RemoteItem = true;
+		StrCpy(t->IpTables[i].RemoteHostname, sizeof(t->IpTables[i].RemoteHostname),
+			f->hostname);
+	}
+
+	FreePack(p);
+}
+
+// MAC テーブル列挙指令送信
+void SiCallEnumMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_MAC_TABLE *t)
+{
+	PACK *p;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL || t == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+
+	p = SiCallTask(f, p, "enummactable");
+
+	Zero(t, sizeof(RPC_ENUM_MAC_TABLE));
+	InRpcEnumMacTable(t, p);
+
+	for (i = 0;i < t->NumMacTable;i++)
+	{
+		t->MacTables[i].RemoteItem = true;
+		StrCpy(t->MacTables[i].RemoteHostname, sizeof(t->MacTables[i].RemoteHostname),
+			f->hostname);
+	}
+
+	FreePack(p);
+}
+
+// SecureNAT 状況の取得指令送信
+void SiCallGetNatStatus(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_NAT_STATUS *t)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL || t == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+
+	p = SiCallTask(f, p, "getnatstatus");
+
+	Zero(t, sizeof(RPC_NAT_STATUS));
+	InRpcNatStatus(t, p);
+
+	FreePack(p);
+}
+
+// DHCP エントリ列挙指令送信
+void SiCallEnumDhcp(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_DHCP *t)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL || t == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+
+	p = SiCallTask(f, p, "enumdhcp");
+
+	Zero(t, sizeof(RPC_ENUM_DHCP));
+	InRpcEnumDhcp(t, p);
+
+	FreePack(p);
+}
+
+// NAT エントリ列挙指令送信
+void SiCallEnumNat(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_NAT *t)
+{
+	PACK *p;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL || t == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+
+	p = SiCallTask(f, p, "enumnat");
+
+	Zero(t, sizeof(RPC_ENUM_NAT));
+	InRpcEnumNat(t, p);
+
+	FreePack(p);
+}
+
+// セッション列挙指令送信
+void SiCallEnumSession(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_SESSION *t)
+{
+	PACK *p;
+	UINT i;
+	// 引数チェック
+	if (s == NULL || f == NULL || hubname == NULL || t == NULL)
+	{
+		return;
+	}
+
+	p = NewPack();
+	PackAddStr(p, "HubName", hubname);
+
+	p = SiCallTask(f, p, "enumsession");
+
+	Zero(t, sizeof(RPC_ENUM_SESSION));
+	InRpcEnumSession(t, p);
+
+	for (i = 0;i < t->NumSession;i++)
+	{
+		t->Sessions[i].RemoteSession = true;
+		StrCpy(t->Sessions[i].RemoteHostname, sizeof(t->Sessions[i].RemoteHostname),
+			f->hostname);
+	}
+
+	FreePack(p);
+}
+
+// HUB 作成指令送信
+void SiCallCreateHub(SERVER *s, FARM_MEMBER *f, HUB *h)
+{
+	PACK *p;
+	HUB_LIST *hh;
+	// 引数チェック
+	if (s == NULL || f == NULL)
+	{
+		return;
+	}
+
+	if (f->Me == false)
+	{
+		p = NewPack();
+
+		SiPackAddCreateHub(p, h);
+
+		p = SiCallTask(f, p, "createhub");
+		FreePack(p);
+	}
+
+	hh = ZeroMalloc(sizeof(HUB_LIST));
+	hh->DynamicHub = (h->Type == HUB_TYPE_FARM_DYNAMIC ? true : false);
+	StrCpy(hh->Name, sizeof(hh->Name), h->Name);
+	hh->FarmMember = f;
+
+	LockList(f->HubList);
+	{
+		bool exists = false;
+		UINT i;
+		for (i = 0;i < LIST_NUM(f->HubList);i++)
+		{
+			HUB_LIST *t = LIST_DATA(f->HubList, i);
+			if (StrCmpi(t->Name, hh->Name) == 0)
+			{
+				exists = true;
+			}
+		}
+		if (exists == false)
+		{
+			Add(f->HubList, hh);
+		}
+		else
+		{
+			Free(hh);
+		}
+	}
+	UnlockList(f->HubList);
+}
+
+// HUB 作成用 PACK の書き込み
+void SiPackAddCreateHub(PACK *p, HUB *h)
+{
+	UINT i;
+	UINT max_session;
+	SERVER *s;
+	LICENSE_STATUS license;
+	// 引数チェック
+	if (p == NULL || h == NULL)
+	{
+		return;
+	}
+
+	Zero(&license, sizeof(license));
+	s = h->Cedar->Server;
+	if (s != NULL)
+	{
+		LiParseCurrentLicenseStatus(s->LicenseSystem, &license);
+	}
+
+	PackAddStr(p, "HubName", h->Name);
+	PackAddInt(p, "HubType", h->Type);
+
+	max_session = h->Option->MaxSession;
+
+	if (GetHubAdminOption(h, "max_sessions") != 0)
+	{
+		if (max_session == 0)
+		{
+			max_session = GetHubAdminOption(h, "max_sessions");
+		}
+		else
+		{
+			max_session = MIN(max_session, GetHubAdminOption(h, "max_sessions"));
+		}
+	}
+
+	PackAddInt(p, "MaxSession", max_session);
+
+	if (GetHubAdminOption(h, "max_sessions_client_bridge_apply") != 0 || license.CarrierEdition)
+	{
+		PackAddInt(p, "MaxSessionClient", GetHubAdminOption(h, "max_sessions_client"));
+		PackAddInt(p, "MaxSessionBridge", GetHubAdminOption(h, "max_sessions_bridge"));
+		PackAddBool(p, "MaxSessionClientBridgeApply", true);
+	}
+	else
+	{
+		PackAddInt(p, "MaxSessionClient", INFINITE);
+		PackAddInt(p, "MaxSessionBridge", INFINITE);
+	}
+
+	PackAddBool(p, "NoArpPolling", h->Option->NoArpPolling);
+	PackAddBool(p, "NoIPv6AddrPolling", h->Option->NoIPv6AddrPolling);
+	PackAddBool(p, "NoIpTable", h->Option->NoIpTable);
+	PackAddBool(p, "NoEnum", h->Option->NoEnum);
+	PackAddBool(p, "FilterPPPoE", h->Option->FilterPPPoE);
+	PackAddBool(p, "YieldAfterStorePacket", h->Option->YieldAfterStorePacket);
+	PackAddBool(p, "NoSpinLockForPacketDelay", h->Option->NoSpinLockForPacketDelay);
+	PackAddInt(p, "BroadcastStormDetectionThreshold", h->Option->BroadcastStormDetectionThreshold);
+	PackAddInt(p, "ClientMinimumRequiredBuild", h->Option->ClientMinimumRequiredBuild);
+	PackAddBool(p, "FixForDLinkBPDU", h->Option->FixForDLinkBPDU);
+	PackAddBool(p, "NoLookBPDUBridgeId", h->Option->NoLookBPDUBridgeId);
+	PackAddBool(p, "NoManageVlanId", h->Option->NoManageVlanId);
+	PackAddInt(p, "VlanTypeId", h->Option->VlanTypeId);
+	PackAddBool(p, "FilterOSPF", h->Option->FilterOSPF);
+	PackAddBool(p, "FilterIPv4", h->Option->FilterIPv4);
+	PackAddBool(p, "FilterIPv6", h->Option->FilterIPv6);
+	PackAddBool(p, "FilterNonIP", h->Option->FilterNonIP);
+	PackAddBool(p, "NoIPv4PacketLog", h->Option->NoIPv4PacketLog);
+	PackAddBool(p, "NoIPv6PacketLog", h->Option->NoIPv6PacketLog);
+	PackAddBool(p, "FilterBPDU", h->Option->FilterBPDU);
+	PackAddBool(p, "NoIPv6DefaultRouterInRAWhenIPv6", h->Option->NoIPv6DefaultRouterInRAWhenIPv6);
+	PackAddBool(p, "NoMacAddressLog", h->Option->NoMacAddressLog);
+	PackAddBool(p, "ManageOnlyPrivateIP", h->Option->ManageOnlyPrivateIP);
+	PackAddBool(p, "ManageOnlyLocalUnicastIPv6", h->Option->ManageOnlyLocalUnicastIPv6);
+	PackAddBool(p, "DisableIPParsing", h->Option->DisableIPParsing);
+
+	PackAddInt(p, "SavePacketLog", h->LogSetting.SavePacketLog);
+	PackAddInt(p, "PacketLogSwitchType", h->LogSetting.PacketLogSwitchType);
+	for (i = 0;i < NUM_PACKET_LOG;i++)
+	{
+		PackAddIntEx(p, "PacketLogConfig", h->LogSetting.PacketLogConfig[i], i, NUM_PACKET_LOG);
+	}
+	PackAddInt(p, "SaveSecurityLog", h->LogSetting.SaveSecurityLog);
+	PackAddInt(p, "SecurityLogSwitchType", h->LogSetting.SecurityLogSwitchType);
+	PackAddData(p, "HashedPassword", h->HashedPassword, SHA1_SIZE);
+	PackAddData(p, "SecurePassword", h->SecurePassword, SHA1_SIZE);
+
+	SiAccessListToPack(p, h->AccessList);
+
+	if (h->EnableSecureNAT)
+	{
+		PackAddBool(p, "EnableSecureNAT", h->EnableSecureNAT);
+		OutVhOption(p, h->SecureNATOption);
+	}
+}
+
+// HUB の設定が更新された
+void SiHubUpdateProc(HUB *h)
+{
+	SERVER *s;
+	UINT i;
+	// 引数チェック
+	if (h == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		return;
+	}
+
+	s = h->Cedar->Server;
+
+	if (s->FarmMemberList == NULL)
+	{
+		return;
+	}
+
+	if (h->LastVersion != h->CurrentVersion || h->CurrentVersion == 0)
+	{
+		if (h->CurrentVersion == 0)
+		{
+			h->CurrentVersion = 1;
+		}
+		h->LastVersion = h->CurrentVersion;
+
+		LockList(s->FarmMemberList);
+		{
+			// すべてのメンバで HUB を更新する
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+				if (f->Me == false)
+				{
+					SiCallUpdateHub(s, f, h);
+				}
+			}
+		}
+		UnlockList(s->FarmMemberList);
+	}
+
+	if (h->Offline == false)
+	{
+		SiHubOnlineProc(h);
+	}
+}
+
+// HUB がオンラインになった
+void SiHubOnlineProc(HUB *h)
+{
+	SERVER *s;
+	UINT i;
+	// 引数チェック
+	if (h == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// ファームコントローラ以外では処理しない
+		return;
+	}
+
+	s = h->Cedar->Server;
+
+	if (s->FarmMemberList == NULL)
+	{
+		return;
+	}
+
+	LockList(s->FarmMemberList);
+	{
+		if (h->Type == HUB_TYPE_FARM_STATIC)
+		{
+			// スタティック HUB
+			// すべてのメンバで HUB を作成する
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				UINT j;
+				bool exists = false;
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+				LockList(f->HubList);
+				{
+					for (j = 0;j < LIST_NUM(f->HubList);j++)
+					{
+						HUB_LIST *hh = LIST_DATA(f->HubList, j);
+						if (StrCmpi(hh->Name, h->Name) == 0)
+						{
+							exists = true;
+						}
+					}
+				}
+				UnlockList(f->HubList);
+
+				if (exists == false)
+				{
+					SiCallCreateHub(s, f, h);
+				}
+			}
+		}
+	}
+	UnlockList(s->FarmMemberList);
+}
+
+// HUB がオフラインになった
+void SiHubOfflineProc(HUB *h)
+{
+	SERVER *s;
+	char hubname[MAX_HUBNAME_LEN + 1];
+	UINT i;
+	// 引数チェック
+	if (h == NULL || h->Cedar->Server == NULL || h->Cedar->Server->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+	{
+		// ファームコントローラ以外では処理しない
+		return;
+	}
+
+	s = h->Cedar->Server;
+
+	if (s->FarmMemberList == NULL)
+	{
+		return;
+	}
+
+	StrCpy(hubname, sizeof(hubname), h->Name);
+
+	LockList(s->FarmMemberList);
+	{
+		// すべてのメンバで HUB を停止する
+		for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+		{
+			FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+			SiCallDeleteHub(s, f, h);
+		}
+	}
+	UnlockList(s->FarmMemberList);
+}
+
+// アクセスを PACK に変換する
+void SiAccessToPack(PACK *p, ACCESS *a, UINT i, UINT total)
+{
+	// 引数チェック
+	if (p == NULL || a == NULL)
+	{
+		return;
+	}
+
+	PackAddUniStrEx(p, "Note", a->Note, i, total);
+	PackAddIntEx(p, "Active", a->Active, i, total);
+	PackAddIntEx(p, "Priority", a->Priority, i, total);
+	PackAddIntEx(p, "Discard", a->Discard, i, total);
+	if (a->IsIPv6)
+	{
+		PackAddIp32Ex(p, "SrcIpAddress", 0xFDFFFFDF, i, total);
+		PackAddIp32Ex(p, "SrcSubnetMask", 0xFFFFFFFF, i, total);
+		PackAddIp32Ex(p, "DestIpAddress", 0xFDFFFFDF, i, total);
+		PackAddIp32Ex(p, "DestSubnetMask", 0xFFFFFFFF, i, total);
+	}
+	else
+	{
+		PackAddIp32Ex(p, "SrcIpAddress", a->SrcIpAddress, i, total);
+		PackAddIp32Ex(p, "SrcSubnetMask", a->SrcSubnetMask, i, total);
+		PackAddIp32Ex(p, "DestIpAddress", a->DestIpAddress, i, total);
+		PackAddIp32Ex(p, "DestSubnetMask", a->DestSubnetMask, i, total);
+	}
+	PackAddIntEx(p, "Protocol", a->Protocol, i, total);
+	PackAddIntEx(p, "SrcPortStart", a->SrcPortStart, i, total);
+	PackAddIntEx(p, "SrcPortEnd", a->SrcPortEnd, i, total);
+	PackAddIntEx(p, "DestPortStart", a->DestPortStart, i, total);
+	PackAddIntEx(p, "DestPortEnd", a->DestPortEnd, i, total);
+	PackAddStrEx(p, "SrcUsername", a->SrcUsername, i, total);
+	PackAddStrEx(p, "DestUsername", a->DestUsername, i, total);
+	PackAddBoolEx(p, "CheckSrcMac", a->CheckSrcMac, i, total);
+	PackAddDataEx(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), i, total);
+	PackAddDataEx(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), i, total);
+	PackAddBoolEx(p, "CheckDstMac", a->CheckDstMac, i, total);
+	PackAddDataEx(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), i, total);
+	PackAddDataEx(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), i, total);
+	PackAddBoolEx(p, "CheckTcpState", a->CheckTcpState, i, total);
+	PackAddBoolEx(p, "Established", a->Established, i, total);
+	PackAddIntEx(p, "Delay", a->Delay, i, total);
+	PackAddIntEx(p, "Jitter", a->Jitter, i, total);
+	PackAddIntEx(p, "Loss", a->Loss, i, total);
+	PackAddBoolEx(p, "IsIPv6", a->IsIPv6, i, total);
+	if (a->IsIPv6)
+	{
+		PackAddIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, i, total);
+		PackAddIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, i, total);
+		PackAddIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, i, total);
+		PackAddIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, i, total);
+	}
+	else
+	{
+		IPV6_ADDR zero;
+
+		Zero(&zero, sizeof(zero));
+
+		PackAddIp6AddrEx(p, "SrcIpAddress6", &zero, i, total);
+		PackAddIp6AddrEx(p, "SrcSubnetMask6", &zero, i, total);
+		PackAddIp6AddrEx(p, "DestIpAddress6", &zero, i, total);
+		PackAddIp6AddrEx(p, "DestSubnetMask6", &zero, i, total);
+	}
+}
+
+// PACK に入っているアクセス個数を取得
+UINT SiNumAccessFromPack(PACK *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return 0;
+	}
+
+	return PackGetIndexCount(p, "Active");
+}
+
+// PACK をアクセスに変換する
+ACCESS *SiPackToAccess(PACK *p, UINT i)
+{
+	ACCESS *a;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return NULL;
+	}
+
+	a = ZeroMalloc(sizeof(ACCESS));
+
+	PackGetUniStrEx(p, "Note", a->Note, sizeof(a->Note), i);
+	a->Active = PackGetIntEx(p, "Active", i);
+	a->Priority = PackGetIntEx(p, "Priority", i);
+	a->Discard = PackGetIntEx(p, "Discard", i);
+	a->SrcIpAddress = PackGetIp32Ex(p, "SrcIpAddress", i);
+	a->SrcSubnetMask = PackGetIp32Ex(p, "SrcSubnetMask", i);
+	a->DestIpAddress = PackGetIp32Ex(p, "DestIpAddress", i);
+	a->DestSubnetMask = PackGetIp32Ex(p, "DestSubnetMask", i);
+	a->Protocol = PackGetIntEx(p, "Protocol", i);
+	a->SrcPortStart = PackGetIntEx(p, "SrcPortStart", i);
+	a->SrcPortEnd = PackGetIntEx(p, "SrcPortEnd", i);
+	a->DestPortStart = PackGetIntEx(p, "DestPortStart", i);
+	a->DestPortEnd = PackGetIntEx(p, "DestPortEnd", i);
+	PackGetStrEx(p, "SrcUsername", a->SrcUsername, sizeof(a->SrcUsername), i);
+	PackGetStrEx(p, "DestUsername", a->DestUsername, sizeof(a->DestUsername), i);
+	a->CheckSrcMac = PackGetBoolEx(p, "CheckSrcMac", i);
+	PackGetDataEx2(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), i);
+	PackGetDataEx2(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), i);
+	a->CheckDstMac = PackGetBoolEx(p, "CheckDstMac", i);
+	PackGetDataEx2(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), i);
+	PackGetDataEx2(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), i);
+	a->CheckTcpState = PackGetBoolEx(p, "CheckTcpState", i);
+	a->Established = PackGetBoolEx(p, "Established", i);
+	a->Delay = PackGetIntEx(p, "Delay", i);
+	a->Jitter = PackGetIntEx(p, "Jitter", i);
+	a->Loss = PackGetIntEx(p, "Loss", i);
+	a->IsIPv6 = PackGetBoolEx(p, "IsIPv6", i);
+	if (a->IsIPv6)
+	{
+		PackGetIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, i);
+		PackGetIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, i);
+		PackGetIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, i);
+		PackGetIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, i);
+	}
+
+	return a;
+}
+
+// アクセスリストを PACK に変換する
+void SiAccessListToPack(PACK *p, LIST *o)
+{
+	// 引数チェック
+	if (p == NULL || o == NULL)
+	{
+		return;
+	}
+
+	LockList(o);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			ACCESS *a = LIST_DATA(o, i);
+			SiAccessToPack(p, a, i, LIST_NUM(o));
+		}
+	}
+	UnlockList(o);
+}
+
+// 指定した HUB をホストしているメンバを取得する
+FARM_MEMBER *SiGetHubHostingMember(SERVER *s, HUB *h, bool admin_mode)
+{
+	FARM_MEMBER *ret = NULL;
+	char name[MAX_SIZE];
+	// 引数チェック
+	if (s == NULL || h == NULL)
+	{
+		return NULL;
+	}
+
+	StrCpy(name, sizeof(name), h->Name);
+
+	if (h->Type == HUB_TYPE_FARM_STATIC)
+	{
+		// スタティック HUB の場合 任意のメンバを選択すれば良い
+		if (admin_mode == false)
+		{
+			ret = SiGetNextFarmMember(s);
+		}
+		else
+		{
+			UINT i;
+			ret = NULL;
+
+			for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+			{
+				FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+				if (f->Me)
+				{
+					ret = f;
+					break;
+				}
+			}
+		}
+	}
+	else
+	{
+		// ダイナミック HUB の場合
+		// すでに HUB をホストしているメンバがあるかどうか調べる
+		UINT i;
+
+		for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+		{
+			FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+			HUB_LIST *hh, t;
+			StrCpy(t.Name, sizeof(t.Name), name);
+			LockList(f->HubList);
+			{
+				hh = Search(f->HubList, &t);
+				if (hh != NULL)
+				{
+					// 発見した
+					ret = f;
+				}
+			}
+			UnlockList(f->HubList);
+		}
+
+		if (ret == NULL)
+		{
+			// 新しく HUB をホストさせる
+			FARM_MEMBER *f;
+
+			// ホストさせるメンバの選択
+			ret = SiGetNextFarmMember(s);
+
+			f = ret;
+			if (f != NULL)
+			{
+				// HUB 作成指令
+				SiAddHubCreateHistory(s, name);
+				SiCallCreateHub(s, f, h);
+				SiCallUpdateHub(s, f, h);
+			}
+		}
+	}
+
+	return ret;
+}
+
+// タスクが呼び出された
+PACK *SiCalledTask(FARM_CONTROLLER *f, PACK *p, char *taskname)
+{
+	PACK *ret;
+	SERVER *s;
+	// 引数チェック
+	if (f == NULL || p == NULL || taskname == NULL)
+	{
+		return NULL;
+	}
+
+	ret = NULL;
+	s = f->Server;
+
+	if (StrCmpi(taskname, "noop") == 0)
+	{
+		// NO OPERATION
+		ret = NewPack();
+	}
+	else
+	{
+		Debug("Task Called: [%s].\n", taskname);
+		if (StrCmpi(taskname, "createhub") == 0)
+		{
+			SiCalledCreateHub(s, p);
+			ret = NewPack();
+		}
+		else if (StrCmpi(taskname, "deletehub") == 0)
+		{
+			SiCalledDeleteHub(s, p);
+			ret = NewPack();
+		}
+		else if (StrCmpi(taskname, "enumhub") == 0)
+		{
+			ret = NewPack();
+			SiCalledEnumHub(s, ret, p);
+		}
+		else if (StrCmpi(taskname, "updatehub") == 0)
+		{
+			SiCalledUpdateHub(s, p);
+			ret = NewPack();
+		}
+		else if (StrCmpi(taskname, "createticket") == 0)
+		{
+			ret = SiCalledCreateTicket(s, p);
+		}
+		else if (StrCmpi(taskname, "enumnat") == 0)
+		{
+			ret = SiCalledEnumNat(s, p);
+		}
+		else if (StrCmpi(taskname, "enumdhcp") == 0)
+		{
+			ret = SiCalledEnumDhcp(s, p);
+		}
+		else if (StrCmpi(taskname, "getnatstatus") == 0)
+		{
+			ret = SiCalledGetNatStatus(s, p);
+		}
+		else if (StrCmpi(taskname, "enumsession") == 0)
+		{
+			ret = SiCalledEnumSession(s, p);
+		}
+		else if (StrCmpi(taskname, "deletesession") == 0)
+		{
+			SiCalledDeleteSession(s, p);
+			ret = NewPack();
+		}
+		else if (StrCmpi(taskname, "deletemactable") == 0)
+		{
+			SiCalledDeleteMacTable(s, p);
+			ret = NewPack();
+		}
+		else if (StrCmpi(taskname, "deleteiptable") == 0)
+		{
+			SiCalledDeleteIpTable(s, p);
+			ret = NewPack();
+		}
+		else if (StrCmpi(taskname, "enummactable") == 0)
+		{
+			ret = SiCalledEnumMacTable(s, p);
+		}
+		else if (StrCmpi(taskname, "enumiptable") == 0)
+		{
+			ret = SiCalledEnumIpTable(s, p);
+		}
+		else if (StrCmpi(taskname, "getsessionstatus") == 0)
+		{
+			ret = SiCalledGetSessionStatus(s, p);
+		}
+		else if (StrCmpi(taskname, "enumlogfilelist") == 0)
+		{
+			ret = SiCalledEnumLogFileList(s, p);
+		}
+		else if (StrCmpi(taskname, "readlogfile") == 0)
+		{
+			ret = SiCalledReadLogFile(s, p);
+		}
+	}
+
+	return ret;
+}
+
+// タスクを呼び出す
+PACK *SiCallTask(FARM_MEMBER *f, PACK *p, char *taskname)
+{
+	PACK *ret;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (f == NULL || p == NULL || taskname == NULL)
+	{
+		return NULL;
+	}
+
+	PackAddStr(p, "taskname", taskname);
+
+	Debug("Call Task [%s] (%s)\n", taskname, f->hostname);
+
+	Format(tmp, sizeof(tmp), "CLUSTER_CALL: Entering Call [%s] to %s", taskname, f->hostname);
+	SiDebugLog(f->Cedar->Server, tmp);
+
+	ret = SiExecTask(f, p);
+
+	Format(tmp, sizeof(tmp), "CLUSTER_CALL: Leaving Call [%s] to %s", taskname, f->hostname);
+	SiDebugLog(f->Cedar->Server, tmp);
+
+	return ret;
+}
+
+// タスク待ちうけプロシージャ (メイン処理)
+void SiAcceptTasksFromControllerMain(FARM_CONTROLLER *f, SOCK *sock)
+{
+	PACK *request;
+	PACK *response;
+	char taskname[MAX_SIZE];
+	// 引数チェック
+	if (f == NULL || sock == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		bool ret;
+		// PACK を受信する
+		request = HttpClientRecv(sock);
+		if (request == NULL)
+		{
+			// 切断
+			return;
+		}
+
+		response = NULL;
+
+		// 名前の取得
+		if (PackGetStr(request, "taskname", taskname, sizeof(taskname)))
+		{
+			Lock(f->Server->TasksFromFarmControllerLock);
+			{
+				response = SiCalledTask(f, request, taskname);
+			}
+			Unlock(f->Server->TasksFromFarmControllerLock);
+		}
+
+		FreePack(request);
+
+		// 応答を返す
+		if (response == NULL)
+		{
+			response = NewPack();
+		}
+		else
+		{
+			PackAddInt(response, "succeed", 1);
+		}
+
+		ret = HttpClientSend(sock, response);
+		FreePack(response);
+
+		if (ret == false)
+		{
+			// 切断
+			return;
+		}
+	}
+}
+
+// タスク待ちうけプロシージャ
+void SiAcceptTasksFromController(FARM_CONTROLLER *f, SOCK *sock)
+{
+	UINT i;
+	HUB **hubs;
+	UINT num_hubs;
+	CEDAR *c;
+	SERVER *s;
+	// 引数チェック
+	if (f == NULL || sock == NULL)
+	{
+		return;
+	}
+
+	s = f->Server;
+	c = s->Cedar;
+
+	// メイン処理
+	SiAcceptTasksFromControllerMain(f, sock);
+
+	// コントローラとの接続が切断されたためすべての仮想 HUB を停止する
+	LockList(c->HubList);
+	{
+		hubs = ToArray(c->HubList);
+		num_hubs = LIST_NUM(c->HubList);
+		for (i = 0;i < num_hubs;i++)
+		{
+			AddRef(hubs[i]->ref);
+		}
+	}
+	UnlockList(c->HubList);
+
+	for (i = 0;i < num_hubs;i++)
+	{
+		SetHubOffline(hubs[i]);
+		DelHub(c, hubs[i]);
+		ReleaseHub(hubs[i]);
+	}
+
+	Free(hubs);
+}
+
+// タスクを実行する
+PACK *SiExecTask(FARM_MEMBER *f, PACK *p)
+{
+	FARM_TASK *t;
+	// 引数チェック
+	if (f == NULL || p == NULL)
+	{
+		return NULL;
+	}
+
+	t = SiFarmServPostTask(f, p);
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	return SiFarmServWaitTask(t);
+}
+
+// タスク投入
+FARM_TASK *SiFarmServPostTask(FARM_MEMBER *f, PACK *request)
+{
+	FARM_TASK *t;
+	// 引数チェック
+	if (f == NULL || request == NULL)
+	{
+		return NULL;
+	}
+
+	t = ZeroMalloc(sizeof(FARM_TASK));
+	t->CompleteEvent = NewEvent();
+	t->Request = request;
+
+	LockQueue(f->TaskQueue);
+	{
+		if (f->Halting)
+		{
+			// 停止中 (失敗)
+			UnlockQueue(f->TaskQueue);
+			ReleaseEvent(t->CompleteEvent);
+			Free(t);
+			return NULL;
+		}
+
+		InsertQueue(f->TaskQueue, t);
+	}
+	UnlockQueue(f->TaskQueue);
+
+	Set(f->TaskPostEvent);
+
+	return t;
+}
+
+// タスク結果待ち
+PACK *SiFarmServWaitTask(FARM_TASK *t)
+{
+	PACK *response;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	Wait(t->CompleteEvent, INFINITE);
+	ReleaseEvent(t->CompleteEvent);
+	FreePack(t->Request);
+
+	response = t->Response;
+	Free(t);
+
+	if (PackGetInt(response, "succeed") == 0)
+	{
+		// 何らかの原因でタスク呼び出しが失敗した
+		FreePack(response);
+		return NULL;
+	}
+
+	return response;
+}
+
+// ファームサーバー処理メイン
+void SiFarmServMain(SERVER *server, SOCK *sock, FARM_MEMBER *f)
+{
+	UINT wait_time = SERVER_CONTROL_TCP_TIMEOUT / 2;
+	bool send_noop = false;
+	UINT i;
+	CEDAR *c;
+	// 引数チェック
+	if (server == NULL || sock == NULL || f == NULL)
+	{
+		Debug("SiFarmServMain Failed.\n");
+		return;
+	}
+
+	Debug("SiFarmServMain Started.\n");
+
+	c = server->Cedar;
+
+	// メンバがコントローラに接続してきた段階で
+	// すべてのスタティック HUB の作成指令を送信する
+	LockList(c->HubList);
+	{
+		for (i = 0;i < LIST_NUM(c->HubList);i++)
+		{
+			HUB *h = LIST_DATA(c->HubList, i);
+			if (h->Offline == false)
+			{
+				if (h->Type == HUB_TYPE_FARM_STATIC)
+				{
+					PACK *p;
+					HUB_LIST *hh;
+					p = NewPack();
+					SiPackAddCreateHub(p, h);
+					PackAddStr(p, "taskname", "createhub");
+					HttpServerSend(sock, p);
+					FreePack(p);
+					p = HttpServerRecv(sock);
+					FreePack(p);
+
+					p = NewPack();
+					SiPackAddCreateHub(p, h);
+					PackAddStr(p, "taskname", "updatehub");
+					HttpServerSend(sock, p);
+					FreePack(p);
+					p = HttpServerRecv(sock);
+					FreePack(p);
+
+					hh = ZeroMalloc(sizeof(HUB_LIST));
+					hh->DynamicHub = false;
+					hh->FarmMember = f;
+					StrCpy(hh->Name, sizeof(hh->Name), h->Name);
+					LockList(f->HubList);
+					{
+						Add(f->HubList, hh);
+					}
+					UnlockList(f->HubList);
+				}
+			}
+		}
+	}
+	UnlockList(c->HubList);
+
+	Debug("SiFarmServMain: while (true)\n");
+
+	while (true)
+	{
+		FARM_TASK *t;
+		UINT64 tick;
+
+		do
+		{
+			// 新しいタスクが到着していないかどうか調べる
+			LockQueue(f->TaskQueue);
+			{
+				t = GetNext(f->TaskQueue);
+			}
+			UnlockQueue(f->TaskQueue);
+
+			if (t != NULL)
+			{
+				// このタスクを処理する
+				PACK *p = t->Request;
+				bool ret;
+
+				// 送信
+				ret = HttpServerSend(sock, p);
+				send_noop = false;
+
+				if (ret == false)
+				{
+					// 接続が切れた
+					// このタスクをキャンセルする
+					Set(t->CompleteEvent);
+					goto DISCONNECTED;
+				}
+
+				// 受信
+				p = HttpServerRecv(sock);
+
+				t->Response = p;
+				Set(t->CompleteEvent);
+
+				send_noop = false;
+			}
+		}
+		while (t != NULL);
+
+		if (send_noop)
+		{
+			// NOOP を送信する
+			PACK *p;
+			bool ret;
+			p = NewPack();
+			PackAddStr(p, "taskname", "noop");
+
+			ret = HttpServerSend(sock, p);
+			FreePack(p);
+
+			if (ret == false)
+			{
+				goto DISCONNECTED;
+			}
+
+			p = HttpServerRecv(sock);
+			if (p == NULL)
+			{
+				goto DISCONNECTED;
+			}
+
+			FreePack(p);
+		}
+
+		tick = Tick64();
+
+		while (true)
+		{
+			bool break_flag;
+			if ((tick + wait_time) <= Tick64())
+			{
+				break;
+			}
+
+			Wait(f->TaskPostEvent, 250);
+
+			break_flag = false;
+			LockQueue(f->TaskQueue);
+			{
+				if (f->TaskQueue->num_item != 0)
+				{
+					break_flag = true;
+				}
+			}
+			UnlockQueue(f->TaskQueue);
+
+			if (break_flag || f->Halting || server->Halt)
+			{
+				break;
+			}
+		}
+		send_noop = true;
+	}
+
+DISCONNECTED:
+
+	Debug("SiFarmServMain: DISCONNECTED\n");
+
+	f->Halting = true;
+	// すべての未処理のタスクをキャンセルする
+	LockQueue(f->TaskQueue);
+	{
+		FARM_TASK *t;
+
+		while (t = GetNext(f->TaskQueue))
+		{
+			Set(t->CompleteEvent);
+		}
+	}
+	UnlockQueue(f->TaskQueue);
+}
+
+// ファームメンバからの接続を処理するファームサーバー関数
+void SiFarmServ(SERVER *server, SOCK *sock, X *cert, UINT ip, UINT num_port, UINT *ports, char *hostname, UINT point, UINT weight, UINT max_sessions)
+{
+	PACK *p;
+	FARM_MEMBER *f;
+	UINT i;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (server == NULL || sock == NULL || cert == NULL || num_port == 0 || ports == NULL || hostname == NULL)
+	{
+		return;
+	}
+
+	if (weight == 0)
+	{
+		weight = FARM_DEFAULT_WEIGHT;
+	}
+
+	if (max_sessions == 0)
+	{
+		max_sessions = SERVER_MAX_SESSIONS;
+	}
+
+	if (ip == 0)
+	{
+		// 公開 IP アドレスが指定されていない場合はこのファームメンバサーバーの
+		// 接続元 IP アドレスを指定する
+		ip = IPToUINT(&sock->RemoteIP);
+	}
+
+	IPToStr32(tmp, sizeof(tmp), ip);
+	SLog(server->Cedar, "LS_FARM_SERV_START", tmp, hostname);
+
+	// 成功を知らせる
+	p = NewPack();
+	HttpServerSend(sock, p);
+	FreePack(p);
+
+	IPToStr32(tmp, sizeof(tmp), ip);
+	Debug("Farm Member %s Connected. IP: %s\n", hostname, tmp);
+
+	SetTimeout(sock, SERVER_CONTROL_TCP_TIMEOUT);
+
+	f = ZeroMalloc(sizeof(FARM_MEMBER));
+	f->Cedar = server->Cedar;
+	f->Ip = ip;
+	f->NumPort = num_port;
+	f->Ports = ports;
+	StrCpy(f->hostname, sizeof(f->hostname), hostname);
+	f->ServerCert = cert;
+	f->ConnectedTime = SystemTime64();
+	f->Weight = weight;
+	f->MaxSessions = max_sessions;
+
+	f->HubList = NewList(CompareHubList);
+	f->Point = point;
+
+	f->TaskQueue = NewQueue();
+	f->TaskPostEvent = NewEvent();
+
+	// リストに追加する
+	LockList(server->FarmMemberList);
+	{
+		Add(server->FarmMemberList, f);
+	}
+	UnlockList(server->FarmMemberList);
+
+	// メイン処理
+	SiFarmServMain(server, sock, f);
+
+	// リストから削除する
+	LockList(server->FarmMemberList);
+	{
+		Delete(server->FarmMemberList, f);
+	}
+	UnlockList(server->FarmMemberList);
+
+	ReleaseQueue(f->TaskQueue);
+	ReleaseEvent(f->TaskPostEvent);
+
+	for (i = 0;i < LIST_NUM(f->HubList);i++)
+	{
+		HUB_LIST *hh = LIST_DATA(f->HubList, i);
+		Free(hh);
+	}
+
+	ReleaseList(f->HubList);
+
+	Free(f);
+
+	SLog(server->Cedar, "LS_FARM_SERV_END", hostname);
+}
+
+// HUB リストの検索
+int CompareHubList(void *p1, void *p2)
+{
+	HUB_LIST *h1, *h2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	h1 = *(HUB_LIST **)p1;
+	h2 = *(HUB_LIST **)p2;
+	if (h1 == NULL || h2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(h1->Name, h2->Name);
+}
+
+// コントローラへの接続スレッド
+void SiConnectToControllerThread(THREAD *thread, void *param)
+{
+	FARM_CONTROLLER *f;
+	SESSION *s;
+	CONNECTION *c;
+	SERVER *server;
+	bool first_failed;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	MsSetThreadPriorityRealtime();
+#endif	// OS_WIN32
+
+	f = (FARM_CONTROLLER *)param;
+	f->Thread = thread;
+	AddRef(f->Thread->ref);
+	NoticeThreadInit(thread);
+
+	f->StartedTime = SystemTime64();
+
+	server = f->Server;
+
+	f->StartedTime = SystemTime64();
+
+	SLog(server->Cedar, "LS_FARM_CONNECT_1", server->ControllerName);
+
+	first_failed = true;
+
+	while (true)
+	{
+		// 接続を試行
+		CLIENT_OPTION o;
+
+		f->LastError = ERR_TRYING_TO_CONNECT;
+
+		Zero(&o, sizeof(CLIENT_OPTION));
+		StrCpy(o.Hostname, sizeof(o.Hostname), server->ControllerName);
+		o.Port = server->ControllerPort;
+		f->NumTry++;
+
+		Debug("Try to Connect %s (Controller).\n", server->ControllerName);
+
+		s = NewRpcSessionEx(server->Cedar, &o, NULL, CEDAR_SERVER_FARM_STR);
+
+		if (s != NULL)
+		{
+			// 接続成功: 認証データを送信
+			PACK *p = NewPack();
+			UCHAR secure_password[SHA1_SIZE];
+			BUF *b;
+
+			c = s->Connection;
+
+			Lock(f->lock);
+			{
+				f->Sock = c->FirstSock;
+				AddRef(f->Sock->ref);
+				SetTimeout(f->Sock, SERVER_CONTROL_TCP_TIMEOUT);
+			}
+			Unlock(f->lock);
+
+			// メソッド
+			PackAddStr(p, "method", "farm_connect");
+			PackAddClientVersion(p, s->Connection);
+
+			// パスワード
+			SecurePassword(secure_password, server->MemberPassword, s->Connection->Random);
+			PackAddData(p, "SecurePassword", secure_password, sizeof(secure_password));
+
+			Lock(server->Cedar->lock);
+			{
+				b = XToBuf(server->Cedar->ServerX, false);
+			}
+			Unlock(server->Cedar->lock);
+
+			if (b != NULL)
+			{
+				char tmp[MAX_SIZE];
+				bool ret;
+				UINT i;
+				// サーバー証明書
+				PackAddBuf(p, "ServerCert", b);
+				FreeBuf(b);
+
+				// 最大セッション数
+				PackAddInt(p, "MaxSessions", GetServerCapsInt(server, "i_max_sessions"));
+
+				// ポイント
+				PackAddInt(p, "Point", SiGetPoint(server));
+				PackAddInt(p, "Weight", server->Weight);
+
+				// ホスト名
+				GetMachineName(tmp, sizeof(tmp));
+				PackAddStr(p, "HostName", tmp);
+
+				// 公開 IP
+				PackAddIp32(p, "PublicIp", server->PublicIp);
+
+				// 公開ポート
+				for (i = 0;i < server->NumPublicPort;i++)
+				{
+					PackAddIntEx(p, "PublicPort", server->PublicPorts[i], i, server->NumPublicPort);
+				}
+
+				ret = HttpClientSend(c->FirstSock, p);
+
+				if (ret)
+				{
+					PACK *p;
+					UINT err = ERR_PROTOCOL_ERROR;
+
+					first_failed = true;
+					p = HttpClientRecv(c->FirstSock);
+					if (p != NULL && (err = GetErrorFromPack(p)) == 0)
+					{
+						// 接続成功
+						SLog(server->Cedar, "LS_FARM_START");
+						f->CurrentConnectedTime = SystemTime64();
+						if (f->FirstConnectedTime == 0)
+						{
+							f->FirstConnectedTime = SystemTime64();
+						}
+						f->NumConnected++;
+						Debug("Connect Succeed.\n");
+						f->Online = true;
+
+						// メイン処理
+						SiAcceptTasksFromController(f, c->FirstSock);
+
+						f->Online = false;
+					}
+					else
+					{
+						// エラー
+						f->LastError = err;
+						SLog(server->Cedar, "LS_FARM_CONNECT_2", server->ControllerName,
+							GetUniErrorStr(err), err);
+					}
+					FreePack(p);
+				}
+				else
+				{
+					f->LastError = ERR_DISCONNECTED;
+
+					if (first_failed)
+					{
+						SLog(server->Cedar, "LS_FARM_CONNECT_3", server->ControllerName, RETRY_CONNECT_TO_CONTROLLER_INTERVAL / 1000);
+						first_failed = false;
+					}
+				}
+			}
+
+			FreePack(p);
+
+			// 接続切断
+			Lock(f->lock);
+			{
+				if (f->Sock != NULL)
+				{
+					ReleaseSock(f->Sock);
+					f->Sock = NULL;
+				}
+			}
+			Unlock(f->lock);
+
+			ReleaseSession(s);
+			s = NULL;
+
+			if (f->LastError == ERR_TRYING_TO_CONNECT)
+			{
+				f->LastError = ERR_DISCONNECTED;
+			}
+		}
+		else
+		{
+			// 接続失敗
+			f->LastError = ERR_CONNECT_TO_FARM_CONTROLLER;
+
+			if (first_failed)
+			{
+				SLog(server->Cedar, "LS_FARM_CONNECT_3", server->ControllerName, RETRY_CONNECT_TO_CONTROLLER_INTERVAL / 1000);
+				first_failed = false;
+			}
+		}
+
+		Debug("Controller Disconnected. ERROR = %S\n", _E(f->LastError));
+
+		f->NumFailed = f->NumTry - f->NumConnected;
+
+		// イベント待機
+		Wait(f->HaltEvent, RETRY_CONNECT_TO_CONTROLLER_INTERVAL);
+
+		if (f->Halt)
+		{
+			// 停止フラグ
+			break;
+		}
+	}
+
+	SLog(server->Cedar, "LS_FARM_DISCONNECT");
+}
+
+// コントローラへの接続を切断
+void SiStopConnectToController(FARM_CONTROLLER *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	f->Halt = true;
+
+	// 接続を停止
+	Lock(f->lock);
+	{
+		Disconnect(f->Sock);
+	}
+	Unlock(f->lock);
+
+	Set(f->HaltEvent);
+
+	// スレッド停止を待機
+	WaitThread(f->Thread, INFINITE);
+	ReleaseThread(f->Thread);
+
+	DeleteLock(f->lock);
+	ReleaseEvent(f->HaltEvent);
+
+	Free(f);
+}
+
+// コントローラへの接続の開始
+FARM_CONTROLLER *SiStartConnectToController(SERVER *s)
+{
+	FARM_CONTROLLER *f;
+	THREAD *t;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	f = ZeroMalloc(sizeof(FARM_CONTROLLER));
+	f->Server = s;
+	f->LastError = ERR_TRYING_TO_CONNECT;
+	f->HaltEvent = NewEvent();
+	f->lock = NewLock();
+
+	t = NewThread(SiConnectToControllerThread, f);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+
+	return f;
+}
+
+// サーバーの作成
+SERVER *SiNewServer(bool bridge)
+{
+	SERVER *s;
+
+	s = ZeroMalloc(sizeof(SERVER));
+
+	SiInitHubCreateHistory(s);
+
+	InitServerCapsCache(s);
+
+	Rand(s->MyRandomKey, sizeof(s->MyRandomKey));
+
+	s->lock = NewLock();
+	s->SaveCfgLock = NewLock();
+	s->ref = NewRef();
+	s->Cedar = NewCedar(NULL, NULL);
+	s->Cedar->Server = s;
+	s->Cedar->CheckExpires = true;
+	s->ServerListenerList = NewList(CompareServerListener);
+	s->StartTime = SystemTime64();
+	s->TasksFromFarmControllerLock = NewLock();
+
+	if (bridge)
+	{
+		SetCedarVpnBridge(s->Cedar);
+	}
+
+#ifdef OS_WIN32
+	if (IsHamMode() == false)
+	{
+		RegistWindowsFirewallAll();
+	}
+#endif
+
+	s->Keep = StartKeep();
+
+	// ログ関係
+	MakeDir(bridge == false ? SERVER_LOG_DIR_NAME : BRIDGE_LOG_DIR_NAME);
+	s->Logger = NewLog(bridge == false ? SERVER_LOG_DIR_NAME : BRIDGE_LOG_DIR_NAME, SERVER_LOG_PERFIX, LOG_SWITCH_DAY);
+
+	SLog(s->Cedar, "L_LINE");
+	SLog(s->Cedar, "LS_START_2", s->Cedar->ServerStr, s->Cedar->VerString);
+	SLog(s->Cedar, "LS_START_3", s->Cedar->BuildInfo);
+	SLog(s->Cedar, "LS_START_UTF8");
+	SLog(s->Cedar, "LS_START_1");
+
+	if (s->Cedar->Bridge == false)
+	{
+		s->LicenseSystem = LiNewLicenseSystem();
+	}
+
+	// コンフィグレーション初期化
+	SiInitConfiguration(s);
+
+	// 優先順位を上げる
+	if (s->NoHighPriorityProcess == false)
+	{
+		OSSetHighPriority();
+	}
+
+	if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+	{
+		// コントローラへの接続を開始する
+		s->FarmController = SiStartConnectToController(s);
+	}
+	else if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+	{
+		FARM_MEMBER *f;
+		// コントローラとしての動作を開始する
+		s->FarmMemberList = NewList(NULL);
+
+		f = ZeroMalloc(sizeof(FARM_MEMBER));
+		f->Cedar = s->Cedar;
+		GetMachineName(f->hostname, sizeof(f->hostname));
+		f->Me = true;
+		f->HubList = NewList(CompareHubList);
+		f->Weight = s->Weight;
+
+		s->Me = f;
+
+		Add(s->FarmMemberList, f);
+
+		SiStartFarmControl(s);
+
+		s->FarmControllerInited = true;
+	}
+
+	InitServerSnapshot(s);
+
+	SiInitDeadLockCheck(s);
+
+	return s;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Server.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Server.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Server.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,580 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Server.h
+// Server.c のヘッダ
+
+#ifndef	SERVER_H
+#define	SERVER_H
+
+extern char *SERVER_CONFIG_FILE_NAME;
+#define	SERVER_DEFAULT_CIPHER_NAME		"RC4-MD5"
+#define	SERVER_DEFAULT_CERT_DAYS		(365 * 10)
+#define	SERVER_DEFAULT_HUB_NAME			"DEFAULT"
+#define	SERVER_DEFAULT_BRIDGE_NAME		"BRIDGE"
+#define	SERVER_CONTROL_TCP_TIMEOUT		(60 * 1000)
+#define	SERVER_FARM_CONTROL_INTERVAL	(10 * 1000)
+
+#define	SERVER_FILE_SAVE_INTERVAL_DEFAULT	(5 * 60 * 1000)
+#define	SERVER_FILE_SAVE_INTERVAL_MIN		(5 * 1000)
+#define	SERVER_FILE_SAVE_INTERVAL_MAX		(3600 * 1000)
+
+#define	SERVER_LICENSE_VIOLATION_SPAN	(SERVER_FARM_CONTROL_INTERVAL * 2)
+
+
+#define SERVER_DEADLOCK_CHECK_SPAN		(2 * 60 * 1000)
+#define SERVER_DEADLOCK_CHECK_TIMEOUT	(3 * 60 * 1000)
+
+
+#define	RETRY_CONNECT_TO_CONTROLLER_INTERVAL	(1 * 1000)
+
+#define	MAX_PUBLIC_PORT_NUM				128
+
+// 各ファームメンバによってホストされている仮想 HUB リスト
+struct HUB_LIST
+{
+	struct FARM_MEMBER *FarmMember;		// ファームメンバ
+	bool DynamicHub;					// ダイナミック HUB
+	char Name[MAX_HUBNAME_LEN + 1];		// HUB 名
+	UINT NumSessions;					// セッション数
+	UINT NumSessionsClient;				// クライアントセッション数
+	UINT NumSessionsBridge;				// ブリッジセッション数
+	UINT NumMacTables;					// MAC テーブル数
+	UINT NumIpTables;					// IP テーブル数
+};
+
+// タスク
+struct FARM_TASK
+{
+	EVENT *CompleteEvent;				// 完了通知
+	PACK *Request;						// 要求
+	PACK *Response;						// 応答
+};
+
+// ファームメンバ
+struct FARM_MEMBER
+{
+	CEDAR *Cedar;						// Cedar
+	UINT64 ConnectedTime;				// 接続日時
+	UINT Me;							// 自分自身
+	UINT Ip;							// IP アドレス
+	UINT NumPort;						// ポート番号数
+	UINT *Ports;						// ポート番号
+	char hostname[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	X *ServerCert;						// サーバー証明書
+	LIST *HubList;						// 仮想 HUB リスト
+	QUEUE *TaskQueue;					// タスクキュー
+	EVENT *TaskPostEvent;				// タスク投入イベント
+	UINT Point;							// 点数
+	volatile bool Halting;				// 停止中
+	UINT NumSessions;					// セッション数
+	UINT MaxSessions;					// 最大セッション数
+	UINT NumTcpConnections;				// TCP コネクション数
+	TRAFFIC Traffic;					// トラフィック情報
+	UINT AssignedClientLicense;			// 割り当て済みクライアントライセンス数
+	UINT AssignedBridgeLicense;			// 割り当て済みブリッジライセンス数
+	UINT Weight;						// 性能基準比
+	UCHAR RandomKey[SHA1_SIZE];			// 乱数キー (ライセンスチェック)
+	UINT64 SystemId;					// システム ID (ライセンスチェック)
+};
+
+// ファームコントローラへの接続
+struct FARM_CONTROLLER
+{
+	LOCK *lock;							// ロック
+	struct SERVER *Server;				// サーバー
+	THREAD *Thread;						// スレッド
+	SOCK *Sock;							// ソケット
+	SESSION *Session;					// セッション
+	volatile bool Halt;					// 停止フラグ
+	EVENT *HaltEvent;					// 停止イベント
+	UINT LastError;						// 最終エラー
+	bool Online;						// オンライン フラグ
+	UINT64 StartedTime;					// 接続開始時刻
+	UINT64 CurrentConnectedTime;		// 今回の接続時刻
+	UINT64 FirstConnectedTime;			// 最初の接続時刻
+	UINT NumConnected;					// 接続回数
+	UINT NumTry;						// 試行回数
+	UINT NumFailed;						// 接続失敗回数
+};
+
+// サーバーリスナー
+struct SERVER_LISTENER
+{
+	UINT Port;							// ポート番号
+	bool Enabled;						// 有効フラグ
+	LISTENER *Listener;					// リスナーオブジェクト
+};
+
+// syslog 設定
+struct SYSLOG_SETTING
+{
+	UINT SaveType;							// 保存種類
+	char Hostname[MAX_HOST_NAME_LEN + 1];	// ホスト名
+	UINT Port;								// ポート番号
+};
+
+// サーバー オブジェクト
+struct SERVER
+{
+	UINT ServerType;					// サーバーの種類
+	UINT UpdatedServerType;				// 更新されたサーバーの種類
+	LIST *ServerListenerList;			// サーバーリスナーリスト
+	UCHAR HashedPassword[SHA1_SIZE];	// パスワード
+	char ControllerName[MAX_HOST_NAME_LEN + 1];		// コントローラ名
+	UINT ControllerPort;				// コントローラポート
+	UINT Weight;						// 性能基準比
+	bool ControllerOnly;				// コントローラ機能のみ
+	UCHAR MemberPassword[SHA1_SIZE];	// ファームメンバ用パスワード
+	UINT PublicIp;						// 公開 IP 
+	UINT NumPublicPort;					// 公開ポート数
+	UINT *PublicPorts;					// 公開ポート配列
+	UINT64 StartTime;					// 起動時刻
+	UINT AutoSaveConfigSpan;			// 自動保存間隔
+	UINT ConfigRevision;				// 設定ファイルリビジョン
+	UCHAR MyRandomKey[SHA1_SIZE];		// 自分のランダムキー
+	bool FarmControllerInited;			// ファームコントローラの初期化が完了した
+	bool DisableDeadLockCheck;			// デッドロックチェックを無効化する
+	bool NoSendSignature;				// クライアントにシグネチャを送信させない
+	bool SaveDebugLog;					// デバッグログを保存する
+	bool NoLinuxArpFilter;				// Linux における arp_filter を設定しない
+	bool NoHighPriorityProcess;			// プロセスの優先順位を上げない
+	bool NoDebugDump;					// デバッグダンプを出力しない
+
+	volatile bool Halt;					// 停止フラグ
+	LOCK *lock;							// ロック
+	REF *ref;							// 参照カウンタ
+	CEDAR *Cedar;						// Cedar
+	CFG_RW *CfgRw;						// 設定ファイル R/W
+	LOCK *SaveCfgLock;					// 設定保存ロック
+	EVENT *SaveHaltEvent;				// 保存スレッド停止イベント
+	THREAD *SaveThread;					// 設定保存スレッド
+	FARM_CONTROLLER *FarmController;	// ファームコントローラ
+	LOCK *TasksFromFarmControllerLock;	// ファームコントローラからのタスクを処理中にかけるロック
+	LIST *FarmMemberList;				// ファームメンバーリスト
+	FARM_MEMBER *Me;					// 自分自身のファームメンバ登録
+	THREAD *FarmControlThread;			// ファームコントロールスレッド
+	EVENT *FarmControlThreadHaltEvent;	// ファームコントロールスレッド停止イベント
+	LIST *HubCreateHistoryList;			// 仮想 HUB 作成履歴リスト
+
+	KEEP *Keep;							// コネクション維持
+	LOG *Logger;						// サーバー ロガー
+	ERASER *Eraser;						// 自動ファイル削除器
+
+	UINT CurrentTotalNumSessionsOnFarm;	// サーバー ファーム全体での合計のセッション数
+	UINT CurrentAssignedClientLicense;	// 現在のクライアントライセンス割り当て数
+	UINT CurrentAssignedBridgeLicense;	// 現在のブリッジライセンス割り当て数
+	LICENSE_SYSTEM *LicenseSystem;		// ライセンスシステム
+
+	LOCK *CapsCacheLock;				// Caps キャッシュ用ロック
+	CAPSLIST *CapsListCache;			// Caps キャッシュ
+	UINT LicenseHash;					// ライセンスリストのハッシュ値
+
+	bool SnapshotInited;
+	EVENT *SnapshotHaltEvent;			// スナップショット停止イベント
+	volatile bool HaltSnapshot;			// スナップショット停止フラグ
+	THREAD *SnapshotThread;				// スナップショットスレッド
+	LOG *SnapshotLogger;				// スナップショットロガー
+	UINT64 LastSnapshotTime;			// 最後にスナップショットを作成した時刻
+
+	THREAD *DeadLockCheckThread;		// デッドロックチェックスレッド
+	volatile bool HaltDeadLockThread;	// 停止フラグ
+	EVENT *DeadLockWaitEvent;			// 待機イベント
+
+	TINY_LOG *DebugLog;					// デバッグログ
+};
+
+
+// セッションの列挙*
+struct RPC_ENUM_SESSION
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	UINT NumSession;								// セッション数
+	struct RPC_ENUM_SESSION_ITEM *Sessions;			// セッションリスト
+};
+
+// セッション状態*
+struct RPC_SESSION_STATUS
+{
+	char HubName[MAX_HUBNAME_LEN + 1];				// HUB 名
+	char Name[MAX_SESSION_NAME_LEN + 1];			// セッション名
+	char Username[MAX_USERNAME_LEN + 1];			// ユーザー名
+	char RealUsername[MAX_USERNAME_LEN + 1];		// 本当のユーザー名
+	char GroupName[MAX_USERNAME_LEN + 1];			// グループ名
+	bool LinkMode;									// リンクモード
+	RPC_CLIENT_GET_CONNECTION_STATUS Status;		// ステータス
+	UINT ClientIp;									// クライアント IP アドレス
+	UCHAR ClientIp6[16];							// クライアント IPv6 アドレス
+	char ClientHostName[MAX_HOST_NAME_LEN + 1];		// クライアントホスト名
+	NODE_INFO NodeInfo;								// ノード情報
+};
+
+
+// サーバーの種類
+#define	SERVER_TYPE_STANDALONE			0		// スタンドアロン サーバー
+#define	SERVER_TYPE_FARM_CONTROLLER		1		// ファームコントローラ サーバー
+#define	SERVER_TYPE_FARM_MEMBER			2		// ファームメンバ サーバー
+
+
+// Caps 関係
+struct CAPS
+{
+	char *Name;							// 名前
+	UINT Value;							// 値
+};
+struct CAPSLIST
+{
+	LIST *CapsList;						// Caps リスト
+};
+
+// ログファイル
+struct LOG_FILE
+{
+	char Path[MAX_PATH];				// パス名
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	UINT FileSize;						// ファイルサイズ
+	UINT64 UpdatedTime;					// 更新日時
+};
+
+// 仮想 HUB のスナップショット
+struct HUB_SNAPSHOT
+{
+	char HubName[MAX_HUBNAME_LEN + 1];
+	bool HubStatus;
+	UINT HubMaxSessionsClient;
+	UINT HubMaxSessionsBridge;
+};
+
+// Server のスナップショット
+struct SERVER_SNAPSHOT
+{
+	UINT64 DateTime;
+	IP ServerIp;
+	char ServerHostname[MAX_HOST_NAME_LEN + 1];
+	char ServerProduct[MAX_SIZE];
+	char ServerVersion[MAX_SIZE];
+	char ServerBuild[MAX_SIZE];
+	char ServerOs[MAX_SIZE];
+	UINT64 ServerLicenseId;
+	UINT64 ServerLicenseExpires;
+	UINT ServerType;
+	UINT64 ServerStartupDatetime;
+	UINT NumClusterNodes;
+	LIST *HubList;
+};
+
+// 仮想 HUB 作成履歴
+struct SERVER_HUB_CREATE_HISTORY
+{
+	char HubName[MAX_HUBNAME_LEN + 1];
+	UINT64 CreatedTime;
+};
+
+// 関数プロトタイプ宣言
+SERVER *SiNewServer(bool bridge);
+void SiReleaseServer(SERVER *s);
+void SiCleanupServer(SERVER *s);
+void StStartServer(bool bridge);
+void StStopServer();
+void SiInitConfiguration(SERVER *s);
+void SiFreeConfiguration(SERVER *s);
+UINT SiWriteConfigurationFile(SERVER *s);
+void SiLoadInitialConfiguration(SERVER *s);
+bool SiLoadConfigurationFile(SERVER *s);
+bool SiLoadConfigurationFileMain(SERVER *s, FOLDER *root);
+void SiInitDefaultServerCert(SERVER *s);
+void SiInitCipherName(SERVER *s);
+void SiGenerateDefualtCert(X **server_x, K **server_k);
+void SiInitListenerList(SERVER *s);
+void SiLockListenerList(SERVER *s);
+void SiUnlockListenerList(SERVER *s);
+bool SiAddListener(SERVER *s, UINT port, bool enabled);
+bool SiEnableListener(SERVER *s, UINT port);
+bool SiDisableListener(SERVER *s, UINT port);
+bool SiDeleteListener(SERVER *s, UINT port);
+SERVER_LISTENER *SiGetListener(SERVER *s, UINT port);
+int CompareServerListener(void *p1, void *p2);
+void SiStopAllListener(SERVER *s);
+void SiInitDefaultHubList(SERVER *s);
+void SiInitBridge(SERVER *s);
+void SiTest(SERVER *s);
+FOLDER *SiWriteConfigurationToCfg(SERVER *s);
+bool SiLoadConfigurationCfg(SERVER *s, FOLDER *root);
+void SiWriteLocalBridges(FOLDER *f, SERVER *s);
+void SiLoadLocalBridges(SERVER *s, FOLDER *f);
+void SiWriteLocalBridgeCfg(FOLDER *f, LOCALBRIDGE *br);
+void SiLoadLocalBridgeCfg(SERVER *s, FOLDER *f);
+void SiWriteListeners(FOLDER *f, SERVER *s);
+void SiLoadListeners(SERVER *s, FOLDER *f);
+void SiWriteListenerCfg(FOLDER *f, SERVER_LISTENER *r);
+void SiLoadListenerCfg(SERVER *s, FOLDER *f);
+void SiWriteServerCfg(FOLDER *f, SERVER *s);
+void SiLoadServerCfg(SERVER *s, FOLDER *f);
+void SiWriteTraffic(FOLDER *parent, char *name, TRAFFIC *t);
+void SiWriteTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e);
+void SiLoadTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e);
+void SiLoadTraffic(FOLDER *parent, char *name, TRAFFIC *t);
+void SiSaverThread(THREAD *thread, void *param);
+void SiLoadLicenseManager(SERVER *s, FOLDER *f);
+void SiWriteLicenseManager(FOLDER *f, SERVER *s);
+void SiLoadL3Switchs(SERVER *s, FOLDER *f);
+void SiLoadL3SwitchCfg(L3SW *sw, FOLDER *f);
+void SiWriteL3Switchs(FOLDER *f, SERVER *s);
+void SiWriteL3SwitchCfg(FOLDER *f, L3SW *sw);
+void SiWriteHubs(FOLDER *f, SERVER *s);
+void SiLoadHubs(SERVER *s, FOLDER *f);
+void SiWriteHubCfg(FOLDER *f, HUB *h);
+void SiLoadHubCfg(SERVER *s, FOLDER *f, char *name);
+void SiLoadHubLogCfg(HUB_LOG *g, FOLDER *f);
+void SiWriteHubOptionCfg(FOLDER *f, HUB_OPTION *o);
+void SiWriteHubLogCfg(FOLDER *f, HUB_LOG *g);
+void SiWriteHubLogCfgEx(FOLDER *f, HUB_LOG *g, bool el_mode);
+void SiLoadHubOptionCfg(FOLDER *f, HUB_OPTION *o);
+void SiWriteHubLinks(FOLDER *f, HUB *h);
+void SiLoadHubLinks(HUB *h, FOLDER *f);
+void SiWriteHubAdminOptions(FOLDER *f, HUB *h);
+void SiLoadHubAdminOptions(HUB *h, FOLDER *f);
+void SiWriteHubLinkCfg(FOLDER *f, LINK *k);
+void SiLoadHubLinkCfg(FOLDER *f, HUB *h);
+void SiWriteHubAccessLists(FOLDER *f, HUB *h);
+void SiLoadHubAccessLists(HUB *h, FOLDER *f);
+void SiWriteHubAccessCfg(FOLDER *f, ACCESS *a);
+void SiLoadHubAccessCfg(HUB *h, FOLDER *f);
+void SiWriteHubDb(FOLDER *f, HUBDB *db);
+void SiLoadHubDb(HUB *h, FOLDER *f);
+void SiWriteUserList(FOLDER *f, LIST *o);
+void SiLoadUserList(HUB *h, FOLDER *f);
+void SiWriteUserCfg(FOLDER *f, USER *u);
+void SiLoadUserCfg(HUB *h, FOLDER *f);
+void SiWriteGroupList(FOLDER *f, LIST *o);
+void SiLoadGroupList(HUB *h, FOLDER *f);
+void SiWriteGroupCfg(FOLDER *f, USERGROUP *g);
+void SiLoadGroupCfg(HUB *h, FOLDER *f);
+void SiWriteCertList(FOLDER *f, LIST *o);
+void SiLoadCertList(LIST *o, FOLDER *f);
+void SiWriteCrlList(FOLDER *f, LIST *o);
+void SiLoadCrlList(LIST *o, FOLDER *f);
+void SiWritePolicyCfg(FOLDER *f, POLICY *p, bool cascade_mode);
+void SiLoadPolicyCfg(POLICY *p, FOLDER *f);
+void SiLoadSecureNAT(HUB *h, FOLDER *f);
+void SiWriteSecureNAT(HUB *h, FOLDER *f);
+void SiRebootServerEx(bool bridge, bool reset_setting);
+void SiRebootServer(bool bridge);
+void SiRebootServerThread(THREAD *thread, void *param);
+void StInit();
+void StFree();
+SERVER *StGetServer();
+void SiSetServerType(SERVER *s, UINT type,
+					 UINT ip, UINT num_port, UINT *ports,
+					 char *controller_name, UINT controller_port, UCHAR *password, UINT weight, bool controller_only);
+FARM_CONTROLLER *SiStartConnectToController(SERVER *s);
+void SiStopConnectToController(FARM_CONTROLLER *f);
+void SiFarmServ(SERVER *server, SOCK *sock, X *cert, UINT ip, UINT num_port, UINT *ports, char *hostname, UINT point, UINT weight, UINT max_sessions);
+int CompareHubList(void *p1, void *p2);
+void SiFarmServMain(SERVER *server, SOCK *sock, FARM_MEMBER *f);
+FARM_TASK *SiFarmServPostTask(FARM_MEMBER *f, PACK *request);
+PACK *SiFarmServWaitTask(FARM_TASK *t);
+PACK *SiExecTask(FARM_MEMBER *f, PACK *p);
+PACK *SiCallTask(FARM_MEMBER *f, PACK *p, char *taskname);
+void SiAcceptTasksFromController(FARM_CONTROLLER *f, SOCK *sock);
+void SiAcceptTasksFromControllerMain(FARM_CONTROLLER *f, SOCK *sock);
+PACK *SiCalledTask(FARM_CONTROLLER *f, PACK *p, char *taskname);
+void SiHubOnlineProc(HUB *h);
+void SiHubOfflineProc(HUB *h);
+FARM_MEMBER *SiGetNextFarmMember(SERVER *s);
+void SiCallCreateHub(SERVER *s, FARM_MEMBER *f, HUB *h);
+void SiCallUpdateHub(SERVER *s, FARM_MEMBER *f, HUB *h);
+void SiCallDeleteHub(SERVER *s, FARM_MEMBER *f, HUB *h);
+void SiCallEnumSession(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_SESSION *t);
+void SiCallEnumNat(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_NAT *t);
+void SiCallEnumDhcp(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_DHCP *t);
+void SiCallGetNatStatus(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_NAT_STATUS *t);
+void SiCallEnumMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_MAC_TABLE *t);
+void SiCallEnumIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_IP_TABLE *t);
+void SiCallDeleteSession(SERVER *s, FARM_MEMBER *f, char *hubname, char *session_name);
+void SiCallCreateTicket(SERVER *s, FARM_MEMBER *f, char *hubname, char *username, char *realusername, POLICY *policy, UCHAR *ticket, UINT counter, char *groupname);
+void SiCallDeleteMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key);
+void SiCallDeleteIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key);
+void SiCalledCreateHub(SERVER *s, PACK *p);
+void SiCalledUpdateHub(SERVER *s, PACK *p);
+void SiCalledDeleteHub(SERVER *s, PACK *p);
+void SiCalledDeleteSession(SERVER *s, PACK *p);
+void SiCalledDeleteMacTable(SERVER *s, PACK *p);
+void SiCalledDeleteIpTable(SERVER *s, PACK *p);
+PACK *SiCalledCreateTicket(SERVER *s, PACK *p);
+PACK *SiCalledEnumSession(SERVER *s, PACK *p);
+PACK *SiCalledEnumNat(SERVER *s, PACK *p);
+PACK *SiCalledEnumDhcp(SERVER *s, PACK *p);
+PACK *SiCalledGetNatStatus(SERVER *s, PACK *p);
+PACK *SiCalledEnumMacTable(SERVER *s, PACK *p);
+PACK *SiCalledEnumIpTable(SERVER *s, PACK *p);
+void SiCalledEnumHub(SERVER *s, PACK *p, PACK *req);
+void SiPackAddCreateHub(PACK *p, HUB *h);
+FARM_MEMBER *SiGetHubHostingMember(SERVER *s, HUB *h, bool admin_mode);
+void SiCallEnumHub(SERVER *s, FARM_MEMBER *f);
+void SiStartFarmControl(SERVER *s);
+void SiStopFarmControl(SERVER *s);
+void SiFarmControlThread(THREAD *thread, void *param);
+void SiAccessListToPack(PACK *p, LIST *o);
+void SiAccessToPack(PACK *p, ACCESS *a, UINT i, UINT total);
+ACCESS *SiPackToAccess(PACK *p, UINT i);
+UINT SiNumAccessFromPack(PACK *p);
+void SiHubUpdateProc(HUB *h);
+bool SiCheckTicket(HUB *h, UCHAR *ticket, char *username, UINT username_size, char *usernamereal, UINT usernamereal_size, POLICY *policy, char *sessionname, UINT sessionname_size, char *groupname, UINT groupname_size);
+UINT SiGetPoint(SERVER *s);
+UINT SiCalcPoint(SERVER *s, UINT num, UINT weight);
+bool SiCallGetSessionStatus(SERVER *s, FARM_MEMBER *f, RPC_SESSION_STATUS *t);
+PACK *SiCalledGetSessionStatus(SERVER *s, PACK *p);
+bool SiCallEnumLogFileList(SERVER *s, FARM_MEMBER *f, RPC_ENUM_LOG_FILE *t, char *hubname);
+PACK *SiCalledEnumLogFileList(SERVER *s, PACK *p);
+bool SiCallReadLogFile(SERVER *s, FARM_MEMBER *f, RPC_READ_LOG_FILE *t);
+PACK *SiCalledReadLogFile(SERVER *s, PACK *p);
+int CmpLogFile(void *p1, void *p2);
+LIST *EnumLogFile(char *hubname);
+void EnumLogFileDir(LIST *o, char *dirname);
+void FreeEnumLogFile(LIST *o);
+bool CheckLogFileNameFromEnumList(LIST *o, char *name, char *server_name);
+void AdjoinEnumLogFile(LIST *o, LIST *src);
+void IncrementServerConfigRevision(SERVER *s);
+void GetServerProductName(SERVER *s, char *name, UINT size);
+void GetServerProductNameInternal(SERVER *s, char *name, UINT size);
+void SiGetServerLicenseStatus(SERVER *s, LICENSE_STATUS *st);
+void SiInitDeadLockCheck(SERVER *s);
+void SiFreeDeadLockCheck(SERVER *s);
+void SiDeadLockCheckThread(THREAD *t, void *param);
+void SiCheckDeadLockMain(SERVER *s, UINT timeout);
+void SiDebugLog(SERVER *s, char *msg);
+UINT SiDebug(SERVER *s, RPC_TEST *ret, UINT i, char *str);
+UINT SiDebugProcHelloWorld(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcExit(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcDump(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcRestorePriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcSetHighPriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcGetExeFileName(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcCrash(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+
+typedef UINT (SI_DEBUG_PROC)(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+
+CAPS *NewCaps(char *name, UINT value);
+void FreeCaps(CAPS *c);
+CAPSLIST *NewCapsList();
+int CompareCaps(void *p1, void *p2);
+void AddCaps(CAPSLIST *caps, CAPS *c);
+CAPS *GetCaps(CAPSLIST *caps, char *name);
+void FreeCapsList(CAPSLIST *caps);
+bool GetCapsBool(CAPSLIST *caps, char *name);
+UINT GetCapsInt(CAPSLIST *caps, char *name);
+void AddCapsBool(CAPSLIST *caps, char *name, bool b);
+void AddCapsInt(CAPSLIST *caps, char *name, UINT i);
+void InRpcCapsList(CAPSLIST *t, PACK *p);
+void OutRpcCapsList(PACK *p, CAPSLIST *t);
+void FreeRpcCapsList(CAPSLIST *t);
+void InitCapsList(CAPSLIST *t);
+void InRpcSysLogSetting(SYSLOG_SETTING *t, PACK *p);
+void OutRpcSysLogSetting(PACK *p, SYSLOG_SETTING *t);
+
+void GetServerCaps(SERVER *s, CAPSLIST *t);
+bool GetServerCapsBool(SERVER *s, char *name);
+UINT GetServerCapsInt(SERVER *s, char *name);
+void GetServerCapsMain(SERVER *s, CAPSLIST *t);
+void InitServerCapsCache(SERVER *s);
+void FreeServerCapsCache(SERVER *s);
+void DestroyServerCapsCache(SERVER *s);
+
+bool MakeServerSnapshot(SERVER *s, UINT64 now, SERVER_SNAPSHOT *t);
+void FreeSnapshot(SERVER_SNAPSHOT *t);
+void InitServerSnapshot(SERVER *s);
+void FreeServerSnapshot(SERVER *s);
+void ServerSnapshotThread(THREAD *t, void *param);
+void WriteServerSnapshotLog(SERVER *s, SERVER_SNAPSHOT *t);
+BUF *ServerSnapshotToBuf(SERVER_SNAPSHOT *t);
+bool IsAdminPackSupportedServerProduct(char *name);
+
+void SiInitHubCreateHistory(SERVER *s);
+void SiFreeHubCreateHistory(SERVER *s);
+void SiDeleteOldHubCreateHistory(SERVER *s);
+void SiAddHubCreateHistory(SERVER *s, char *name);
+void SiDelHubCreateHistory(SERVER *s, char *name);
+bool SiIsHubRegistedOnCreateHistory(SERVER *s, char *name);
+
+UINT SiGetServerNumUserObjects(SERVER *s);
+bool SiTooManyUserObjectsInServer(SERVER *s, bool oneMore);
+
+#endif	// SERVER_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Session.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Session.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Session.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2103 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Session.c
+// セッションマネージャ
+
+#include "CedarPch.h"
+
+// セッションのメインルーチン
+void SessionMain(SESSION *s)
+{
+	CONNECTION *c;
+	POLICY *policy;
+	UINT64 now;
+	UINT i = 0;
+	PACKET_ADAPTER *pa;
+	bool pa_inited = false;
+	UINT packet_size;
+	void *packet;
+	bool packet_put;
+	bool pa_fail = false;
+	UINT test = 0;
+	bool update_hub_last_comm = false;
+	UINT err = ERR_SESSION_TIMEOUT;
+	UINT64 next_update_hub_last_comm = 0;
+	UINT64 auto_disconnect_tick = 0;
+	TRAFFIC t;
+	SOCK *msgdlg_sock = NULL;
+	SOCK *nicinfo_sock = NULL;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+	Debug("SessionMain: %s\n", s->Name);
+
+	Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+	// リトライ回数のリセット
+	s->CurrentRetryCount = 0;
+	s->ConnectSucceed = true;
+	s->SessionTimeOuted = false;
+
+	c = s->Connection;
+	policy = s->Policy;
+
+	// パケットアダプタの初期化
+	pa = s->PacketAdapter;
+	if (pa->Init(s) == false)
+	{
+		// 初期化失敗
+		if (s->VLanDeviceErrorCount >= 2)
+		{
+			s->ForceStopFlag = true;
+		}
+		else
+		{
+			s->VLanDeviceErrorCount++;
+		}
+		err = ERR_DEVICE_DRIVER_ERROR;
+		goto CLEANUP;
+	}
+	pa_inited = true;
+
+	if (s->BridgeMode == false)
+	{
+		s->Cancel2 = pa->GetCancel(s);
+	}
+	else
+	{
+		CANCEL *c = pa->GetCancel(s);
+		CANCEL *old = s->Cancel1;
+		s->Cancel1 = c;
+		ReleaseCancel(old);
+	}
+
+	s->RetryFlag = false;
+
+	s->LastCommTime = Tick64();
+	if (s->ServerMode == false)
+	{
+		s->NextConnectionTime = Tick64() + (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000);
+	}
+
+	s->NumConnectionsEatablished++;
+	s->CurrentConnectionEstablishTime = Tick64();
+	if (s->FirstConnectionEstablisiedTime == 0)
+	{
+		s->FirstConnectionEstablisiedTime = Tick64();
+	}
+
+	if (s->ServerMode == false && s->Cedar->Client != NULL)
+	{
+		if (s->Policy != NULL)
+		{
+			if (s->Policy->AutoDisconnect)
+			{
+				auto_disconnect_tick = s->CurrentConnectionEstablishTime +
+					(UINT64)s->Policy->AutoDisconnect * 1000ULL;
+			}
+		}
+	}
+
+	s->LastIncrementTraffic = Tick64();
+
+	c->Err = ERR_SESSION_TIMEOUT;
+	s->VLanDeviceErrorCount = 0;
+
+	s->LastTryAddConnectTime = Tick64();
+
+	Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+	if (policy != NULL)
+	{
+		// ポリシーの内容を見てモードを決定する
+		if (policy->MonitorPort)
+		{
+			s->IsMonitorMode = true;
+		}
+
+		if (policy->NoRouting == false || policy->NoBridge == false)
+		{
+			s->IsBridgeMode = true;
+		}
+	}
+
+	if (s->ServerMode == false && s->Cedar->Client != NULL)
+	{
+		if (IsEmptyUniStr(s->Client_Message) == false)
+		{
+			UI_MSG_DLG dlg;
+
+			Zero(&dlg, sizeof(dlg));
+			if (s->ClientOption != NULL)
+			{
+				StrCpy(dlg.HubName, sizeof(dlg.HubName), s->ClientOption->HubName);
+				StrCpy(dlg.ServerName, sizeof(dlg.ServerName), s->ClientOption->Hostname);
+			}
+
+			dlg.Msg = s->Client_Message;
+
+			msgdlg_sock = CncMsgDlg(&dlg);
+		}
+
+		if (s->Win32HideNicInfoWindow == false)
+		{
+			UI_NICINFO info;
+
+			Zero(&info, sizeof(info));
+			if (s->ClientOption != NULL)
+			{
+				StrCpy(info.NicName, sizeof(info.NicName), s->ClientOption->DeviceName);
+				UniStrCpy(info.AccountName, sizeof(info.AccountName), s->ClientOption->AccountName);
+			}
+
+			nicinfo_sock = CncNicInfo(&info);
+		}
+	}
+
+	while (true)
+	{
+		Zero(&t, sizeof(t));
+
+		if (next_update_hub_last_comm == 0 ||
+			(next_update_hub_last_comm <= Tick64()))
+		{
+			next_update_hub_last_comm = Tick64() + 1000;
+
+			if (s->Hub != NULL)
+			{
+				if (update_hub_last_comm)
+				{
+					Lock(s->Hub->lock);
+					{
+						s->Hub->LastCommTime = SystemTime64();
+					}
+					Unlock(s->Hub->lock);
+
+					update_hub_last_comm = false;
+				}
+			}
+		}
+
+		// 追加接続のチャンス
+		ClientAdditionalConnectChance(s);
+
+		// ブロックを受信
+		ConnectionReceive(c, s->Cancel1, s->Cancel2);
+
+		// 受信したブロックを PacketAdapter に渡す
+		LockQueue(c->ReceivedBlocks);
+		{
+			BLOCK *b;
+			packet_put = false;
+			while (true)
+			{
+				b = GetNext(c->ReceivedBlocks);
+				if (b == NULL)
+				{
+					break;
+				}
+
+				PROBE_DATA2("GetNext", b->Buf, b->Size);
+
+				update_hub_last_comm = true;
+
+				if (s->ServerMode == false && b->Size >= 14)
+				{
+					if (b->Buf[0] & 0x40)
+					{
+						t.Recv.BroadcastCount++;
+						t.Recv.BroadcastBytes += (UINT64)b->Size;
+					}
+					else
+					{
+						t.Recv.UnicastCount++;
+						t.Recv.UnicastBytes += (UINT64)b->Size;
+					}
+				}
+
+				packet_put = true;
+				PROBE_DATA2("pa->PutPacket", b->Buf, b->Size);
+				if (pa->PutPacket(s, b->Buf, b->Size) == false)
+				{
+					pa_fail = true;
+					err = ERR_DEVICE_DRIVER_ERROR;
+					Free(b->Buf);
+					Debug("  Error: pa->PutPacket(Packet) Failed.\n");
+				}
+				Free(b);
+			}
+
+			if (packet_put || s->ServerMode)
+			{
+				PROBE_DATA2("pa->PutPacket", NULL, 0);
+				if (pa->PutPacket(s, NULL, 0) == false)
+				{
+					Debug("  Error: pa->PutPacket(NULL) Failed.\n");
+					pa_fail = true;
+					err = ERR_DEVICE_DRIVER_ERROR;
+				}
+			}
+		}
+		UnlockQueue(c->ReceivedBlocks);
+
+		// 送信するべきパケットを PacketAdapter から取得して SendBlocks に追加
+		LockQueue(c->SendBlocks);
+		{
+			UINT i, max_num = MAX_SEND_SOCKET_QUEUE_NUM;
+			i = 0;
+			while (packet_size = pa->GetNextPacket(s, &packet))
+			{
+				BLOCK *b;
+				if (packet_size == INFINITE)
+				{
+					err = ERR_DEVICE_DRIVER_ERROR;
+					pa_fail = true;
+					Debug("  Error: pa->GetNextPacket() Failed.\n");
+					break;
+				}
+
+				update_hub_last_comm = true;
+
+				if ((c->CurrentSendQueueSize > MAX_BUFFERING_PACKET_SIZE))
+				{
+//					WHERE;
+					// バッファリングサイズ制限値を超過しているので破棄
+					Free(packet);
+				}
+				else
+				{
+					bool priority;
+					// バッファリングする
+					if (s->ServerMode == false && packet_size >= 14)
+					{
+						UCHAR *buf = (UCHAR *)packet;
+						if (buf[0] & 0x01)
+						{
+							t.Send.BroadcastCount++;
+							t.Send.BroadcastBytes += (UINT64)packet_size;
+						}
+						else
+						{
+							t.Send.UnicastCount++;
+							t.Send.UnicastBytes += (UINT64)packet_size;
+						}
+					}
+					priority = IsPriorityHighestPacketForQoS(packet, packet_size);
+					b = NewBlock(packet, packet_size, s->UseCompress ? 1 : 0);
+					b->PriorityQoS = priority;
+					c->CurrentSendQueueSize += b->Size;
+
+					if (b->PriorityQoS && c->Protocol == CONNECTION_TCP && s->QoS)
+					{
+						InsertQueue(c->SendBlocks2, b);
+					}
+					else
+					{
+						InsertQueue(c->SendBlocks, b);
+					}
+				}
+				i++;
+				if (i >= max_num)
+				{
+					break;
+				}
+			}
+		}
+		UnlockQueue(c->SendBlocks);
+
+		AddTrafficForSession(s, &t);
+
+		// ブロックを送信
+		ConnectionSend(c);
+
+		// 自動切断判定
+		if (auto_disconnect_tick != 0 && auto_disconnect_tick <= Tick64())
+		{
+			err = ERR_AUTO_DISCONNECTED;
+			s->CurrentRetryCount = INFINITE;
+			break;
+		}
+
+		// 停止判定
+		if (s->Halt)
+		{
+			if (s->ForceStopFlag)
+			{
+				err = ERR_USER_CANCEL;
+			}
+			break;
+		}
+
+		// 現在時刻を取得
+		now = Tick64();
+
+		if (s->ServerMode)
+		{
+			HUB *hub;
+
+			// ユーザーのトラフィックデータの更新
+			if ((s->LastIncrementTraffic + INCREMENT_TRAFFIC_INTERVAL) <= now)
+			{
+				IncrementUserTraffic(s->Hub, s->UserNameReal, s);
+				s->LastIncrementTraffic = now;
+			}
+
+			hub = s->Hub;
+
+			if (hub != NULL)
+			{
+				Lock(hub->lock);
+				{
+					if ((hub->LastIncrementTraffic + INCREMENT_TRAFFIC_INTERVAL) <= now)
+					{
+						IncrementHubTraffic(s->Hub);
+						hub->LastIncrementTraffic = now;
+					}
+				}
+				Unlock(hub->lock);
+			}
+		}
+
+		// リンクモードサーバーセッションの場合はタイムアウトしない
+		// それ以外のセッションの場合はタイムアウトを判定する
+		if (s->LinkModeServer == false && s->SecureNATMode == false && s->BridgeMode == false && s->L3SwitchMode == false)
+		{
+			bool timeouted = false;
+
+			if ((now > s->LastCommTime) && ((now - s->LastCommTime) >= ((UINT64)s->Timeout)))
+			{
+				// 一定時間通信ができていない場合
+				timeouted = true;
+			}
+
+			if (s->ServerMode == false && s->ClientOption != NULL && s->ClientOption->ConnectionDisconnectSpan == 0)
+			{
+				if (LIST_NUM(s->Connection->Tcp->TcpSockList) < s->MaxConnection)
+				{
+					if ((s->LastTryAddConnectTime +
+						(UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000 * 2 + CONNECTING_TIMEOUT * 2))
+						<= Tick64())
+					{
+						timeouted = true;
+					}
+				}
+			}
+
+			if (timeouted)
+			{
+				// タイムアウトが発生した
+				Debug("** Session Timeouted.\n");
+				s->SessionTimeOuted = true;
+				err = ERR_SESSION_TIMEOUT;
+			}
+		}
+
+		// タイムアウト判定
+		if (pa_fail || s->SessionTimeOuted)
+		{
+			s->Halt = true;
+			s->RetryFlag = true;	// リトライフラグ
+			break;
+		}
+	}
+
+CLEANUP:
+	Debug("Session %s Finishing...\n", s->Name);
+
+	// HUB のセッション一覧から削除する
+	if (s->ServerMode)
+	{
+		// ユーザー情報を更新する
+		IncrementUserTraffic(s->Hub, s->UserNameReal, s);
+
+		DelSession(s->Hub, s);
+	}
+
+	s->ConnectSucceed = false;
+	Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+	if (s->Connection)
+	{
+		s->Connection->Halt = true;
+	}
+
+	// パケットアダプタの解放
+	if (pa_inited)
+	{
+		pa->Free(s);
+	}
+
+	if (s->ServerMode == false)
+	{
+		// すべての追加コネクションの作成をキャンセルする
+		StopAllAdditionalConnectThread(s->Connection);
+	}
+
+	if (s->BridgeMode)
+	{
+		// ブリッジの終了
+		if (s->Bridge->Active)
+		{
+			CloseEth(s->Bridge->Eth);
+			s->Bridge->Eth = NULL;
+		}
+	}
+
+	if (s->Cancel2 != NULL)
+	{
+		// キャンセル2 の解放
+		ReleaseCancel(s->Cancel2);
+		s->Cancel2 = NULL;
+	}
+
+	// コネクションの終了
+	EndTunnelingMode(c);
+
+	if (nicinfo_sock != NULL)
+	{
+		CncNicInfoFree(nicinfo_sock);
+	}
+
+	if (msgdlg_sock != NULL)
+	{
+		CndMsgDlgFree(msgdlg_sock);
+	}
+
+	c->Err = err;
+}
+
+// 次の遅延パケットまでの時間を取得する
+UINT GetNextDelayedPacketTickDiff(SESSION *s)
+{
+	UINT i;
+	UINT ret = 0x7fffffff;
+	UINT64 now;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	if (LIST_NUM(s->DelayedPacketList) >= 1)
+	{
+		now = TickHighres64();
+
+		LockList(s->DelayedPacketList);
+		{
+			for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
+			{
+				PKT *p = LIST_DATA(s->DelayedPacketList, i);
+				UINT64 t = p->DelayedForwardTick;
+				UINT d = 0x7fffffff;
+
+				if (now >= t)
+				{
+					d = 0;
+				}
+				else
+				{
+					d = (UINT)(t - now);
+				}
+
+				ret = MIN(ret, d);
+			}
+		}
+		UnlockList(s->DelayedPacketList);
+	}
+
+	return ret;
+}
+
+// VoIP / QoS 機能で優先すべきパケットかどうか判定する
+bool IsPriorityHighestPacketForQoS(void *data, UINT size)
+{
+	UCHAR *buf;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return false;
+	}
+
+	buf = (UCHAR *)data;
+	if (size >= 16)
+	{
+		if (buf[12] == 0x08 && buf[13] == 0x00 && buf[15] != 0x00 && buf[15] != 0x08)
+		{
+			// IPv4 パケットかつ ToS != 0
+			return true;
+		}
+
+		if (size >= 34 && size <= 128)
+		{
+			if (buf[12] == 0x08 && buf[13] == 0x00 && buf[23] == 0x01)
+			{
+				// IMCPv4 パケット
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+// ユーザーのトラフィック情報を更新する
+void IncrementUserTraffic(HUB *hub, char *username, SESSION *s)
+{
+	TRAFFIC report_traffic;
+	// 引数チェック
+	if (hub == NULL || username == NULL || s == NULL)
+	{
+		return;
+	}
+
+	Lock(s->TrafficLock);
+	{
+		// 報告するトラフィック情報 (前回との差分) を計算する
+		Zero(&report_traffic, sizeof(report_traffic));
+		report_traffic.Send.BroadcastBytes =
+			s->Traffic->Send.BroadcastBytes - s->OldTraffic->Send.BroadcastBytes;
+		report_traffic.Send.BroadcastCount =
+			s->Traffic->Send.BroadcastCount - s->OldTraffic->Send.BroadcastCount;
+		report_traffic.Send.UnicastBytes =
+			s->Traffic->Send.UnicastBytes - s->OldTraffic->Send.UnicastBytes;
+		report_traffic.Send.UnicastCount =
+			s->Traffic->Send.UnicastCount - s->OldTraffic->Send.UnicastCount;
+		report_traffic.Recv.BroadcastBytes =
+			s->Traffic->Recv.BroadcastBytes - s->OldTraffic->Recv.BroadcastBytes;
+		report_traffic.Recv.BroadcastCount =
+			s->Traffic->Recv.BroadcastCount - s->OldTraffic->Recv.BroadcastCount;
+		report_traffic.Recv.UnicastBytes =
+			s->Traffic->Recv.UnicastBytes - s->OldTraffic->Recv.UnicastBytes;
+		report_traffic.Recv.UnicastCount =
+			s->Traffic->Recv.UnicastCount - s->OldTraffic->Recv.UnicastCount;
+		Copy(s->OldTraffic, s->Traffic, sizeof(TRAFFIC));
+
+		if (hub->FarmMember == false)
+		{
+			// ファームメンバーでない場合はローカルデータベースのユーザー情報を更新する
+			AcLock(hub);
+			{
+				USER *u = AcGetUser(hub, username);
+				if (u != NULL)
+				{
+					Lock(u->lock);
+					{
+						AddTraffic(u->Traffic, &report_traffic);
+					}
+					Unlock(u->lock);
+					if (u->Group != NULL)
+					{
+						Lock(u->Group->lock);
+						{
+							AddTraffic(u->Group->Traffic, &report_traffic);
+						}
+						Unlock(u->Group->lock);
+					}
+					ReleaseUser(u);
+				}
+			}
+			AcUnlock(hub);
+		}
+		else
+		{
+			// ファームメンバの場合はトラフィック差分報告リストを更新する
+			AddTrafficDiff(hub, username, TRAFFIC_DIFF_USER, &report_traffic);
+		}
+	}
+	Unlock(s->TrafficLock);
+}
+
+// コネクションのトラフィック情報を加算
+void AddTrafficForSession(SESSION *s, TRAFFIC *t)
+{
+	HUB *h;
+	TRAFFIC t2;
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return;
+	}
+
+	Lock(s->TrafficLock);
+	{
+		AddTraffic(s->Traffic, t);
+	}
+	Unlock(s->TrafficLock);
+
+	if (s->ServerMode)
+	{
+		Zero(&t2, sizeof(t2));
+		Copy(&t2.Recv, &t->Send, sizeof(TRAFFIC_ENTRY));
+		Copy(&t2.Send, &t->Recv, sizeof(TRAFFIC_ENTRY));
+		Lock(s->Cedar->TrafficLock);
+		{
+			AddTraffic(s->Cedar->Traffic, &t2);
+		}
+		Unlock(s->Cedar->TrafficLock);
+
+		h = s->Hub;
+		Lock(h->TrafficLock);
+		{
+			AddTraffic(h->Traffic, &t2);
+		}
+		Unlock(h->TrafficLock);
+	}
+}
+
+// クライアントの追加コネクション確立のチャンス
+void ClientAdditionalConnectChance(SESSION *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (s->ServerMode)
+	{
+		// サーバーモードの場合は追加接続しない
+		return;
+	}
+	if (s->Connection->Protocol != CONNECTION_TCP)
+	{
+		// TCP プロトコル以外の場合は追加接続しない
+		return;
+	}
+
+	while (true)
+	{
+		if (s->Halt)
+		{
+			return;
+		}
+		// 追加コネクションを張る必要があるかどうかを
+		// 現在張っている または 張ろうとしているコネクション数と
+		// MaxConnection プロパティを見て検討する。
+		if (Count(s->Connection->CurrentNumConnection) < s->MaxConnection)
+		{
+			// 現在時刻を取得
+			UINT64 now = Tick64();
+
+			// NextConnectionTime を調べてその時刻を過ぎていればコネクションを
+			// 張ろうとする
+			if (s->NextConnectionTime == 0 ||
+				s->ClientOption->AdditionalConnectionInterval == 0 ||
+				(s->NextConnectionTime <= now))
+			{
+				// 追加コネクションを張る作業を開始する
+				s->NextConnectionTime = now + (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000);
+				SessionAdditionalConnect(s);
+			}
+			else
+			{
+				break;
+			}
+		}
+		else
+		{
+			break;
+		}
+	}
+}
+
+// パケットアダプタの解放
+void FreePacketAdapter(PACKET_ADAPTER *pa)
+{
+	// 引数チェック
+	if (pa == NULL)
+	{
+		return;
+	}
+
+	Free(pa);
+}
+
+// 新しいパケットアダプタの作成
+PACKET_ADAPTER *NewPacketAdapter(PA_INIT *init, PA_GETCANCEL *getcancel, PA_GETNEXTPACKET *getnext,
+								 PA_PUTPACKET *put, PA_FREE *free)
+{
+	PACKET_ADAPTER *pa;
+	// 引数チェック
+	if (init == NULL || getcancel == NULL || getnext == NULL || put == NULL || free == NULL)
+	{
+		return NULL;
+	}
+
+	pa = ZeroMalloc(sizeof(PACKET_ADAPTER));
+
+	pa->Init = init;
+	pa->Free = free;
+	pa->GetCancel = getcancel;
+	pa->GetNextPacket = getnext;
+	pa->PutPacket = put;
+
+	return pa;
+}
+
+// 追加コネクションを張るためのスレッド
+void ClientAdditionalThread(THREAD *t, void *param)
+{
+	SESSION *s;
+	CONNECTION *c;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	s = (SESSION *)param;
+
+	// s->LastTryAddConnectTime = Tick64();
+
+	c = s->Connection;
+	// 接続中カウンタのインクリメント
+	Inc(c->CurrentNumConnection);
+	LockList(c->ConnectingThreads);
+	{
+		// 処理中スレッドに追加
+		Add(c->ConnectingThreads, t);
+		AddRef(t->ref);
+	}
+	UnlockList(c->ConnectingThreads);
+
+	// 初期化の完了を通知
+	NoticeThreadInit(t);
+
+	Debug("Additional Connection #%u\n", Count(c->CurrentNumConnection));
+
+	// 追加コネクションを張る
+	if (ClientAdditionalConnect(c, t) == false)
+	{
+		// 現在処理中のカウンタをデクリメントする
+		Dec(c->CurrentNumConnection);
+	}
+	else
+	{
+		s->LastTryAddConnectTime = Tick64();
+	}
+
+	// 処理中スレッドから削除
+	LockList(c->ConnectingThreads);
+	{
+		// 処理中スレッドから削除
+		if (Delete(c->ConnectingThreads, t))
+		{
+			ReleaseThread(t);
+		}
+	}
+	UnlockList(c->ConnectingThreads);
+	ReleaseSession(s);
+}
+
+// クライアントからサーバーに追加コネクションを張る
+void SessionAdditionalConnect(SESSION *s)
+{
+	THREAD *t;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// s->LastTryAddConnectTime = Tick64();
+
+	AddRef(s->ref);
+	t = NewThread(ClientAdditionalThread, (void *)s);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+}
+
+// クライアントセッションをサーバーに接続する
+bool SessionConnect(SESSION *s)
+{
+	CONNECTION *c;
+	bool ret = false;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	s->ClientStatus = CLIENT_STATUS_CONNECTING;
+
+	Debug("SessionConnect() Started.\n");
+
+	// セッションの初期化
+	Lock(s->lock);
+	{
+		s->Err = ERR_NO_ERROR;
+		if (s->Policy != NULL)
+		{
+			Free(s->Policy);
+			s->Policy = NULL;
+		}
+	}
+	Unlock(s->lock);
+
+	s->CancelConnect = false;
+
+	// クライアントコネクションの作成
+	c = NewClientConnection(s);
+	s->Connection = c;
+
+	// クライアントをサーバーに接続する
+	ret = ClientConnect(c);
+	s->Err = c->Err;
+
+	s->CancelConnect = false;
+
+	if (s->Cedar->Client != NULL)
+	{
+		if (s->Policy != NULL)
+		{
+			if (s->Policy->NoSavePassword)
+			{
+				s->Client_NoSavePassword = true;
+
+				if (s->Account != NULL)
+				{
+					Lock(s->Account->lock);
+					{
+						if (s->Account->ClientAuth != NULL)
+						{
+							if (s->Account->ClientAuth->AuthType == AUTHTYPE_PASSWORD ||
+								s->Account->ClientAuth->AuthType == AUTHTYPE_RADIUS)
+							{
+								Zero(s->Account->ClientAuth->HashedPassword, sizeof(s->Account->ClientAuth->HashedPassword));
+								Zero(s->Account->ClientAuth->PlainPassword, sizeof(s->Account->ClientAuth->PlainPassword));
+							}
+						}
+					}
+					Unlock(s->Account->lock);
+
+					CiSaveConfigurationFile(s->Cedar->Client);
+				}
+			}
+		}
+	}
+
+	if (c->ClientConnectError_NoSavePassword)
+	{
+		s->Client_NoSavePassword = true;
+	}
+
+	// クライアントコネクションの解放
+	s->Connection = NULL;
+	ReleaseConnection(c);
+
+	Lock(s->lock);
+	{
+		if (s->Policy != NULL)
+		{
+			Free(s->Policy);
+			s->Policy = NULL;
+		}
+	}
+	Unlock(s->lock);
+
+	return ret;
+}
+
+// セッションの停止
+void StopSession(SESSION *s)
+{
+	StopSessionEx(s, false);
+}
+void StopSessionEx(SESSION *s, bool no_wait)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// 停止フラグ
+	s->UserCanceled = true;
+	s->CancelConnect = true;
+	s->Halt = true;
+
+	Debug("Stop Session %s\n", s->Name);
+
+	// キャンセル
+	Cancel(s->Cancel1);
+
+	// イベント
+	Set(s->HaltEvent);
+
+	if (s->ServerMode == false)
+	{
+		// クライアントモード
+		if (s->Connection)
+		{
+			StopConnection(s->Connection, no_wait);
+		}
+	}
+	else
+	{
+		// サーバーモード
+		if (s->Connection)
+		{
+			StopConnection(s->Connection, no_wait);
+		}
+	}
+
+	// 停止まで待機
+	if (no_wait == false)
+	{
+		while (true)
+		{
+			s->ForceStopFlag = true;
+			s->Halt = true;
+			if (WaitThread(s->Thread, 20))
+			{
+				break;
+			}
+		}
+	}
+	else
+	{
+		s->ForceStopFlag = true;
+		s->Halt = true;
+	}
+}
+
+// セッションのクリーンアップ
+void CleanupSession(SESSION *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// 遅延パケットリストの解放
+	if (s->DelayedPacketList != NULL)
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
+		{
+			PKT *p = LIST_DATA(s->DelayedPacketList, i);
+
+			Free(p->PacketData);
+			FreePacket(p);
+		}
+
+		ReleaseList(s->DelayedPacketList);
+	}
+
+	// クライアント接続オプションの解放
+	if (s->ClientOption != NULL)
+	{
+		Free(s->ClientOption);
+	}
+
+	// クライアント認証データの解放
+	if (s->ClientAuth != NULL)
+	{
+		if (s->ClientAuth->ClientX != NULL)
+		{
+			FreeX(s->ClientAuth->ClientX);
+		}
+		if (s->ClientAuth->ClientX != NULL)
+		{
+			FreeK(s->ClientAuth->ClientK);
+		}
+		Free(s->ClientAuth);
+	}
+
+	FreeTraffic(s->Traffic);
+	Free(s->Name);
+
+	if (s->Thread != NULL)
+	{
+		ReleaseThread(s->Thread);
+	}
+
+	DeleteLock(s->lock);
+
+	ReleaseEvent(s->HaltEvent);
+
+	if (s->Cancel1)
+	{
+		ReleaseCancel(s->Cancel1);
+	}
+
+	if (s->Cancel2)
+	{
+		ReleaseCancel(s->Cancel2);
+	}
+
+	if (s->Policy)
+	{
+		Free(s->Policy);
+	}
+
+	if (s->Connection)
+	{
+		ReleaseConnection(s->Connection);
+	}
+
+	Free(s->Username);
+
+	if (s->PacketAdapter)
+	{
+		FreePacketAdapter(s->PacketAdapter);
+	}
+
+	if (s->OldTraffic != NULL)
+	{
+		FreeTraffic(s->OldTraffic);
+	}
+
+	DeleteLock(s->TrafficLock);
+
+	if (s->CancelList != NULL)
+	{
+		ReleaseCancelList(s->CancelList);
+	}
+
+	if (s->Client_Message != NULL)
+	{
+		Free(s->Client_Message);
+	}
+
+	DeleteCounter(s->LoggingRecordCount);
+
+	Free(s);
+}
+
+// セッションの解放
+void ReleaseSession(SESSION *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (Release(s->ref) == 0)
+	{
+		CleanupSession(s);
+	}
+}
+
+// セッションの転送データサイズ合計を表示する
+void PrintSessionTotalDataSize(SESSION *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Debug(
+		"-- SESSION TOTAL PKT INFORMATION --\n\n"
+		"      TotalSendSize: %I64u\n"
+		"  TotalSendSizeReal: %I64u\n"
+		"      TotalRecvSize: %I64u\n"
+		"  TotalRecvSizeReal: %I64u\n"
+		"   Compression Rate: %.2f%% (Send)\n"
+		"                     %.2f%% (Recv)\n",
+		s->TotalSendSize, s->TotalSendSizeReal,
+		s->TotalRecvSize, s->TotalRecvSizeReal,
+		(float)((double)s->TotalSendSizeReal / (double)s->TotalSendSize * 100.0f),
+		(float)((double)s->TotalRecvSizeReal / (double)s->TotalRecvSize * 100.0f)
+		);
+
+}
+
+// クライアントスレッド
+void ClientThread(THREAD *t, void *param)
+{
+	SESSION *s;
+	bool use_password_dlg;
+	bool no_save_password = false;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	Debug("ClientThread 0x%x Started.\n", t);
+
+	s = (SESSION *)param;
+	AddRef(s->ref);
+	s->Thread = t;
+	AddRef(t->ref);
+	NoticeThreadInit(t);
+
+	s->ClientStatus = CLIENT_STATUS_CONNECTING;
+	s->RetryFlag = true;
+	s->CurrentRetryCount = 0;
+
+	Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+	if (s->Cedar->Client != NULL)
+	{
+		no_save_password = s->Cedar->Client->DontSavePassword;
+	}
+
+	s->Win32HideConnectWindow = s->ClientOption->HideStatusWindow;
+	s->Win32HideNicInfoWindow = s->ClientOption->HideNicInfoWindow;
+
+	while (true)
+	{
+		CLog(s->Cedar->Client, "LC_CONNECT_1", s->ClientOption->AccountName, s->CurrentRetryCount + 1);
+		if (s->LinkModeClient && s->Link != NULL)
+		{
+			HLog(s->Link->Hub, "LH_CONNECT_1", s->ClientOption->AccountName, s->CurrentRetryCount + 1);
+		}
+
+		Debug("Trying to Connect to Server... (%u / %u)\n", s->CurrentRetryCount + 0,
+			s->ClientOption->NumRetry);
+
+		// 初期化
+//		s->TotalRecvSize = s->TotalRecvSizeReal = 
+//			s->TotalSendSize = s->TotalSendSizeReal = 0;
+		s->NextConnectionTime = 0;
+
+		// 接続を行う
+		s->ClientStatus = CLIENT_STATUS_CONNECTING;
+		s->Halt = false;
+		SessionConnect(s);
+		if (s->UserCanceled)
+		{
+			s->Err = ERR_USER_CANCEL;
+		}
+		Debug("Disconnected. Err = %u : %S\n", s->Err, _E(s->Err));
+
+		PrintSessionTotalDataSize(s);
+
+		CLog(s->Cedar->Client, "LC_CONNECT_ERROR", s->ClientOption->AccountName,
+			GetUniErrorStr(s->Err), s->Err);
+
+		if (s->LinkModeClient && s->Link != NULL)
+		{
+			HLog(s->Link->Hub, "LH_CONNECT_ERROR", s->ClientOption->AccountName,
+				GetUniErrorStr(s->Err), s->Err);
+		}
+
+		s->ClientStatus = CLIENT_STATUS_RETRY;
+
+		if (s->Link != NULL)
+		{
+			((LINK *)s->Link)->LastError = s->Err;
+		}
+
+		if (s->Halt && (s->RetryFlag == false) || s->ForceStopFlag)
+		{
+			// 中断しなければならない
+			if (s->Err == ERR_DEVICE_DRIVER_ERROR)
+			{
+#ifdef	OS_WIN32
+				wchar_t tmp[MAX_SIZE];
+				if (s->Account != NULL && s->Cedar->Client != NULL)
+				{
+					UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_DEVICE_ERROR"), s->ClientOption->DeviceName,
+						s->Err, _E(s->Err));
+					MsgBox(NULL, 0x10000 | 0x40000 | 0x200000 | 0x30, tmp);
+				}
+#endif	// OS_WIN32
+			}
+			break;
+		}
+		// パスワード再入力ダイアログを表示するかどうか判断する
+		use_password_dlg = false;
+
+		if (s->Account != NULL && s->Cedar->Client != NULL)
+		{
+#ifdef	OS_WIN32
+			if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD || s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
+			{
+				if (s->Err == ERR_AUTH_FAILED || s->Err == ERR_PROXY_AUTH_FAILED)
+				{
+					use_password_dlg = true;
+				}
+			}
+#endif	// OS_WIN32
+		}
+
+		// 接続に失敗した または接続が切断された
+		// リトライ間隔の間待機する
+
+		if (use_password_dlg == false)
+		{
+			UINT retry_interval = s->RetryInterval;
+
+			if (s->Err == ERR_HUB_IS_BUSY || s->Err == ERR_LICENSE_ERROR ||
+				s->Err == ERR_HUB_STOPPING || s->Err == ERR_TOO_MANY_USER_SESSION)
+			{
+				retry_interval = RETRY_INTERVAL_SPECIAL;
+			}
+
+			if (s->CurrentRetryCount >= s->ClientOption->NumRetry)
+			{
+				// リトライ回数超過
+
+#ifndef	OS_WIN32
+
+				break;
+
+#else	// OS_WIN32
+
+				if (s->Win32HideConnectWindow == false &&
+					s->Cedar->Client != NULL && s->Account != NULL)
+				{
+					// 再接続ダイアログを出す
+					UI_CONNECTERROR_DLG p;
+					Zero(&p, sizeof(p));
+					UniStrCpy(p.AccountName, sizeof(p.AccountName), s->ClientOption->AccountName);
+					StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
+					p.Err = s->Err;
+					p.CurrentRetryCount = s->CurrentRetryCount + 1;
+					s->Halt = false;
+					p.RetryLimit = 0;
+					p.RetryIntervalSec = 0;
+					p.CancelEvent = s->HaltEvent;
+					p.HideWindow = s->Win32HideConnectWindow;
+					if (CncConnectErrorDlg(s, &p) == false)
+					{
+						// 中断
+						break;
+					}
+					else
+					{
+						s->Win32HideConnectWindow = p.HideWindow;
+						goto SKIP;
+					}
+				}
+				else
+				{
+					break;
+				}
+
+#endif
+			}
+
+#ifndef	OS_WIN32
+
+			// 単純な待機
+			Wait(s->HaltEvent, retry_interval);
+
+#else	// OS_WIN32
+
+			if (s->Win32HideConnectWindow == false &&
+				s->Cedar->Client != NULL && s->Account != NULL)
+			{
+				// 再接続ダイアログを出す
+				UI_CONNECTERROR_DLG p;
+				Zero(&p, sizeof(p));
+				UniStrCpy(p.AccountName, sizeof(p.AccountName), s->ClientOption->AccountName);
+				StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
+				p.Err = s->Err;
+				p.CurrentRetryCount = s->CurrentRetryCount + 1;
+				p.RetryLimit = s->ClientOption->NumRetry;
+				p.RetryIntervalSec = retry_interval;
+				p.CancelEvent = s->HaltEvent;
+				s->Halt = false;
+				p.HideWindow = s->Win32HideConnectWindow;
+				if (CncConnectErrorDlg(s, &p) == false)
+				{
+					// 中断
+					break;
+				}
+				s->Win32HideConnectWindow = p.HideWindow;
+			}
+			else
+			{
+				// 単純な待機
+				Wait(s->HaltEvent, s->RetryInterval);
+			}
+
+#endif	// OS_WIN32
+		}
+		else
+		{
+#ifdef	OS_WIN32
+			// パスワードの再入力を求めて待機
+			UI_PASSWORD_DLG p;
+			Zero(&p, sizeof(p));
+			if (s->Client_NoSavePassword == false)
+			{
+				p.ShowNoSavePassword = true;
+			}
+			p.NoSavePassword = no_save_password;
+			p.CancelEvent = s->HaltEvent;
+			if (s->Err == ERR_PROXY_AUTH_FAILED)
+			{
+				p.ProxyServer = true;
+			}
+
+			if (p.ProxyServer)
+			{
+				StrCpy(p.Username, sizeof(p.Username), s->ClientOption->ProxyUsername);
+				StrCpy(p.Password, sizeof(p.Password), s->ClientOption->ProxyPassword);
+				StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->ProxyName);
+			}
+			else
+			{
+				bool empty = false;
+
+				StrCpy(p.Username, sizeof(p.Username), s->ClientAuth->Username);
+				if (s->ClientAuth->AuthType == AUTHTYPE_RADIUS)
+				{
+					if (StrLen(s->ClientAuth->PlainPassword) == 0)
+					{
+						empty = true;
+					}
+				}
+				else if (s->ClientAuth->AuthType == AUTHTYPE_PASSWORD)
+				{
+					if (IsZero(s->ClientAuth->HashedPassword, sizeof(s->ClientAuth->HashedPassword)))
+					{
+						empty = true;
+					}
+				}
+
+				StrCpy(p.Password, sizeof(p.Password), empty ? "" : HIDDEN_PASSWORD);
+				StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
+			}
+
+			p.RetryIntervalSec = s->RetryInterval / 1000;
+			p.Type = s->ClientAuth->AuthType;
+
+			// パスワード再入力ダイアログを表示する
+			if (CncPasswordDlg(s, &p) == false)
+			{
+				// 接続を中断する
+				break;
+			}
+			else
+			{
+				// ユーザー名を上書きする
+				if (p.ProxyServer)
+				{
+					// プロキシのユーザー名
+					StrCpy(s->ClientOption->ProxyUsername, sizeof(s->ClientOption->ProxyUsername), p.Username);
+				}
+				else
+				{
+					// Server への接続のためのユーザー名
+					StrCpy(s->ClientAuth->Username, sizeof(s->ClientAuth->Username), p.Username);
+					s->ClientAuth->AuthType = p.Type;
+				}
+
+				if (StrCmp(p.Password, HIDDEN_PASSWORD) != 0)
+				{
+					// パスワードを再入力した
+					if (p.ProxyServer)
+					{
+						// プロキシサーバーのパスワード
+						StrCpy(s->ClientOption->ProxyPassword, sizeof(s->ClientOption->ProxyPassword), p.Password);
+					}
+					else
+					{
+						if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
+						{
+							// 平文パスワード認証
+							StrCpy(s->ClientAuth->PlainPassword, sizeof(s->ClientAuth->PlainPassword), p.Password);
+						}
+						else
+						{
+							// 暗号化パスワード認証
+							HashPassword(s->ClientAuth->HashedPassword, s->ClientAuth->Username, p.Password);
+						}
+					}
+				}
+
+				no_save_password = p.NoSavePassword;
+
+				if (s->Account != NULL && s->Cedar->Client != NULL)
+				{
+					s->Cedar->Client->DontSavePassword = no_save_password;
+					if (p.NoSavePassword == false)
+					{
+						// クライアントのアカウントデータベースを更新する
+						if (p.ProxyServer == false)
+						{
+							// Server 接続情報の更新
+							ACCOUNT *a = s->Account;
+							Lock(a->lock);
+							{
+								CiFreeClientAuth(a->ClientAuth);
+								a->ClientAuth = CopyClientAuth(s->ClientAuth);
+							}
+							Unlock(a->lock);
+							CiSaveConfigurationFile(s->Cedar->Client);
+						}
+						else
+						{
+							// Proxy 接続情報の更新
+							ACCOUNT *a = s->Account;
+							Lock(a->lock);
+							{
+								Copy(a->ClientOption, s->ClientOption, sizeof(CLIENT_OPTION));
+							}
+							Unlock(a->lock);
+							CiSaveConfigurationFile(s->Cedar->Client);
+						}
+					}
+				}
+			}
+#endif	// OS_WIN32
+		}
+
+SKIP:
+		// リトライ回数増加
+		if (s->ConnectSucceed == false)
+		{
+			s->CurrentRetryCount++;
+		}
+
+		if (s->ForceStopFlag)
+		{
+			break;
+		}
+	}
+
+	Debug("Session Halt.\n");
+
+	s->ClientStatus = CLIENT_STATUS_IDLE;
+
+	// ここでセッションは終了したとみなす
+	if (s->Account != NULL)
+	{
+		s->Account->ClientSession = NULL;
+		ReleaseSession(s);
+	}
+
+	Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+	ReleaseSession(s);
+}
+
+// セッションの名前比較
+int CompareSession(void *p1, void *p2)
+{
+	SESSION *s1, *s2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(SESSION **)p1;
+	s2 = *(SESSION **)p2;
+	if (s1 == NULL || s2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(s1->Name, s2->Name);
+}
+
+// RPC セッションの作成
+SESSION *NewRpcSession(CEDAR *cedar, CLIENT_OPTION *option)
+{
+	return NewRpcSessionEx(cedar, option, NULL, NULL);
+}
+SESSION *NewRpcSessionEx(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str)
+{
+	return NewRpcSessionEx2(cedar, option, err, client_str, NULL);
+}
+SESSION *NewRpcSessionEx2(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str, void *hWnd)
+{
+	SESSION *s;
+	CONNECTION *c;
+	SOCK *sock;
+	// 引数チェック
+	if (cedar == NULL || option == NULL)
+	{
+		return NULL;
+	}
+
+	s = ZeroMalloc(sizeof(SESSION));
+
+	s->LoggingRecordCount = NewCounter();
+	s->lock = NewLock();
+	s->ref = NewRef();
+	s->Cedar = cedar;
+	s->ServerMode = false;
+	s->Name = CopyStr("CLIENT_RPC_SESSION");
+	s->CreatedTime = s->LastCommTime = Tick64();
+	s->Traffic = NewTraffic();
+	s->HaltEvent = NewEvent();
+	s->TrafficLock = NewLock();
+	s->Cancel1 = NewCancel();
+
+	// クライアント接続オプションのコピー
+	s->ClientOption = Malloc(sizeof(CLIENT_OPTION));
+	Copy(s->ClientOption, option, sizeof(CLIENT_OPTION));
+
+	s->MaxConnection = option->MaxConnection;
+	s->UseEncrypt = option->UseEncrypt;
+	s->UseCompress = option->UseCompress;
+
+	// コネクションの作成
+	c = s->Connection = NewClientConnectionEx(s, client_str, cedar->Version, cedar->Build);
+	c->hWndForUI = hWnd;
+
+	// サーバーへ接続
+	sock = ClientConnectToServer(c);
+	if (sock == NULL)
+	{
+		// 接続失敗
+		if (err != NULL)
+		{
+			*err = c->Err;
+		}
+		ReleaseSession(s);
+		return NULL;
+	}
+
+	// シグネチャの送信
+	if (ClientUploadSignature(sock) == false)
+	{
+		// 失敗
+		if (err != NULL)
+		{
+			*err = c->Err;
+		}
+		ReleaseSession(s);
+		return NULL;
+	}
+
+	// Hello パケットの受信
+	if (ClientDownloadHello(c, sock) == false)
+	{
+		// 失敗
+		if (err != NULL)
+		{
+			*err = c->Err;
+		}
+		ReleaseSession(s);
+		return NULL;
+	}
+
+	return s;
+}
+
+// クライアントセッションの作成
+SESSION *NewClientSessionEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa, ACCOUNT *account)
+{
+	SESSION *s;
+	THREAD *t;
+	// 引数チェック
+	if (cedar == NULL || option == NULL || auth == NULL || pa == NULL ||
+		(auth->AuthType == CLIENT_AUTHTYPE_SECURE && auth->SecureSignProc == NULL))
+	{
+		return NULL;
+	}
+
+	// SESSION オブジェクトの初期化
+	s = ZeroMalloc(sizeof(SESSION));
+
+	s->LoggingRecordCount = NewCounter();
+
+	s->lock = NewLock();
+	s->ref = NewRef();
+	s->Cedar = cedar;
+	s->ServerMode = false;
+	s->Name = CopyStr("CLIENT_SESSION");
+	s->CreatedTime = s->LastCommTime = Tick64();
+	s->Traffic = NewTraffic();
+	s->HaltEvent = NewEvent();
+	s->PacketAdapter = pa;
+	s->TrafficLock = NewLock();
+	s->OldTraffic = NewTraffic();
+	s->Cancel1 = NewCancel();
+	s->CancelList = NewCancelList();
+
+	// クライアント接続オプションのコピー
+	s->ClientOption = Malloc(sizeof(CLIENT_OPTION));
+	Copy(s->ClientOption, option, sizeof(CLIENT_OPTION));
+
+	s->MaxConnection = option->MaxConnection;
+	s->UseEncrypt = option->UseEncrypt;
+	s->UseCompress = option->UseCompress;
+
+	// リトライ間隔の設定
+	s->RetryInterval = MAKESURE(option->RetryInterval, 0, 4000000) * 1000;
+	s->RetryInterval = MAKESURE(s->RetryInterval, MIN_RETRY_INTERVAL, MAX_RETRY_INTERVAL);
+
+	// 追加コネクション作成間隔は最低 1 秒
+	s->ClientOption->AdditionalConnectionInterval = MAX(s->ClientOption->AdditionalConnectionInterval, 1);
+
+	// クライアントモードで仮想 LAN カードを使用しているかどうか保持
+	s->ClientModeAndUseVLan = (StrLen(s->ClientOption->DeviceName) == 0) ? false : true;
+	if (s->ClientOption->NoRoutingTracking)
+	{
+		s->ClientModeAndUseVLan = false;
+	}
+
+	if (StrLen(option->DeviceName) == 0)
+	{
+		// NAT モード
+		s->ClientModeAndUseVLan = false;
+		s->VirtualHost = true;
+	}
+
+	if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+	{
+		// Win9x の場合は半二重モードを禁止する
+		s->ClientOption->HalfConnection = false;
+	}
+
+	// クライアント認証データのコピー
+	s->ClientAuth = Malloc(sizeof(CLIENT_AUTH));
+	Copy(s->ClientAuth, auth, sizeof(CLIENT_AUTH));
+
+	// 証明書と秘密鍵のクローン
+	if (s->ClientAuth->ClientX != NULL)
+	{
+		s->ClientAuth->ClientX = CloneX(s->ClientAuth->ClientX);
+	}
+	if (s->ClientAuth->ClientK != NULL)
+	{
+		s->ClientAuth->ClientK = CloneK(s->ClientAuth->ClientK);
+	}
+
+	if (StrCmpi(s->ClientOption->DeviceName, LINK_DEVICE_NAME) == 0)
+	{
+		// リンククライアントモード
+		s->LinkModeClient = true;
+		s->Link = (LINK *)s->PacketAdapter->Param;
+	}
+
+	if (StrCmpi(s->ClientOption->DeviceName, SNAT_DEVICE_NAME) == 0)
+	{
+		// SecureNAT モード
+		s->SecureNATMode = true;
+	}
+
+	if (StrCmpi(s->ClientOption->DeviceName, BRIDGE_DEVICE_NAME) == 0)
+	{
+		// Bridge モード
+		s->BridgeMode = true;
+	}
+
+	if (s->VirtualHost)
+	{
+		VH *v = (VH *)s->PacketAdapter->Param;
+
+		// セッションオブジェクトを VH に追加
+		v->Session = s;
+		AddRef(s->ref);
+	}
+
+	s->Account = account;
+
+	if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+	{
+		// スマートカード認証の場合はリトライしない
+		s->ClientOption->NumRetry = 0;
+	}
+
+	// クライアントスレッドの作成
+	t = NewThread(ClientThread, (void *)s);
+	WaitThreadInit(t);
+	ReleaseThread(t);
+
+	return s;
+}
+SESSION *NewClientSession(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa)
+{
+	return NewClientSessionEx(cedar, option, auth, pa, NULL);
+}
+
+// 32bit のセッションキーからセッションを取得
+SESSION *GetSessionFromKey32(CEDAR *cedar, UINT key32)
+{
+	HUB *h;
+	UINT i, j;
+	// 引数チェック
+	if (cedar == NULL)
+	{
+		return NULL;
+	}
+
+	LockList(cedar->HubList);
+	{
+		for (i = 0;i < LIST_NUM(cedar->HubList);i++)
+		{
+			h = LIST_DATA(cedar->HubList, i);
+			LockList(h->SessionList);
+			{
+				for (j = 0;j < LIST_NUM(h->SessionList);j++)
+				{
+					SESSION *s = LIST_DATA(h->SessionList, j);
+					Lock(s->lock);
+					{
+						if (s->SessionKey32 == key32)
+						{
+							// セッション発見
+							AddRef(s->ref);
+
+							// ロック解除
+							Unlock(s->lock);
+							UnlockList(h->SessionList);
+							UnlockList(cedar->HubList);
+							return s;
+						}
+					}
+					Unlock(s->lock);
+				}
+			}
+			UnlockList(h->SessionList);
+		}
+	}
+	UnlockList(cedar->HubList);
+
+	return NULL;
+}
+
+// セッションキーからセッションを取得
+SESSION *GetSessionFromKey(CEDAR *cedar, UCHAR *session_key)
+{
+	HUB *h;
+	UINT i, j;
+	// 引数チェック
+	if (cedar == NULL || session_key == NULL)
+	{
+		return NULL;
+	}
+
+	LockList(cedar->HubList);
+	{
+		for (i = 0;i < LIST_NUM(cedar->HubList);i++)
+		{
+			h = LIST_DATA(cedar->HubList, i);
+			LockList(h->SessionList);
+			{
+				for (j = 0;j < LIST_NUM(h->SessionList);j++)
+				{
+					SESSION *s = LIST_DATA(h->SessionList, j);
+					Lock(s->lock);
+					{
+						if (Cmp(s->SessionKey, session_key, SHA1_SIZE) == 0)
+						{
+							// セッション発見
+							AddRef(s->ref);
+
+							// ロック解除
+							Unlock(s->lock);
+							UnlockList(h->SessionList);
+							UnlockList(cedar->HubList);
+							return s;
+						}
+					}
+					Unlock(s->lock);
+				}
+			}
+			UnlockList(h->SessionList);
+		}
+	}
+	UnlockList(cedar->HubList);
+
+	return NULL;
+}
+
+// 新しいセッションキーを作成
+void NewSessionKey(CEDAR *cedar, UCHAR *session_key, UINT *session_key_32)
+{
+	// 引数チェック
+	if (cedar == NULL || session_key == NULL || session_key_32 == NULL)
+	{
+		return;
+	}
+
+	Rand(session_key, SHA1_SIZE);
+	*session_key_32 = Rand32();
+}
+
+bool if_init(SESSION *s);
+CANCEL *if_getcancel(SESSION *s);
+UINT if_getnext(SESSION *s, void **data);
+bool if_putpacket(SESSION *s, void *data, UINT size);
+void if_free(SESSION *s);
+
+
+// サーバーセッションの作成
+SESSION *NewServerSession(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy)
+{
+	SESSION *s;
+	char name[MAX_SIZE];
+	char hub_name_upper[MAX_SIZE];
+	char user_name_upper[MAX_USERNAME_LEN + 1];
+	// 引数チェック
+	if (cedar == NULL || c == NULL || h == NULL || username == NULL || policy == NULL)
+	{
+		return NULL;
+	}
+
+	// SESSION オブジェクトの初期化
+	s = ZeroMalloc(sizeof(SESSION));
+
+	s->LoggingRecordCount = NewCounter();
+	s->lock = NewLock();
+	s->ref = NewRef();
+	s->Cedar = cedar;
+	s->ServerMode = true;
+	s->CreatedTime = s->LastCommTime = Tick64();
+	s->Traffic = NewTraffic();
+	s->HaltEvent = NewEvent();
+	s->Cancel1 = NewCancel();
+	s->CancelList = NewCancelList();
+	s->Thread = c->Thread;
+	s->TrafficLock = NewLock();
+	s->OldTraffic = NewTraffic();
+	s->QoS = GetServerCapsBool(cedar->Server, "b_support_qos");
+	AddRef(s->Thread->ref);
+	s->Hub = h;
+	s->ClientStatus = CLIENT_STATUS_ESTABLISHED;
+
+	// 遅延パケットリスト
+	s->DelayedPacketList = NewList(NULL);
+
+	// HUB 用のパケットアダプタ
+	s->PacketAdapter = GetHubPacketAdapter();
+
+	s->Connection = c;
+	AddRef(c->ref);
+
+	// 新しいセッション名の決定
+	StrCpy(hub_name_upper, sizeof(hub_name_upper), h->Name);
+	StrUpper(hub_name_upper);
+	StrCpy(user_name_upper, sizeof(user_name_upper), username);
+	StrUpper(user_name_upper);
+
+	if ((StrCmpi(username, ADMINISTRATOR_USERNAME) != 0) && (StrCmpi(username, BRIDGE_USER_NAME) != 0) || (cedar->Server == NULL || cedar->Server->ServerType == SERVER_TYPE_STANDALONE))
+	{
+		Format(name, sizeof(name), "SID-%s-%u", user_name_upper, Inc(h->SessionCounter));
+	}
+	else
+	{
+		UCHAR rand[SHA1_SIZE];
+		char tmp[MAX_SIZE];
+		Rand(rand, sizeof(rand));
+		BinToStr(tmp, sizeof(tmp), rand, 3);
+
+		if (StrCmpi(username, BRIDGE_USER_NAME) != 0)
+		{
+			Format(name, sizeof(name), "SID-%s-%s", user_name_upper,
+				tmp);
+		}
+		else
+		{
+			char pc_name[MAX_SIZE];
+			TOKEN_LIST *t;
+
+			GetMachineName(tmp, sizeof(tmp));
+			t = ParseToken(tmp, ".");
+			if (t->NumTokens >= 1)
+			{
+				StrCpy(pc_name, sizeof(pc_name), t->Token[0]);
+			}
+			else
+			{
+				StrCpy(pc_name, sizeof(pc_name), "pc");
+			}
+			FreeToken(t);
+
+			StrUpper(pc_name);
+
+			Format(name, sizeof(name), "SID-%s-%s-%u", user_name_upper, pc_name,
+				Inc(h->SessionCounter));
+		}
+	}
+
+	s->Name = CopyStr(name);
+	s->Policy = policy;
+
+	// HUB に SESSION を追加
+	AddSession(h, s);
+
+	// キーを作成
+	NewSessionKey(cedar, s->SessionKey, &s->SessionKey32);
+
+	return s;
+}
+
+// セッションキーをデバッグ用に表示
+void DebugPrintSessionKey(UCHAR *session_key)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (session_key == NULL)
+	{
+		return;
+	}
+
+	Bit160ToStr(tmp, session_key);
+	Debug("SessionKey: %s\n", tmp);
+}
+
+// クライアントにステータスを表示する
+void PrintStatus(SESSION *s, wchar_t *str)
+{
+	// 引数チェック
+	if (s == NULL || str == NULL || s->Account == NULL || s->Cedar->Client == NULL
+		|| s->Account->StatusPrinter == NULL)
+	{
+		return;
+	}
+
+	// コールバック関数に対してステータスを通知する
+	s->Account->StatusPrinter(s, str);
+}
+
+// キャンセルリストの作成
+LIST *NewCancelList()
+{
+	return NewList(NULL);
+}
+
+// キャンセルリストにキャンセルを追加
+void AddCancelList(LIST *o, CANCEL *c)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || c == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		CANCEL *t = LIST_DATA(o, i);
+		if (t == c)
+		{
+			return;
+		}
+	}
+
+	AddRef(c->ref);
+	Add(o, c);
+}
+
+// キャンセルリスト内の全キャンセルの発行
+void CancelList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		CANCEL *c = LIST_DATA(o, i);
+		Cancel(c);
+		ReleaseCancel(c);
+	}
+
+	DeleteAll(o);
+}
+
+// キャンセルリストの解放
+void ReleaseCancelList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		CANCEL *c = LIST_DATA(o, i);
+		ReleaseCancel(c);
+	}
+
+	ReleaseList(o);
+}
+
+// クライアントに通知
+void Notify(SESSION *s, UINT code)
+{
+	// 引数チェック
+	if (s == NULL || s->Account == NULL || s->Cedar->Client == NULL)
+	{
+		return;
+	}
+
+	CiNotify(s->Cedar->Client);
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Session.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Session.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Session.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,355 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Session.h
+// Session.c のヘッダ
+
+#ifndef	SESSION_H
+#define	SESSION_H
+
+
+
+// パケットアダプタ関数
+typedef bool (PA_INIT)(SESSION *s);
+typedef CANCEL *(PA_GETCANCEL)(SESSION *s);
+typedef UINT (PA_GETNEXTPACKET)(SESSION *s, void **data);
+typedef bool (PA_PUTPACKET)(SESSION *s, void *data, UINT size);
+typedef void (PA_FREE)(SESSION *s);
+
+// クライアント関係関数
+typedef void (CLIENT_STATUS_PRINTER)(SESSION *s, wchar_t *status);
+
+// ノード情報
+struct NODE_INFO
+{
+	char ClientProductName[64];		// クライアント製品名
+	UINT ClientProductVer;			// クライアントバージョン
+	UINT ClientProductBuild;		// クライアントビルド番号
+	char ServerProductName[64];		// サーバー製品名
+	UINT ServerProductVer;			// サーバーバージョン
+	UINT ServerProductBuild;		// サーバービルド番号
+	char ClientOsName[64];			// クライアント OS 名
+	char ClientOsVer[128];			// クライアント OS バージョン
+	char ClientOsProductId[64];		// クライアント OS プロダクト ID
+	char ClientHostname[64];		// クライアントホスト名
+	UINT ClientIpAddress;			// クライアント IP アドレス
+	UINT ClientPort;				// クライアントポート番号
+	char ServerHostname[64];		// サーバーホスト名
+	UINT ServerIpAddress;			// サーバー IP アドレス
+	UINT ServerPort;				// サーバーポート番号
+	char ProxyHostname[64];			// プロキシホスト名
+	UINT ProxyIpAddress;			// プロキシ IP アドレス
+	UINT ProxyPort;					// プロキシポート番号
+	char HubName[64];				// HUB 名
+	UCHAR UniqueId[16];				// ユニーク ID
+	// 以下は IPv6 対応用
+	UCHAR ClientIpAddress6[16];		// クライアント IPv6 アドレス
+	UCHAR ServerIpAddress6[16];		// サーバー IP アドレス
+	UCHAR ProxyIpAddress6[16];		// プロキシ IP アドレス
+	char Padding[304 - (16 * 3)];	// パディング
+};
+
+// パケットアダプタ
+struct PACKET_ADAPTER
+{
+	PA_INIT *Init;
+	PA_GETCANCEL *GetCancel;
+	PA_GETNEXTPACKET *GetNextPacket;
+	PA_PUTPACKET *PutPacket;
+	PA_FREE *Free;
+	void *Param;
+};
+
+// セッション構造体
+struct SESSION
+{
+	LOCK *lock;						// ロック
+	REF *ref;						// 参照カウンタ
+	CEDAR *Cedar;					// Cedar
+	bool LocalHostSession;			// ローカルホストセッション
+	bool ServerMode;				// サーバーモードセッション
+	bool LinkModeClient;			// リンクモードクライアント
+	bool LinkModeServer;			// リンクモードサーバー
+	bool SecureNATMode;				// SecureNAT セッション
+	bool BridgeMode;				// Bridge セッション
+	bool VirtualHost;				// 仮想ホストモード
+	bool L3SwitchMode;				// Layer-3 スイッチモード
+	THREAD *Thread;					// 管理スレッド
+	CONNECTION *Connection;			// コネクション
+	CLIENT_OPTION *ClientOption;	// クライアント接続オプション
+	CLIENT_AUTH *ClientAuth;		// クライアント認証データ
+	volatile bool Halt;				// 停止フラグ
+	volatile bool CancelConnect;	// 接続のキャンセル
+	EVENT *HaltEvent;				// 停止イベント
+	UINT Err;						// エラー値
+	HUB *Hub;						// HUB
+	CANCEL *Cancel1;				// キャンセルオブジェクト 1
+	CANCEL *Cancel2;				// キャンセルオブジェクト 2
+	PACKET_ADAPTER *PacketAdapter;	// パケットアダプタ
+	UCHAR UdpSendKey[16];			// UDP 送信用暗号化鍵
+	UCHAR UdpRecvKey[16];			// UDP 受信用暗号化鍵
+	UINT ClientStatus;				// クライアントステータス
+	bool RetryFlag;					// リトライフラグ (クライアント)
+	bool ForceStopFlag;				// 強制停止フラグ (クライアント)
+	UINT CurrentRetryCount;			// 現在のリトライカウンタ (クライアント)
+	UINT RetryInterval;				// リトライ間隔 (クライアント)
+	bool ConnectSucceed;			// 接続成功フラグ (クライアント)
+	bool SessionTimeOuted;			// セッションがタイムアウトした
+	UINT Timeout;					// タイムアウト時間
+	UINT64 NextConnectionTime;		// 次に追加コネクションを張る時刻
+	IP ServerIP;					// サーバーの IP アドレス
+	bool ClientModeAndUseVLan;		// クライアントモードで仮想 LAN カードを使用
+	bool UseSSLDataEncryption;		// SSL データ暗号化を使用する
+	LOCK *TrafficLock;				// トラフィックデータロック
+	LINK *Link;						// リンクオブジェクトへの参照
+	SNAT *SecureNAT;				// SecureNAT オブジェクトへの参照
+	BRIDGE *Bridge;					// Bridge オブジェクトへの参照
+	NODE_INFO NodeInfo;				// ノード情報
+	UINT64 LastIncrementTraffic;	// 最後にユーザーのトラフィックデータを更新した時刻
+	bool AdministratorMode;			// 管理者モード
+	LIST *CancelList;				// キャンセルリスト
+	L3IF *L3If;						// Layer-3 インターフェイス
+	IP DefaultDns;					// デフォルトの DNS サーバーの IP アドレス
+	bool IPv6Session;				// IPv6 セッション (物理的な通信が IPv6 である)
+	UINT VLanId;					// VLAN ID
+
+	UINT64 CreatedTime;				// 作成日時
+	UINT64 LastCommTime;			// 最終通信日時
+	TRAFFIC *Traffic;				// トラフィックデータ
+	TRAFFIC *OldTraffic;			// 古いトラフィックデータ
+	UINT64 TotalSendSize;			// 合計送信データサイズ
+	UINT64 TotalRecvSize;			// 合計受信データサイズ
+	UINT64 TotalSendSizeReal;		// 合計送信データサイズ (無圧縮)
+	UINT64 TotalRecvSizeReal;		// 合計受信データサイズ (無圧縮)
+	char *Name;						// セッション名
+	char *Username;					// ユーザー名
+	char UserNameReal[MAX_USERNAME_LEN + 1];	// ユーザー名 (本物)
+	char GroupName[MAX_USERNAME_LEN + 1];	// グループ名
+	POLICY *Policy;					// ポリシー
+	UCHAR SessionKey[SHA1_SIZE];	// セッションキー
+	UINT SessionKey32;				// 32bit のセッションキー
+	UINT MaxConnection;				// 最大同時接続 TCP コネクション数
+	bool UseEncrypt;				// 暗号化通信を使用
+	bool UseFastRC4;				// 高速 RC4 暗号化を使用
+	bool UseCompress;				// データ圧縮を使用
+	bool HalfConnection;			// ハーフコネクションモード
+	bool QoS;						// VoIP / QoS
+	bool NoSendSignature;			// シグネチャを送信しない
+	UINT64 FirstConnectionEstablisiedTime;	// 最初のコネクションの接続完了時刻
+	UINT64 CurrentConnectionEstablishTime;	// このコネクションの接続完了時刻
+	UINT NumConnectionsEatablished;	// これまでに確立したコネクション数
+
+	ACCOUNT *Account;				// クライアント アカウント
+	UINT VLanDeviceErrorCount;		// 仮想 LAN カードでエラーが発生した回数
+	bool Win32HideConnectWindow;	// 接続ウインドウを非表示にする
+	bool Win32HideNicInfoWindow;	// NIC 情報ウインドウを非表示にする
+	bool UserCanceled;				// ユーザーによってキャンセルされた
+	UINT64 LastTryAddConnectTime;	// 最後にコネクションの追加を試行しようとした時刻
+
+	bool IsMonitorMode;				// モニタモードか否か
+	bool IsBridgeMode;				// ブリッジモードか否か
+	bool UseClientLicense;			// 割り当てられたクライアントライセンス数
+	bool UseBridgeLicense;			// 割り当てられたブリッジライセンス数
+
+	COUNTER *LoggingRecordCount;	// ロギング中のレコード数のカウンタ
+
+	bool Client_NoSavePassword;		// パスワードの保存を禁止
+	wchar_t *Client_Message;		// サーバーから送信されてきたメッセージ
+
+	LIST *DelayedPacketList;		// 遅延パケットリスト
+	UINT Flag1;
+
+	// D-Link バグ対策
+	UINT64 LastDLinkSTPPacketSendTick;	// 最後の D-Link STP パケット送出時刻
+	UCHAR LastDLinkSTPPacketDataHash[MD5_SIZE];	// 最後の D-Link STP パケットハッシュ
+};
+
+// パスワードダイアログ
+struct UI_PASSWORD_DLG
+{
+	UINT Type;						// パスワードの種類
+	char Username[MAX_USERNAME_LEN + 1];	// ユーザー名
+	char Password[MAX_PASSWORD_LEN + 1];	// パスワード
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	UINT RetryIntervalSec;			// リトライまでの時間
+	EVENT *CancelEvent;				// ダイアログ表示をキャンセルするイベント
+	bool ProxyServer;				// プロキシサーバーに関する認証
+	UINT64 StartTick;				// 開始時刻
+	bool AdminMode;					// 管理モード
+	bool ShowNoSavePassword;		// パスワードを保存しないチェックボックスを表示するかどうか
+	bool NoSavePassword;			// パスワードを保存しないモード
+	SOCK *Sock;						// ソケット
+};
+
+// メッセージダイアログ
+struct UI_MSG_DLG
+{
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	char HubName[MAX_HUBNAME_LEN + 1];	// 仮想 HUB 名
+	wchar_t *Msg;					// 本文
+	SOCK *Sock;						// ソケット
+	bool Halt;						// 閉じるフラグ
+};
+
+// NIC 情報
+struct UI_NICINFO
+{
+	wchar_t AccountName[MAX_SIZE];	// 接続設定名
+	char NicName[MAX_SIZE];			// 仮想 NIC 名
+
+	SOCK *Sock;						// ソケット
+	bool Halt;						// 閉じるフラグ
+	ROUTE_CHANGE *RouteChange;		// ルーティングテーブル変更通知
+	UINT CurrentIcon;				// 現在のアイコン
+	UINT64 CloseAfterTime;			// 自動で閉じる
+};
+
+// 接続エラーダイアログ
+struct UI_CONNECTERROR_DLG
+{
+	EVENT *CancelEvent;				// ダイアログ表示をキャンセルするイベント
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	UINT Err;						// エラーコード
+	UINT CurrentRetryCount;			// 現在のリトライ回数
+	UINT RetryLimit;				// リトライ回数のリミット
+	UINT64 StartTick;				// 開始時刻
+	UINT RetryIntervalSec;			// リトライまでの時間
+	bool HideWindow;				// ウインドウを非表示にする
+	SOCK *Sock;						// ソケット
+};
+
+// サーバー証明書チェックダイアログ
+struct UI_CHECKCERT
+{
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];	// アカウント名
+	char ServerName[MAX_HOST_NAME_LEN + 1];	// サーバー名
+	X *x;							// サーバー証明書
+	X *parent_x;					// 親証明書
+	X *old_x;						// 前回の証明書
+	bool DiffWarning;				// 証明書変造の警告を表示する
+	bool Ok;						// 接続許可フラグ
+	bool SaveServerCert;			// サーバー証明書を保存する
+	SESSION *Session;				// セッション
+	volatile bool Halt;				// 停止フラグ
+	SOCK *Sock;						// ソケット
+};
+
+
+// 関数プロトタイプ
+SESSION *NewClientSessionEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa, struct ACCOUNT *account);
+SESSION *NewClientSession(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa);
+SESSION *NewRpcSession(CEDAR *cedar, CLIENT_OPTION *option);
+SESSION *NewRpcSessionEx(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str);
+SESSION *NewRpcSessionEx2(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str, void *hWnd);
+SESSION *NewServerSession(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy);
+void ClientThread(THREAD *t, void *param);
+void ReleaseSession(SESSION *s);
+void CleanupSession(SESSION *s);
+void StopSession(SESSION *s);
+void StopSessionEx(SESSION *s, bool no_wait);
+bool SessionConnect(SESSION *s);
+bool ClientConnect(CONNECTION *c);
+int CompareSession(void *p1, void *p2);
+PACKET_ADAPTER *NewPacketAdapter(PA_INIT *init, PA_GETCANCEL *getcancel, PA_GETNEXTPACKET *getnext,
+								 PA_PUTPACKET *put, PA_FREE *free);
+void FreePacketAdapter(PACKET_ADAPTER *pa);
+void SessionMain(SESSION *s);
+void NewSessionKey(CEDAR *cedar, UCHAR *session_key, UINT *session_key_32);
+SESSION *GetSessionFromKey(CEDAR *cedar, UCHAR *session_key);
+SESSION *GetSessionFromKey32(CEDAR *cedar, UINT key32);
+void DebugPrintSessionKey(UCHAR *session_key);
+void ClientAdditionalConnectChance(SESSION *s);
+void SessionAdditionalConnect(SESSION *s);
+void ClientAdditionalThread(THREAD *t, void *param);
+void PrintSessionTotalDataSize(SESSION *s);
+void AddTrafficForSession(SESSION *s, TRAFFIC *t);
+void IncrementUserTraffic(HUB *hub, char *username, SESSION *s);
+void Notify(SESSION *s, UINT code);
+void PrintStatus(SESSION *s, wchar_t *str);
+LIST *NewCancelList();
+void ReleaseCancelList(LIST *o);
+void AddCancelList(LIST *o, CANCEL *c);
+void CancelList(LIST *o);
+bool CompareNodeInfo(NODE_INFO *a, NODE_INFO *b);
+bool IsPriorityHighestPacketForQoS(void *data, UINT size);
+UINT GetNextDelayedPacketTickDiff(SESSION *s);
+
+#endif	// SESSION_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/TcpIp.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/TcpIp.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/TcpIp.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1736 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// TcpIp.c
+// TCP/IP プロトコル パケットアナライザ
+
+#include "CedarPch.h"
+
+// パケットに VLAN タグを埋め込む
+void VLanInsertTag(void **packet_data, UINT *packet_size, UINT vlan_id)
+{
+	UINT dest_size;
+	UCHAR *dest_data;
+	UINT src_size;
+	UCHAR *src_data;
+	USHORT vlan_ushort = Endian16(((USHORT)vlan_id) & 0xFFF);
+	// 引数チェック
+	if (packet_data == NULL || *packet_data == NULL || packet_size == NULL ||
+		*packet_size < 14 || vlan_id == 0)
+	{
+		return;
+	}
+
+	src_size = *packet_size;
+	src_data = (UCHAR *)(*packet_data);
+
+	dest_size = src_size + 4;
+	dest_data = Malloc(dest_size);
+
+	dest_data[12] = 0x81;
+	dest_data[13] = 0x00;
+	Copy(&dest_data[14], &vlan_ushort, sizeof(USHORT));
+
+	Copy(&dest_data[0], &src_data[0], 12);
+	Copy(&dest_data[16], &src_data[12], src_size - 12);
+
+	*packet_size = dest_size;
+	*packet_data = dest_data;
+
+	Free(src_data);
+}
+
+// パケットから VLAN タグを取り除く
+bool VLanRemoveTag(void **packet_data, UINT *packet_size, UINT vlan_id)
+{
+	bool has_vlan_tag = false;
+	UCHAR *src_data;
+	UINT src_size;
+	// 引数チェック
+	if (packet_data == NULL || *packet_data == NULL || packet_size == NULL ||
+		*packet_size < 14)
+	{
+		return false;
+	}
+
+	src_data = (UCHAR *)(*packet_data);
+	src_size = *packet_size;
+
+	if (src_data[12] == 0x81 && src_data[13] == 0x00)
+	{
+		if (src_size >= 18)
+		{
+			USHORT vlan_ushort;
+
+			vlan_ushort = Endian16(*((USHORT *)&src_data[14]));
+			vlan_ushort = vlan_ushort & 0xFFF;
+
+			if (vlan_id == 0 || (vlan_ushort == vlan_id))
+			{
+				UINT dest_size = src_size - 4;
+				UINT i;
+
+				for (i = 12;i < dest_size;i++)
+				{
+					src_data[i] = src_data[i + 4];
+				}
+
+				*packet_size = dest_size;
+
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+// ICMPv6 パケットの送信
+BUF *BuildICMPv6(IPV6_ADDR *src_ip, IPV6_ADDR *dest_ip, UCHAR hop_limit, UCHAR type, UCHAR code, void *data, UINT size, UINT id)
+{
+	ICMP_HEADER *icmp;
+	void *data_buf;
+	BUF *ret;
+	// 引数チェック
+	if (src_ip == NULL || dest_ip == NULL || data == NULL)
+	{
+		return NULL;
+	}
+
+	// ヘッダの組み立て
+	icmp = ZeroMalloc(sizeof(ICMP_HEADER) + size);
+	data_buf = ((UCHAR *)icmp) + sizeof(ICMP_HEADER);
+	Copy(data_buf, data, size);
+
+	icmp->Type = type;
+	icmp->Code = code;
+	icmp->Checksum = CalcChecksumForIPv6(src_ip, dest_ip, IP_PROTO_ICMPV6, icmp,
+		sizeof(ICMP_HEADER) + size);
+
+	ret = BuildIPv6(dest_ip, src_ip, id, IP_PROTO_ICMPV6, hop_limit, icmp,
+		sizeof(ICMP_HEADER) + size);
+
+	Free(icmp);
+
+	return ret;
+}
+
+// ICMPv6 近隣要請パケットのビルド
+BUF *BuildICMPv6NeighborSoliciation(IPV6_ADDR *src_ip, IPV6_ADDR *target_ip, UCHAR *my_mac_address, UINT id)
+{
+	ICMPV6_OPTION_LIST opt;
+	ICMPV6_OPTION_LINK_LAYER link;
+	ICMPV6_NEIGHBOR_SOLICIATION_HEADER header;
+	BUF *b;
+	BUF *b2;
+	BUF *ret;
+	// 引数チェック
+	if (src_ip == NULL || target_ip == NULL || my_mac_address == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&link, sizeof(link));
+	Copy(link.Address, my_mac_address, 6);
+
+	Zero(&opt, sizeof(opt));
+	opt.SourceLinkLayer = &link;
+
+	b = BuildICMPv6Options(&opt);
+
+	Zero(&header, sizeof(header));
+	Copy(&header.TargetAddress, target_ip, sizeof(IPV6_ADDR));
+
+	b2 = NewBuf();
+
+	WriteBuf(b2, &header, sizeof(header));
+	WriteBufBuf(b2, b);
+
+	ret = BuildICMPv6(src_ip, target_ip, 255,
+		ICMPV6_TYPE_NEIGHBOR_SOLICIATION, 0, b2->Buf, b2->Size, id);
+
+	FreeBuf(b);
+	FreeBuf(b2);
+
+	return ret;
+}
+
+// キューから次のヘッダ番号を取得
+UCHAR IPv6GetNextHeaderFromQueue(QUEUE *q)
+{
+	UINT *p;
+	UCHAR v;
+	// 引数チェック
+	if (q == NULL)
+	{
+		return IPV6_HEADER_NONE;
+	}
+
+	p = (UINT *)GetNext(q);
+	v = (UCHAR)(*p);
+	Free(p);
+
+	return v;
+}
+
+// IPv6 拡張オプションヘッダ (可変長) の追加
+void BuildAndAddIPv6PacketOptionHeader(BUF *b, IPV6_OPTION_HEADER *opt, UCHAR next_header, UINT size)
+{
+	IPV6_OPTION_HEADER *h;
+	UINT total_size;
+	// 引数チェック
+	if (b == NULL || opt == NULL)
+	{
+		return;
+	}
+
+	total_size = size;
+	if ((total_size % 8) != 0)
+	{
+		total_size = ((total_size / 8) + 1) * 8;
+	}
+
+	h = ZeroMalloc(total_size);
+	Copy(h, opt, size);
+	h->Size = (total_size / 8) - 1;
+	h->NextHeader = next_header;
+
+	WriteBuf(b, h, total_size);
+
+	Free(h);
+}
+
+// IPv6 パケットのビルド
+BUF *BuildIPv6(IPV6_ADDR *dest_ip, IPV6_ADDR *src_ip, UINT id, UCHAR protocol, UCHAR hop_limit, void *data,
+			   UINT size)
+{
+	IPV6_HEADER_PACKET_INFO info;
+	IPV6_HEADER ip_header;
+	BUF *buf;
+	UINT size_for_headers;
+	// 引数チェック
+	if (dest_ip == NULL || src_ip == NULL || data == NULL)
+	{
+		return NULL;
+	}
+	if (hop_limit == 0)
+	{
+		hop_limit = 255;
+	}
+
+	// IPv6 ヘッダ
+	Zero(&ip_header, sizeof(ip_header));
+	IPV6_SET_VERSION(&ip_header, 6);
+	ip_header.HopLimit = hop_limit;
+	Copy(&ip_header.SrcAddress, src_ip, sizeof(IPV6_ADDR));
+	Copy(&ip_header.DestAddress, dest_ip, sizeof(IPV6_ADDR));
+
+	// ヘッダパケット情報の整理
+	Zero(&info, sizeof(info));
+	info.IPv6Header = &ip_header;
+	info.Protocol = protocol;
+	info.Payload = data;
+	info.PayloadSize = size;
+
+	buf = BuildIPv6PacketHeader(&info, &size_for_headers);
+	if (buf == NULL)
+	{
+		return NULL;
+	}
+
+	return buf;
+}
+
+// IPv6 パケットヘッダ部のビルド
+BUF *BuildIPv6PacketHeader(IPV6_HEADER_PACKET_INFO *info, UINT *bytes_before_payload)
+{
+	BUF *b;
+	QUEUE *q;
+	UINT bbp = 0;
+	// 引数チェック
+	if (info == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+	q = NewQueueFast();
+
+	// オプションヘッダの一覧を作成
+	if (info->HopHeader != NULL)
+	{
+		InsertQueueInt(q, IPV6_HEADER_HOP);
+	}
+	if (info->EndPointHeader != NULL)
+	{
+		InsertQueueInt(q, IPV6_HEADER_ENDPOINT);
+	}
+	if (info->RoutingHeader != NULL)
+	{
+		InsertQueueInt(q, IPV6_HEADER_ROUTING);
+	}
+	if (info->FragmentHeader != NULL)
+	{
+		InsertQueueInt(q, IPV6_HEADER_FRAGMENT);
+	}
+	InsertQueueInt(q, info->Protocol);
+
+	// IPv6 ヘッダ
+	info->IPv6Header->NextHeader = IPv6GetNextHeaderFromQueue(q);
+	WriteBuf(b, info->IPv6Header, sizeof(IPV6_HEADER));
+
+	// ホップバイホップオプションヘッダ
+	if (info->HopHeader != NULL)
+	{
+		BuildAndAddIPv6PacketOptionHeader(b, info->HopHeader,
+			IPv6GetNextHeaderFromQueue(q), info->HopHeaderSize);
+	}
+
+	// 終点オプションヘッダ
+	if (info->EndPointHeader != NULL)
+	{
+		BuildAndAddIPv6PacketOptionHeader(b, info->EndPointHeader,
+			IPv6GetNextHeaderFromQueue(q), info->EndPointHeaderSize);
+	}
+
+	// ルーティングヘッダ
+	if (info->RoutingHeader != NULL)
+	{
+		BuildAndAddIPv6PacketOptionHeader(b, info->RoutingHeader,
+			IPv6GetNextHeaderFromQueue(q), info->RoutingHeaderSize);
+	}
+
+	// フラグメントヘッダ
+	if (info->FragmentHeader != NULL)
+	{
+		info->FragmentHeader->NextHeader = IPv6GetNextHeaderFromQueue(q);
+		WriteBuf(b, info->FragmentHeader, sizeof(IPV6_FRAGMENT_HEADER));
+	}
+
+	bbp = b->Size;
+	if (info->FragmentHeader == NULL)
+	{
+		bbp += sizeof(IPV6_FRAGMENT_HEADER);
+	}
+
+	// ペイロード
+	if (info->Protocol != IPV6_HEADER_NONE)
+	{
+		WriteBuf(b, info->Payload, info->PayloadSize);
+	}
+
+	ReleaseQueue(q);
+
+	SeekBuf(b, 0, 0);
+
+	// ペイロード長さ
+	((IPV6_HEADER *)b->Buf)->PayloadLength = Endian16(b->Size - (USHORT)sizeof(IPV6_HEADER));
+
+	if (bytes_before_payload != NULL)
+	{
+		// ペイロードの直前までの長さ (ただしフラグメントヘッダは必ず含まれると仮定)
+		// を計算する
+		*bytes_before_payload = bbp;
+	}
+
+	return b;
+}
+
+// ICMPv6 パケットのオプション値のビルド
+void BuildICMPv6OptionValue(BUF *b, UCHAR type, void *header_pointer, UINT total_size)
+{
+	UINT packet_size;
+	UCHAR *packet;
+	ICMPV6_OPTION *opt;
+	// 引数チェック
+	if (b == NULL || header_pointer == NULL)
+	{
+		return;
+	}
+
+	packet_size = ((total_size + 7) / 8) * 8;
+	packet = ZeroMalloc(packet_size);
+
+	Copy(packet, header_pointer, total_size);
+	opt = (ICMPV6_OPTION *)packet;
+	opt->Length = (UCHAR)(packet_size / 8);
+	opt->Type = type;
+
+	WriteBuf(b, packet, packet_size);
+
+	Free(packet);
+}
+
+// ICMPv6 パケットのオプションのビルド
+BUF *BuildICMPv6Options(ICMPV6_OPTION_LIST *o)
+{
+	BUF *b;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+
+	if (o->SourceLinkLayer != NULL)
+	{
+		BuildICMPv6OptionValue(b, ICMPV6_OPTION_TYPE_SOURCE_LINK_LAYER, o->SourceLinkLayer, sizeof(ICMPV6_OPTION_LINK_LAYER));
+	}
+	if (o->TargetLinkLayer != NULL)
+	{
+		BuildICMPv6OptionValue(b, ICMPV6_OPTION_TYPE_TARGET_LINK_LAYER, o->TargetLinkLayer, sizeof(ICMPV6_OPTION_LINK_LAYER));
+	}
+	if (o->Prefix != NULL)
+	{
+		BuildICMPv6OptionValue(b, ICMPV6_OPTION_TYPE_PREFIX, o->Prefix, sizeof(ICMPV6_OPTION_PREFIX));
+	}
+	if (o->Mtu != NULL)
+	{
+		BuildICMPv6OptionValue(b, ICMPV6_OPTION_TYPE_MTU, o->Mtu, sizeof(ICMPV6_OPTION_MTU));
+	}
+
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// チェックサム計算
+USHORT CalcChecksumForIPv6(IPV6_ADDR *src_ip, IPV6_ADDR *dest_ip, UCHAR protocol, void *data, UINT size)
+{
+	UCHAR *tmp;
+	UINT tmp_size;
+	IPV6_PSEUDO_HEADER *ph;
+	USHORT ret;
+	// 引数チェック
+	if (data == NULL && size != 0)
+	{
+		return 0;
+	}
+
+	tmp_size = size + sizeof(IPV6_PSEUDO_HEADER);
+	tmp = ZeroMalloc(tmp_size);
+
+	ph = (IPV6_PSEUDO_HEADER *)tmp;
+	Copy(&ph->SrcAddress, src_ip, sizeof(IPV6_ADDR));
+	Copy(&ph->DestAddress, dest_ip, sizeof(IPV6_ADDR));
+	ph->UpperLayerPacketSize = Endian32(size);
+	ph->NextHeader = protocol;
+
+	Copy(((UCHAR *)tmp) + sizeof(IPV6_PSEUDO_HEADER), data, size);
+
+	ret = IpChecksum(tmp, tmp_size);
+
+	Free(tmp);
+
+	return ret;
+}
+
+// クローンされたパケットを解放する
+void FreeClonePacket(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	Free(p->IPv6HeaderPacketInfo.IPv6Header);
+	Free(p->IPv6HeaderPacketInfo.HopHeader);
+	Free(p->IPv6HeaderPacketInfo.EndPointHeader);
+	Free(p->IPv6HeaderPacketInfo.RoutingHeader);
+	Free(p->IPv6HeaderPacketInfo.FragmentHeader);
+	Free(p->IPv6HeaderPacketInfo.Payload);
+	Free(p->ICMPv6HeaderPacketInfo.Data);
+	Free(p->ICMPv6HeaderPacketInfo.EchoData);
+	Free(p->ICMPv6HeaderPacketInfo.Headers.HeaderPointer);
+	FreeCloneICMPv6Options(&p->ICMPv6HeaderPacketInfo.OptionList);
+	Free(p->L3.PointerL3);
+	Free(p->L4.PointerL4);
+	Free(p->L7.PointerL7);
+	Free(p->PacketData);
+	Free(p->MacHeader);
+	Free(p);
+}
+
+// パケットヘッダをコピーする
+PKT *ClonePacket(PKT *p, bool copy_data)
+{
+	PKT *ret;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMallocFast(sizeof(PKT));
+	ret->PacketSize = p->PacketSize;
+
+	// MAC ヘッダのコピー
+	ret->MacHeader = MallocFast(sizeof(MAC_HEADER));
+	Copy(ret->MacHeader, p->MacHeader, sizeof(MAC_HEADER));
+
+	// MAC フラグのコピー
+	ret->BroadcastPacket = p->BroadcastPacket;
+	ret->InvalidSourcePacket = p->InvalidSourcePacket;
+
+	// IPv6 関係構造体のコピー
+	Copy(&ret->IPv6HeaderPacketInfo, &p->IPv6HeaderPacketInfo, sizeof(IPV6_HEADER_PACKET_INFO));
+	Copy(&ret->ICMPv6HeaderPacketInfo, &p->ICMPv6HeaderPacketInfo, sizeof(ICMPV6_HEADER_INFO));
+
+	// Layer 3
+	ret->TypeL3 = p->TypeL3;
+	switch (ret->TypeL3)
+	{
+	case L3_ARPV4:
+		// ARP パケット
+		ret->L3.ARPv4Header = MallocFast(sizeof(ARPV4_HEADER));
+		Copy(ret->L3.ARPv4Header, p->L3.ARPv4Header, sizeof(ARPV4_HEADER));
+		break;
+
+	case L3_IPV4:
+		// IPv4 パケット
+		ret->L3.IPv4Header = MallocFast(sizeof(IPV4_HEADER));
+		Copy(ret->L3.IPv4Header, p->L3.IPv4Header, sizeof(IPV4_HEADER));
+		break;
+
+	case L3_IPV6:
+		// IPv6 パケット
+		ret->L3.IPv6Header = MallocFast(sizeof(IPV6_HEADER));
+		Copy(ret->L3.IPv6Header, p->L3.IPv6Header, sizeof(IPV6_HEADER));
+
+		ret->IPv6HeaderPacketInfo.IPv6Header = Clone(p->IPv6HeaderPacketInfo.IPv6Header,
+			sizeof(IPV6_HEADER));
+
+		ret->IPv6HeaderPacketInfo.HopHeader = Clone(p->IPv6HeaderPacketInfo.HopHeader,
+			sizeof(IPV6_OPTION_HEADER));
+
+		ret->IPv6HeaderPacketInfo.EndPointHeader = Clone(p->IPv6HeaderPacketInfo.EndPointHeader,
+			sizeof(IPV6_OPTION_HEADER));
+
+		ret->IPv6HeaderPacketInfo.RoutingHeader = Clone(p->IPv6HeaderPacketInfo.RoutingHeader,
+			sizeof(IPV6_OPTION_HEADER));
+
+		ret->IPv6HeaderPacketInfo.FragmentHeader = Clone(p->IPv6HeaderPacketInfo.FragmentHeader,
+			sizeof(IPV6_FRAGMENT_HEADER));
+
+		ret->IPv6HeaderPacketInfo.Payload = Clone(p->IPv6HeaderPacketInfo.Payload,
+			p->IPv6HeaderPacketInfo.PayloadSize);
+		break;
+	}
+
+	// Layer 4
+	ret->TypeL4 = p->TypeL4;
+	switch (ret->TypeL4)
+	{
+	case L4_ICMPV4:
+		// ICMPv4 パケット
+		ret->L4.ICMPHeader = MallocFast(sizeof(ICMP_HEADER));
+		Copy(ret->L4.ICMPHeader, p->L4.ICMPHeader, sizeof(ICMP_HEADER));
+		break;
+
+	case L4_ICMPV6:
+		// ICMPv6 パケット
+		ret->L4.ICMPHeader = MallocFast(sizeof(ICMP_HEADER));
+		Copy(ret->L4.ICMPHeader, p->L4.ICMPHeader, sizeof(ICMP_HEADER));
+
+		ret->ICMPv6HeaderPacketInfo.Data = Clone(p->ICMPv6HeaderPacketInfo.Data,
+			p->ICMPv6HeaderPacketInfo.DataSize);
+
+		ret->ICMPv6HeaderPacketInfo.EchoData = Clone(p->ICMPv6HeaderPacketInfo.EchoData,
+			p->ICMPv6HeaderPacketInfo.EchoDataSize);
+
+		switch (ret->ICMPv6HeaderPacketInfo.Type)
+		{
+		case ICMPV6_TYPE_ECHO_REQUEST:
+		case ICMPV6_TYPE_ECHO_RESPONSE:
+			break;
+
+		case ICMPV6_TYPE_ROUTER_SOLICIATION:
+			ret->ICMPv6HeaderPacketInfo.Headers.RouterSoliciationHeader =
+				Clone(p->ICMPv6HeaderPacketInfo.Headers.RouterSoliciationHeader,
+				sizeof(ICMPV6_ROUTER_SOLICIATION_HEADER));
+			break;
+
+		case ICMPV6_TYPE_ROUTER_ADVERTISEMENT:
+			ret->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader =
+				Clone(p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader,
+				sizeof(ICMPV6_ROUTER_ADVERTISEMENT_HEADER));
+			break;
+
+		case ICMPV6_TYPE_NEIGHBOR_SOLICIATION:
+			ret->ICMPv6HeaderPacketInfo.Headers.NeighborSoliciationHeader =
+				Clone(p->ICMPv6HeaderPacketInfo.Headers.NeighborSoliciationHeader,
+				sizeof(ICMPV6_NEIGHBOR_SOLICIATION_HEADER));
+			break;
+
+		case ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT:
+			ret->ICMPv6HeaderPacketInfo.Headers.NeighborAdvertisementHeader =
+				Clone(p->ICMPv6HeaderPacketInfo.Headers.NeighborAdvertisementHeader,
+				sizeof(ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER));
+			break;
+		}
+
+		CloneICMPv6Options(&ret->ICMPv6HeaderPacketInfo.OptionList,
+			&p->ICMPv6HeaderPacketInfo.OptionList);
+		break;
+
+	case L4_TCP:
+		// TCP パケット
+		ret->L4.TCPHeader = MallocFast(sizeof(TCP_HEADER));
+		Copy(ret->L4.TCPHeader, p->L4.TCPHeader, sizeof(TCP_HEADER));
+		break;
+
+	case L4_UDP:
+		// UDP パケット
+		ret->L4.UDPHeader = MallocFast(sizeof(UDP_HEADER));
+		Copy(ret->L4.UDPHeader, p->L4.UDPHeader, sizeof(UDP_HEADER));
+		break;
+	}
+
+	// Layer 7
+	ret->TypeL7 = p->TypeL7;
+	switch (ret->TypeL7)
+	{
+	case L7_DHCPV4:
+		// DHCP パケット
+		ret->L7.DHCPv4Header = MallocFast(sizeof(DHCPV4_HEADER));
+		Copy(ret->L7.DHCPv4Header, p->L7.DHCPv4Header, sizeof(DHCPV4_HEADER));
+		break;
+	}
+
+	// アドレスデータ
+	ret->MacAddressSrc = ret->MacHeader->SrcAddress;
+	ret->MacAddressDest = ret->MacHeader->DestAddress;
+
+	if (copy_data)
+	{
+		// パケット本体もコピー
+		ret->PacketData = MallocFast(p->PacketSize);
+		Copy(ret->PacketData, p->PacketData, p->PacketSize);
+	}
+
+	return ret;
+}
+
+// パケットの中身をパースする
+PKT *ParsePacket(UCHAR *buf, UINT size)
+{
+	return ParsePacketEx(buf, size, false);
+}
+PKT *ParsePacketEx(UCHAR *buf, UINT size, bool no_l3)
+{
+	return ParsePacketEx2(buf, size, no_l3, 0);
+}
+PKT *ParsePacketEx2(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id)
+{
+	return ParsePacketEx3(buf, size, no_l3, vlan_type_id, true);
+}
+PKT *ParsePacketEx3(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id, bool bridge_id_as_mac_address)
+{
+	PKT *p;
+	// 引数チェック
+	if (buf == NULL || size == 0)
+	{
+		return NULL;
+	}
+
+	if (vlan_type_id == 0)
+	{
+		vlan_type_id = MAC_PROTO_TAGVLAN;
+	}
+
+	p = ZeroMallocFast(sizeof(PKT));
+
+	p->VlanTypeID = vlan_type_id;
+
+	// パース実行
+	if (ParsePacketL2Ex(p, buf, size, no_l3) == false)
+	{
+		// パース失敗
+		FreePacket(p);
+		return NULL;
+	}
+
+	p->PacketData = buf;
+	p->PacketSize = size;
+
+	p->MacAddressSrc = p->MacHeader->SrcAddress;
+	p->MacAddressDest = p->MacHeader->DestAddress;
+
+	if (bridge_id_as_mac_address)
+	{
+		if (p->TypeL3 == L3_BPDU)
+		{
+			if (p->L3.BpduHeader != NULL)
+			{
+				p->MacAddressSrc = p->L3.BpduHeader->BridgeMacAddress;
+			}
+		}
+	}
+
+	// パース成功
+	return p;
+}
+
+
+// Layer-2 パース
+bool ParsePacketL2(PKT *p, UCHAR *buf, UINT size)
+{
+	return ParsePacketL2Ex(p, buf, size, false);
+}
+bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3)
+{
+	UINT i;
+	bool b1, b2;
+	USHORT type_id_16;
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(MAC_HEADER))
+	{
+		return false;
+	}
+
+	// MAC ヘッダ
+	p->MacHeader = (MAC_HEADER *)buf;
+
+	buf += sizeof(MAC_HEADER);
+	size -= sizeof(MAC_HEADER);
+
+	// MAC ヘッダの解析
+	p->BroadcastPacket = true;
+	b1 = true;
+	b2 = true;
+	for (i = 0;i < 6;i++)
+	{
+		if (p->MacHeader->DestAddress[i] != 0xff)
+		{
+			p->BroadcastPacket = false;
+		}
+		if (p->MacHeader->SrcAddress[i] != 0xff)
+		{
+			b1 = false;
+		}
+		if (p->MacHeader->SrcAddress[i] != 0x00)
+		{
+			b2 = false;
+		}
+	}
+	if (b1 || b2 || (Cmp(p->MacHeader->SrcAddress, p->MacHeader->DestAddress, 6) == 0))
+	{
+		p->InvalidSourcePacket = true;
+	}
+	else
+	{
+		p->InvalidSourcePacket = false;
+	}
+
+	if (p->MacHeader->DestAddress[0] & 0x01)
+	{
+		p->BroadcastPacket = true;
+	}
+
+	// L3 パケットのパース
+	type_id_16 = Endian16(p->MacHeader->Protocol);
+
+	if (type_id_16 > 1500)
+	{
+		// 通常の Ethernet フレーム
+		switch (type_id_16)
+		{
+		case MAC_PROTO_ARPV4:	// ARPv4
+			if (no_l3)
+			{
+				return true;
+			}
+
+			return ParsePacketARPv4(p, buf, size);
+
+		case MAC_PROTO_IPV4:	// IPv4
+			if (no_l3)
+			{
+				return true;
+			}
+
+			return ParsePacketIPv4(p, buf, size);
+
+		case MAC_PROTO_IPV6:	// IPv6
+			if (no_l3)
+			{
+				return true;
+			}
+
+			return ParsePacketIPv6(p, buf, size);
+
+		default:				// 不明
+			if (type_id_16 == p->VlanTypeID)
+			{
+				// VLAN
+				return ParsePacketTAGVLAN(p, buf, size);
+			}
+			else
+			{
+				return true;
+			}
+		}
+	}
+	else
+	{
+		// IEEE 802.3 の古い (パケットのペイロード長が書いてある) フレーム
+		// (BPDU 等で使われていることがある)
+		UINT length = (UINT)type_id_16;
+		LLC_HEADER *llc;
+
+		// 長さが残っているかどうかチェック
+		if (size < length || size < sizeof(LLC_HEADER))
+		{
+			return true;
+		}
+
+		// LLC ヘッダを読む
+		llc = (LLC_HEADER *)buf;
+		buf += sizeof(LLC_HEADER);
+		size -= sizeof(LLC_HEADER);
+
+		// DSAP, SSAP の値によってプロトコルを判定する
+		if (llc->Dsap == LLC_DSAP_BPDU && llc->Ssap == LLC_SSAP_BPDU)
+		{
+			// BPDU (Spanning Tree) である
+			return ParsePacketBPDU(p, buf, size);
+		}
+		else
+		{
+			// 不明なプロトコルである
+			return true;
+		}
+	}
+}
+
+// TAG VLAN パース
+bool ParsePacketTAGVLAN(PKT *p, UCHAR *buf, UINT size)
+{
+	USHORT vlan_ushort;
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(TAGVLAN_HEADER))
+	{
+		return false;
+	}
+
+	// TAG VLAN ヘッダ
+	p->L3.TagVlanHeader = (TAGVLAN_HEADER *)buf;
+	p->TypeL3 = L3_TAGVLAN;
+
+	buf += sizeof(TAGVLAN_HEADER);
+	size -= sizeof(TAGVLAN_HEADER);
+
+	vlan_ushort = Endian16(*((USHORT *)p->L3.TagVlanHeader->Data));
+	vlan_ushort = vlan_ushort & 0xFFF;
+
+	p->VlanId = vlan_ushort;
+
+	return true;
+}
+
+// BPDU パース
+bool ParsePacketBPDU(PKT *p, UCHAR *buf, UINT size)
+{
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(BPDU_HEADER))
+	{
+		return true;
+	}
+
+	// BPDU ヘッダ
+	p->L3.BpduHeader = (BPDU_HEADER *)buf;
+	p->TypeL3 = L3_BPDU;
+
+	buf += sizeof(BPDU_HEADER);
+	size -= sizeof(BPDU_HEADER);
+
+	return true;
+}
+
+// ARPv4 パース
+bool ParsePacketARPv4(PKT *p, UCHAR *buf, UINT size)
+{
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(ARPV4_HEADER))
+	{
+		return false;
+	}
+
+	// ARPv4 ヘッダ
+	p->L3.ARPv4Header = (ARPV4_HEADER *)buf;
+	p->TypeL3 = L3_ARPV4;
+
+	buf += sizeof(ARPV4_HEADER);
+	size -= sizeof(ARPV4_HEADER);
+
+	return true;
+}
+
+// IPv6 拡張ヘッダの解析
+bool ParseIPv6ExtHeader(IPV6_HEADER_PACKET_INFO *info, UCHAR next_header, UCHAR *buf, UINT size)
+{
+	bool ret = false;
+	IPV6_OPTION_HEADER *option_header;
+	UINT option_header_size;
+	UCHAR next_header_2 = IPV6_HEADER_NONE;
+	// 引数チェック
+	if (info == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	info->IsFragment = false;
+
+	while (true)
+	{
+		if (size > 8)
+		{
+			next_header_2 = *((UCHAR *)buf);
+		}
+
+		switch (next_header)
+		{
+		case IPV6_HEADER_HOP:
+		case IPV6_HEADER_ENDPOINT:
+		case IPV6_HEADER_ROUTING:
+			// 可変長ヘッダ
+			if (size < 8)
+			{
+				return false;
+			}
+
+			option_header = (IPV6_OPTION_HEADER *)buf;
+			option_header_size = (option_header->Size + 1) * 8;
+			if (size < option_header_size)
+			{
+				return false;
+			}
+
+			switch (next_header)
+			{
+			case IPV6_HEADER_HOP:
+				info->HopHeader = (IPV6_OPTION_HEADER *)buf;
+				info->HopHeaderSize = option_header_size;
+				break;
+
+			case IPV6_HEADER_ENDPOINT:
+				info->EndPointHeader = (IPV6_OPTION_HEADER *)buf;
+				info->EndPointHeaderSize = option_header_size;
+				break;
+
+			case IPV6_HEADER_ROUTING:
+				info->RoutingHeader = (IPV6_OPTION_HEADER *)buf;
+				info->RoutingHeaderSize = option_header_size;
+				break;
+			}
+
+			buf += option_header_size;
+			size -= option_header_size;
+			break;
+
+		case IPV6_HEADER_FRAGMENT:
+			// フラグメントヘッダ (固定長)
+			if (size < sizeof(IPV6_FRAGMENT_HEADER))
+			{
+				return false;
+			}
+
+			info->FragmentHeader = (IPV6_FRAGMENT_HEADER *)buf;
+
+			if (IPV6_GET_FRAGMENT_OFFSET(info->FragmentHeader) != 0)
+			{
+				info->IsFragment = true;
+			}
+
+			buf += sizeof(IPV6_FRAGMENT_HEADER);
+			size -= sizeof(IPV6_FRAGMENT_HEADER);
+			break;
+
+		default:
+			// 後にペイロードが続くとみなす
+			if (next_header != IPV6_HEADER_NONE)
+			{
+				info->Payload = buf;
+				info->PayloadSize = size;
+			}
+			else
+			{
+				info->Payload = NULL;
+				info->PayloadSize = 0;
+			}
+			info->Protocol = next_header;
+			return true;
+		}
+
+		next_header = next_header_2;
+	}
+}
+
+// IPv6 ヘッダの解析
+bool ParsePacketIPv6Header(IPV6_HEADER_PACKET_INFO *info, UCHAR *buf, UINT size)
+{
+	// 引数チェック
+	if (info == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	Zero(info, sizeof(IPV6_HEADER_PACKET_INFO));
+
+	// IPv6 ヘッダ
+	if (size < sizeof(IPV6_HEADER))
+	{
+		// サイズ不正
+		return false;
+	}
+
+	info->IPv6Header = (IPV6_HEADER *)buf;
+	buf += sizeof(IPV6_HEADER);
+	size -= sizeof(IPV6_HEADER);
+
+	if (IPV6_GET_VERSION(info->IPv6Header) != 6)
+	{
+		// バージョン不正
+		return false;
+	}
+
+	// 拡張ヘッダの解析
+	return ParseIPv6ExtHeader(info, info->IPv6Header->NextHeader, buf, size);
+}
+
+// ICMPv6 パケットのオプションの解析
+bool ParseICMPv6Options(ICMPV6_OPTION_LIST *o, UCHAR *buf, UINT size)
+{
+	// 引数チェック
+	if (o == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	Zero(o, sizeof(ICMPV6_OPTION_LIST));
+
+	// ヘッダ部分の読み込み
+	while (true)
+	{
+		ICMPV6_OPTION *option_header;
+		UINT header_total_size;
+		UCHAR *header_pointer;
+		if (size < sizeof(ICMPV6_OPTION))
+		{
+			// サイズ不足
+			return true;
+		}
+
+		option_header = (ICMPV6_OPTION *)buf;
+		// ヘッダ全体サイズの計算
+		header_total_size = option_header->Length * 8;
+		if (header_total_size == 0)
+		{
+			// サイズがゼロ
+			return true;
+		}
+		if (size < header_total_size)
+		{
+			// サイズ不足
+			return true;
+		}
+
+		header_pointer = buf;
+		buf += header_total_size;
+		size -= header_total_size;
+
+		switch (option_header->Type)
+		{
+		case ICMPV6_OPTION_TYPE_SOURCE_LINK_LAYER:
+		case ICMPV6_OPTION_TYPE_TARGET_LINK_LAYER:
+			// ソース or ターゲットリンクレイヤオプション
+			if (header_total_size >= sizeof(ICMPV6_OPTION_LINK_LAYER))
+			{
+				if (option_header->Type == ICMPV6_OPTION_TYPE_SOURCE_LINK_LAYER)
+				{
+					o->SourceLinkLayer = (ICMPV6_OPTION_LINK_LAYER *)header_pointer;
+				}
+				else
+				{
+					o->TargetLinkLayer = (ICMPV6_OPTION_LINK_LAYER *)header_pointer;
+				}
+			}
+			else
+			{
+				// ICMPv6 パケット破損?
+				return false;
+			}
+			break;
+
+		case ICMPV6_OPTION_TYPE_PREFIX:
+			// プレフィックス情報
+			if (header_total_size >= sizeof(ICMPV6_OPTION_PREFIX))
+			{
+				o->Prefix = (ICMPV6_OPTION_PREFIX *)header_pointer;
+			}
+			else
+			{
+				// ICMPv6 パケット破損?
+			}
+			break;
+
+		case ICMPV6_OPTION_TYPE_MTU:
+			// MTU
+			if (header_total_size >= sizeof(ICMPV6_OPTION_MTU))
+			{
+				o->Mtu = (ICMPV6_OPTION_MTU *)header_pointer;
+			}
+			else
+			{
+				// ICMPv6 パケット破損?
+			}
+			break;
+		}
+	}
+}
+
+// ICMPv6 パース
+bool ParseICMPv6(PKT *p, UCHAR *buf, UINT size)
+{
+	ICMPV6_HEADER_INFO icmp_info;
+	ICMP_HEADER *icmp;
+	ICMP_ECHO *echo;
+	UINT msg_size;
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	Zero(&icmp_info, sizeof(icmp_info));
+
+	if (size < sizeof(ICMP_HEADER))
+	{
+		return false;
+	}
+
+	icmp = (ICMP_HEADER *)buf;
+	p->L4.ICMPHeader = icmp;
+
+	msg_size = size - sizeof(ICMP_HEADER);
+
+	icmp_info.Type = icmp->Type;
+	icmp_info.Code = icmp->Code;
+	icmp_info.Data = ((UCHAR *)buf) + sizeof(ICMP_HEADER);
+	icmp_info.DataSize = msg_size;
+
+	switch (icmp_info.Type)
+	{
+	case ICMPV6_TYPE_ECHO_REQUEST:
+	case ICMPV6_TYPE_ECHO_RESPONSE:
+		// ICMP Echo Request / Response
+		if (icmp_info.DataSize < sizeof(ICMP_ECHO))
+		{
+			return false;
+		}
+
+		echo = (ICMP_ECHO *)icmp_info.Data;
+
+		icmp_info.EchoHeader.Identifier = Endian16(echo->Identifier);
+		icmp_info.EchoHeader.SeqNo = Endian16(echo->SeqNo);
+		icmp_info.EchoData = (UCHAR *)echo + sizeof(ICMP_ECHO);
+		icmp_info.EchoDataSize = icmp_info.DataSize - sizeof(ICMP_ECHO);
+
+		break;
+
+	case ICMPV6_TYPE_ROUTER_SOLICIATION:
+		// ルータ要請
+		if (icmp_info.DataSize < sizeof(ICMPV6_ROUTER_SOLICIATION_HEADER))
+		{
+			return false;
+		}
+
+		icmp_info.Headers.RouterSoliciationHeader =
+			(ICMPV6_ROUTER_SOLICIATION_HEADER *)(((UCHAR *)icmp_info.Data));
+
+		if (ParseICMPv6Options(&icmp_info.OptionList, ((UCHAR *)icmp_info.Headers.HeaderPointer) + sizeof(ICMPV6_ROUTER_SOLICIATION_HEADER),
+			icmp_info.DataSize - sizeof(ICMPV6_ROUTER_SOLICIATION_HEADER)) == false)
+		{
+			return false;
+		}
+
+		break;
+
+	case ICMPV6_TYPE_ROUTER_ADVERTISEMENT:
+		// ルータ広告
+		if (icmp_info.DataSize < sizeof(ICMPV6_ROUTER_ADVERTISEMENT_HEADER))
+		{
+			return false;
+		}
+
+		icmp_info.Headers.RouterAdvertisementHeader =
+			(ICMPV6_ROUTER_ADVERTISEMENT_HEADER *)(((UCHAR *)icmp_info.Data));
+
+		if (ParseICMPv6Options(&icmp_info.OptionList, ((UCHAR *)icmp_info.Headers.HeaderPointer) + sizeof(ICMPV6_ROUTER_ADVERTISEMENT_HEADER),
+			icmp_info.DataSize - sizeof(ICMPV6_ROUTER_ADVERTISEMENT_HEADER)) == false)
+		{
+			return false;
+		}
+
+		break;
+
+	case ICMPV6_TYPE_NEIGHBOR_SOLICIATION:
+		// 近隣要請
+		if (icmp_info.DataSize < sizeof(ICMPV6_NEIGHBOR_SOLICIATION_HEADER))
+		{
+			return false;
+		}
+
+		icmp_info.Headers.NeighborSoliciationHeader =
+			(ICMPV6_NEIGHBOR_SOLICIATION_HEADER *)(((UCHAR *)icmp_info.Data));
+
+		if (ParseICMPv6Options(&icmp_info.OptionList, ((UCHAR *)icmp_info.Headers.HeaderPointer) + sizeof(ICMPV6_NEIGHBOR_SOLICIATION_HEADER),
+			icmp_info.DataSize - sizeof(ICMPV6_NEIGHBOR_SOLICIATION_HEADER)) == false)
+		{
+			return false;
+		}
+
+		break;
+
+	case ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT:
+		// 近隣広告
+		if (icmp_info.DataSize < sizeof(ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER))
+		{
+			return false;
+		}
+
+		icmp_info.Headers.NeighborAdvertisementHeader =
+			(ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER *)(((UCHAR *)icmp_info.Data));
+
+		if (ParseICMPv6Options(&icmp_info.OptionList, ((UCHAR *)icmp_info.Headers.HeaderPointer) + sizeof(ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER),
+			icmp_info.DataSize - sizeof(ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER)) == false)
+		{
+			return false;
+		}
+
+		break;
+	}
+
+	p->TypeL4 = L4_ICMPV6;
+	Copy(&p->ICMPv6HeaderPacketInfo, &icmp_info, sizeof(ICMPV6_HEADER_INFO));
+
+	return true;
+}
+
+// ICMPv6 オプションの解放
+void FreeCloneICMPv6Options(ICMPV6_OPTION_LIST *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	Free(o->SourceLinkLayer);
+	Free(o->TargetLinkLayer);
+	Free(o->Prefix);
+	Free(o->Mtu);
+}
+
+// ICMPv6 オプションのクローン
+void CloneICMPv6Options(ICMPV6_OPTION_LIST *dst, ICMPV6_OPTION_LIST *src)
+{
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	Zero(dst, sizeof(ICMPV6_OPTION_LIST));
+
+	dst->SourceLinkLayer = Clone(src->SourceLinkLayer, sizeof(ICMPV6_OPTION_LINK_LAYER));
+	dst->TargetLinkLayer = Clone(src->TargetLinkLayer, sizeof(ICMPV6_OPTION_LINK_LAYER));
+	dst->Prefix = Clone(src->Prefix, sizeof(ICMPV6_OPTION_PREFIX));
+	dst->Mtu = Clone(src->Mtu, sizeof(ICMPV6_OPTION_MTU));
+}
+
+// IPv6 パース
+bool ParsePacketIPv6(PKT *p, UCHAR *buf, UINT size)
+{
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	if (ParsePacketIPv6Header(&p->IPv6HeaderPacketInfo, buf, size) == false)
+	{
+		return false;
+	}
+
+	p->TypeL3 = L3_IPV6;
+	p->L3.IPv6Header = p->IPv6HeaderPacketInfo.IPv6Header;
+
+	if (p->IPv6HeaderPacketInfo.Payload == NULL)
+	{
+		// ペイロードなし
+		return true;
+	}
+
+	buf = p->IPv6HeaderPacketInfo.Payload;
+	size = p->IPv6HeaderPacketInfo.PayloadSize;
+
+	if (p->IPv6HeaderPacketInfo.IsFragment)
+	{
+		// フラグメントパケットであるからこれ以上解釈しない
+		p->TypeL4 = L4_FRAGMENT;
+		return true;
+	}
+
+	// L4 パケットのパース
+	switch (p->IPv6HeaderPacketInfo.Protocol)
+	{
+	case IP_PROTO_ICMPV6:	// ICMPv6
+		if (ParseICMPv6(p, buf, size) == false)
+		{
+			// ICMPv6 のパースに失敗しても true を返す
+			return true;
+		}
+		else
+		{
+			return true;
+		}
+
+	case IP_PROTO_TCP:		// TCP
+		return ParseTCP(p, buf, size);
+
+	case IP_PROTO_UDP:		// UDP
+		return ParseUDP(p, buf, size);
+
+	default:				// 不明
+		return true;
+	}
+
+	return true;
+}
+
+// IPv4 パース
+bool ParsePacketIPv4(PKT *p, UCHAR *buf, UINT size)
+{
+	UINT header_size;
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(IPV4_HEADER))
+	{
+		return false;
+	}
+
+	// IPv4 ヘッダ
+	p->L3.IPv4Header = (IPV4_HEADER *)buf;
+	p->TypeL3 = L3_IPV4;
+
+	// ヘッダのチェック
+	header_size = IPV4_GET_HEADER_LEN(p->L3.IPv4Header) * 4;
+	if (header_size < sizeof(IPV4_HEADER) || size < header_size)
+	{
+		// ヘッダサイズが不正
+		p->L3.IPv4Header = NULL;
+		p->TypeL3= L3_UNKNOWN;
+		return true;
+	}
+
+	if (IPV4_GET_OFFSET(p->L3.IPv4Header) != 0)
+	{
+		// フラグメント化されているからこれ以上解析しない
+		p->TypeL4 = L4_FRAGMENT;
+		return true;
+	}
+
+	buf += header_size;
+	size -= header_size;
+
+	// L4 パケットのパース
+	switch (p->L3.IPv4Header->Protocol)
+	{
+	case IP_PROTO_ICMPV4:	// ICMPv4
+		return ParseICMPv4(p, buf, size);
+
+	case IP_PROTO_UDP:		// UDP
+		return ParseUDP(p, buf, size);
+
+	case IP_PROTO_TCP:		// TCP
+		return ParseTCP(p, buf, size);
+
+	default:				// 不明
+		return true;
+	}
+}
+
+// ICMPv4 パース
+bool ParseICMPv4(PKT *p, UCHAR *buf, UINT size)
+{
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(ICMP_HEADER))
+	{
+		// サイズが不正
+		return false;
+	}
+
+	// ICMPv4 ヘッダ
+	p->L4.ICMPHeader = (ICMP_HEADER *)buf;
+	p->TypeL4 = L4_ICMPV4;
+
+	buf += sizeof(ICMP_HEADER);
+	size -= sizeof(ICMP_HEADER);
+
+	return true;
+}
+
+// TCP パース
+bool ParseTCP(PKT *p, UCHAR *buf, UINT size)
+{
+	UINT header_size;
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(TCP_HEADER))
+	{
+		// サイズが不正
+		return false;
+	}
+
+	// TCP ヘッダ
+	p->L4.TCPHeader = (TCP_HEADER *)buf;
+	p->TypeL4 = L4_TCP;
+
+	// ヘッダサイズをチェック
+	header_size = TCP_GET_HEADER_SIZE(p->L4.TCPHeader) * 4;
+	if (header_size < sizeof(TCP_HEADER) || size < header_size)
+	{
+		// ヘッダサイズが不正
+		p->L4.TCPHeader = NULL;
+		p->TypeL4 = L4_UNKNOWN;
+		return true;
+	}
+
+	buf += header_size;
+	size -= header_size;
+
+	return true;
+}
+
+// UDP パース
+bool ParseUDP(PKT *p, UCHAR *buf, UINT size)
+{
+	USHORT src_port, dst_port;
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(UDP_HEADER))
+	{
+		// サイズが不正
+		return false;
+	}
+
+	// UDP ヘッダ
+	p->L4.UDPHeader = (UDP_HEADER *)buf;
+	p->TypeL4 = L4_UDP;
+
+	buf += sizeof(UDP_HEADER);
+	size -= sizeof(UDP_HEADER);
+
+	// ポート番号をチェック
+	src_port = Endian16(p->L4.UDPHeader->SrcPort);
+	dst_port = Endian16(p->L4.UDPHeader->DstPort);
+
+	if ((src_port == 67 && dst_port == 68) ||
+		(src_port == 68 && dst_port == 67))
+	{
+		if (p->TypeL3 == L3_IPV4)
+		{
+			// DHCP パケットを発見
+			ParseDHCPv4(p, buf, size);
+		}
+	}
+
+	return true;
+}
+
+// DHCPv4 パース
+void ParseDHCPv4(PKT *p, UCHAR *buf, UINT size)
+{
+	// 引数チェック
+	if (p == NULL || buf == NULL)
+	{
+		return;
+	}
+
+	// サイズをチェック
+	if (size < sizeof(DHCPV4_HEADER))
+	{
+		// サイズが不正
+		return;
+	}
+
+	// DHCPv4 ヘッダ
+	p->L7.DHCPv4Header = (DHCPV4_HEADER *)buf;
+	p->TypeL7 = L7_DHCPV4;
+}
+
+// パケットのメモリを解放する
+void FreePacket(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	if (p->MacHeader != NULL)
+	{
+		switch (p->TypeL3)
+		{
+		case L3_IPV4:
+			FreePacketIPv4(p);
+			break;
+
+		case L3_ARPV4:
+			FreePacketARPv4(p);
+			break;
+
+		case L3_TAGVLAN:
+			FreePacketTagVlan(p);
+			break;
+		}
+	}
+
+	Free(p);
+}
+
+// IPv4 パケットのメモリを解放する
+void FreePacketIPv4(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	switch (p->TypeL4)
+	{
+	case L4_ICMPV4:
+		FreePacketICMPv4(p);
+		break;
+
+	case L4_TCP:
+		FreePacketTCPv4(p);
+		break;
+
+	case L4_UDP:
+		FreePacketUDPv4(p);
+		break;
+	}
+
+	p->L3.IPv4Header = NULL;
+	p->TypeL3 = L3_UNKNOWN;
+}
+
+// タグ VLAN パケットのメモリを解放する
+void FreePacketTagVlan(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	p->L3.TagVlanHeader = NULL;
+	p->TypeL3 = L3_UNKNOWN;
+}
+
+// ARPv4 パケットのメモリを解放する
+void FreePacketARPv4(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	p->L3.ARPv4Header = NULL;
+	p->TypeL3 = L3_UNKNOWN;
+}
+
+// UDPv4 パケットのメモリを解放する
+void FreePacketUDPv4(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	switch (p->TypeL7)
+	{
+	case L7_DHCPV4:
+		FreePacketDHCPv4(p);
+		break;
+	}
+
+	p->L4.UDPHeader = NULL;
+	p->TypeL4 = L4_UNKNOWN;
+}
+
+// TCPv4 パケットのメモリを解放する
+void FreePacketTCPv4(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	p->L4.TCPHeader = NULL;
+	p->TypeL4 = L4_UNKNOWN;
+}
+
+// ICMPv4 パケットのメモリを解放する
+void FreePacketICMPv4(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	p->L4.ICMPHeader = NULL;
+	p->TypeL4 = L4_UNKNOWN;
+}
+
+// DHCPv4 パケットのメモリを解放する
+void FreePacketDHCPv4(PKT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	p->L7.DHCPv4Header = NULL;
+	p->TypeL7 = L7_UNKNOWN;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/TcpIp.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/TcpIp.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/TcpIp.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,666 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// TcpIp.h
+// TcpIp.c のヘッダ
+
+#ifndef	TCPIP_H
+#define	TCPIP_H
+
+#ifdef	OS_WIN32
+#pragma pack(push, 1)
+#endif	// OS_WIN32
+
+// MAC ヘッダ
+struct MAC_HEADER
+{
+	UCHAR	DestAddress[6];			// 送信元 MAC アドレス
+	UCHAR	SrcAddress[6];			// 宛先 MAC アドレス
+	USHORT	Protocol;				// プロトコル
+} GCC_PACKED;
+
+// MAC プロトコル
+#define	MAC_PROTO_ARPV4		0x0806	// ARPv4 パケット
+#define	MAC_PROTO_IPV4		0x0800	// IPv4 パケット
+#define	MAC_PROTO_IPV6		0x86dd	// IPv6 パケット
+#define	MAC_PROTO_TAGVLAN	0x8100	// タグ付き VLAN パケット
+
+// LLC ヘッダ
+struct LLC_HEADER
+{
+	UCHAR	Dsap;
+	UCHAR	Ssap;
+	UCHAR	Ctl;
+} GCC_PACKED;
+
+// LLC ヘッダの DSAP, SSAP の値
+#define	LLC_DSAP_BPDU		0x42
+#define	LLC_SSAP_BPDU		0x42
+
+// BPDU ヘッダ
+struct BPDU_HEADER
+{
+	USHORT	ProtocolId;				// プロトコル ID (STP == 0x0000)
+	UCHAR	Version;				// バージョン
+	UCHAR	Type;					// 種類
+	UCHAR	Flags;					// フラグ
+	USHORT	RootPriority;			// ルートブリッジのプライオリティ
+	UCHAR	RootMacAddress[6];		// ルートブリッジの MAC アドレス
+	UINT	RootPathCost;			// ルートブリッジまでのパスコスト
+	USHORT	BridgePriority;			// 発信ブリッジのプライオリティ
+	UCHAR	BridgeMacAddress[6];	// 発信ブリッジの MAC アドレス
+	USHORT	BridgePortId;			// 発信ブリッジのポート ID
+	USHORT	MessageAge;				// 有効期限
+	USHORT	MaxAge;					// 最大有効期限
+	USHORT	HelloTime;				// Hello Time
+	USHORT	ForwardDelay;			// Forward Delay
+} GCC_PACKED;
+
+// ARPv4 ヘッダ
+struct ARPV4_HEADER
+{
+	USHORT	HardwareType;			// ハードウェアタイプ
+	USHORT	ProtocolType;			// プロトコルタイプ
+	UCHAR	HardwareSize;			// ハードウェアサイズ
+	UCHAR	ProtocolSize;			// プロトコルサイズ
+	USHORT	Operation;				// オペレーション
+	UCHAR	SrcAddress[6];			// 送信元 MAC アドレス
+	UINT	SrcIP;					// 送信元 IP アドレス
+	UCHAR	TargetAddress[6];		// ターゲット MAC アドレス
+	UINT	TargetIP;				// ターゲット IP アドレス
+} GCC_PACKED;
+
+// ARP ハードウェア種類
+#define	ARP_HARDWARE_TYPE_ETHERNET		0x0001
+
+// ARP オペレーション種類
+#define	ARP_OPERATION_REQUEST			1
+#define	ARP_OPERATION_RESPONSE			2
+
+// タグ付き VLAN ヘッダ
+struct TAGVLAN_HEADER
+{
+	UCHAR Data[2];					// データ
+} GCC_PACKED;
+
+// IPv4 ヘッダ
+struct IPV4_HEADER
+{
+	UCHAR	VersionAndHeaderLength;		// バージョンとヘッダサイズ
+	UCHAR	TypeOfService;				// サービスタイプ
+	USHORT	TotalLength;				// 合計サイズ
+	USHORT	Identification;				// 識別子
+	UCHAR	FlagsAndFlagmentOffset[2];	// フラグとフラグメントオフセット
+	UCHAR	TimeToLive;					// TTL
+	UCHAR	Protocol;					// プロトコル
+	USHORT	Checksum;					// チェックサム
+	UINT	SrcIP;						// 送信元 IP アドレス
+	UINT	DstIP;						// 宛先 IP アドレス
+} GCC_PACKED;
+
+// IPv4 ヘッダ操作用マクロ
+#define	IPV4_GET_VERSION(h)			(((h)->VersionAndHeaderLength >> 4 & 0x0f))
+#define	IPV4_SET_VERSION(h, v)		((h)->VersionAndHeaderLength |= (((v) & 0x0f) << 4))
+#define	IPV4_GET_HEADER_LEN(h)		((h)->VersionAndHeaderLength & 0x0f)
+#define	IPV4_SET_HEADER_LEN(h, v)	((h)->VersionAndHeaderLength |= ((v) & 0x0f))
+
+// IPv4 フラグメント関係操作用マクロ
+#define	IPV4_GET_FLAGS(h)			(((h)->FlagsAndFlagmentOffset[0] >> 5) & 0x07)
+#define	IPV4_SET_FLAGS(h, v)		((h)->FlagsAndFlagmentOffset[0] |= (((v) & 0x07) << 5))
+#define	IPV4_GET_OFFSET(h)			(((h)->FlagsAndFlagmentOffset[0] & 0x1f) * 256 + ((h)->FlagsAndFlagmentOffset[1]))
+#define	IPV4_SET_OFFSET(h, v)		{(h)->FlagsAndFlagmentOffset[0] |= (UCHAR)((v) / 256); (h)->FlagsAndFlagmentOffset[1] = (UCHAR)((v) % 256);}
+
+// IPv4 プロトコル
+#define	IP_PROTO_ICMPV4		0x01	// ICMPv4 プロトコル
+
+// IPv6 プロトコル
+#define	IP_PROTO_ICMPV6		0x3a	// ICMPv6 プロトコル
+
+// IPv4 / IPv6 共通プロトコル
+#define	IP_PROTO_TCP		0x06	// TCP プロトコル
+#define	IP_PROTO_UDP		0x11	// UDP プロトコル
+
+
+// UDP ヘッダ
+struct UDP_HEADER
+{
+	USHORT	SrcPort;					// 送信元ポート番号
+	USHORT	DstPort;					// 宛先ポート番号
+	USHORT	PacketLength;			// データ長
+	USHORT	Checksum;				// チェックサム
+} GCC_PACKED;
+
+// UDPv4 擬似ヘッダ
+struct UDPV4_PSEUDO_HEADER
+{
+	UINT	SrcIP;					// 送信元 IP アドレス
+	UINT	DstIP;					// 宛先 IP アドレス
+	UCHAR	Reserved;				// 未使用
+	UCHAR	Protocol;				// プロトコル番号
+	USHORT	PacketLength1;			// UDP データ長 1
+	USHORT	SrcPort;					// 送信元ポート番号
+	USHORT	DstPort;					// 宛先ポート番号
+	USHORT	PacketLength2;			// UDP データ長 2
+	USHORT	Checksum;				// チェックサム
+} GCC_PACKED;
+
+// TCPv4 擬似ヘッダ
+struct TCPV4_PSEUDO_HEADER
+{
+	UINT	SrcIP;					// 送信元 IP アドレス
+	UINT	DstIP;					// 宛先 IP アドレス
+	UCHAR	Reserved;				// 未使用
+	UCHAR	Protocol;				// プロトコル番号
+	USHORT	PacketLength;			// UDP データ長 1
+} GCC_PACKED;
+
+// TCP ヘッダ
+struct TCP_HEADER
+{
+	USHORT	SrcPort;					// 送信元ポート番号
+	USHORT	DstPort;					// 宛先ポート番号
+	UINT	SeqNumber;				// シーケンス番号
+	UINT	AckNumber;				// 確認応答番号
+	UCHAR	HeaderSizeAndReserved;	// ヘッダサイズと予約領域
+	UCHAR	Flag;					// フラグ
+	USHORT	WindowSize;				// ウインドウサイズ
+	USHORT	Checksum;				// チェックサム
+	USHORT	UrgentPointer;			// 緊急ポインタ
+} GCC_PACKED;
+
+// TCP マクロ
+#define	TCP_GET_HEADER_SIZE(h)	(((h)->HeaderSizeAndReserved >> 4) & 0x0f)
+#define	TCP_SET_HEADER_SIZE(h, v)	((h)->HeaderSizeAndReserved = (((v) & 0x0f) << 4))
+
+// TCP フラグ
+#define	TCP_FIN						1
+#define	TCP_SYN						2
+#define	TCP_RST						4
+#define	TCP_PSH						8
+#define	TCP_ACK						16
+#define	TCP_URG						32
+
+// ICMP ヘッダ
+struct ICMP_HEADER
+{
+	UCHAR	Type;					// タイプ
+	UCHAR	Code;					// コード
+	USHORT	Checksum;				// チェックサム
+} GCC_PACKED;
+
+#define	ICMP_TYPE_ECHO_REQUEST		8		// ICMP Echo 要求
+#define	ICMP_TYPE_ECHO_RESPONSE		0		// ICMP Echo 応答
+
+// ICMP Echo
+struct ICMP_ECHO
+{
+	USHORT	Identifier;						// ID
+	USHORT	SeqNo;							// シーケンス番号
+} GCC_PACKED;
+
+// DHCPv4 ヘッダ
+struct DHCPV4_HEADER
+{
+	UCHAR	OpCode;				// オペコード
+	UCHAR	HardwareType;		// ハードウェア種類
+	UCHAR	HardwareAddressSize;	// ハードウェアアドレスサイズ
+	UCHAR	Hops;				// ホップ数
+	UINT	TransactionId;		// トランザクション ID
+	USHORT	Seconds;				// 秒数
+	USHORT	Flags;				// フラグ
+	UINT	ClientIP;			// クライアント IP アドレス
+	UINT	YourIP;				// 割り当て IP アドレス
+	UINT	ServerIP;			// サーバー IP アドレス
+	UINT	RelayIP;				// リレー IP アドレス
+	UCHAR	ClientMacAddress[6];	// クライアント MAC アドレス
+	UCHAR	Padding[10];			// Ethernet 以外のためにパディング
+} GCC_PACKED;
+
+// DNSv4 ヘッダ
+struct DNSV4_HEADER
+{
+	USHORT	TransactionId;			// トランザクション ID
+	UCHAR	Flag1;					// フラグ 1
+	UCHAR	Flag2;					// フラグ 2
+	USHORT	NumQuery;				// クエリ数
+	USHORT	AnswerRRs;				// 回答 RR 数
+	USHORT	AuthorityRRs;			// 権威 RR 数
+	USHORT	AdditionalRRs;			// 追加 RR 数
+} GCC_PACKED;
+
+#define	DHCP_MAGIC_COOKIE	0x63825363	// Magic Cookie (固定)
+
+// IPv6 ヘッダパケット情報
+struct IPV6_HEADER_PACKET_INFO
+{
+	IPV6_HEADER *IPv6Header;					// IPv6 ヘッダ
+	IPV6_OPTION_HEADER *HopHeader;				// ホップバイホップオプションヘッダ
+	UINT HopHeaderSize;							// ホップバイホップオプションヘッダサイズ
+	IPV6_OPTION_HEADER *EndPointHeader;			// 終点オプションヘッダ
+	UINT EndPointHeaderSize;					// 終点オプションヘッダサイズ
+	IPV6_OPTION_HEADER *RoutingHeader;			// ルーティングヘッダ
+	UINT RoutingHeaderSize;						// ルーティングヘッダサイズ
+	IPV6_FRAGMENT_HEADER *FragmentHeader;		// フラグメントヘッダ
+	void *Payload;								// ペイロード
+	UINT PayloadSize;							// ペイロードサイズ
+	UCHAR Protocol;								// ペイロードプロトコル
+	bool IsFragment;							// フラグメントパケットかどうか
+};
+
+// IPv6 ヘッダ
+struct IPV6_HEADER
+{
+	UCHAR VersionAndTrafficClass1;		// バージョン番号 (4 bit) とトラフィッククラス 1 (4 bit)
+	UCHAR TrafficClass2AndFlowLabel1;	// トラフィッククラス 2 (4 bit) とフローラベル 1 (4 bit)
+	UCHAR FlowLabel2;					// フローラベル 2 (8 bit)
+	UCHAR FlowLabel3;					// フローラベル 3 (8 bit)
+	USHORT PayloadLength;				// ペイロードの長さ (拡張ヘッダを含む)
+	UCHAR NextHeader;					// 次のヘッダ
+	UCHAR HopLimit;						// ホップリミット
+	IPV6_ADDR SrcAddress;				// ソースアドレス
+	IPV6_ADDR DestAddress;				// 宛先アドレス
+} GCC_PACKED;
+
+
+// IPv6 ヘッダ操作用マクロ
+#define IPV6_GET_VERSION(h)			(((h)->VersionAndTrafficClass1 >> 4) & 0x0f)
+#define IPV6_SET_VERSION(h, v)		((h)->VersionAndTrafficClass1 = ((h)->VersionAndTrafficClass1 & 0x0f) | ((v) << 4) & 0xf0)
+#define IPV6_GET_TRAFFIC_CLASS(h)	((((h)->VersionAndTrafficClass1 << 4) & 0xf0) | ((h)->TrafficClass2AndFlowLabel1 >> 4) & 0x0f)
+#define	IPV6_SET_TRAFFIC_CLASS(h, v)	((h)->VersionAndTrafficClass1 = ((h)->VersionAndTrafficClass1 & 0xf0) | (((v) >> 4) & 0x0f),\
+	(h)->TrafficClass2AndFlowLabel1 = (h)->TrafficClass2AndFlowLabel1 & 0x0f | ((v) << 4) & 0xf0)
+#define	IPV6_GET_FLOW_LABEL(h)		((((h)->TrafficClass2AndFlowLabel1 << 16) & 0xf0000) | (((h)->FlowLabel2 << 8) & 0xff00) |\
+	(((h)->FlowLabel3) & 0xff))
+#define IPV6_SET_FLOW_LABEL(h, v)	((h)->TrafficClass2AndFlowLabel1 = ((h)->TrafficClass2AndFlowLabel1 & 0xf0 | ((v) >> 16) & 0x0f),\
+	(h)->FlowLabel2 = ((v) >> 8) & 0xff,\
+	(h)->FlowLabel3 = (v) & 0xff)
+
+
+// IPv6 ホップ最大値 (ルーティングしない)
+#define IPV6_HOP_MAX					255
+
+// IPv6 ホップ標準数
+#define IPV6_HOP_DEFAULT				127
+
+// IPv6 ヘッダ番号
+#define IPV6_HEADER_HOP					0	// ホップバイホップオプションヘッダ
+#define IPV6_HEADER_ENDPOINT			60	// 終点オプションヘッダ
+#define IPV6_HEADER_ROUTING				43	// ルーティングヘッダ
+#define IPV6_HEADER_FRAGMENT			44	// フラグメントヘッダ
+#define IPV6_HEADER_NONE				59	// 次ヘッダ無し
+
+// IPv6 オプションヘッダ
+// (ホップオプションヘッダ、終点オプションヘッダ、ルーティングヘッダで使用される)
+struct IPV6_OPTION_HEADER
+{
+	UCHAR NextHeader;					// 次のヘッダ
+	UCHAR Size;							// ヘッダサイズ (/8)
+} GCC_PACKED;
+
+// IPv6 フラグメントヘッダ
+// (フラグメント不可能部分は、ルーティングヘッダがある場合はその直前まで、
+//  ホップバイホップオプションヘッダがある場合はその直前まで、
+//  それ以外の場合は最初の拡張ヘッダもしくはペイロードの直前まで)
+struct IPV6_FRAGMENT_HEADER
+{
+	UCHAR NextHeader;					// 次のヘッダ
+	UCHAR Reserved;						// 予約
+	UCHAR FlagmentOffset1;				// フラグメントオフセット 1 (/8, 8 bit)
+	UCHAR FlagmentOffset2AndFlags;		// フラグメントオフセット 2 (/8, 5 bit) + 予約 (2 bit) + More フラグ (1 bit)
+	UINT Identification;				// ID
+} GCC_PACKED;
+
+// IPv6 フラグメントヘッダ操作用マクロ
+#define IPV6_GET_FRAGMENT_OFFSET(h)		(((((h)->FlagmentOffset1) << 5) & 0x1fe0) | (((h)->FlagmentOffset2AndFlags >> 3) & 0x1f))
+#define IPV6_SET_FRAGMENT_OFFSET(h, v)	((h)->FlagmentOffset1 = (v / 32) & 0xff,	\
+	((h)->FlagmentOffset2AndFlags = ((v % 256) << 3) & 0xf8) | ((h)->FlagmentOffset2AndFlags & 0x07))
+#define IPV6_GET_FLAGS(h)				((h)->FlagmentOffset2AndFlags & 0x0f)
+#define IPV6_SET_FLAGS(h, v)				((h)->FlagmentOffset2AndFlags = (((h)->FlagmentOffset2AndFlags & 0xf8) | (v & 0x07)))
+
+// フラグ
+#define IPV6_FRAGMENT_HEADER_FLAG_MORE_FRAGMENTS		0x01	// 次のフラグメントがある
+
+// IPv6 仮想ヘッダ
+struct IPV6_PSEUDO_HEADER
+{
+	IPV6_ADDR SrcAddress;				// ソースアドレス
+	IPV6_ADDR DestAddress;				// 宛先アドレス
+	UINT UpperLayerPacketSize;			// 上位レイヤのパケットサイズ
+	UCHAR Padding[3];					// パディング
+	UCHAR NextHeader;					// 次ヘッダ (TCP / UDP)
+} GCC_PACKED;
+
+// ICMPv6 ルータ要請ヘッダ
+struct ICMPV6_ROUTER_SOLICIATION_HEADER
+{
+	UINT Reserved;							// 予約
+	// + オプション (ソースリンクレイヤアドレス[任意])
+} GCC_PACKED;
+
+// ICMPv6 ルータ広告ヘッダ
+struct ICMPV6_ROUTER_ADVERTISEMENT_HEADER
+{
+	UCHAR CurHopLimit;						// デフォルトのホップリミット数
+	UCHAR Flags;							// フラグ (0)
+	USHORT Lifetime;						// 寿命
+	UINT ReachableTime;						// 0
+	UINT RetransTimer;						// 0
+	// + オプション (プレフィックス情報[必須], MTU[任意])
+} GCC_PACKED;
+
+// ICMPv6 近隣要請ヘッダ
+struct ICMPV6_NEIGHBOR_SOLICIATION_HEADER
+{
+	UINT Reserved;							// 予約
+	IPV6_ADDR TargetAddress;				// ターゲットアドレス
+	// + オプション (ソースリンクレイヤアドレス[必須])
+} GCC_PACKED;
+
+// ICMPv6 近隣広告ヘッダ
+struct ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER
+{
+	UCHAR Flags;							// フラグ
+	UCHAR Reserved[3];						// 予約
+	IPV6_ADDR TargetAddress;				// ターゲットアドレス
+	// + オプション (ターゲットリンクレイヤアドレス)
+} GCC_PACKED;
+
+#define ICMPV6_NEIGHBOR_ADVERTISEMENT_FLAG_ROUTER		0x80	// ルータ
+#define ICMPV6_NEIGHBOR_ADVERTISEMENT_FLAG_SOLICITED	0x40	// 要請フラグ
+#define ICMPV6_NEIGHBOR_ADVERTISEMENT_FLAG_OVERWRITE	0x20	// 上書きフラグ
+
+// ICMPv6 オプションリスト
+struct ICMPV6_OPTION_LIST
+{
+	ICMPV6_OPTION_LINK_LAYER *SourceLinkLayer;		// ソースリンクレイヤアドレス
+	ICMPV6_OPTION_LINK_LAYER *TargetLinkLayer;		// ターゲットリンクレイヤアドレス
+	ICMPV6_OPTION_PREFIX *Prefix;					// プレフィックス情報
+	ICMPV6_OPTION_MTU *Mtu;							// MTU
+} GCC_PACKED;
+
+// ICMPv6 オプション
+struct ICMPV6_OPTION
+{
+	UCHAR Type;								// タイプ
+	UCHAR Length;							// 長さ (/8, タイプと長さを含める)
+} GCC_PACKED;
+
+#define	ICMPV6_OPTION_TYPE_SOURCE_LINK_LAYER	1		// ソースリンクレイヤアドレス
+#define ICMPV6_OPTION_TYPE_TARGET_LINK_LAYER	2		// ターゲットリンクレイヤアドレス
+#define ICMPV6_OPTION_TYPE_PREFIX				3		// プレフィックス情報
+#define ICMPV6_OPTION_TYPE_MTU					5		// MTU
+
+// ICMPv6 リンクレイヤオプション
+struct ICMPV6_OPTION_LINK_LAYER
+{
+	ICMPV6_OPTION IcmpOptionHeader;			// オプションヘッダ
+	UCHAR Address[6];						// MAC アドレス
+} GCC_PACKED;
+
+// ICMPv6 プレフィックス情報オプション
+struct ICMPV6_OPTION_PREFIX
+{
+	ICMPV6_OPTION IcmpOptionHeader;			// オプションヘッダ
+	UCHAR SubnetLength;						// サブネット長
+	UCHAR Flags;							// フラグ
+	UINT ValidLifetime;						// 正式な寿命
+	UINT PreferredLifetime;					// 望ましい寿命
+	UINT Reserved;							// 予約
+	IPV6_ADDR Prefix;						// プレフィックスアドレス
+} GCC_PACKED;
+
+#define ICMPV6_OPTION_PREFIX_FLAG_ONLINK		0x80	// リンク上
+#define ICMPV6_OPTION_PREFIX_FLAG_AUTO			0x40	// 自動
+
+// ICMPv6 MTU オプション
+struct ICMPV6_OPTION_MTU
+{
+	ICMPV6_OPTION IcmpOptionHeader;			// オプションヘッダ
+	USHORT Reserved;						// 予約
+	UINT Mtu;								// MTU 値
+} GCC_PACKED;
+
+
+// IPv6 ヘッダ情報
+struct IPV6_HEADER_INFO
+{
+	bool IsRawIpPacket;
+	USHORT Size;
+	UINT Id;
+	UCHAR Protocol;
+	UCHAR HopLimit;
+	IPV6_ADDR SrcIpAddress;
+	IPV6_ADDR DestIpAddress;
+	bool UnicastForMe;
+	bool UnicastForRouting;
+	bool UnicastForRoutingWithProxyNdp;
+	bool IsBroadcast;
+	UINT TypeL4;
+};
+
+// ICMPv6 ヘッダ情報
+struct ICMPV6_HEADER_INFO
+{
+	UCHAR Type;
+	UCHAR Code;
+	USHORT DataSize;
+	void *Data;
+	ICMP_ECHO EchoHeader;
+	void *EchoData;
+	UINT EchoDataSize;
+
+	union
+	{
+		// Type の値によって意味が決まる
+		ICMPV6_ROUTER_SOLICIATION_HEADER *RouterSoliciationHeader;
+		ICMPV6_ROUTER_ADVERTISEMENT_HEADER *RouterAdvertisementHeader;
+		ICMPV6_NEIGHBOR_SOLICIATION_HEADER *NeighborSoliciationHeader;
+		ICMPV6_NEIGHBOR_ADVERTISEMENT_HEADER *NeighborAdvertisementHeader;
+		void *HeaderPointer;
+	} Headers;
+
+	ICMPV6_OPTION_LIST OptionList;
+};
+
+// ICMPv6 の Type の値
+#define ICMPV6_TYPE_ECHO_REQUEST				128		// ICMPv6 Echo 要求
+#define ICMPV6_TYPE_ECHO_RESPONSE				129		// ICMPv6 Echo 応答
+#define ICMPV6_TYPE_ROUTER_SOLICIATION			133		// ルータ要請
+#define ICMPV6_TYPE_ROUTER_ADVERTISEMENT		134		// ルータ広告
+#define ICMPV6_TYPE_NEIGHBOR_SOLICIATION		135		// 近隣要請
+#define ICMPV6_TYPE_NEIGHBOR_ADVERTISEMENT		136		// 近隣広告
+
+// パケット
+struct PKT
+{
+	// このあたりは急いで実装したのでコードがあまり美しくない。
+	UCHAR			*PacketData;	// パケットデータ本体
+	UINT			PacketSize;		// パケットサイズ
+	MAC_HEADER		*MacHeader;		// MAC ヘッダ
+	UCHAR			*MacAddressSrc;	// 送信元 MAC アドレス
+	UCHAR			*MacAddressDest;	// 宛先 MAC アドレス
+	bool			BroadcastPacket;		// ブロードキャストパケット
+	bool			InvalidSourcePacket;	// ソースアドレスが不正なパケット
+	bool			AccessChecked;	// アクセスリストで通過が確認されたパケット
+	UINT			VlanTypeID;		// タグ付き VLAN の TypeID (通常は 0x8100)
+	UINT			VlanId;			// VLAN ID
+	UINT			Delay;			// 遅延
+	UINT			Jitter;			// ジッタ
+	UINT			Loss;			// パケットロス
+	UINT64			DelayedForwardTick;	// 遅延した場合における送信時刻
+	SESSION			*DelayedSrcSession;	// 送信元のセッション
+	UINT			TypeL3;			// Layer-3 パケット分類
+	IPV6_HEADER_PACKET_INFO IPv6HeaderPacketInfo;	// IPv6 ヘッダパケット情報 (TypeL3 == L3_IPV6 の場合のみ)
+	ICMPV6_HEADER_INFO ICMPv6HeaderPacketInfo;		// ICMPv6 ヘッダ情報 (TypeL4 == L4_ICMPV6 の場合のみ)
+	union
+	{
+		IPV4_HEADER		*IPv4Header;	// IPv4 ヘッダ
+		ARPV4_HEADER	*ARPv4Header;	// ARPv4 ヘッダ
+		IPV6_HEADER		*IPv6Header;	// IPv6 ヘッダ
+		TAGVLAN_HEADER	*TagVlanHeader;	// タグヘッダ
+		BPDU_HEADER		*BpduHeader;	// BPDU ヘッダ
+		void			*PointerL3;
+	} L3;
+	UINT			TypeL4;				// Layer-4 パケット分類
+	union
+	{
+		UDP_HEADER	*UDPHeader;			// UDP ヘッダ
+		TCP_HEADER	*TCPHeader;			// TCP ヘッダ
+		ICMP_HEADER	*ICMPHeader;		// ICMP ヘッダ
+		void		*PointerL4;
+	} L4;
+	UINT			TypeL7;			// Layer-7 パケット分類
+	union
+	{
+		DHCPV4_HEADER	*DHCPv4Header;	// DHCPv4 ヘッダ
+		void			*PointerL7;
+	} L7;
+} GCC_PACKED;
+
+// Layer-3 パケット分類
+#define	L3_UNKNOWN			0		// 不明
+#define	L3_ARPV4			1		// ARPv4 パケット
+#define	L3_IPV4				2		// IPv4 パケット
+#define	L3_TAGVLAN			3		// タグ付き VLAN パケット
+#define	L3_BPDU				4		// BPDU パケット
+#define L3_IPV6				5		// IPv6 パケット
+
+// Layer-4 パケット分類
+#define	L4_UNKNOWN			0		// 不明
+#define	L4_UDP				1		// UDPv4 パケット
+#define	L4_TCP				2		// TCPv4 パケット
+#define	L4_ICMPV4			3		// ICMPv4 パケット
+#define	L4_ICMPV6			4		// ICMPv6 パケット
+#define	L4_FRAGMENT			5		// フラグメントパケット
+
+// Layer-7 パケット分類
+#define	L7_UNKNOWN			0		// 不明
+#define	L7_DHCPV4			1		// DHCPv4 パケット
+
+
+PKT *ParsePacket(UCHAR *buf, UINT size);
+PKT *ParsePacketEx(UCHAR *buf, UINT size, bool no_l3);
+PKT *ParsePacketEx2(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id);
+PKT *ParsePacketEx3(UCHAR *buf, UINT size, bool no_l3, UINT vlan_type_id, bool bridge_id_as_mac_address);
+void FreePacket(PKT *p);
+void FreePacketIPv4(PKT *p);
+void FreePacketTagVlan(PKT *p);
+void FreePacketARPv4(PKT *p);
+void FreePacketUDPv4(PKT *p);
+void FreePacketTCPv4(PKT *p);
+void FreePacketICMPv4(PKT *p);
+void FreePacketDHCPv4(PKT *p);
+bool ParsePacketL2(PKT *p, UCHAR *buf, UINT size);
+bool ParsePacketL2Ex(PKT *p, UCHAR *buf, UINT size, bool no_l3);
+bool ParsePacketARPv4(PKT *p, UCHAR *buf, UINT size);
+bool ParsePacketIPv4(PKT *p, UCHAR *buf, UINT size);
+bool ParsePacketBPDU(PKT *p, UCHAR *buf, UINT size);
+bool ParsePacketTAGVLAN(PKT *p, UCHAR *buf, UINT size);
+bool ParseICMPv4(PKT *p, UCHAR *buf, UINT size);
+bool ParseICMPv6(PKT *p, UCHAR *buf, UINT size);
+bool ParseTCP(PKT *p, UCHAR *buf, UINT size);
+bool ParseUDP(PKT *p, UCHAR *buf, UINT size);
+void ParseDHCPv4(PKT *p, UCHAR *buf, UINT size);
+PKT *ClonePacket(PKT *p, bool copy_data);
+void FreeClonePacket(PKT *p);
+
+bool ParsePacketIPv6(PKT *p, UCHAR *buf, UINT size);
+bool ParsePacketIPv6Header(IPV6_HEADER_PACKET_INFO *info, UCHAR *buf, UINT size);
+bool ParseIPv6ExtHeader(IPV6_HEADER_PACKET_INFO *info, UCHAR next_header, UCHAR *buf, UINT size);
+bool ParseICMPv6Options(ICMPV6_OPTION_LIST *o, UCHAR *buf, UINT size);
+void CloneICMPv6Options(ICMPV6_OPTION_LIST *dst, ICMPV6_OPTION_LIST *src);
+void FreeCloneICMPv6Options(ICMPV6_OPTION_LIST *o);
+USHORT CalcChecksumForIPv6(IPV6_ADDR *src_ip, IPV6_ADDR *dest_ip, UCHAR protocol, void *data, UINT size);
+BUF *BuildICMPv6Options(ICMPV6_OPTION_LIST *o);
+void BuildICMPv6OptionValue(BUF *b, UCHAR type, void *header_pointer, UINT total_size);
+BUF *BuildIPv6(IPV6_ADDR *dest_ip, IPV6_ADDR *src_ip, UINT id, UCHAR protocol, UCHAR hop_limit, void *data,
+			   UINT size);
+BUF *BuildIPv6PacketHeader(IPV6_HEADER_PACKET_INFO *info, UINT *bytes_before_payload);
+UCHAR IPv6GetNextHeaderFromQueue(QUEUE *q);
+void BuildAndAddIPv6PacketOptionHeader(BUF *b, IPV6_OPTION_HEADER *opt, UCHAR next_header, UINT size);
+BUF *BuildICMPv6NeighborSoliciation(IPV6_ADDR *src_ip, IPV6_ADDR *target_ip, UCHAR *my_mac_address, UINT id);
+BUF *BuildICMPv6(IPV6_ADDR *src_ip, IPV6_ADDR *dest_ip, UCHAR hop_limit, UCHAR type, UCHAR code, void *data, UINT size, UINT id);
+
+bool VLanRemoveTag(void **packet_data, UINT *packet_size, UINT vlan_id);
+void VLanInsertTag(void **packet_data, UINT *packet_size, UINT vlan_id);
+
+#ifdef	OS_WIN32
+#pragma pack(pop)
+#endif	// OS_WIN32
+
+#endif	// TCPIP_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/UT.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/UT.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/UT.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,378 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// UT.c
+// Win32 用 SoftEther Network Utility
+
+#ifdef	WIN32
+
+#define	UT_C
+
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "../PenCore/resource.h"
+
+static char *selected_adapter = NULL;
+
+// Q. 「スピードメーター」という関数名になっているがこれはどういう意味か? 警察のオービスなのか?
+// A. もともとこのネットワーク情報表示ユーティリティは、通信速度を測定するために開発
+//    されたのである。しかし、その後「TrafficServer」、「TrafficClient」機能が別途
+//    開発されたため、速度測定機能はこのユーティリティからは削除された。
+//    関数名はその時代の名残である。
+
+// ステータスの更新
+void UtSpeedMeterDlgRefreshStatus(HWND hWnd)
+{
+	char *title;
+	MS_ADAPTER *a;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	title = selected_adapter;
+
+	a = MsGetAdapter(title);
+	if (a == NULL)
+	{
+		LbReset(hWnd, L_STATUS);
+		Disable(hWnd, L_STATUS);
+	}
+	else
+	{
+		LVB *b;
+		wchar_t tmp[MAX_SIZE];
+		wchar_t tmp2[MAX_SIZE];
+		char str[MAX_SIZE];
+		b = LvInsertStart();
+
+		StrToUni(tmp, sizeof(tmp), a->Title);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_TITLE"), tmp);
+
+		StrToUni(tmp, sizeof(tmp), a->Guid);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_GUID"), tmp);
+
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_TYPE"), MsGetAdapterTypeStr(a->Type));
+
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_STATUS"), MsGetAdapterStatusStr(a->Status));
+
+		UniToStr3(tmp, sizeof(tmp), a->Mtu);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_MTU"), tmp);
+
+		UniToStr3(tmp, sizeof(tmp), a->Speed);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_SPEED"), tmp);
+
+		Zero(str, sizeof(str));
+		BinToStrEx2(str, sizeof(str), a->Address, a->AddressSize, '-');
+		StrToUni(tmp, sizeof(tmp), str);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_ADDRESS"), tmp);
+
+		UniToStr3(tmp, sizeof(tmp), a->RecvBytes);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_RECV_BYTES"), tmp);
+
+		UniToStr3(tmp, sizeof(tmp), a->RecvPacketsBroadcast);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_RECV_BCASTS"), tmp);
+
+		UniToStr3(tmp, sizeof(tmp), a->RecvPacketsUnicast);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_RECV_UNICASTS"), tmp);
+
+		UniToStr3(tmp, sizeof(tmp), a->SendBytes);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_SEND_BYTES"), tmp);
+
+		UniToStr3(tmp, sizeof(tmp), a->SendPacketsBroadcast);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_SEND_BCASTS"), tmp);
+
+		UniToStr3(tmp, sizeof(tmp), a->SendPacketsUnicast);
+		LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_SEND_UNICASTS"), tmp);
+
+		for (i = 0;i < a->NumIpAddress;i++)
+		{
+			UniFormat(tmp2, sizeof(tmp2), _UU("UT_SM_ST_IP"), i + 1);
+			IPToUniStr(tmp, sizeof(tmp), &a->IpAddresses[i]);
+			LvInsertAdd(b, 0, NULL, 2, tmp2, tmp);
+
+			UniFormat(tmp2, sizeof(tmp2), _UU("UT_SM_ST_SUBNET"), i + 1);
+			IPToUniStr(tmp, sizeof(tmp), &a->SubnetMasks[i]);
+			LvInsertAdd(b, 0, NULL, 2, tmp2, tmp);
+		}
+
+		for (i = 0;i < a->NumGateway;i++)
+		{
+			UniFormat(tmp2, sizeof(tmp2), _UU("UT_SM_ST_GATEWAY"), i + 1);
+			IPToUniStr(tmp, sizeof(tmp), &a->Gateways[i]);
+			LvInsertAdd(b, 0, NULL, 2, tmp2, tmp);
+		}
+
+		if (a->UseDhcp)
+		{
+			IPToUniStr(tmp, sizeof(tmp), &a->DhcpServer);
+			LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_DHCP"), tmp);
+
+			GetDateTimeStrEx64(tmp, sizeof(tmp), a->DhcpLeaseStart, NULL);
+			LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_DHCP_1"), tmp);
+
+			GetDateTimeStrEx64(tmp, sizeof(tmp), a->DhcpLeaseExpires, NULL);
+			LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_DHCP_2"), tmp);
+		}
+
+		if (a->UseWins)
+		{
+			IPToUniStr(tmp, sizeof(tmp), &a->PrimaryWinsServer);
+			LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_WINS_1"), tmp);
+
+			IPToUniStr(tmp, sizeof(tmp), &a->SecondaryWinsServer);
+			LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_WINS_2"), tmp);
+		}
+
+		LvInsertEnd(b, hWnd, L_STATUS);
+		Enable(hWnd, L_STATUS);
+
+		MsFreeAdapter(a);
+	}
+
+}
+
+// アダプタリストの更新
+void UtSpeedMeterDlgRefreshList(HWND hWnd)
+{
+	wchar_t *old;
+	MS_ADAPTER_LIST *o;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 現在の選択を取得
+	old = GetText(hWnd, E_LIST);
+	if (old != NULL)
+	{
+		if (UniStrLen(old) == 0)
+		{
+			Free(old);
+			old = NULL;
+		}
+	}
+
+	o = MsCreateAdapterList();
+	CbReset(hWnd, E_LIST);
+	CbSetHeight(hWnd, E_LIST, 18);
+
+	for (i = 0;i < o->Num;i++)
+	{
+		wchar_t tmp[MAX_SIZE];
+		MS_ADAPTER *a = o->Adapters[i];
+
+		if (a->Info)
+		{
+			StrToUni(tmp, sizeof(tmp), a->Title);
+			CbAddStr(hWnd, E_LIST, tmp, 0);
+		}
+	}
+
+
+	// 前回の選択を再選択
+	if (old != NULL)
+	{
+		CbSelectIndex(hWnd, E_LIST, CbFindStr(hWnd, E_LIST, old));
+		Free(old);
+	}
+
+	MsFreeAdapterList(o);
+}
+
+// スピードメーターダイアログコントロール更新
+void UtSpeedMeterDlgUpdate(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+}
+
+// スピードメーターダイアログ初期化
+void UtSpeedMeterDlgInit(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	LvInitEx(hWnd, L_STATUS, true);
+	LvInsertColumn(hWnd, L_STATUS, 0, _UU("UT_SM_COLUMN_1"), 150);
+	LvInsertColumn(hWnd, L_STATUS, 1, _UU("UT_SM_COLUMN_2"), 290);
+
+	UtSpeedMeterDlgRefreshList(hWnd);
+	selected_adapter = GetTextA(hWnd, E_LIST);
+	UtSpeedMeterDlgRefreshStatus(hWnd);
+	UtSpeedMeterDlgUpdate(hWnd);
+}
+
+// スピードメーターダイアログ
+UINT UtSpeedMeterDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+		UtSpeedMeterDlgInit(hWnd);
+		SetTimer(hWnd, 1, SPEED_METER_REFRESH_INTERVAL, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			UtSpeedMeterDlgRefreshStatus(hWnd);
+			UtSpeedMeterDlgUpdate(hWnd);
+			SetTimer(hWnd, 1, SPEED_METER_REFRESH_INTERVAL, NULL);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		if (HIWORD(wParam) == CBN_SELCHANGE) {
+			Free(selected_adapter);
+			selected_adapter = GetTextA(hWnd, E_LIST);
+			UtSpeedMeterDlgUpdate(hWnd);
+		} else {
+			switch (wParam)
+			{
+			case B_REFRESH:
+				UtSpeedMeterDlgRefreshList(hWnd);
+				Free(selected_adapter);
+				selected_adapter = GetTextA(hWnd, E_LIST);
+				UtSpeedMeterDlgUpdate(hWnd);
+				break;
+
+			case IDCANCEL:
+				Close(hWnd);
+				break;
+			}
+		}
+		break;
+
+	case WM_CLOSE:
+		Free(selected_adapter);
+		selected_adapter = NULL;
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// スピードメーター
+void UtSpeedMeter()
+{
+	UtSpeedMeterEx(NULL);
+}
+void UtSpeedMeterEx(void *hWnd)
+{
+	Dialog((HWND)hWnd, D_SPEEDMETER, UtSpeedMeterDlgProc, NULL);
+}
+
+#endif // WIN32
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/UT.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/UT.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/UT.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,105 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// UT.h
+// UT.c のヘッダ
+
+#ifndef	UT_H
+#define	UT_H
+
+// 定数
+#define	SPEED_METER_REFRESH_INTERVAL			500
+
+#ifdef	UT_C
+// 内部向け宣言
+
+// 関数プロトタイプ
+UINT UtSpeedMeterDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void UtSpeedMeterDlgInit(HWND hWnd);
+void UtSpeedMeterDlgRefreshList(HWND hWnd);
+void UtSpeedMeterDlgRefreshStatus(HWND hWnd);
+void UtSpeedMeterDlgUpdate(HWND hWnd);
+void UtSpeedMeterDlgRefreshStatus(HWND hWnd);
+
+#endif	// UT_C
+
+// 関数プロトタイプ
+void UtSpeedMeter();
+void UtSpeedMeterEx(void *hWnd);
+
+#endif	// UT_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLan.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLan.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLan.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,99 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// VLan.c
+// 仮想 LAN カードアダプタ操作用ライブラリ
+
+#define	VLAN_C
+
+#ifdef	WIN32
+#define	OS_WIN32
+#endif
+
+#ifdef	OS_WIN32
+
+// Win32 用
+#include "VLanWin32.c"
+
+#else
+
+// UNIX 用
+#include "VLanUnix.c"
+
+#endif	// OS_WIN32
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLan.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLan.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLan.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,105 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// VLan.h
+// VLan.c のヘッダ
+
+#ifndef	VLAN_H
+#define	VLAN_H
+
+// VLAN 関係のパラメータ
+struct VLAN_PARAM
+{
+	UCHAR MacAddress[6];
+	UCHAR Padding[2];
+};
+
+#ifdef	OS_WIN32
+
+// Win32 用
+#include <Cedar/VLanWin32.h>
+
+#else	// OS_WIN32
+
+// UNIX 用
+#include <Cedar/VLanUnix.h>
+
+#endif	// OS_WIN32
+
+#endif	// VLAN_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanUnix.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanUnix.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanUnix.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,782 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// VLanUnix.c
+// UNIX 用仮想デバイスドライバライブラリ
+
+#ifdef	VLAN_C
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+#ifdef	OS_UNIX
+
+static LIST *unix_vlan = NULL;
+
+#ifndef	NO_VLAN
+
+// PACKET_ADAPTER の取得
+PACKET_ADAPTER *VLanGetPacketAdapter()
+{
+	PACKET_ADAPTER *pa;
+
+	pa = NewPacketAdapter(VLanPaInit, VLanPaGetCancel,
+		VLanPaGetNextPacket, VLanPaPutPacket, VLanPaFree);
+	if (pa == NULL)
+	{
+		return NULL;
+	}
+
+	return pa;
+}
+
+// PA 初期化
+bool VLanPaInit(SESSION *s)
+{
+	VLAN *v;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	// ドライバに接続
+	v = NewVLan(s->ClientOption->DeviceName, NULL);
+	if (v == NULL)
+	{
+		// 失敗
+		return false;
+	}
+
+	s->PacketAdapter->Param = v;
+
+	return true;
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *VLanPaGetCancel(SESSION *s)
+{
+	VLAN *v;
+	// 引数チェック
+	if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+	{
+		return NULL;
+	}
+
+	return VLanGetCancel(v);
+}
+
+// パケットアダプタの解放
+void VLanPaFree(SESSION *s)
+{
+	VLAN *v;
+	// 引数チェック
+	if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+	{
+		return;
+	}
+
+	// 仮想 LAN カードの終了
+	FreeVLan(v);
+
+	s->PacketAdapter->Param = NULL;
+}
+
+// パケットの書き込み
+bool VLanPaPutPacket(SESSION *s, void *data, UINT size)
+{
+	VLAN *v;
+	// 引数チェック
+	if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+	{
+		return false;
+	}
+
+	return VLanPutPacket(v, data, size);
+}
+
+// 次のパケットを取得
+UINT VLanPaGetNextPacket(SESSION *s, void **data)
+{
+	VLAN *v;
+	UINT size;
+	// 引数チェック
+	if (data == NULL || (s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+	{
+		return INFINITE;
+	}
+
+	if (VLanGetNextPacket(v, data, &size) == false)
+	{
+		return INFINITE;
+	}
+
+	return size;
+}
+
+// パケットを仮想 LAN カードに書き込む
+bool VLanPutPacket(VLAN *v, void *buf, UINT size)
+{
+	UINT ret;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return false;
+	}
+	if (v->Halt)
+	{
+		return false;
+	}
+	if (size > MAX_PACKET_SIZE)
+	{
+		return false;
+	}
+	if (buf == NULL || size == 0)
+	{
+		if (buf != NULL)
+		{
+			Free(buf);
+		}
+		return true;
+	}
+
+	ret = write(v->fd, buf, size);
+
+	if (ret >= 1)
+	{
+		Free(buf);
+		return true;
+	}
+
+	if (errno == EAGAIN || ret == 0)
+	{
+		Free(buf);
+		return true;
+	}
+
+	return false;
+}
+
+// 仮想 LAN カードから次のパケットを取得する
+bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size)
+{
+	UCHAR tmp[TAP_READ_BUF_SIZE];
+	int ret;
+	// 引数チェック
+	if (v == NULL || buf == NULL || size == 0)
+	{
+		return false;
+	}
+	if (v->Halt)
+	{
+		return false;
+	}
+
+	// 読み込み
+	ret = read(v->fd, tmp, sizeof(tmp));
+
+	if (ret == 0 ||
+		(ret == -1 && errno == EAGAIN))
+	{
+		// パケット無し
+		*buf = NULL;
+		*size = 0;
+		return true;
+	}
+	else if (ret == -1 || ret > TAP_READ_BUF_SIZE)
+	{
+		// エラー
+		return false;
+	}
+	else
+	{
+		// パケット読み込み成功
+		*buf = Malloc(ret);
+		Copy(*buf, tmp, ret);
+		*size = ret;
+		return true;
+	}
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *VLanGetCancel(VLAN *v)
+{
+	CANCEL *c;
+	int fd;
+	int yes = 0;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	c = NewCancel();
+	UnixDeletePipe(c->pipe_read, c->pipe_write);
+	c->pipe_read = c->pipe_write = -1;
+
+	fd = v->fd;
+
+#ifndef	UNIX_MACOS
+	UnixSetSocketNonBlockingMode(fd, true);
+#else	// UNIX_MACOS
+	UnixSetSocketNonBlockingMode(fd, false);
+#endif	// UNIX_MACOS
+
+	c->SpecialFlag = true;
+	c->pipe_read = fd;
+
+	return c;
+}
+
+// 仮想 LAN カードを閉じる
+void FreeVLan(VLAN *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	Free(v->InstanceName);
+
+	Free(v);
+}
+
+// tap の作成
+VLAN *NewTap(char *name, char *mac_address)
+{
+	int fd;
+	VLAN *v;
+	// 引数チェック
+	if (name == NULL || mac_address == NULL)
+	{
+		return NULL;
+	}
+
+	fd = UnixCreateTapDeviceEx(name, "tap", mac_address);
+	if (fd == -1)
+	{
+		return NULL;
+	}
+
+	v = ZeroMalloc(sizeof(VLAN));
+	v->Halt = false;
+	v->InstanceName = CopyStr(name);
+	v->fd = fd;
+
+	return v;
+}
+
+// tap を閉じる
+void FreeTap(VLAN *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	close(v->fd);
+	FreeVLan(v);
+}
+
+// 仮想 LAN カードの取得
+VLAN *NewVLan(char *instance_name, VLAN_PARAM *param)
+{
+	int fd;
+	VLAN *v;
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return NULL;
+	}
+
+	// tap を開く
+	fd = UnixVLanGet(instance_name);
+	if (fd == -1)
+	{
+		return NULL;
+	}
+
+	v = ZeroMalloc(sizeof(VLAN));
+	v->Halt = false;
+	v->InstanceName = CopyStr(instance_name);
+	v->fd = fd;
+
+	return v;
+}
+
+// tap デバイスの作成
+int UnixCreateTapDeviceEx(char *name, char *prefix, UCHAR *mac_address)
+{
+	int fd;
+	struct ifreq ifr;
+	char eth_name[MAX_SIZE];
+	char instance_name_lower[MAX_SIZE];
+	struct sockaddr sa;
+	char *tap_name = TAP_FILENAME_1;
+	int s;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return -1;
+	}
+
+	// デバイス名を生成
+	StrCpy(instance_name_lower, sizeof(instance_name_lower), name);
+	Trim(instance_name_lower);
+	StrLower(instance_name_lower);
+	Format(eth_name, sizeof(eth_name), "%s_%s", prefix, instance_name_lower);
+
+	eth_name[15] = 0;
+
+	// tun/tap を開く
+#ifndef	UNIX_MACOS
+	if (GetOsInfo()->OsType == OSTYPE_LINUX)
+	{
+		// Linux
+		if (IsFile(TAP_FILENAME_1) == false)
+		{
+			char tmp[MAX_SIZE];
+
+			Format(tmp, sizeof(tmp), "%s c 10 200", TAP_FILENAME_1);
+			Run("mknod", tmp, true, true);
+
+			Format(tmp, sizeof(tmp), "600 %s", TAP_FILENAME_1);
+			Run("chmod", tmp, true, true);
+		}
+	}
+	// MacOS X 以外
+	fd = open(TAP_FILENAME_1, O_RDWR);
+	if (fd == -1)
+	{
+		// 失敗
+		fd = open(TAP_FILENAME_2, O_RDWR);
+		if (fd == -1)
+		{
+			return -1;
+		}
+		tap_name = TAP_FILENAME_2;
+	}
+#else	// UNIX_MACOS
+	// MacOS X
+	fd = open(TAP_MACOS_FILENAME, O_RDWR);
+	if (fd == -1)
+	{
+		return -1;
+	}
+	tap_name = TAP_MACOS_FILENAME;
+#endif	// UNIX_MACOS
+
+#ifdef	UNIX_LINUX
+	// Linux 用 tap の作成
+
+	// デバイス名設定
+	Zero(&ifr, sizeof(ifr));
+
+	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+	StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), eth_name);
+
+	if (ioctl(fd, TUNSETIFF, &ifr) == -1)
+	{
+		// 失敗
+		close(fd);
+		return -1;
+	}
+
+	// MAC アドレス設定
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s != -1)
+	{
+		if (mac_address != NULL)
+		{
+			Zero(&ifr, sizeof(ifr));
+			StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), eth_name);
+			ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+			Copy(&ifr.ifr_hwaddr.sa_data, mac_address, 6);
+			ioctl(s, SIOCSIFHWADDR, &ifr);
+		}
+
+		Zero(&ifr, sizeof(ifr));
+		StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), eth_name);
+		ioctl(s, SIOCGIFFLAGS, &ifr);
+
+		ifr.ifr_flags |= IFF_UP;
+		ioctl(s, SIOCSIFFLAGS, &ifr);
+
+		close(s);
+	}
+
+#else	// UNIX_LINUX
+#ifdef	UNIX_SOLARIS
+	// Solaris 用 tap の作成
+	{
+		int ip_fd;
+		int tun_fd;
+		int ppa;
+
+		tun_fd = open(tap_name, O_RDWR);
+		if (tun_fd == -1)
+		{
+			// 失敗
+			close(fd);
+			return -1;
+		}
+
+		ip_fd = open("/dev/ip", O_RDWR);
+		if (ip_fd == -1)
+		{
+			// 失敗
+			close(tun_fd);
+			close(fd);
+			return -1;
+		}
+
+		ppa = -1;
+		ppa = ioctl(tun_fd, TUNNEWPPA, ppa);
+		if (ppa == -1)
+		{
+			// 失敗
+			close(tun_fd);
+			close(fd);
+			close(ip_fd);
+			return -1;
+		}
+
+		if (ioctl(fd, I_PUSH, "ip") < 0)
+		{
+			// 失敗
+			close(tun_fd);
+			close(fd);
+			close(ip_fd);
+			return -1;
+		}
+
+		if (ioctl(fd, IF_UNITSEL, (char *)&ppa) < 0)
+		{
+			// 失敗
+			close(tun_fd);
+			close(fd);
+			close(ip_fd);
+			return -1;
+		}
+
+		if (ioctl(ip_fd, I_LINK, fd) < 0)
+		{
+			// 失敗
+			close(tun_fd);
+			close(fd);
+			close(ip_fd);
+			return -1;
+		}
+
+		close(tun_fd);
+		close(ip_fd);
+	}
+
+#endif	// UNIX_SOLARIS
+#endif	// UNIX_LINUX
+
+	return fd;
+}
+int UnixCreateTapDevice(char *name, UCHAR *mac_address)
+{
+	return UnixCreateTapDeviceEx(name, "utvpn", mac_address);
+}
+
+// tap デバイスを閉じる
+void UnixCloseTapDevice(int fd)
+{
+	// 引数チェック
+	if (fd == -1)
+	{
+		return;
+	}
+
+	close(fd);
+}
+
+#else	// NO_VLAN
+
+void UnixCloseTapDevice(int fd)
+{
+}
+
+int UnixCreateTapDeviceEx(char *name, char *prefix, UCHAR *mac_address)
+{
+	return -1;
+}
+int UnixCreateTapDevice(char *name, UCHAR *mac_address)
+{
+	return -1;
+}
+
+#endif	// NO_VLAN
+
+// VLAN リストの比較
+int UnixCompareVLan(void *p1, void *p2)
+{
+	UNIX_VLAN_LIST *v1, *v2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	v1 = *(UNIX_VLAN_LIST **)p1;
+	v2 = *(UNIX_VLAN_LIST **)p2;
+	if (v1 == NULL || v2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(v1->Name, v2->Name);
+}
+
+// VLAN リストの初期化
+void UnixVLanInit()
+{
+	unix_vlan = NewList(UnixCompareVLan);
+}
+
+// VLAN の作成
+bool UnixVLanCreateEx(char *name, char *prefix, UCHAR *mac_address)
+{
+	// 引数チェック
+	char tmp[MAX_SIZE];
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(tmp, sizeof(tmp), name);
+	Trim(tmp);
+	name = tmp;
+
+	LockList(unix_vlan);
+	{
+		UNIX_VLAN_LIST *t, tt;
+		int fd;
+
+		// 同一名のデバイスが存在していないかどうかチェック
+		Zero(&tt, sizeof(tt));
+		StrCpy(tt.Name, sizeof(tt.Name), name);
+
+		t = Search(unix_vlan, &tt);
+		if (t != NULL)
+		{
+			// すでに存在する
+			UnlockList(unix_vlan);
+			return false;
+		}
+
+		// tap デバイスを作成
+		fd = UnixCreateTapDeviceEx(name, prefix, mac_address);
+		if (fd == -1)
+		{
+			// 作成失敗
+			UnlockList(unix_vlan);
+			return false;
+		}
+
+		t = ZeroMalloc(sizeof(UNIX_VLAN_LIST));
+		t->fd = fd;
+		StrCpy(t->Name, sizeof(t->Name), name);
+
+		Insert(unix_vlan, t);
+	}
+	UnlockList(unix_vlan);
+
+	return true;
+}
+bool UnixVLanCreate(char *name, UCHAR *mac_address)
+{
+	return UnixVLanCreateEx(name, "utvpn", mac_address);
+}
+
+// VLAN の列挙
+TOKEN_LIST *UnixVLanEnum()
+{
+	TOKEN_LIST *ret;
+	UINT i;
+	if (unix_vlan == NULL)
+	{
+		return NullToken();
+	}
+
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+
+	LockList(unix_vlan);
+	{
+		ret->NumTokens = LIST_NUM(unix_vlan);
+		ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+
+		for (i = 0;i < ret->NumTokens;i++)
+		{
+			UNIX_VLAN_LIST *t = LIST_DATA(unix_vlan, i);
+
+			ret->Token[i] = CopyStr(t->Name);
+		}
+	}
+	UnlockList(unix_vlan);
+
+	return ret;
+}
+
+// VLAN の削除
+void UnixVLanDelete(char *name)
+{
+	// 引数チェック
+	if (name == NULL || unix_vlan == NULL)
+	{
+		return;
+	}
+
+	LockList(unix_vlan);
+	{
+		UINT i;
+		UNIX_VLAN_LIST *t, tt;
+
+		Zero(&tt, sizeof(tt));
+		StrCpy(tt.Name, sizeof(tt.Name), name);
+
+		t = Search(unix_vlan, &tt);
+		if (t != NULL)
+		{
+			UnixCloseTapDevice(t->fd);
+			Delete(unix_vlan, t);
+			Free(t);
+		}
+	}
+	UnlockList(unix_vlan);
+}
+
+// VLAN の取得
+int UnixVLanGet(char *name)
+{
+	int fd = -1;
+	// 引数チェック
+	if (name == NULL || unix_vlan == NULL)
+	{
+		return -1;
+	}
+
+	LockList(unix_vlan);
+	{
+		UINT i;
+		UNIX_VLAN_LIST *t, tt;
+
+		Zero(&tt, sizeof(tt));
+		StrCpy(tt.Name, sizeof(tt.Name), name);
+
+		t = Search(unix_vlan, &tt);
+		if (t != NULL)
+		{
+			fd = t->fd;
+		}
+	}
+	UnlockList(unix_vlan);
+
+	return fd;
+}
+
+// VLAN リストの解放
+void UnixVLanFree()
+{
+	UINT i;
+
+	for (i = 0;i < LIST_NUM(unix_vlan);i++)
+	{
+		UNIX_VLAN_LIST *t = LIST_DATA(unix_vlan, i);
+
+		UnixCloseTapDevice(t->fd);
+		Free(t);
+	}
+
+	ReleaseList(unix_vlan);
+	unix_vlan = NULL;
+}
+
+#endif	// OS_UNIX
+
+#endif	// VLAN_C
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanUnix.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanUnix.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanUnix.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,137 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// VLanUnix.h
+// VLanUnix.c のヘッダ
+
+#ifndef	VLANUNIX_H
+#define	VLANUNIX_H
+
+// 定数
+#define	TAP_READ_BUF_SIZE			1600
+
+#ifndef	NO_VLAN
+
+// VLAN 構造体
+struct VLAN
+{
+	volatile bool Halt;			// 停止フラグ
+	char *InstanceName;			// インスタンス名
+	int fd;						// ファイル
+};
+
+// 関数プロトタイプ
+VLAN *NewVLan(char *instance_name, VLAN_PARAM *param);
+VLAN *NewTap(char *name, char *mac_address);
+void FreeVLan(VLAN *v);
+CANCEL *VLanGetCancel(VLAN *v);
+bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size);
+bool VLanPutPacket(VLAN *v, void *buf, UINT size);
+
+PACKET_ADAPTER *VLanGetPacketAdapter();
+bool VLanPaInit(SESSION *s);
+CANCEL *VLanPaGetCancel(SESSION *s);
+UINT VLanPaGetNextPacket(SESSION *s, void **data);
+bool VLanPaPutPacket(SESSION *s, void *data, UINT size);
+void VLanPaFree(SESSION *s);
+
+#else	// NO_VLAN
+
+#define	VLanGetPacketAdapter	NullGetPacketAdapter
+
+#endif	// NO_VLAN
+
+struct UNIX_VLAN_LIST
+{
+	char Name[MAX_SIZE];		// デバイス名
+	int fd;						// fd
+};
+
+int UnixCreateTapDevice(char *name, UCHAR *mac_address);
+int UnixCreateTapDeviceEx(char *name, char *prefix, UCHAR *mac_address);
+void UnixCloseTapDevice(int fd);
+void UnixVLanInit();
+void UnixVLanFree();
+bool UnixVLanCreate(char *name, UCHAR *mac_address);
+bool UnixVLanCreateEx(char *name, char *prefix, UCHAR *mac_address);
+TOKEN_LIST *UnixVLanEnum();
+void UnixVLanDelete(char *name);
+int UnixVLanGet(char *name);
+int UnixCompareVLan(void *p1, void *p2);
+
+#endif	// VLANUNIX_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanWin32.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanWin32.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanWin32.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1406 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// VLanWin32.c
+// Win32 用仮想デバイスドライバライブラリ
+
+#ifdef	VLAN_C
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+#ifdef	OS_WIN32
+
+typedef DWORD(CALLBACK* OPENVXDHANDLE)(HANDLE);
+
+// Windows のバージョン情報の取得
+void Win32GetWinVer(RPC_WINVER *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	Zero(v, sizeof(RPC_WINVER));
+
+	v->IsWindows = true;
+
+	if (OS_IS_WINDOWS_NT(GetOsType()) == false)
+	{
+		// Windows 9x
+		OSVERSIONINFO os;
+		Zero(&os, sizeof(os));
+		os.dwOSVersionInfoSize = sizeof(os);
+		GetVersionEx(&os);
+
+		v->Build = LOWORD(os.dwBuildNumber);
+		v->VerMajor = os.dwMajorVersion;
+		v->VerMinor = os.dwMinorVersion;
+
+		Format(v->Title, sizeof(v->Title), "%s %s",
+			GetOsInfo()->OsProductName,
+			GetOsInfo()->OsVersion);
+		Trim(v->Title);
+	}
+	else
+	{
+		// Windows NT 4.0 SP6 以降
+		OSVERSIONINFOEX os;
+		Zero(&os, sizeof(os));
+		os.dwOSVersionInfoSize = sizeof(os);
+		GetVersionEx((LPOSVERSIONINFOA)&os);
+
+		v->IsNT = true;
+		v->Build = os.dwBuildNumber;
+		v->ServicePack = os.wServicePackMajor;
+
+		if (os.wProductType != VER_NT_WORKSTATION)
+		{
+			v->IsServer = true;
+		}
+		v->VerMajor = os.dwMajorVersion;
+		v->VerMinor = os.dwMinorVersion;
+
+		if (GetOsInfo()->OsServicePack == 0)
+		{
+			StrCpy(v->Title, sizeof(v->Title), GetOsInfo()->OsProductName);
+		}
+		else
+		{
+			Format(v->Title, sizeof(v->Title), "%s Service Pack %u",
+				GetOsInfo()->OsProductName,
+				GetOsInfo()->OsServicePack);
+		}
+		Trim(v->Title);
+
+		if (InStr(GetOsInfo()->OsVersion, "rc") ||
+			InStr(GetOsInfo()->OsVersion, "beta"))
+		{
+			v->IsBeta = true;
+		}
+	}
+}
+
+// すべての仮想 LAN カードの DHCP アドレスを解放する
+void Win32ReleaseAllDhcp9x(bool wait)
+{
+	TOKEN_LIST *t;
+	UINT i;
+
+	t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, "---dummy-string-ut--");
+	if (t == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *name = t->Token[i];
+		UINT id = GetInstanceId(name);
+		if (id != 0)
+		{
+			Win32ReleaseDhcp9x(id, wait);
+		}
+	}
+
+	FreeToken(t);
+}
+
+// ルーティングテーブル追跡メイン
+void RouteTrackingMain(SESSION *s)
+{
+	ROUTE_TRACKING *t;
+	UINT64 now;
+	ROUTE_TABLE *table;
+	ROUTE_ENTRY *rs;
+	bool changed = false;
+	bool check = false;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+	if (s->ClientModeAndUseVLan == false)
+	{
+		return;
+	}
+
+	// 状態の取得
+	t = ((VLAN *)s->PacketAdapter->Param)->RouteState;
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// 現在時刻
+	PROBE_STR("RouteTrackingMain 1");
+	now = Tick64();
+
+	if (t->RouteChange != NULL)
+	{
+		if (t->NextRouteChangeCheckTime == 0 ||
+			t->NextRouteChangeCheckTime <= now)
+		{
+			t->NextRouteChangeCheckTime = now + 1000ULL;
+
+			check = IsRouteChanged(t->RouteChange);
+
+			if (check)
+			{
+				Debug("*** Routing Table Changed ***\n");
+				t->NextTrackingTime = 0;
+			}
+		}
+	}
+	if (t->NextTrackingTime != 0 && t->NextTrackingTime > now)
+	{
+		PROBE_STR("RouteTrackingMain 2");
+		return;
+	}
+	PROBE_STR("RouteTrackingMain 3");
+
+	// 現在のルーティングテーブルを取得
+	table = GetRouteTable();
+	rs = t->RouteToServer;
+	if (table != NULL)
+	{
+		UINT i;
+		bool route_to_server_erased = true;
+		bool is_vlan_want_to_be_default_gateway = false;
+		UINT vlan_default_gatewat_metric = 0;
+		UINT other_if_default_gateway_metric_min = INFINITE;
+
+		// ルーティングテーブルが変更されたかどうか取得
+		if (t->LastRoutingTableHash != table->HashedValue)
+		{
+			t->LastRoutingTableHash = table->HashedValue;
+			changed = true;
+		}
+
+		//DebugPrintRouteTable(table);
+
+		// ルーティングテーブルを走査
+		for (i = 0;i < table->NumEntry;i++)
+		{
+			ROUTE_ENTRY *e = table->Entry[i];
+
+			if (rs != NULL)
+			{
+				if (CmpIpAddr(&e->DestIP, &rs->DestIP) == 0 &&
+					CmpIpAddr(&e->DestMask, &rs->DestMask) == 0
+//					&& CmpIpAddr(&e->GatewayIP, &rs->GatewayIP) == 0
+//					&& e->InterfaceID == rs->InterfaceID &&
+//					e->LocalRouting == rs->LocalRouting &&
+//					e->Metric == rs->Metric
+					)
+				{
+					// 接続時に追加したサーバーへのルーティングテーブルが見つかった
+					route_to_server_erased = false;
+				}
+			}
+
+			// デフォルトゲートウェイの検索
+			if (IPToUINT(&e->DestIP) == 0 &&
+				IPToUINT(&e->DestMask) == 0)
+			{
+				//Debug("e->InterfaceID = %u, t->VLanInterfaceId = %u\n",
+				//	e->InterfaceID, t->VLanInterfaceId);
+
+				if (e->InterfaceID == t->VLanInterfaceId)
+				{
+					// 仮想 LAN カードがデフォルトゲートウェイになりたいと思っている
+					is_vlan_want_to_be_default_gateway = true;
+					vlan_default_gatewat_metric = e->Metric;
+
+					if (vlan_default_gatewat_metric >= 2 &&
+						t->OldDefaultGatewayMetric == (vlan_default_gatewat_metric - 1))
+					{
+						// PPP サーバーが勝手に
+						// ルーティングテーブルを書き換えたので戻す
+						DeleteRouteEntry(e);
+						e->Metric--;
+						AddRouteEntry(e);
+						Debug("** Restore metric destroyed by PPP.\n");
+					}
+
+					// このエントリを保存しておく
+					if (t->DefaultGatewayByVLan != NULL)
+					{
+						// 前回追加したものがあれば削除する
+						FreeRouteEntry(t->DefaultGatewayByVLan);
+					}
+
+					t->DefaultGatewayByVLan = ZeroMalloc(sizeof(ROUTE_ENTRY));
+					Copy(t->DefaultGatewayByVLan, e, sizeof(ROUTE_ENTRY));
+
+					t->OldDefaultGatewayMetric = vlan_default_gatewat_metric;
+				}
+				else
+				{
+					// 仮想 LAN カード以外にデフォルトゲートウェイが存在している
+					// このデフォルトゲートウェイのメトリック値を記録しておく
+					if (other_if_default_gateway_metric_min > e->Metric)
+					{
+						// Windows Vista の場合はすべての PPP 接続のメトリック値は無視する
+						if (MsIsVista() == false || e->PPPConnection == false)
+						{
+							other_if_default_gateway_metric_min = e->Metric;
+						}
+						else
+						{
+							// Windows Vista を使用しており PPP を使ってネットワーク
+							// に接続している
+							t->VistaAndUsingPPP = true;
+						}
+					}
+				}
+			}
+		}
+
+		if (t->VistaAndUsingPPP)
+		{
+			if (t->DefaultGatewayByVLan != NULL)
+			{
+				if (is_vlan_want_to_be_default_gateway)
+				{
+					if (t->VistaOldDefaultGatewayByVLan == NULL || Cmp(t->VistaOldDefaultGatewayByVLan, t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY)) != 0)
+					{
+						ROUTE_ENTRY *e;
+						// Windows Vista で PPP を使用して接続しており、かつ
+						// 仮想 LAN カードがデフォルトゲートウェイになるべき場合は
+						// 0.0.0.0/128.0.0.0 および 128.0.0.0/128.0.0.0 のルートを
+						// システムに追加する
+
+						if (t->VistaOldDefaultGatewayByVLan != NULL)
+						{
+							FreeRouteEntry(t->VistaOldDefaultGatewayByVLan);
+						}
+
+						if (t->VistaDefaultGateway1 != NULL)
+						{
+							DeleteRouteEntry(t->VistaDefaultGateway1);
+							FreeRouteEntry(t->VistaDefaultGateway1);
+
+							DeleteRouteEntry(t->VistaDefaultGateway2);
+							FreeRouteEntry(t->VistaDefaultGateway2);
+						}
+
+						t->VistaOldDefaultGatewayByVLan = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY));
+
+						e = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY));
+						SetIP(&e->DestIP, 0, 0, 0, 0);
+						SetIP(&e->DestMask, 128, 0, 0, 0);
+						t->VistaDefaultGateway1 = e;
+
+						e = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY));
+						SetIP(&e->DestIP, 128, 0, 0, 0);
+						SetIP(&e->DestMask, 128, 0, 0, 0);
+						t->VistaDefaultGateway2 = e;
+
+						AddRouteEntry(t->VistaDefaultGateway1);
+						AddRouteEntry(t->VistaDefaultGateway2);
+
+						Debug("Vista PPP Fix Route Table Added.\n");
+					}
+				}
+				else
+				{
+					if (t->VistaOldDefaultGatewayByVLan != NULL)
+					{
+						FreeRouteEntry(t->VistaOldDefaultGatewayByVLan);
+						t->VistaOldDefaultGatewayByVLan = NULL;
+					}
+
+					if (t->VistaDefaultGateway1 != NULL)
+					{
+						Debug("Vista PPP Fix Route Table Deleted.\n");
+						DeleteRouteEntry(t->VistaDefaultGateway1);
+						FreeRouteEntry(t->VistaDefaultGateway1);
+
+						DeleteRouteEntry(t->VistaDefaultGateway2);
+						FreeRouteEntry(t->VistaDefaultGateway2);
+
+						t->VistaDefaultGateway1 = t->VistaDefaultGateway2 = NULL;
+					}
+				}
+			}
+		}
+
+		// 仮想 LAN カードがデフォルトゲートウェイになることを希望しており
+		// かつ仮想 LAN カードの 0.0.0.0/0.0.0.0 のメトリック値よりも小さなメトリック値の
+		// LAN カードが他に 1 枚も無い場合は、他のデフォルトゲートウェイエントリを削除して
+		// 仮想 LAN カードをデフォルトゲートウェイに強制的に選出する
+		if (is_vlan_want_to_be_default_gateway && (rs != NULL && route_to_server_erased == false) &&
+			other_if_default_gateway_metric_min >= vlan_default_gatewat_metric)
+		{
+			// 再度ルーティングテーブルを走査
+			for (i = 0;i < table->NumEntry;i++)
+			{
+				ROUTE_ENTRY *e = table->Entry[i];
+
+				if (e->InterfaceID != t->VLanInterfaceId)
+				{
+					if (IPToUINT(&e->DestIP) == 0 &&
+					IPToUINT(&e->DestMask) == 0)
+					{
+						char str[64];
+						// デフォルトゲートウェイを発見
+						ROUTE_ENTRY *r = ZeroMalloc(sizeof(ROUTE_ENTRY));
+
+						Copy(r, e, sizeof(ROUTE_ENTRY));
+
+						// キューに入れておく
+						InsertQueue(t->DeletedDefaultGateway, r);
+
+						// このゲートウェイエントリを一旦削除する
+						DeleteRouteEntry(e);
+
+						IPToStr(str, sizeof(str), &e->GatewayIP);
+						Debug("Default Gateway %s Deleted.\n", str);
+					}
+				}
+			}
+		}
+
+		if (rs != NULL && route_to_server_erased)
+		{
+			// サーバーへの物理的なエントリが消滅している
+			Debug("Route to Server entry ERASED !!!\n");
+
+			// 強制切断 (再接続有効)
+			s->RetryFlag = true;
+			s->Halt = true;
+		}
+
+		// ルーティングテーブルを解放
+		FreeRouteTable(table);
+	}
+
+	// 次回トラッキングを行う時刻を設定
+	if (t->NextTrackingTimeAdd == 0 || changed)
+	{
+		t->NextTrackingTimeAdd = TRACKING_INTERVAL_INITIAL;
+	}
+	else
+	{
+		UINT64 max_value = TRACKING_INTERVAL_MAX;
+		if (t->RouteChange != NULL)
+		{
+			max_value = TRACKING_INTERVAL_MAX_RC;
+		}
+
+		t->NextTrackingTimeAdd += TRACKING_INTERVAL_ADD;
+
+		if (t->NextTrackingTimeAdd >= max_value)
+		{
+			t->NextTrackingTimeAdd = max_value;
+		}
+	}
+	//Debug("t->NextTrackingTimeAdd = %I64u\n", t->NextTrackingTimeAdd);
+	t->NextTrackingTime = now + t->NextTrackingTimeAdd;
+}
+
+// ルーティングテーブルの追跡を開始する
+void RouteTrackingStart(SESSION *s)
+{
+	VLAN *v;
+	ROUTE_TRACKING *t;
+	UINT if_id = 0;
+	ROUTE_ENTRY *e;
+	ROUTE_ENTRY *dns = NULL;
+	char tmp[64];
+	UINT exclude_if_id = 0;
+	bool already_exists = false;
+	bool already_exists_by_other_account = false;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	v = (VLAN *)s->PacketAdapter->Param;
+	if (v->RouteState != NULL)
+	{
+		return;
+	}
+
+	// 仮想 LAN カードのインターフェース ID を取得する
+	if_id = GetInstanceId(v->InstanceName);
+	Debug("[InstanceId of %s] = 0x%x\n", v->InstanceName, if_id);
+
+	if (MsIsVista())
+	{
+		// Windows Vista では明示的に仮想 LAN カード本体によるルーティングテーブル
+		// を除外しなければならない
+		exclude_if_id = if_id;
+	}
+
+	// サーバーまでのルートを取得する
+	e = GetBestRouteEntryEx(&s->ServerIP, exclude_if_id);
+	if (e == NULL)
+	{
+		// 取得失敗
+		Debug("Failed to get GetBestRouteEntry().\n");
+		return;
+	}
+	IPToStr(tmp, sizeof(tmp), &e->GatewayIP);
+	Debug("GetBestRouteEntry() Succeed. [Gateway: %s]\n", tmp);
+
+	// ルートを追加する
+	if (MsIsVista())
+	{
+		e->Metric = e->OldIfMetric;
+	}
+	if (AddRouteEntryEx(e, &already_exists) == false)
+	{
+		FreeRouteEntry(e);
+		e = NULL;
+	}
+	Debug("already_exists: %u\n", already_exists);
+
+	if (already_exists)
+	{
+		if (s->Cedar->Client != NULL && s->Account != NULL)
+		{
+			UINT i;
+			ACCOUNT *a;
+			for (i = 0;i < LIST_NUM(s->Cedar->Client->AccountList);i++)
+			{
+				a = LIST_DATA(s->Cedar->Client->AccountList, i);
+				Lock(a->lock);
+				{
+					SESSION *sess = a->ClientSession;
+					if (sess != NULL && sess != s)
+					{
+						VLAN *v = sess->PacketAdapter->Param;
+						if (v != NULL)
+						{
+							ROUTE_TRACKING *tr = v->RouteState;
+							if (tr != NULL && e != NULL)
+							{
+								if (Cmp(tr->RouteToServer, e, sizeof(ROUTE_ENTRY)) == 0)
+								{
+									already_exists_by_other_account = true;
+								}
+							}
+						}
+					}
+				}
+				Unlock(a->lock);
+			}
+		}
+
+		if (already_exists_by_other_account)
+		{
+			Debug("already_exists_by_other_account = %u\n", already_exists_by_other_account);
+			already_exists = false;
+		}
+	}
+
+	// DNS サーバーまでのルーティングテーブルを取得する
+	dns = GetBestRouteEntryEx(&s->DefaultDns, exclude_if_id);
+	if (dns == NULL)
+	{
+		// 取得失敗
+		Debug("Failed to get GetBestRouteEntry DNS.\n");
+	}
+	else
+	{
+		// ルートを追加する
+		if (MsIsVista())
+		{
+			dns->Metric = dns->OldIfMetric;
+
+			if (AddRouteEntry(dns) == false)
+			{
+				FreeRouteEntry(dns);
+				dns = NULL;
+			}
+		}
+	}
+
+	// 初期化
+	if (s->Cedar->Client != NULL && s->Account != NULL)
+	{
+		Lock(s->Account->lock);
+	}
+
+	t = ZeroMalloc(sizeof(ROUTE_TRACKING));
+	v->RouteState = t;
+
+	t->RouteToServerAlreadyExists = already_exists;
+	t->RouteToServer = e;
+	t->RouteToDefaultDns = dns;
+	t->VLanInterfaceId = if_id;
+	t->NextTrackingTime = 0;
+	t->DeletedDefaultGateway = NewQueue();
+	t->OldDefaultGatewayMetric = 0x7fffffff;
+
+	if (s->Cedar->Client != NULL && s->Account != NULL)
+	{
+		Unlock(s->Account->lock);
+	}
+
+	// ネットワーク変更を検出するために
+	// 現在のデフォルト DNS サーバーを取得しておく
+	GetDefaultDns(&t->OldDnsServer);
+
+	// DHCP を使用する場合は IP アドレスを解放してすぐに取得する
+	if (IsNt())
+	{
+		char tmp[MAX_SIZE];
+		MS_ADAPTER *a;
+
+		Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG, v->InstanceName);
+		a = MsGetAdapter(tmp);
+
+		if (a != NULL)
+		{
+			if (a->UseDhcp)
+			{
+				bool ret = Win32ReleaseAddressByGuidEx(a->Guid, 100);
+				Debug("*** Win32ReleaseAddressByGuidEx = %u\n", ret);
+
+				ret = Win32RenewAddressByGuidEx(a->Guid, 100);
+				Debug("*** Win32RenewAddressByGuidEx = %u\n", ret);
+			}
+
+			MsFreeAdapter(a);
+		}
+	}
+	else
+	{
+		// Win9x の場合
+		Win32RenewDhcp9x(if_id);
+	}
+
+	// ルーティングテーブルの変更を検出 (対応 OS のみ)
+	t->RouteChange = NewRouteChange();
+	Debug("t->RouteChange = 0x%p\n", t->RouteChange);
+}
+
+// ルーティングテーブルの追跡を終了する
+void RouteTrackingStop(SESSION *s, ROUTE_TRACKING *t)
+{
+	ROUTE_ENTRY *e;
+	ROUTE_TABLE *table;
+	IP dns_ip;
+	bool network_has_changed = false;
+	bool do_not_delete_routing_entry = false;
+	// 引数チェック
+	if (s == NULL || t == NULL)
+	{
+		return;
+	}
+
+	Zero(&dns_ip, sizeof(dns_ip));
+
+	// 仮想 LAN カードが追加したデフォルトゲートウェイを削除する
+	if (t->DefaultGatewayByVLan != NULL)
+	{
+		Debug("Default Gateway by VLAN was deleted.\n");
+		DeleteRouteEntry(t->DefaultGatewayByVLan);
+		FreeRouteEntry(t->DefaultGatewayByVLan);
+		t->DefaultGatewayByVLan = NULL;
+	}
+
+	if (t->VistaOldDefaultGatewayByVLan != NULL)
+	{
+		FreeRouteEntry(t->VistaOldDefaultGatewayByVLan);
+	}
+
+	if (t->VistaDefaultGateway1 != NULL)
+	{
+		Debug("Vista PPP Fix Route Table Deleted.\n");
+		DeleteRouteEntry(t->VistaDefaultGateway1);
+		FreeRouteEntry(t->VistaDefaultGateway1);
+
+		DeleteRouteEntry(t->VistaDefaultGateway2);
+		FreeRouteEntry(t->VistaDefaultGateway2);
+	}
+
+	if (MsIsNt() == false)
+	{
+		// Windows 9x の場合のみ、仮想 LAN カードの DHCP アドレスを解放する
+		Win32ReleaseDhcp9x(t->VLanInterfaceId, false);
+	}
+
+	if (s->Cedar->Client != NULL && s->Account != NULL)
+	{
+		UINT i;
+		ACCOUNT *a;
+		for (i = 0;i < LIST_NUM(s->Cedar->Client->AccountList);i++)
+		{
+			a = LIST_DATA(s->Cedar->Client->AccountList, i);
+			Lock(a->lock);
+			{
+				SESSION *sess = a->ClientSession;
+				if (sess != NULL && sess != s)
+				{
+					VLAN *v = sess->PacketAdapter->Param;
+					if (v != NULL)
+					{
+						ROUTE_TRACKING *tr = v->RouteState;
+						if (tr != NULL)
+						{
+							if (Cmp(tr->RouteToServer, t->RouteToServer, sizeof(ROUTE_ENTRY)) == 0)
+							{
+								do_not_delete_routing_entry = true;
+							}
+						}
+					}
+				}
+			}
+			Unlock(a->lock);
+		}
+
+		Lock(s->Account->lock);
+	}
+
+	if (do_not_delete_routing_entry == false)
+	{
+		// 最初に追加したルートを削除する
+		if (t->RouteToServerAlreadyExists == false)
+		{
+			DeleteRouteEntry(t->RouteToServer);
+		}
+
+		DeleteRouteEntry(t->RouteToDefaultDns);
+	}
+
+	FreeRouteEntry(t->RouteToDefaultDns);
+	FreeRouteEntry(t->RouteToServer);
+	t->RouteToDefaultDns = t->RouteToServer = NULL;
+
+	if (s->Cedar->Client != NULL && s->Account != NULL)
+	{
+		Unlock(s->Account->lock);
+	}
+
+#if	0
+	// 現在の DNS サーバーを取得する
+	if (GetDefaultDns(&dns_ip))
+	{
+		if (IPToUINT(&t->OldDnsServer) != 0)
+		{
+			if (IPToUINT(&t->OldDnsServer) != IPToUINT(&dns_ip))
+			{
+				char s1[MAX_SIZE], s2[MAX_SIZE];
+				network_has_changed = true;
+				IPToStr(s1, sizeof(s1), &t->OldDnsServer);
+				IPToStr(s2, sizeof(s2), &dns_ip);
+				Debug("Old Dns: %s, New Dns: %s\n",
+					s1, s2);
+			}
+		}
+	}
+
+	if (network_has_changed == false)
+	{
+		Debug("Network: not changed.\n");
+	}
+	else
+	{
+		Debug("Network: Changed.\n");
+	}
+
+#endif
+
+	// 現在のルーティングテーブルを取得する
+	table = GetRouteTable();
+
+	// これまで削除してきたルーティングテーブルを復元する
+	while (e = GetNext(t->DeletedDefaultGateway))
+	{
+		bool restore = true;
+		UINT i;
+		// 復元しようとしているルーティングテーブルがデフォルトゲートウェイの場合
+		// かつ既存のルーティングテーブルでそのインターフェースによるデフォルト
+		// ルートが 1 つでも登録されている場合は復元しない
+		if (IPToUINT(&e->DestIP) == 0 && IPToUINT(&e->DestMask) == 0)
+		{
+			for (i = 0;i < table->NumEntry;i++)
+			{
+				ROUTE_ENTRY *r = table->Entry[i];
+				if (IPToUINT(&r->DestIP) == 0 && IPToUINT(&r->DestMask) == 0)
+				{
+					if (r->InterfaceID == e->InterfaceID)
+					{
+						restore = false;
+					}
+				}
+			}
+			if (network_has_changed)
+			{
+				restore = false;
+			}
+		}
+
+		if (restore)
+		{
+			// ルーティングテーブル復元
+			AddRouteEntry(e);
+		}
+
+		// メモリ解放
+		FreeRouteEntry(e);
+	}
+
+	// 解放
+	FreeRouteTable(table);
+	ReleaseQueue(t->DeletedDefaultGateway);
+
+	FreeRouteChange(t->RouteChange);
+
+	Free(t);
+}
+
+// 仮想 LAN カードのインスタンス ID を取得する
+UINT GetInstanceId(char *name)
+{
+	char tmp[MAX_SIZE];
+	UINT id = 0;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return 0;
+	}
+
+	Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG, name);
+
+	id = GetVLanInterfaceID(tmp);
+	if (id != 0)
+	{
+		return id;
+	}
+
+	return 0;
+}
+
+// 仮想 LAN カードのインスタンスリストを取得する
+INSTANCE_LIST *GetInstanceList()
+{
+	INSTANCE_LIST *n = ZeroMalloc(sizeof(INSTANCE_LIST));
+
+	// 列挙
+	char **ss = EnumVLan(VLAN_ADAPTER_NAME);
+
+	if (ss == NULL)
+	{
+		// 失敗
+		n->NumInstance = 0;
+		n->InstanceName = Malloc(0);
+		return n;
+	}
+	else
+	{
+		UINT i, num;
+		i = num = 0;
+		while (true)
+		{
+			if (ss[i++] == NULL)
+			{
+				break;
+			}
+			num++;
+		}
+		i = 0;
+		n->NumInstance = num;
+		n->InstanceName = (char **)ZeroMalloc(sizeof(char *) * n->NumInstance);
+		for (i = 0;i < num;i++)
+		{
+			char *s = ss[i] + StrLen(VLAN_ADAPTER_NAME) + StrLen(" - ");
+			if (StrLen(ss[i]) > StrLen(VLAN_ADAPTER_NAME) + StrLen(" - "))
+			{
+				n->InstanceName[i] = CopyStr(s);
+			}
+		}
+		FreeEnumVLan(ss);
+	}
+
+	return n;
+}
+
+// インスタンスリストを解放する
+void FreeInstanceList(INSTANCE_LIST *n)
+{
+	UINT i;
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < n->NumInstance;i++)
+	{
+		Free(n->InstanceName[i]);
+	}
+	Free(n->InstanceName);
+	Free(n);
+}
+
+// パケットアダプタの解放
+void VLanPaFree(SESSION *s)
+{
+	VLAN *v;
+	ROUTE_TRACKING *t;
+	// 引数チェック
+	if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+	{
+		return;
+	}
+
+	// DHCP を使用している場合は IP アドレスを解放する
+	if (IsNt())
+	{
+		char tmp[MAX_SIZE];
+		MS_ADAPTER *a;
+
+		Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG, v->InstanceName);
+		a = MsGetAdapter(tmp);
+
+		if (a != NULL)
+		{
+			if (a->UseDhcp)
+			{
+				bool ret = Win32ReleaseAddressByGuidEx(a->Guid, 50);
+				Debug("*** Win32ReleaseAddressByGuid = %u\n", ret);
+			}
+
+			MsFreeAdapter(a);
+		}
+	}
+
+	t = v->RouteState;
+	// 仮想 LAN カードの終了
+	FreeVLan(v);
+
+	// ルーティングテーブル追跡終了
+	if (s->ClientModeAndUseVLan)
+	{
+		RouteTrackingStop(s, t);
+	}
+	s->PacketAdapter->Param = NULL;
+}
+
+
+// パケットの書き込み
+bool VLanPaPutPacket(SESSION *s, void *data, UINT size)
+{
+	VLAN *v;
+	// 引数チェック
+	if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+	{
+		return false;
+	}
+
+	return VLanPutPacket(v, data, size);
+}
+
+// 次のパケットを取得
+UINT VLanPaGetNextPacket(SESSION *s, void **data)
+{
+	VLAN *v;
+	UINT size;
+	// 引数チェック
+	if (data == NULL || (s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+	{
+		return 0;
+	}
+
+	RouteTrackingMain(s);
+
+	if (VLanGetNextPacket(v, data, &size) == false)
+	{
+		return INFINITE;
+	}
+
+	return size;
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *VLanPaGetCancel(SESSION *s)
+{
+	VLAN *v;
+	// 引数チェック
+	if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+	{
+		return NULL;
+	}
+
+	return VLanGetCancel(v);
+}
+
+// パケットアダプタ初期化
+bool VLanPaInit(SESSION *s)
+{
+	VLAN *v;
+	// 引数チェック
+	if ((s == NULL)/* || (s->ServerMode != false) || (s->ClientOption == NULL)*/)
+	{
+		return false;
+	}
+
+	// 接続直前の DNS サーバーの IP アドレスの取得
+	if (s->ClientModeAndUseVLan)
+	{
+		Zero(&s->DefaultDns, sizeof(IP));
+		GetDefaultDns(&s->DefaultDns);
+	}
+
+	// ドライバに接続
+	v = NewVLan(s->ClientOption->DeviceName, NULL);
+	if (v == NULL)
+	{
+		// 失敗
+		return false;
+	}
+
+	s->PacketAdapter->Param = v;
+
+	// ルーティングテーブル追跡開始
+	if (s->ClientModeAndUseVLan)
+	{
+		RouteTrackingStart(s);
+	}
+
+	return true;
+}
+
+// VLAN のパケットアダプタを取得
+PACKET_ADAPTER *VLanGetPacketAdapter()
+{
+	PACKET_ADAPTER *pa;
+
+	pa = NewPacketAdapter(VLanPaInit, VLanPaGetCancel,
+		VLanPaGetNextPacket, VLanPaPutPacket, VLanPaFree);
+	if (pa == NULL)
+	{
+		return NULL;
+	}
+
+	return pa;
+}
+
+
+// 次の受信パケットをドライバに書き込む
+bool VLanPutPacket(VLAN *v, void *buf, UINT size)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return false;
+	}
+	if (v->Halt)
+	{
+		return false;
+	}
+	if (size > MAX_PACKET_SIZE)
+	{
+		return false;
+	}
+
+	// まず、現在のバッファが一杯になっているかどうか調べる
+	if ((SEN_NUM_PACKET(v->PutBuffer) >= SEN_MAX_PACKET_EXCHANGE) ||
+		(buf == NULL && SEN_NUM_PACKET(v->PutBuffer) != 0))
+	{
+#ifdef	USE_PROBE
+		{
+			char tmp[MAX_SIZE];
+			snprintf(tmp, sizeof(tmp), "VLanPutPacket: SEN_NUM_PACKET(v->PutBuffer) = %u", SEN_NUM_PACKET(v->PutBuffer));
+			PROBE_DATA2(tmp, NULL, 0);
+		}
+#endif	// USE_PROBE
+		// パケットをドライバに書き出す
+		if (VLanPutPacketsToDriver(v) == false)
+		{
+			return false;
+		}
+		SEN_NUM_PACKET(v->PutBuffer) = 0;
+	}
+
+	// 次のパケットをバッファに追加する
+	if (buf != NULL)
+	{
+		UINT i = SEN_NUM_PACKET(v->PutBuffer);
+		SEN_NUM_PACKET(v->PutBuffer)++;
+
+		SEN_SIZE_OF_PACKET(v->PutBuffer, i) = size;
+		Copy(SEN_ADDR_OF_PACKET(v->PutBuffer, i), buf, size);
+		Free(buf);
+	}
+
+	return true;
+}
+
+// 次の送信パケットをドライバから読み出す
+bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size)
+{
+	// 引数チェック
+	if (v == NULL || buf == NULL || size == NULL)
+	{
+		return false;
+	}
+	if (v->Halt)
+	{
+		return false;
+	}
+
+	PROBE_STR("VLanGetNextPacket");
+
+	while (true)
+	{
+		if (v->CurrentPacketCount < SEN_NUM_PACKET(v->GetBuffer))
+		{
+			// すでに読み込まれたパケットがまだ残っている
+			*size = SEN_SIZE_OF_PACKET(v->GetBuffer, v->CurrentPacketCount);
+			*buf = MallocFast(*size);
+			Copy(*buf, SEN_ADDR_OF_PACKET(v->GetBuffer, v->CurrentPacketCount), *size);
+
+			// パケット番号をインクリメントする
+			v->CurrentPacketCount++;
+
+			return true;
+		}
+		else
+		{
+			// 次のパケットをドライバから読み込む
+			if (VLanGetPacketsFromDriver(v) == false)
+			{
+				return false;
+			}
+
+			if (SEN_NUM_PACKET(v->GetBuffer) == 0)
+			{
+				// 現在パケットは届いていない
+				*buf = NULL;
+				*size = 0;
+				return true;
+			}
+
+			v->CurrentPacketCount = 0;
+		}
+	}
+}
+
+// ドライバに現在のすべてのパケットを書き込む
+bool VLanPutPacketsToDriver(VLAN *v)
+{
+	DWORD write_size;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return false;
+	}
+	if (v->Halt)
+	{
+		return false;
+	}
+
+	if (v->Win9xMode == false)
+	{
+		// Windows NT
+		PROBE_STR("VLanPutPacketsToDriver: WriteFile");
+		if (WriteFile(v->Handle, v->PutBuffer, SEN_EXCHANGE_BUFFER_SIZE, &write_size,
+			NULL) == false)
+		{
+			v->Halt = true;
+			return false;
+		}
+		PROBE_STR("VLanPutPacketsToDriver: WriteFile Completed.");
+
+		if (write_size != SEN_EXCHANGE_BUFFER_SIZE)
+		{
+			v->Halt = true;
+			return false;
+		}
+	}
+	else
+	{
+		// Windows 9x
+		if (DeviceIoControl(v->Handle, SEN_IOCTL_PUT_PACKET, v->PutBuffer,
+			SEN_EXCHANGE_BUFFER_SIZE, NULL, 0, &write_size, NULL) == false)
+		{
+			v->Halt = true;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// ドライバから次のパケットを読み込む
+bool VLanGetPacketsFromDriver(VLAN *v)
+{
+	DWORD read_size;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return false;
+	}
+	if (v->Halt)
+	{
+		return false;
+	}
+
+	if (v->Win9xMode == false)
+	{
+		// Windows NT
+		PROBE_STR("VLanGetPacketsFromDriver: ReadFile");
+		if (ReadFile(v->Handle, v->GetBuffer, SEN_EXCHANGE_BUFFER_SIZE,
+			&read_size, NULL) == false)
+		{
+			v->Halt = true;
+			return false;
+		}
+	}
+	else
+	{
+		// Windows 9x
+		if (DeviceIoControl(v->Handle, SEN_IOCTL_GET_PACKET, NULL, 0,
+			v->GetBuffer, SEN_EXCHANGE_BUFFER_SIZE, &read_size, NULL) == false)
+		{
+			v->Halt = true;
+			return false;
+		}
+	}
+
+	if (read_size != SEN_EXCHANGE_BUFFER_SIZE)
+	{
+		v->Halt = true;
+		return false;
+	}
+
+	return true;
+}
+
+// キャンセルオブジェクトの取得
+CANCEL *VLanGetCancel(VLAN *v)
+{
+	CANCEL *c;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	// キャンセルオブジェクトの作成
+	c = NewCancel();
+	c->SpecialFlag = true;
+	CloseHandle(c->hEvent);
+
+	c->hEvent = v->Event;
+
+	return c;
+}
+
+// VLAN オブジェクトの解放
+void FreeVLan(VLAN *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// ハンドルを閉じる
+	CloseHandle(v->Event);
+	CloseHandle(v->Handle);
+
+	// メモリ解放
+	Free(v->InstanceName);
+	Free(v->EventNameWin32);
+	Free(v->DeviceNameWin32);
+	Free(v->PutBuffer);
+	Free(v->GetBuffer);
+	Free(v);
+}
+
+// VLAN オブジェクトの作成
+VLAN *NewVLan(char *instance_name, VLAN_PARAM *param)
+{
+	VLAN *v;
+	HANDLE h = INVALID_HANDLE_VALUE;
+	HANDLE e = INVALID_HANDLE_VALUE;
+	char tmp[MAX_SIZE];
+	char name_upper[MAX_SIZE];
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return NULL;
+	}
+
+	v = ZeroMalloc(sizeof(VLAN));
+
+	if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+	{
+		v->Win9xMode = true;
+	}
+
+	// 名前の初期化
+	Format(name_upper, sizeof(name_upper), "%s", instance_name);
+	StrUpper(name_upper);
+	v->InstanceName = CopyStr(name_upper);
+	Format(tmp, sizeof(tmp), NDIS_SEN_DEVICE_FILE_NAME, v->InstanceName);
+	v->DeviceNameWin32 = CopyStr(tmp);
+
+	if (v->Win9xMode == false)
+	{
+		Format(tmp, sizeof(tmp), NDIS_SEN_EVENT_NAME_WIN32, v->InstanceName);
+		v->EventNameWin32 = CopyStr(tmp);
+	}
+
+	// デバイスに接続
+	h = CreateFile(v->DeviceNameWin32,
+		GENERIC_READ | GENERIC_WRITE,
+		0,
+		NULL,
+		OPEN_EXISTING,
+		0,
+		NULL);
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		// 接続失敗
+		goto CLEANUP;
+	}
+
+	if (v->Win9xMode == false)
+	{
+		// イベントに接続
+		e = OpenEvent(SYNCHRONIZE, FALSE, v->EventNameWin32);
+		if (e == INVALID_HANDLE_VALUE)
+		{
+			// 接続失敗
+			goto CLEANUP;
+		}
+	}
+	else
+	{
+		OPENVXDHANDLE OpenVxDHandle;
+		DWORD vxd_handle;
+		UINT bytes_returned;
+
+		OpenVxDHandle = (OPENVXDHANDLE)GetProcAddress(GetModuleHandleA("KERNEL32"),
+			"OpenVxDHandle");
+
+		// イベントを作成してドライバに渡す
+		e = CreateEvent(NULL, FALSE, FALSE, NULL);
+		vxd_handle = (DWORD)OpenVxDHandle(e);
+
+		DeviceIoControl(h, SEN_IOCTL_SET_EVENT, &vxd_handle, sizeof(DWORD),
+			NULL, 0, &bytes_returned, NULL);
+	}
+
+	v->Event = e;
+	v->Handle = h;
+
+	v->GetBuffer = ZeroMalloc(SEN_EXCHANGE_BUFFER_SIZE);
+	v->PutBuffer = ZeroMalloc(SEN_EXCHANGE_BUFFER_SIZE);
+
+	return v;
+
+CLEANUP:
+	if (h != INVALID_HANDLE_VALUE)
+	{
+		CloseHandle(h);
+	}
+	if (e != INVALID_HANDLE_VALUE)
+	{
+		CloseHandle(e);
+	}
+
+	Free(v->InstanceName);
+	Free(v->EventNameWin32);
+	Free(v->DeviceNameWin32);
+	Free(v);
+
+	return NULL;
+}
+
+#endif	// OS_WIN32
+
+#endif	//VLAN_C
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanWin32.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanWin32.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/VLanWin32.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,164 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// VLanWin32.h
+// VLanWin32.c のヘッダ
+
+#ifndef	VLANWIN32_H
+#define	VLANWIN32_H
+
+// ルーティングテーブル追跡タイマ
+#define	TRACKING_INTERVAL_INITIAL		444		// 初期
+#define	TRACKING_INTERVAL_ADD			444		// 追加値
+#define	TRACKING_INTERVAL_MAX			12345	// 最大値
+#define	TRACKING_INTERVAL_MAX_RC		87654	// 最大値 (変更検出機構有効 OS)
+
+
+typedef void *HANDLE;
+
+// ルーティング追跡用状態マシン
+struct ROUTE_TRACKING
+{
+	UINT VLanInterfaceId;
+	ROUTE_ENTRY *RouteToServer;
+	bool RouteToServerAlreadyExists;
+	ROUTE_ENTRY *DefaultGatewayByVLan;
+	ROUTE_ENTRY *VistaDefaultGateway1, *VistaDefaultGateway2, *VistaOldDefaultGatewayByVLan;
+	ROUTE_ENTRY *RouteToDefaultDns;
+	UINT64 NextTrackingTime;
+	UINT64 NextTrackingTimeAdd;
+	UINT64 NextRouteChangeCheckTime;
+	UINT LastRoutingTableHash;
+	QUEUE *DeletedDefaultGateway;
+	UINT OldDefaultGatewayMetric;
+	IP OldDnsServer;
+	bool VistaAndUsingPPP;
+	ROUTE_CHANGE *RouteChange;
+};
+
+// VLAN 構造体
+struct VLAN
+{
+	volatile bool Halt;			// 停止フラグ
+	bool Win9xMode;				// Windows 9x
+	char *InstanceName;			// インスタンス名
+	char *DeviceNameWin32;		// Win32 デバイス名
+	char *EventNameWin32;		// Win32 イベント名
+	HANDLE Handle;				// デバイスドライバのファイル
+	HANDLE Event;				// イベントのハンドル
+	void *GetBuffer;			// 送信パケット取得用バッファ
+	UINT CurrentPacketCount;	// 次に読み込むパケット番号
+	void *PutBuffer;			// 受信パケット書き込み用バッファ
+	ROUTE_TRACKING *RouteState;	// ルーティング追跡用状態マシン
+};
+
+// インスタンスリスト
+struct INSTANCE_LIST
+{
+	UINT NumInstance;
+	char **InstanceName;
+};
+
+
+// 関数プロトタイプ
+VLAN *NewVLan(char *instance_name, VLAN_PARAM *param);
+void FreeVLan(VLAN *v);
+CANCEL *VLanGetCancel(VLAN *v);
+bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size);
+bool VLanGetPacketsFromDriver(VLAN *v);
+bool VLanPutPacketsToDriver(VLAN *v);
+bool VLanPutPacket(VLAN *v, void *buf, UINT size);
+
+PACKET_ADAPTER *VLanGetPacketAdapter();
+bool VLanPaInit(SESSION *s);
+CANCEL *VLanPaGetCancel(SESSION *s);
+UINT VLanPaGetNextPacket(SESSION *s, void **data);
+bool VLanPaPutPacket(SESSION *s, void *data, UINT size);
+void VLanPaFree(SESSION *s);
+
+INSTANCE_LIST *GetInstanceList();
+void FreeInstanceList(INSTANCE_LIST *n);
+UINT GetInstanceId(char *name);
+
+void RouteTrackingStart(SESSION *s);
+void RouteTrackingStop(SESSION *s, ROUTE_TRACKING *t);
+void RouteTrackingMain(SESSION *s);
+void Win32ReleaseAllDhcp9x(bool wait);
+
+void Win32GetWinVer(RPC_WINVER *v);
+
+#endif	// VLANWIN32_H
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Virtual.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Virtual.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Virtual.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,5729 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Virtual.c
+// ユーザーモード仮想ホストプログラム
+
+// Q. このプログラムには大変多くの TCP/IP 関係の奥の深い処理が入っていて
+//    さらに TCP スタックの簡易的な実装まで完結しているように見えるが
+//    なぜこのように気合の入ったコードを書いたのか?
+// A. 作者の所属していた筑波大学第三学群情報学類という学科では、
+//    「情報特別演習」という授業がある。なんとこれは専門基礎単位を取得
+//    することができる貴重なコマである。専門基礎単位を取得するための他の
+//    方法としては、解析学Ⅲなどという授業等がある。しかし、作者は受験勉強
+//    のような数学のテスト勉強は嫌いであるし、また、SoftEther に関する打ち合わせ
+//    のために大学の某所に駐車したときにその解析学Ⅲの当時の担当教員の車のミラー
+//    をこすってしまって少し怒られたのでその単位の取得は難しくなった (?) のである。
+//    だが、専門基礎の単位を取得しなければ、卒業することができない。
+//    そこで代わりに「情報特別演習」で単位をとることにしたのだが、この授業は、
+//    何か面白いコンピュータの作品を作ってプレゼンテーションすれば 2 単位がくる
+//    という名目なのであった。しかし、実際のところ、ろくな作品を 1 年間で
+//    作ってプレゼンする人はとても少なく、たいていが「無線 LAN の実験」とか
+//    そういうほとんどクリエイティブな作業を必要とせずにできるいいかげんな
+//    「実習」を行ったと言って結果を報告すれば 2 単位来るという程度の難易度
+//    であることが後になって分かった。
+//    作者は大変真面目なので、部類としてはかなり難しい難易度に入る TCP/IP
+//    スタックの開発を実習としてやってみようと思い、数週間かけていろいろ
+//    プログラムを書いた。その成果の一部がこの Virtual.c というコードである。
+//    逆にいうと、大学の授業の実習程度で開発することができるくらいの簡単な
+//    プログラムなので、実装は簡易的であり、効率が悪く、メンテナンス性にも欠け
+//    ている。結構場当たり的なプログラミングを行ったためである。
+//    それでも 2004 年末に本プログラムをインターネットで配布してから今まで
+//    一応は深刻な不具合は発生していない。ただし探せば深刻な障害が潜んでいる
+//    かも知れない。
+
+
+#include "CedarPch.h"
+
+static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+// Virtual Host のログをとる
+void VLog(VH *v, char *str)
+{
+	// とらん！！
+	return;
+}
+
+// NAT が使用可能かどうかチェック
+bool CanCreateNewNatEntry(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return false;
+	}
+
+	if (v->UseNat == false)
+	{
+		// NAT 停止中
+		return false;
+	}
+
+	if (v->NatTable->num_item > NAT_MAX_SESSIONS)
+	{
+		// セッション数超過
+		return false;
+	}
+
+	return true;
+}
+
+// NAT 処理スレッドのメイン関数
+void NatThreadMain(VH *v)
+{
+	bool halt_flag;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	v->TmpBuf = Malloc(NAT_TMPBUF_SIZE);
+
+	while (true)
+	{
+		// 次のイベントがセットされるまで待機する
+		WaitSockEvent(v->SockEvent, SELECT_TIME);
+
+		halt_flag = false;
+
+		LockVirtual(v);
+		{
+			// すべての NAT セッションに対して処理を行う
+			UINT i, num;
+
+			v->Now = Tick64();
+			v->NatDoCancelFlag = false;
+
+LIST_ELEMENT_DELETED:
+			num = LIST_NUM(v->NatTable);
+			for (i = 0;i < num;i++)
+			{
+				NAT_ENTRY *n = LIST_DATA(v->NatTable, i);
+
+				switch (n->Protocol)
+				{
+				case NAT_TCP:		// TCP
+					if (NatTransactTcp(v, n) == false)
+					{
+						goto LIST_ELEMENT_DELETED;
+					}
+					break;
+
+				case NAT_UDP:		// UDP
+					if (NatTransactUdp(v, n) == false)
+					{
+						goto LIST_ELEMENT_DELETED;
+					}
+					break;
+
+				case NAT_DNS:		// DNS
+					if (NatTransactDns(v, n) == false)
+					{
+						goto LIST_ELEMENT_DELETED;
+					}
+					break;
+				}
+			}
+
+			if (v->NatDoCancelFlag)
+			{
+				// 親スレッドの Cancel を叩く
+				Cancel(v->Cancel);
+			}
+
+			// 停止フラグチェック
+			if (v->HaltNat)
+			{
+				halt_flag = true;
+			}
+		}
+		UnlockVirtual(v);
+
+		if (halt_flag)
+		{
+			// すべてのエントリを強制切断してからスレッドを終了する
+			LockVirtual(v);
+			{
+				UINT num = LIST_NUM(v->NatTable);
+				NAT_ENTRY **nn = ToArray(v->NatTable);
+				UINT i;
+
+				for (i = 0;i < num;i++)
+				{
+					NAT_ENTRY *n = nn[i];
+					n->DisconnectNow = true;
+
+					switch (n->Protocol)
+					{
+					case NAT_TCP:		// TCP
+						NatTransactTcp(v, n);
+						break;
+
+					case NAT_UDP:		// UDP
+						NatTransactUdp(v, n);
+						break;
+
+					case NAT_DNS:		// DNS
+						NatTransactDns(v, n);
+						break;
+					}
+				}
+
+				Free(nn);
+			}
+			UnlockVirtual(v);
+			break;
+		}
+	}
+
+	Free(v->TmpBuf);
+}
+
+// DNS: IP アドレスを取得するスレッド
+void NatGetIPThread(THREAD *t, void *param)
+{
+	NAT_DNS_QUERY *q;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	q = (NAT_DNS_QUERY *)param;
+	AddWaitThread(t);
+
+	q->Ok = GetIP(&q->Ip, q->Hostname);
+
+	DelWaitThread(t);
+
+	if (Release(q->ref) == 0)
+	{
+		Free(q);
+	}
+}
+
+// DNS: ホスト名から IP アドレスを取得する
+bool NatGetIP(IP *ip, char *hostname)
+{
+	TOKEN_LIST *t;
+	bool ret = false;
+	// 引数チェック
+	if (ip == NULL || hostname == NULL)
+	{
+		return false;
+	}
+
+	t = ParseToken(hostname, ".");
+	if (t == NULL)
+	{
+		return false;
+	}
+	if (t->NumTokens == 0)
+	{
+		FreeToken(t);
+		return false;
+	}
+
+	if (t->NumTokens == 1)
+	{
+		ret = GetIP(ip, hostname);
+	}
+	else
+	{
+		char *hostname2 = t->Token[0];
+		NAT_DNS_QUERY *q1, *q2;
+		THREAD *t1, *t2;
+
+		q1 = ZeroMalloc(sizeof(NAT_DNS_QUERY));
+		q2 = ZeroMalloc(sizeof(NAT_DNS_QUERY));
+		q1->ref = NewRef();
+		q2->ref = NewRef();
+		AddRef(q1->ref);
+		AddRef(q2->ref);
+		StrCpy(q1->Hostname, sizeof(q1->Hostname), hostname);
+		StrCpy(q2->Hostname, sizeof(q2->Hostname), hostname2);
+
+		t1 = NewThread(NatGetIPThread, q1);
+		t2 = NewThread(NatGetIPThread, q2);
+
+		WaitThread(t1, NAT_DNS_QUERY_TIMEOUT);
+
+		if (q1->Ok)
+		{
+			ret = true;
+			Copy(ip, &q1->Ip, sizeof(IP));
+		}
+		else
+		{
+			WaitThread(t2, NAT_DNS_QUERY_TIMEOUT);
+			if (q1->Ok)
+			{
+				ret = true;
+				Copy(ip, &q1->Ip, sizeof(IP));
+			}
+			else if (q2->Ok)
+			{
+				ret = true;
+				Copy(ip, &q2->Ip, sizeof(IP));
+			}
+		}
+
+		ReleaseThread(t1);
+		ReleaseThread(t2);
+
+		if (Release(q1->ref) == 0)
+		{
+			Free(q1);
+		}
+		if (Release(q2->ref) == 0)
+		{
+			Free(q2);
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// DNS 問い合わせ関数
+void NatDnsThread(THREAD *t, void *param)
+{
+	NAT_ENTRY *n;
+	IP ip;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+	n = (NAT_ENTRY *)param;
+
+	// 初期化完了を通知
+	NoticeThreadInit(t);
+
+	// 処理を実行
+	if (EndWith(n->DnsTargetHostName, ".in-addr.arpa") == false)
+	{
+		// 正引き
+		if (NatGetIP(&ip, n->DnsTargetHostName))
+		{
+			// 正引き成功
+			Copy(&n->DnsResponseIp, &ip, sizeof(IP));
+			n->DnsOk = true;
+		}
+	}
+	else
+	{
+		// 逆引き
+		IP ip;
+		n->DnsGetIpFromHost = true;		// 逆引きフラグを設定
+		// *.in-addr.arpa 文字列を IP アドレスに変換してもらう
+		if (ArpaToIP(&ip, n->DnsTargetHostName))
+		{
+			// 逆引き処理
+			char tmp[256];
+			if (GetHostName(tmp, sizeof(tmp), &ip))
+			{
+				// 逆引き成功
+				n->DnsResponseHostName = CopyStr(tmp);
+				n->DnsOk = true;
+			}
+		}
+	}
+
+	// 結果を通知
+	n->DnsFinished = true;
+
+	SetSockEvent(n->v->SockEvent);
+}
+
+// 逆引き用アドレスを IP アドレスに変換する
+bool ArpaToIP(IP *ip, char *str)
+{
+	TOKEN_LIST *token;
+	bool ret = false;
+	// 引数チェック
+	if (ip == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	// トークン変換
+	token = ParseToken(str, ".");
+	if (token->NumTokens == 6)
+	{
+		// token[0, 1, 2, 3] を IP に変換
+		UINT i;
+		Zero(ip, sizeof(IP));
+		for (i = 0;i < 4;i++)
+		{
+			ip->addr[i] = (UCHAR)ToInt(token->Token[3 - i]);
+		}
+		ret = true;
+	}
+
+	FreeToken(token);
+
+	if (IPToUINT(ip) == 0)
+	{
+		ret = false;
+	}
+
+	return ret;
+}
+
+// DNS エントリを処理する
+bool NatTransactDns(VH *v, NAT_ENTRY *n)
+{
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return true;
+	}
+
+	if (n->DisconnectNow)
+	{
+		goto DISCONNECT;
+	}
+
+	if (n->DnsThread == NULL && n->DnsFinished == false)
+	{
+		// スレッドを作成する
+		THREAD *t = NewThread(NatDnsThread, (void *)n);
+		WaitThreadInit(t);
+		n->DnsThread = t;
+	}
+	else
+	{
+		// 結果を待機する
+		if (n->DnsFinished)
+		{
+			// 結果が届いている
+			WaitThread(n->DnsThread, INFINITE);
+			ReleaseThread(n->DnsThread);
+			n->DnsThread = NULL;
+			// メインスレッドに通知
+			v->NatDoCancelFlag = true;
+		}
+	}
+
+	return true;
+
+DISCONNECT:
+
+	// 解放処理
+	if (n->DnsThread != NULL)
+	{
+		WaitThread(n->DnsThread, INFINITE);
+		ReleaseThread(n->DnsThread);
+		n->DnsThread = NULL;
+	}
+
+	if (n->DnsTargetHostName != NULL)
+	{
+		Free(n->DnsTargetHostName);
+		n->DnsTargetHostName = NULL;
+	}
+
+	if (n->DnsResponseHostName != NULL)
+	{
+		Free(n->DnsResponseHostName);
+		n->DnsResponseHostName = NULL;
+	}
+
+	DeleteLock(n->lock);
+	Delete(v->NatTable, n);
+	Free(n);
+
+	return false;
+}
+
+// UDP エントリを処理する
+bool NatTransactUdp(VH *v, NAT_ENTRY *n)
+{
+	void *buf;
+	UINT recv_size;
+	BLOCK *block;
+	UINT dest_port = n->DestPort;
+	IP dest_ip;
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return true;
+	}
+
+	if (n->DisconnectNow)
+	{
+		goto DISCONNECT;
+	}
+
+	if (n->UdpSocketCreated == false)
+	{
+		// UDP ソケットを作成する
+		n->Sock = NewUDP(0);
+		if (n->Sock == NULL)
+		{
+			// ソケット作成失敗
+			goto DISCONNECT;
+		}
+		else
+		{
+			n->PublicIp = IPToUINT(&n->Sock->LocalIP);
+			n->PublicPort = n->Sock->LocalPort;
+
+			JoinSockToSockEvent(n->Sock, v->SockEvent);
+			n->UdpSocketCreated = true;
+		}
+	}
+
+	buf = v->TmpBuf;
+	if (n->ProxyDns == false)
+	{
+		UINTToIP(&dest_ip, n->DestIp);
+	}
+	else
+	{
+		UINTToIP(&dest_ip, n->DestIpProxy);
+	}
+
+	// UDP ソケットからデータを受信してみる
+	while (true)
+	{
+		IP src_ip;
+		UINT src_port;
+		recv_size = RecvFrom(n->Sock, &src_ip, &src_port, buf, 65536);
+
+		if (recv_size == SOCK_LATER)
+		{
+			// パケットが届いていない
+			break;
+		}
+		else if (recv_size == 0)
+		{
+			// エラー?
+			if (n->Sock->IgnoreRecvErr == false)
+			{
+				// 致命的なエラーが発生した
+				goto DISCONNECT;
+			}
+		}
+		else
+		{
+			// パケットが届いた。送信元 IP をチェック
+			if (IPToUINT(&src_ip) == n->DestIp || (IPToUINT(&src_ip) == n->DestIpProxy && n->ProxyDns) && src_port == n->DestPort)
+			{
+				// キューに挿入
+				void *data = Malloc(recv_size);
+				Copy(data, buf, recv_size);
+				block = NewBlock(data, recv_size, 0);
+				InsertQueue(n->UdpRecvQueue, block);
+				v->NatDoCancelFlag = true;
+				n->LastCommTime = v->Now;
+			}
+		}
+	}
+
+	// UDP ソケットにデータを送信してみる
+	while (block = GetNext(n->UdpSendQueue))
+	{
+		UINT send_size = SendTo(n->Sock, &dest_ip, dest_port, block->Buf, block->Size);
+
+		FreeBlock(block);
+		if (send_size == 0)
+		{
+			// 致命的なエラーかどうか判定
+			if (n->Sock->IgnoreSendErr == false)
+			{
+				// 致命的なエラーが発生した
+				goto DISCONNECT;
+			}
+		}
+		else
+		{
+			n->LastCommTime = v->Now;
+		}
+	}
+
+	// このセッションがタイムアウトになっていないかどうか調べる
+	if ((n->LastCommTime + (UINT64)v->NatUdpTimeout) < v->Now || n->LastCommTime > v->Now)
+	{
+		// タイムアウトである
+		goto DISCONNECT;
+	}
+
+	return true;
+
+DISCONNECT:
+	// このセッションを切断
+	if (n->UdpSocketCreated)
+	{
+		// ソケットを閉じる
+		Disconnect(n->Sock);
+		ReleaseSock(n->Sock);
+		n->Sock = NULL;
+	}
+
+	// エントリを削除
+	DeleteNatUdp(v, n);
+
+	return false;
+}
+
+// TCP ホストへの接続処理を行うためのスレッド
+void NatTcpConnectThread(THREAD *t, void *p)
+{
+	NAT_ENTRY *n = (NAT_ENTRY *)p;
+	IP ip;
+	char hostname[MAX_SIZE];
+	UINT port_number;
+	SOCK *sock;
+	SOCK_EVENT *e;
+	// 引数チェック
+	if (n == NULL || t == NULL)
+	{
+		return;
+	}
+
+	UINTToIP(&ip, n->DestIp);
+	IPToStr(hostname, sizeof(hostname), &ip);
+	port_number = n->DestPort;
+	e = n->v->SockEvent;
+	AddRef(e->ref);
+
+	// 初期化完了を通知
+	NoticeThreadInit(t);
+
+	// TCP ホストへの接続を試行
+	Debug("NatTcpConnect Connecting to %s:%u\n", hostname, port_number);
+	sock = Connect(hostname, port_number);
+	if (sock == NULL)
+	{
+		// 接続失敗
+		n->TcpMakeConnectionFailed = true;
+	}
+	else
+	{
+		// 接続成功
+		n->TcpMakeConnectionSucceed = true;
+	}
+	n->Sock = sock;
+	JoinSockToSockEvent(sock, e);
+	SetSockEvent(e);
+
+	ReleaseSockEvent(e);
+}
+
+// TCP ホストに接続するためのスレッドを作成する
+void CreateNatTcpConnectThread(VH *v, NAT_ENTRY *n)
+{
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return;
+	}
+
+	// スレッド作成
+	n->NatTcpConnectThread = NewThread(NatTcpConnectThread, (void *)n);
+
+	// スレッド初期化完了を待機
+	WaitThreadInit(n->NatTcpConnectThread);
+}
+
+// TCP エントリを処理する
+bool NatTransactTcp(VH *v, NAT_ENTRY *n)
+{
+	char str[MAX_SIZE];
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return false;
+	}
+
+	if (n->DisconnectNow)
+	{
+		goto DISCONNECT;
+	}
+
+	// TCP の状態別に処理を行う
+	switch (n->TcpStatus)
+	{
+	case NAT_TCP_CONNECTING:		// 接続待機中
+		if (n->NatTcpConnectThread == NULL)
+		{
+			// 接続スレッドを作成し接続を開始する
+			CreateNatTcpConnectThread(v, n);
+		}
+		else
+		{
+			// すでに開始されている接続スレッドの結果を待機
+			if (n->TcpMakeConnectionFailed || n->TcpMakeConnectionSucceed)
+			{
+				// スレッドの動作はすでに完了しているので結果を使用する
+				WaitThread(n->NatTcpConnectThread, INFINITE);
+				ReleaseThread(n->NatTcpConnectThread);
+				n->NatTcpConnectThread = NULL;
+
+				if (n->TcpMakeConnectionSucceed)
+				{
+					// 接続は成功し Sock が作成された
+					n->TcpStatus = NAT_TCP_CONNECTED;
+					IPToStr32(str, sizeof(str), n->DestIp);
+					NLog(v, "LH_NAT_TCP_SUCCEED", n->Id, n->Sock->RemoteHostname, str, n->DestPort);
+				}
+				else
+				{
+					// 接続に失敗した
+					n->TcpStatus = NAT_TCP_SEND_RESET;
+					IPToStr32(str, sizeof(str), n->DestIp);
+					NLog(v, "LH_NAT_TCP_FAILED", n->Id, str, n->DestPort);
+				}
+				v->NatDoCancelFlag = true;
+			}
+		}
+		break;
+
+	case NAT_TCP_CONNECTED:			// TCP ソケット接続完了 クライアントホストとの間で交渉中
+		break;
+
+	case NAT_TCP_SEND_RESET:		// TCP 通信切断 クライアントホストへ RST を送信
+		break;
+
+	case NAT_TCP_ESTABLISHED:		// TCP 接続確立済み
+		{
+			// 受信バッファにデータがあればソケットに対して送信する
+			while (n->RecvFifo->size > 0)
+			{
+				UINT sent_size = Send(n->Sock, ((UCHAR *)n->RecvFifo->p) + n->RecvFifo->pos,
+					n->RecvFifo->size, false);
+				if (sent_size == 0)
+				{
+					// 通信が切断された
+					n->TcpFinished = true;
+					v->NatDoCancelFlag = true;
+					break;
+				}
+				else if (sent_size == SOCK_LATER)
+				{
+					// ブロッキング
+					break;
+				}
+				else
+				{
+					// 送信成功
+					ReadFifo(n->RecvFifo, NULL, sent_size);
+					n->SendAckNext = true;
+				}
+			}
+			// ソケットからデータを取得して送信バッファに書き込む
+			while (true)
+			{
+				void *buf = (void *)v->TmpBuf;
+				UINT want_to_recv_size = 0;
+				UINT recv_size;
+				// 受信したいサイズを計算する
+				if (n->SendFifo->size < NAT_SEND_BUF_SIZE)
+				{
+					// まだ受信できる
+					want_to_recv_size = MIN(NAT_SEND_BUF_SIZE - n->SendFifo->size, NAT_TMPBUF_SIZE);
+				}
+				if (want_to_recv_size == 0)
+				{
+					break;
+				}
+				recv_size = Recv(n->Sock, buf, want_to_recv_size, false);
+				if (recv_size == 0)
+				{
+					// 通信が切断された
+					n->TcpFinished = true;
+					v->NatDoCancelFlag = true;
+					break;
+				}
+				else if (recv_size == SOCK_LATER)
+				{
+					// ブロッキング
+					break;
+				}
+				else
+				{
+					// 受信成功
+					WriteFifo(n->SendFifo, buf, recv_size);
+					v->NatDoCancelFlag = true;
+				}
+			}
+		}
+		break;
+
+	}
+
+	// タイムアウトの検出
+	if ((n->LastCommTime + (UINT64)v->NatTcpTimeout) < v->Now || n->LastCommTime > v->Now)
+	{
+		// タイムアウトが発生、セッション切断
+		n->TcpStatus = NAT_TCP_SEND_RESET;
+		v->NatDoCancelFlag = true;
+	}
+
+	return true;
+
+DISCONNECT:		// 切断とセッション廃棄処理
+	DeleteNatTcp(v, n);
+
+	return false;
+}
+
+// TCP NAT エントリの削除
+void DeleteNatTcp(VH *v, NAT_ENTRY *n)
+{
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return;
+	}
+
+	NLog(v, "LH_NAT_TCP_DELETED", n->Id);
+
+	// 接続スレッドのシャットダウン
+	if (n->NatTcpConnectThread != NULL)
+	{
+		WaitThread(n->NatTcpConnectThread, INFINITE);
+		ReleaseThread(n->NatTcpConnectThread);
+		n->NatTcpConnectThread = NULL;
+	}
+	if (n->Sock != NULL)
+	{
+		// ソケット切断
+		Disconnect(n->Sock);
+		ReleaseSock(n->Sock);
+		n->Sock = NULL;
+	}
+
+	// ウインドウメモリ解放
+	if (n->TcpRecvWindow != NULL)
+	{
+		ReleaseFifo(n->TcpRecvWindow);
+		n->TcpRecvWindow = NULL;
+	}
+
+	// ウインドウ受信リスト解放
+	if (n->TcpRecvList != NULL)
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+		{
+			IP_PART *p = LIST_DATA(n->TcpRecvList, i);
+			Free(p);
+		}
+		ReleaseList(n->TcpRecvList);
+		n->TcpRecvList = NULL;
+	}
+
+	// FIFO 解放
+	ReleaseFifo(n->SendFifo);
+	ReleaseFifo(n->RecvFifo);
+
+	// NAT エントリから削除
+	Delete(v->NatTable, n);
+
+	DeleteLock(n->lock);
+
+	// メモリ解放
+	Free(n);
+
+	Debug("NAT_ENTRY: DeleteNatTcp\n");
+}
+
+// NAT 処理スレッド
+void NatThread(THREAD *t, void *param)
+{
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	// 初期化完了を通知
+	NoticeThreadInit(t);
+
+	NatThreadMain((VH *)param);
+}
+
+// ビーコンパケットの送信
+void SendBeacon(VH *v)
+{
+	UINT dest_ip;
+	ARPV4_HEADER arp;
+	static char beacon_str[] =
+		"SecureNAT Virtual TCP/IP Stack Beacon";
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// UDP を送信
+	dest_ip = (v->HostIP & v->HostMask) | (~v->HostMask);
+	SendUdp(v, dest_ip, 7, v->HostIP, 7, beacon_str, sizeof(beacon_str));
+
+	// ARP ヘッダを構築
+	arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+	arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+	arp.HardwareSize = 6;
+	arp.ProtocolSize = 4;
+	arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+	Copy(arp.SrcAddress, v->MacAddress, 6);
+	arp.SrcIP = v->HostIP;
+	arp.TargetAddress[0] =
+		arp.TargetAddress[1] =
+		arp.TargetAddress[2] =
+		arp.TargetAddress[3] =
+		arp.TargetAddress[4] =
+		arp.TargetAddress[5] = 0xff;
+	arp.TargetIP = dest_ip;
+
+	// 送信
+	VirtualLayer2Send(v, broadcast, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// TCP パケットの送信
+void SendTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss, void *data, UINT size)
+{
+	static UCHAR tcp_mss_option[] = {0x02, 0x04, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00};
+	TCPV4_PSEUDO_HEADER *vh;
+	TCP_HEADER *tcp;
+	UINT header_size = TCP_HEADER_SIZE;
+	UINT total_size;
+	// 引数チェック
+	if (v == NULL || (size != 0 && data == NULL))
+	{
+		return;
+	}
+
+	// メモリ確保
+	vh = Malloc(sizeof(TCPV4_PSEUDO_HEADER) + TCP_HEADER_SIZE + size + 32);
+	tcp = (TCP_HEADER *)(((UCHAR *)vh) + sizeof(TCPV4_PSEUDO_HEADER));
+
+	if (mss != 0)
+	{
+		USHORT *mss_size;
+		mss_size = (USHORT *)(&tcp_mss_option[2]);
+		*mss_size = Endian16((USHORT)mss);
+		header_size += sizeof(tcp_mss_option);
+	}
+
+	total_size = header_size + size;
+	if (total_size > 65536)
+	{
+		// パケットが長すぎる
+		Free(vh);
+		return;
+	}
+
+	// 擬似ヘッダ生成
+	vh->SrcIP = src_ip;
+	vh->DstIP = dest_ip;
+	vh->Reserved = 0;
+	vh->Protocol = IP_PROTO_TCP;
+	vh->PacketLength = Endian16((USHORT)total_size);
+
+	// TCP ヘッダ生成
+	tcp->SrcPort = Endian16((USHORT)src_port);
+	tcp->DstPort = Endian16((USHORT)dest_port);
+	tcp->SeqNumber = Endian32(seq);
+	tcp->AckNumber = Endian32(ack);
+	tcp->HeaderSizeAndReserved = 0;
+	TCP_SET_HEADER_SIZE(tcp, (UCHAR)(header_size / 4));
+	tcp->Flag = (UCHAR)flag;
+	tcp->WindowSize = Endian16((USHORT)window_size);
+	tcp->Checksum = 0;
+	tcp->UrgentPointer = 0;
+
+	// オプション値コピー
+	if (mss != 0)
+	{
+		Copy(((UCHAR *)tcp) + TCP_HEADER_SIZE, tcp_mss_option, sizeof(tcp_mss_option));
+	}
+
+	// データコピー
+	Copy(((UCHAR *)tcp) + header_size, data, size);
+
+	// チェックサム計算
+	tcp->Checksum = IpChecksum(vh, total_size + 12);
+
+	// IP パケットとして送信
+	SendIp(v, dest_ip, src_ip, IP_PROTO_TCP, tcp, total_size);
+
+	// メモリ解放
+	Free(vh);
+}
+
+// TCP のポーリング処理
+void PollingNatTcp(VH *v, NAT_ENTRY *n)
+{
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return;
+	}
+
+	switch (n->TcpStatus)
+	{
+	case NAT_TCP_CONNECTING:		// ソケット接続中: 何もしない
+		break;
+
+	case NAT_TCP_CONNECTED:			// ソケット接続が完了した SYN+ACK, ACK 処理
+		if ((n->LastSynAckSentTime > v->Now) || n->LastSynAckSentTime == 0 || ((n->LastSynAckSentTime + (UINT64)(NAT_TCP_SYNACK_SEND_TIMEOUT * (UINT64)(n->SynAckSentCount + 1)) <= v->Now)))
+		{
+			n->LastSynAckSentTime = v->Now;
+			// SYN+ACK を送信する
+			SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+				(UINT)(n->SendSeqInit + n->SendSeq),
+				(UINT)(n->RecvSeqInit + n->RecvSeq),
+				TCP_SYN | TCP_ACK, n->TcpRecvWindowSize,
+				v->TcpMss, NULL, 0);
+			n->SynAckSentCount++;
+		}
+		break;
+
+	case NAT_TCP_SEND_RESET:		// コネクションのリセット
+		// RST を送信する
+		if (n->TcpFinished == false)
+		{
+			SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+				(UINT)(n->SendSeq + n->SendSeqInit),
+				(UINT)(n->SendSeq + n->SendSeqInit),
+				TCP_RST, 0,
+				0, NULL, 0);
+			// 切断する
+			n->TcpStatus = NAT_TCP_WAIT_DISCONNECT;
+			n->DisconnectNow = true;
+		}
+		else
+		{
+			// 合計 NAT_FIN_SEND_MAX_COUNT 回の FIN を送信する
+			if (n->FinSentTime == 0 || (n->FinSentTime > v->Now) || (n->FinSentTime + NAT_FIN_SEND_INTERVAL * (n->FinSentCount + 1)) < v->Now)
+			{
+				SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+					(UINT)(n->SendSeq + n->SendSeqInit),
+					(UINT)(n->RecvSeq + n->RecvSeqInit),
+					TCP_ACK | TCP_FIN, 0,
+					0, NULL, 0);
+				n->FinSentTime = v->Now;
+				n->FinSentCount++;
+				if (n->FinSentCount >= NAT_FIN_SEND_MAX_COUNT)
+				{
+					n->TcpFinished = false;
+				}
+			}
+		}
+		break;
+
+	case NAT_TCP_ESTABLISHED:		// 接続確立済み
+		{
+			UINT send_data_size;
+			UINT current_pointer;
+			UINT notice_window_size_value = 0;
+			UINT buf_free_bytes = 0;
+			// 通知するウインドウサイズの値を決定する
+			if (FifoSize(n->RecvFifo) < NAT_RECV_BUF_SIZE)
+			{
+				buf_free_bytes = NAT_RECV_BUF_SIZE - FifoSize(n->RecvFifo);
+			}
+			notice_window_size_value = MIN(n->TcpRecvWindowSize, buf_free_bytes);
+			if (n->LastSentKeepAliveTime == 0 ||
+				(n->LastSentKeepAliveTime + (UINT64)NAT_ACK_KEEPALIVE_SPAN) < v->Now ||
+				(n->LastSentKeepAliveTime > v->Now))
+			{
+				if (n->LastSentKeepAliveTime != 0)
+				{
+					// Keep-Alive 用 ACK パケットの送信
+					SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+							(UINT)(n->SendSeqInit + n->SendSeq),
+							(UINT)(n->RecvSeqInit + n->RecvSeq) - 1,
+							TCP_ACK,
+							notice_window_size_value,
+							0,
+							NULL,
+							0);
+				}
+				n->LastSentKeepAliveTime = v->Now;
+			}
+			if (n->TcpLastSentTime == 0 ||
+				(n->TcpLastSentTime > v->Now) ||
+				((n->TcpLastSentTime + (UINT64)n->TcpSendTimeoutSpan) < v->Now) ||
+				n->SendAckNext)
+			{
+				// 送信すべきデータがある場合は送信する
+				// 送信すべきセグメントサイズを計算する
+				send_data_size = n->TcpSendWindowSize;
+				if (send_data_size > (n->TcpSendCWnd * n->TcpSendMaxSegmentSize))
+				{
+					// cwnd 値を適用する
+					send_data_size = n->TcpSendCWnd * n->TcpSendMaxSegmentSize;
+				}
+				if (send_data_size > n->SendFifo->size)
+				{
+					// 現在保有しているデータ以上は送れない
+					send_data_size = n->SendFifo->size;
+				}
+				if (send_data_size >= 1)
+				{
+					// セグメントに分割して送信する
+					current_pointer = 0;
+					while (send_data_size > 0)
+					{
+						UINT send_segment_size = MIN(n->TcpSendMaxSegmentSize, send_data_size);
+						void *send_segment = (void *)(((UCHAR *)n->SendFifo->p) + n->SendFifo->pos + current_pointer);
+						SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+							(UINT)(n->SendSeqInit + n->SendSeq + (UINT64)current_pointer),
+							(UINT)(n->RecvSeqInit + n->RecvSeq),
+							TCP_ACK | TCP_PSH,
+							notice_window_size_value,
+							0,
+							send_segment,
+							send_segment_size);
+						current_pointer += send_segment_size;
+						send_data_size -= send_segment_size;
+					}
+					// 送信時刻を記録する
+					n->TcpLastSentTime = v->Now;
+					// 今回送信するストリームサイズを記録する
+					n->SendMissionSize = current_pointer;
+					n->CurrentSendingMission = true;
+					// RTT 測定
+					if (n->CalcRTTStartTime == 0)
+					{
+						n->CalcRTTStartTime = v->Now;
+						n->CalcRTTStartValue = n->SendSeq + current_pointer - 1;
+					}
+					if (n->RetransmissionUsedFlag == false)
+					{
+						n->RetransmissionUsedFlag = true;
+					}
+					else
+					{
+						// 輻輳発生を検出
+						if (n->TcpSendCWnd > 2)
+						{
+							n->TcpSendCWnd--;
+						}
+					}
+				}
+				else if (n->SendAckNext)
+				{
+					// ACK のみ送信する
+					SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+							(UINT)(n->SendSeqInit + n->SendSeq),
+							(UINT)(n->RecvSeqInit + n->RecvSeq),
+							TCP_ACK,
+							notice_window_size_value,
+							0,
+							NULL,
+							0);
+				}
+				n->SendAckNext = false;
+			}
+			if (n->TcpFinished)
+			{
+				// すべてのデータ送信が完了していたら切断する
+				if (n->SendFifo->size == 0)
+				{
+					n->TcpStatus = NAT_TCP_SEND_RESET;
+				}
+			}
+		}
+		break;
+	}
+}
+
+// インターネットへ向かう TCP パケットの受信処理
+void TcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *tcp, void *data, UINT size)
+{
+	NAT_ENTRY *n, t;
+	UINT seq, ack;
+	UINT64 seq64 = 0, ack64 = 0;
+	// 引数チェック
+	if (v == NULL || tcp == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// このパケットに関するセッションを NAT テーブルから検索
+	SetNat(&t, NAT_TCP, src_ip, src_port, dest_ip, dest_port, 0, 0);
+	n = SearchNat(v, &t);
+
+	if (n == NULL)
+	{
+		// 既存のセッションが存在しない
+		// SYN パケットのみ通過を許可する
+		if ((tcp->Flag & TCP_SYN) && ((tcp->Flag & TCP_ACK) == false))
+		{
+			TCP_OPTION o;
+			// 新しいセッションを作成する
+			n = CreateNatTcp(v, src_ip, src_port, dest_ip, dest_port);
+			if (n == NULL)
+			{
+				return;
+			}
+
+			// オプションの取得
+			ParseTcpOption(&o, ((UCHAR *)tcp) + TCP_HEADER_SIZE, TCP_GET_HEADER_SIZE(tcp) * 4 - TCP_HEADER_SIZE);
+			if (o.MaxSegmentSize == 0)
+			{
+				o.MaxSegmentSize = v->TcpMss;
+			}
+
+			Debug("TCP SYN: MSS=%u, WS=%u\n", o.MaxSegmentSize, o.WindowScaling);
+
+			// 初期シーケンス番号
+			n->RecvSeqInit = (UINT64)Endian32(tcp->SeqNumber);
+			n->RecvSeq = 1;
+
+			n->TcpSendMaxSegmentSize = o.MaxSegmentSize;
+			n->TcpRecvWindowSize = NAT_TCP_RECV_WINDOW_SIZE;
+			n->TcpSendWindowSize = (UINT)Endian16(tcp->WindowSize);
+			if (o.WindowScaling != 0)
+			{
+				if (o.WindowScaling > 14)
+				{
+					o.WindowScaling = 14;
+				}
+				n->TcpSendWindowSize = (n->TcpSendWindowSize << o.WindowScaling);
+			}
+		}
+	}
+
+	seq = Endian32(tcp->SeqNumber);
+	ack = Endian32(tcp->AckNumber);
+
+	if (n == NULL)
+	{
+		// NAT エントリに登録されていないパケットが届いたので RST を返す
+		SendTcp(v, dest_ip, dest_port, src_ip, src_port,
+			ack, ack, TCP_RST, 0, 0, NULL, 0);
+		return;
+	}
+
+	switch (n->TcpStatus)
+	{
+	case NAT_TCP_SEND_RESET:		// リセットを送信してコネクションを切断
+		break;
+
+	case NAT_TCP_CONNECTED:			// ソケット接続完了 SYN+ACK, ACK 処理
+		if ((tcp->Flag & TCP_ACK) && ((tcp->Flag & TCP_SYN) == false))
+		{
+			if (seq == (UINT)(n->RecvSeqInit + n->RecvSeq) &&
+				ack == (UINT)(n->SendSeqInit + n->SendSeq + 1))
+			{
+				// ACK パケットが戻ってきたのでハンドシェイク完了
+				n->SendSeq++;		// SYN パケットは seq を 1 消費する
+				Debug("TCP Connection Established.\n");
+				n->TcpStatus = NAT_TCP_ESTABLISHED;
+				// 輻輳ウインドウサイズを初期化
+				n->TcpSendCWnd = 1;
+				n->LastCommTime = v->Now;
+			}
+			else
+			{
+				goto TCP_RESET;
+			}
+		}
+		else if (tcp->Flag & TCP_RST)
+		{
+TCP_RESET:
+			// RST を受信
+			Debug("TCP Connection Reseted.\n");
+			n->TcpStatus = NAT_TCP_SEND_RESET;
+		}
+		break;
+
+	case NAT_TCP_ESTABLISHED:		// 接続確立済み
+		if (tcp->Flag & TCP_FIN)
+		{
+			// 接続を完了させる
+			n->TcpFinished = true;
+		}
+		if (tcp->Flag & TCP_RST)
+		{
+			// RST を受信
+			goto TCP_RESET;
+		}
+		else if (tcp->Flag & TCP_ACK)
+		{
+			TCP_OPTION opt;
+			n->LastCommTime = v->Now;
+			// ウインドウサイズなどのオプションの取得
+			n->TcpSendWindowSize = Endian16(tcp->WindowSize);
+			ParseTcpOption(&opt, ((UCHAR *)tcp) + TCP_HEADER_SIZE, TCP_GET_HEADER_SIZE(tcp) * 4 - TCP_HEADER_SIZE);
+			if (opt.WindowScaling != 0)
+			{
+				if (opt.WindowScaling > 14)
+				{
+					opt.WindowScaling = 14;
+				}
+				n->TcpSendWindowSize = (n->TcpSendWindowSize << opt.WindowScaling);
+			}
+			// まず受信した ACK の処理を行う
+			// ack64 に応答確認を受けたストリームの終端位置を格納する
+			ack64 = n->SendSeq + (UINT64)ack - (n->SendSeqInit + n->SendSeq) % X32;
+			if ((n->SendSeqInit + n->SendSeq) % X32 > ack)
+			{
+				if (((n->SendSeqInit + n->SendSeq) % X32 - ack) >= 0x80000000)
+				{
+					ack64 = n->SendSeq + (UINT64)ack + X32 - (n->SendSeqInit + n->SendSeq) % X32;
+				}
+			}
+			if (ack64 > n->SendSeq)
+			{
+				// クライアントによって 1 バイト以上の受信が完了したらしい
+				UINT slide_offset = (UINT)(ack64 - n->SendSeq);	// ウインドウのスライド量
+				if (slide_offset == 0 || slide_offset > n->TcpSendWindowSize || slide_offset > n->SendFifo->size)
+				{
+					// 確認応答のオフセット値がこれまでに送信したはずのサイズ
+					// よりも大きいので無視する
+				}
+				else
+				{
+					// RTT 測定
+					if (n->CalcRTTStartTime != 0)
+					{
+						if (n->CalcRTTStartValue < ack64)
+						{
+							UINT time_span;
+							if (v->Now > n->CalcRTTStartTime)
+							{
+								time_span = (UINT)(v->Now - n->CalcRTTStartTime);
+							}
+							else
+							{
+								time_span = 100;
+							}
+							n->CalcRTTStartTime = 0;
+
+							// 平滑化
+							n->CurrentRTT =
+								(UINT)
+								(
+									((UINT64)n->CurrentRTT * (UINT64)9 +
+									(UINT64)time_span * (UINT64)1) / (UINT64)10
+								);
+							n->TcpSendTimeoutSpan = n->CurrentRTT * 2;
+						}
+					}
+					// 送信サイズを減少させる
+					n->SendMissionSize -= slide_offset;
+					if (n->SendMissionSize == 0)
+					{
+						// 今回送信する予定であったすべてのセグメントの送受信が完了した
+						// より送信セグメントサイズを大きくしてみる
+						if (n->TcpSendCWnd < 65536)
+						{
+							n->TcpSendCWnd++;
+						}
+						n->CurrentSendingMission = false;
+						n->TcpLastSentTime = 0;
+						n->RetransmissionUsedFlag = false;
+					}
+					// バッファをスライディングする
+					n->SendSeq += slide_offset;
+					ReadFifo(n->SendFifo, NULL, slide_offset);
+					// 今回 ACK によって送信完了が確認できたサイズだけ、さらに送信を実行する
+					if (n->SendMissionSize != 0 && false)
+					{
+						UINT notice_window_size_value = 0;
+						UINT send_data_size;
+						UINT buf_free_bytes;
+						UINT send_offset = n->SendMissionSize;
+						// 通知するウインドウサイズの値を決定する
+						if (FifoSize(n->RecvFifo) < NAT_RECV_BUF_SIZE)
+						{
+							buf_free_bytes = NAT_RECV_BUF_SIZE - FifoSize(n->RecvFifo);
+						}
+						notice_window_size_value = MIN(n->TcpRecvWindowSize, buf_free_bytes);
+						// 送信すべきセグメントサイズを計算する
+						send_data_size = n->TcpSendWindowSize;
+						if (send_data_size > (n->TcpSendCWnd * n->TcpSendMaxSegmentSize))
+						{
+							// cwnd 値を適用する
+							send_data_size = n->TcpSendCWnd * n->TcpSendMaxSegmentSize;
+						}
+						if (n->SendFifo->size > send_offset)
+						{
+							send_data_size = MIN(send_data_size, n->SendFifo->size - send_offset);
+							send_data_size = MIN(send_data_size, slide_offset);
+						}
+						else
+						{
+							send_data_size = 0;
+						}
+						if (send_data_size >= 1)
+						{
+							// セグメントに分割して送信する
+							UINT current_pointer = 0;
+							while (send_data_size > 0)
+							{
+								UINT send_segment_size = MIN(n->TcpSendMaxSegmentSize, send_data_size);
+								void *send_segment = (void *)((
+									(UCHAR *)n->SendFifo->p) + n->SendFifo->pos +
+									current_pointer + send_offset);
+
+								SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+									(UINT)(n->SendSeqInit + n->SendSeq + (UINT64)current_pointer
+									+ (UINT)send_offset),
+									(UINT)(n->RecvSeqInit + n->RecvSeq),
+									TCP_ACK | TCP_PSH,
+									notice_window_size_value,
+									0,
+									send_segment,
+									send_segment_size);
+								current_pointer += send_segment_size;
+								send_data_size -= send_segment_size;
+							}
+							n->SendMissionSize += current_pointer;
+							n->CurrentSendingMission = true;
+							n->TcpLastSentTime = v->Now;
+							// RTT 測定
+							if (n->CalcRTTStartTime == 0)
+							{
+								n->CalcRTTStartTime = v->Now;
+								n->CalcRTTStartValue = n->SendSeq + current_pointer - 1;
+							}
+						}
+					}
+					// イベント発生
+					SetSockEvent(v->SockEvent);
+				}
+			}
+			// 次にデータの受信処理を行う
+			seq64 = n->RecvSeq + (UINT64)seq - (n->RecvSeqInit + n->RecvSeq) % X32;
+			if ((n->RecvSeqInit + n->RecvSeq) % X32 > seq)
+			{
+				if (((n->RecvSeqInit + n->RecvSeq) % X32 - ack) >= 0x80000000)
+				{
+					seq64 = n->RecvSeq + (UINT64)seq + X32 - (n->RecvSeqInit + n->RecvSeq) % X32;
+				}
+			}
+			// この時点で seq64 にはクライアントからのデータ開始点の位置が入っている
+			if (seq64 >= n->RecvSeq && (seq64 + size) <= (n->RecvSeq + n->TcpRecvWindowSize))
+			{
+				if (size >= 1)
+				{
+					// 受信ウインドウの範囲内に 1 バイト以上のデータが届いた
+					UINT offset = (UINT)(seq64 - n->RecvSeq);
+					UINT i;
+					IP_PART *me;
+					if (n->TcpRecvWindow == NULL)
+					{
+						n->TcpRecvWindow = NewFifo();
+					}
+					if (n->TcpRecvList == NULL)
+					{
+						n->TcpRecvList = NewListFast(NULL);
+					}
+					// 届いたパケットをバッファに上書きしリストに追加する
+					if (FifoSize(n->TcpRecvWindow) < (offset + size))
+					{
+						// バッファサイズ拡張
+						WriteFifo(n->TcpRecvWindow, NULL, offset + size - FifoSize(n->TcpRecvWindow));
+					}
+					Copy(((UCHAR *)n->TcpRecvWindow->p) + n->TcpRecvWindow->pos +
+						offset, data, size);
+					me = ZeroMalloc(sizeof(IP_PART));
+					me->Offset = offset;
+					me->Size = size;
+					for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+					{
+						IP_PART *p = LIST_DATA(n->TcpRecvList, i);
+						// 重なる領域があれば重なっている部分があれば除去する
+						if (p->Size != 0)
+						{
+							if (me->Offset <= p->Offset && (me->Offset + me->Size) >= (p->Offset + p->Size))
+							{
+								// このパケットが既存パケットを完全に上書きする
+								p->Size = 0;
+							}
+							else if (me->Offset >= p->Offset && (me->Offset + me->Size) <= (p->Offset + p->Size))
+							{
+								// 既存パケットがこのパケットを完全に上書きする
+								me->Size = 0;
+							}
+							else if (me->Offset > p->Offset && me->Offset < (p->Offset + p->Size) &&
+								(me->Offset + me->Size) > (p->Offset + p->Size))
+							{
+								// 一部重なっている
+								p->Size -= p->Offset + p->Size - me->Offset;
+							}
+							else if (me->Offset < p->Offset && (me->Offset + size) > p->Offset && (me->Offset + size) < (p->Offset + p->Size))
+							{
+								// 一部重なっている
+								me->Size -= me->Offset + me->Size - p->Offset;
+							}
+						}
+					}
+					if (me->Size == 0)
+					{
+						Free(me);
+					}
+					else
+					{
+						Add(n->TcpRecvList, me);
+					}
+KILL_NULL_FIRST:
+					// 受信リストから中身が空白のものをすべて削除する
+					for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+					{
+						IP_PART *p = LIST_DATA(n->TcpRecvList, i);
+						if (p->Size == 0)
+						{
+							Delete(n->TcpRecvList, p);
+							Free(p);
+							goto KILL_NULL_FIRST;
+						}
+					}
+SCAN_FIRST:
+					// 受信リストのうちオフセット 0 から始まるものがあれば抽出する
+					for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+					{
+						IP_PART *p = LIST_DATA(n->TcpRecvList, i);
+						UINT sz;
+						if (p->Offset == 0)
+						{
+							// 0 から始まるデータブロックを発見したので
+							// この分だけ左側にスライドさせてデータを抜き出す
+							// バッファを FIFO に書き出す
+							sz = p->Size;
+							WriteFifo(n->RecvFifo, ((UCHAR *)n->TcpRecvWindow->p) + n->TcpRecvWindow->pos, sz);
+							// リストから解放する
+							Delete(n->TcpRecvList, p);
+							Free(p);
+							ReadFifo(n->TcpRecvWindow, NULL, sz);
+							// すべての項目を左側にスライドする
+							for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+							{
+								p = LIST_DATA(n->TcpRecvList, i);
+								p->Offset -= sz;
+							}
+							// TCB のパラメータを更新
+							n->RecvSeq += (UINT64)sz;
+							SetSockEvent(v->SockEvent);
+							n->SendAckNext = true;
+							// 最初からスキャンし直す
+							goto SCAN_FIRST;
+						}
+					}
+				}
+			}
+		}
+		break;
+	}
+
+	SetSockEvent(v->SockEvent);
+}
+
+// TCP オプションのパース
+void ParseTcpOption(TCP_OPTION *o, void *data, UINT size)
+{
+	UCHAR *buf = (UCHAR *)data;
+	UINT i;
+	UINT value_size = 0;
+	UINT value_id = 0;
+	UCHAR value[128];
+	// 引数チェック
+	if (o == NULL || data == NULL)
+	{
+		return;
+	}
+
+	Zero(o, sizeof(TCP_OPTION));
+
+	for (i = 0;i < size;i++)
+	{
+		if (buf[i] == 0)
+		{
+			return;
+		}
+		if (buf[i] != 1)
+		{
+			value_id = buf[i];
+			i++;
+			if (i >= size)
+			{
+				return;
+			}
+			value_size = buf[i];
+			if (value_size <= 1 || value_size > sizeof(value))
+			{
+				return;
+			}
+			i++;
+			if (i >= size)
+			{
+				return;
+			}
+			value_size -= 2;
+			Copy(value, &buf[i], value_size);
+			i += value_size;
+			if (i >= size)
+			{
+				return;
+			}
+			switch (value_id)
+			{
+			case 2:	// MSS
+				if (value_size == 2)
+				{
+					USHORT *mss = (USHORT *)value;
+					o->MaxSegmentSize = Endian16(*mss);
+				}
+				break;
+
+			case 3: // WSS
+				if (value_size == 1)
+				{
+					UCHAR *wss = (UCHAR *)value;
+					o->WindowScaling = Endian16(*wss);
+				}
+				break;
+
+			}
+		}
+	}
+
+}
+
+// 新しい NAT TCP セッションの作成
+NAT_ENTRY *CreateNatTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port)
+{
+	NAT_ENTRY *n;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	if (CanCreateNewNatEntry(v) == false)
+	{
+		return NULL;
+	}
+
+	// NAT エントリの作成
+	n = ZeroMalloc(sizeof(NAT_ENTRY));
+	n->Id = Inc(v->Counter);
+	n->v = v;
+	n->lock = NewLock();
+	n->Protocol = NAT_TCP;
+	n->SrcIp = src_ip;
+	n->SrcPort = src_port;
+	n->DestIp = dest_ip;
+	n->DestPort = dest_port;
+	n->CreatedTime = n->LastCommTime = v->Now;
+	n->Sock = NULL;
+	n->DisconnectNow = false;
+	n->TcpSendMaxSegmentSize = n->TcpRecvMaxSegmentSize = v->TcpMss;
+
+	n->SendFifo = NewFifo();
+	n->RecvFifo = NewFifo();
+
+	n->TcpStatus = NAT_TCP_CONNECTING;
+
+	n->SendSeqInit = Rand32();
+	n->CurrentRTT = NAT_INITIAL_RTT_VALUE;
+	n->TcpSendTimeoutSpan = n->CurrentRTT * 2;
+
+	// NAT テーブルに追加
+	Add(v->NatTable, n);
+
+
+#if	1
+	{
+		IP ip1, ip2;
+		char s1[MAX_SIZE], s2[MAX_SIZE];
+		UINTToIP(&ip1, src_ip);
+		UINTToIP(&ip2, dest_ip);
+		IPToStr(s1, 0, &ip1);
+		IPToStr(s2, 0, &ip2);
+		Debug("NAT_ENTRY: CreateNatTcp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
+
+		NLog(v, "LH_NAT_TCP_CREATED", n->Id, s1, src_port, s2, dest_port);
+	}
+#endif
+
+	return n;
+}
+
+// TCP パケットを仮想ネットワークから受信した
+void VirtualTcpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size)
+{
+	TCP_HEADER *tcp;
+	UINT src_port, dest_port;
+	UINT header_size, buf_size;
+	void *buf;
+	IP ip1, ip2;
+	// 引数チェック
+	if (v == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// ヘッダを取得
+	if (size < TCP_HEADER_SIZE)
+	{
+		// サイズが小さすぎる
+		return;
+	}
+	tcp = (TCP_HEADER *)data;
+	src_port = Endian16(tcp->SrcPort);
+	dest_port = Endian16(tcp->DstPort);
+	if (src_port == 0 || dest_port == 0)
+	{
+		// ポート番号が不正
+		return;
+	}
+	if (src_ip == dest_ip || src_ip == 0 || src_ip == 0xffffffff || dest_ip == 0 || dest_ip == 0xffffffff)
+	{
+		// IP アドレスが不正
+		return;
+	}
+	UINTToIP(&ip1, src_ip);
+	UINTToIP(&ip2, dest_ip);
+	if (ip1.addr[0] == 127 || ip2.addr[0] == 127)
+	{
+		// ループバック IP アドレスは指定できない
+		return;
+	}
+	if (IsInNetwork(dest_ip, v->HostIP, v->HostMask))
+	{
+		// 仮想 LAN 側のネットワーク向けのパケットは無視する
+		return;
+	}
+	// ヘッダサイズを取得
+	header_size = TCP_GET_HEADER_SIZE(tcp) * 4;
+	if (size < header_size)
+	{
+		// ヘッダサイズが不正
+		return;
+	}
+	// バッファのサイズとアドレスを取得
+	buf_size = size - header_size;
+	buf = (void *)(((UCHAR *)data) + header_size);
+
+	TcpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, tcp, buf, buf_size);
+}
+
+// NAT UDP ポーリング
+void PoolingNatUdp(VH *v, NAT_ENTRY *n)
+{
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return;
+	}
+
+	// 受信キューにパケットが 1 つ以上あれば処理する
+	if (n->UdpRecvQueue->num_item != 0)
+	{
+		BLOCK *block;
+
+		// すべての UDP パケットを仮想ネットワークに送信する
+		while (block = GetNext(n->UdpRecvQueue))
+		{
+			SendUdp(v, n->SrcIp, n->SrcPort, n->DestIp, n->DestPort,
+				block->Buf, block->Size);
+
+			FreeBlock(block);
+		}
+	}
+}
+
+// NAT ポーリング
+void PoolingNat(VH *v)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// すべての NAT エントリを走査し処理を行う
+	for (i = 0;i < LIST_NUM(v->NatTable);i++)
+	{
+		NAT_ENTRY *n = LIST_DATA(v->NatTable, i);
+
+		switch (n->Protocol)
+		{
+		case NAT_TCP:
+			PollingNatTcp(v, n);
+			break;
+
+		case NAT_UDP:
+			PoolingNatUdp(v, n);
+			break;
+
+		case NAT_DNS:
+			PollingNatDns(v, n);
+			break;
+		}
+	}
+}
+
+// NAT テーブルの比較関数
+int CompareNat(void *p1, void *p2)
+{
+	NAT_ENTRY *n1, *n2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	n1 = *(NAT_ENTRY **)p1;
+	n2 = *(NAT_ENTRY **)p2;
+	if (n1 == n2)
+	{
+		return 0;
+	}
+
+	if (n1->SrcIp > n2->SrcIp) return 1;
+	else if (n1->SrcIp < n2->SrcIp) return -1;
+	else if (n1->DestIp > n2->DestIp) return 1;
+	else if (n1->DestIp < n2->DestIp) return -1;
+	else if (n1->SrcPort > n2->SrcPort) return 1;
+	else if (n1->SrcPort < n2->SrcPort) return -1;
+	else if (n1->DestPort > n2->DestPort) return 1;
+	else if (n1->DestPort < n2->DestPort) return -1;
+	else if (n1->Protocol > n2->Protocol) return 1;
+	else if (n1->Protocol < n2->Protocol) return -1;
+	else return 0;
+}
+
+// NAT 構造体の設定
+void SetNat(NAT_ENTRY *n, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT public_ip, UINT public_port)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	n->Protocol = protocol;
+	n->SrcIp = src_ip;
+	n->SrcPort = src_port;
+	n->DestIp = dest_ip;
+	n->DestPort = dest_port;
+	n->PublicIp = public_ip;
+	n->PublicPort = public_port;
+}
+
+// NAT の初期化
+void InitNat(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// NAT テーブルの作成
+	v->NatTable = NewList(CompareNat);
+
+	// ソケットイベントの作成
+	v->SockEvent = NewSockEvent();
+
+	// NAT 用スレッドの作成
+	v->HaltNat = false;
+	v->NatThread = NewThread(NatThread, (void *)v);
+	WaitThreadInit(v->NatThread);
+}
+
+// NAT の解放
+void FreeNat(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// NAT 用スレッドの停止
+	v->HaltNat = true;
+	SetSockEvent(v->SockEvent);
+	WaitThread(v->NatThread, INFINITE);
+	ReleaseThread(v->NatThread);
+	v->NatThread = NULL;
+	ReleaseSockEvent(v->SockEvent);
+	v->SockEvent = NULL;
+
+	// NAT テーブルの解放
+	ReleaseList(v->NatTable);
+}
+
+// NAT テーブルの検索
+NAT_ENTRY *SearchNat(VH *v, NAT_ENTRY *target)
+{
+	NAT_ENTRY *n;
+	// 引数チェック
+	if (v == NULL || target == NULL)
+	{
+		return NULL;
+	}
+
+	// バイナリサーチ
+	n = (NAT_ENTRY *)Search(v->NatTable, target);
+
+	return n;
+}
+
+// UDP NAT エントリの削除
+void DeleteNatUdp(VH *v, NAT_ENTRY *n)
+{
+	BLOCK *block;
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return;
+	}
+
+	NLog(v, "LH_NAT_UDP_DELETED", n->Id);
+
+	// すべてのキューを解放
+	while (block = GetNext(n->UdpRecvQueue))
+	{
+		FreeBlock(block);
+	}
+	ReleaseQueue(n->UdpRecvQueue);
+	while (block = GetNext(n->UdpSendQueue))
+	{
+		FreeBlock(block);
+	}
+	ReleaseQueue(n->UdpSendQueue);
+
+	// ソケットを解放
+	if (n->Sock != NULL)
+	{
+		Disconnect(n->Sock);
+		ReleaseSock(n->Sock);
+		n->Sock = NULL;
+	}
+
+	DeleteLock(n->lock);
+
+	// テーブルから削除
+	Delete(v->NatTable, n);
+
+	// メモリ解放
+	Free(n);
+
+	Debug("NAT: DeleteNatUdp\n");
+
+}
+
+// NAT UDP エントリを作成
+NAT_ENTRY *CreateNatUdp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT dns_proxy_ip)
+{
+	NAT_ENTRY *n;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	if (CanCreateNewNatEntry(v) == false)
+	{
+		return NULL;
+	}
+
+	n = ZeroMalloc(sizeof(NAT_ENTRY));
+	n->Id = Inc(v->Counter);
+	n->v = v;
+	n->lock = NewLock();
+	n->Protocol = NAT_UDP;
+	n->SrcIp = src_ip;
+	n->SrcPort = src_port;
+	n->DestIp = dest_ip;
+	n->DestPort = dest_port;
+
+	if (dns_proxy_ip != 0)
+	{
+		n->ProxyDns = true;
+		n->DestIpProxy = dns_proxy_ip;
+	}
+
+	n->CreatedTime = n->LastCommTime = v->Now;
+
+	n->UdpSendQueue = NewQueue();
+	n->UdpRecvQueue = NewQueue();
+
+	n->UdpSocketCreated = false;
+
+	SetSockEvent(v->SockEvent);
+
+#if	1
+	{
+		IP ip1, ip2;
+		char s1[MAX_SIZE], s2[MAX_SIZE];
+		UINTToIP(&ip1, src_ip);
+		UINTToIP(&ip2, dest_ip);
+		IPToStr(s1, 0, &ip1);
+		IPToStr(s2, 0, &ip2);
+		Debug("NAT_ENTRY: CreateNatUdp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
+
+		NLog(v, "LH_NAT_UDP_CREATED", n->Id, s1, src_port, s2, dest_port);
+	}
+#endif
+
+	Add(v->NatTable, n);
+
+	return n;
+}
+
+// インターネットへの UDP パケットの処理
+void UdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy)
+{
+	NAT_ENTRY *n, t;
+	BLOCK *block;
+	void *buf;
+	UINT dns_ip = 0;
+	// 引数チェック
+	if (data == NULL || v == NULL)
+	{
+		return;
+	}
+
+	if (dns_proxy)
+	{
+		// プロキシ接続先の DNS サーバーを取得する
+		IP ip;
+		char tmp[MAX_SIZE];
+		if (GetDefaultDns(&ip) == false)
+		{
+			// 失敗
+			Debug("Failed to GetDefaultDns()\n");
+			return;
+		}
+		dns_ip = IPToUINT(&ip);
+		IPToStr(tmp, sizeof(tmp), &ip);
+		Debug("Redirect to DNS Server %s\n", tmp);
+	}
+
+	// このパケットに関する NAT エントリがすでに作成されているかどうかを調べる
+	SetNat(&t, NAT_UDP, src_ip, src_port, dest_ip, dest_port, 0, 0);
+	n = SearchNat(v, &t);
+
+	if (n == NULL)
+	{
+		// 最初のパケットなので NAT エントリを作成する
+		n = CreateNatUdp(v, src_ip, src_port, dest_ip, dest_port, dns_proxy ? dns_ip : 0);
+		if (n == NULL)
+		{
+			// エントリ作成失敗
+			return;
+		}
+
+		if (dns_proxy)
+		{
+			n->ProxyDns = true;
+			n->DestIpProxy = dns_ip;
+		}
+	}
+
+	// キューにパケットを挿入してイベントを呼び出す
+	buf = Malloc(size);
+	Copy(buf, data, size);
+	block = NewBlock(buf, size, 0);
+	InsertQueue(n->UdpSendQueue, block);
+
+	SetSockEvent(v->SockEvent);
+}
+
+// DNS パケットの解釈を試行する
+bool ParseDnsPacket(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+	DNSV4_HEADER *dns;
+	NAT_ENTRY *nat;
+	UINT transaction_id;
+	void *query_data;
+	UINT query_data_size;
+	char hostname[256];
+	// 引数チェック
+	if (v == NULL || data == NULL || size == 0)
+	{
+		return false;
+	}
+
+	// ヘッダサイズのチェック
+	if (size < sizeof(DNSV4_HEADER))
+	{
+		// サイズ不足
+		return false;
+	}
+
+	// DNS ヘッダ取得
+	dns = (DNSV4_HEADER *)data;
+	transaction_id = Endian16(dns->TransactionId);
+	if ((dns->Flag1 & 78) != 0 || (dns->Flag1 & 0x80) != 0)
+	{
+		// オペコード不正
+		return false;
+	}
+	if (Endian16(dns->NumQuery) != 1)
+	{
+		// クエリ数不正
+		return false;
+	}
+
+	query_data = ((UCHAR *)dns) + sizeof(DNSV4_HEADER);
+	query_data_size = size - sizeof(DNSV4_HEADER);
+
+	// クエリの解釈
+	if (ParseDnsQuery(hostname, sizeof(hostname), query_data, query_data_size) == false)
+	{
+		// 解釈失敗
+		return false;
+	}
+
+	// DNS エントリの作成
+	nat = CreateNatDns(v, src_ip, src_port, dest_ip, dest_port, transaction_id,
+		false, hostname);
+
+	if (nat == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// NAT DNS 応答パケットの送信
+void SendNatDnsResponse(VH *v, NAT_ENTRY *n)
+{
+	BUF *b;
+	UINT dns_header_size;
+	DNSV4_HEADER *dns;
+	// 引数チェック
+	if (n == NULL || v == NULL)
+	{
+		return;
+	}
+
+	// データの生成
+	b = NewBuf();
+
+	// Query の追加
+	if (n->DnsGetIpFromHost == false)
+	{
+		BuildDnsQueryPacket(b, n->DnsTargetHostName, false);
+	}
+	else
+	{
+		BuildDnsQueryPacket(b, n->DnsTargetHostName, true);
+	}
+
+	// Response の追加
+	if (n->DnsOk)
+	{
+		if (n->DnsGetIpFromHost == false)
+		{
+			BuildDnsResponsePacketA(b, &n->DnsResponseIp);
+		}
+		else
+		{
+			BuildDnsResponsePacketPtr(b, n->DnsResponseHostName);
+		}
+	}
+
+	// DNS ヘッダの生成
+	dns_header_size = sizeof(DNSV4_HEADER) + b->Size;
+
+	dns = ZeroMalloc(dns_header_size);
+	dns->TransactionId = Endian16((USHORT)n->DnsTransactionId);
+
+	// 応答フラグの生成
+	if (n->DnsOk)
+	{
+		dns->Flag1 = 0x85;
+		dns->Flag2 = 0x80;
+	}
+	else
+	{
+		dns->Flag1 = 0x85;
+		dns->Flag2 = 0x83;
+	}
+
+	dns->NumQuery = Endian16(1);
+	dns->AnswerRRs = Endian16(n->DnsOk != false ? 1 : 0);
+	dns->AuthorityRRs = 0;
+	dns->AdditionalRRs = 0;
+
+	// データのコピー
+	Copy(((UCHAR *)dns) + sizeof(DNSV4_HEADER), b->Buf, b->Size);
+
+	// このパケットを送信
+	SendUdp(v, n->SrcIp, n->SrcPort, n->DestIp, n->DestPort, dns, dns_header_size);
+
+	// メモリ解放
+	Free(dns);
+	FreeBuf(b);
+}
+
+// DNS 応答パケット (ホスト名) の生成
+void BuildDnsResponsePacketPtr(BUF *b, char *hostname)
+{
+	USHORT magic;
+	USHORT type, clas;
+	UINT ttl;
+	USHORT len;
+	BUF *c;
+	// 引数チェック
+	if (b == NULL || hostname == NULL)
+	{
+		return;
+	}
+
+	magic = Endian16(0xc00c);
+	type = Endian16(0x000c);
+	clas = Endian16(0x0001);
+	ttl = Endian32(NAT_DNS_RESPONSE_TTL);
+
+	c = BuildDnsHostName(hostname);
+	if (c == NULL)
+	{
+		return;
+	}
+	len = Endian16((USHORT)c->Size);
+
+	WriteBuf(b, &magic, 2);
+	WriteBuf(b, &type, 2);
+	WriteBuf(b, &clas, 2);
+	WriteBuf(b, &ttl, 4);
+	WriteBuf(b, &len, 2);
+	WriteBuf(b, c->Buf, c->Size);
+	FreeBuf(c);
+}
+
+// DNS 応答パケット (ホスト IP アドレス) の生成
+void BuildDnsResponsePacketA(BUF *b, IP *ip)
+{
+	UINT ip_addr;
+	USHORT magic;
+	USHORT type, clas;
+	UINT ttl;
+	USHORT len;
+	// 引数チェック
+	if (b == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	ip_addr = IPToUINT(ip);
+	magic = Endian16(0xc00c);
+	type = Endian16(0x0001);
+	clas = Endian16(0x0001);
+	ttl = Endian32(NAT_DNS_RESPONSE_TTL);
+	len = Endian16((USHORT)sizeof(ttl));
+
+	WriteBuf(b, &magic, sizeof(magic));
+	WriteBuf(b, &type, sizeof(type));
+	WriteBuf(b, &clas, sizeof(clas));
+	WriteBuf(b, &ttl, sizeof(ttl));
+	WriteBuf(b, &len, sizeof(len));
+	WriteBuf(b, &ip_addr, sizeof(ip_addr));
+}
+
+// DNS クエリデータパケットの生成
+void BuildDnsQueryPacket(BUF *b, char *hostname, bool ptr)
+{
+	USHORT val;
+	BUF *c;
+	// 引数チェック
+	if (b == NULL || hostname == NULL)
+	{
+		return;
+	}
+
+	// ホスト名をバッファに変換
+	c = BuildDnsHostName(hostname);
+	if (c == NULL)
+	{
+		return;
+	}
+
+	WriteBuf(b, c->Buf, c->Size);
+	FreeBuf(c);
+
+	// 種類とクラス
+	if (ptr == false)
+	{
+		val = Endian16(0x0001);
+	}
+	else
+	{
+		val = Endian16(0x000c);
+	}
+	WriteBuf(b, &val, 2);
+
+	val = Endian16(0x0001);
+	WriteBuf(b, &val, 2);
+}
+
+// DNS ホスト名バッファの生成
+BUF *BuildDnsHostName(char *hostname)
+{
+	UINT i;
+	UCHAR size;
+	TOKEN_LIST *token;
+	BUF *b;
+	// 引数チェック
+	if (hostname == NULL)
+	{
+		return NULL;
+	}
+
+	// ホスト名をトークンに分割
+	token = ParseToken(hostname, ".");
+	if (token == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+
+	// ホスト文字列を追加
+	for (i = 0;i < token->NumTokens;i++)
+	{
+		size = (UCHAR)StrLen(token->Token[i]);
+		WriteBuf(b, &size, 1);
+		WriteBuf(b, token->Token[i], size);
+	}
+
+	// NULL 文字
+	size = 0;
+	WriteBuf(b, &size, 1);
+
+	SeekBuf(b, 0, 0);
+
+	FreeToken(token);
+
+	return b;
+}
+
+// NAT DNS エントリの処理
+void PollingNatDns(VH *v, NAT_ENTRY *n)
+{
+	// 引数チェック
+	if (v == NULL || n == NULL)
+	{
+		return;
+	}
+
+	if (n->DnsFinished)
+	{
+		if (n->DnsPollingFlag == false)
+		{
+			n->DnsPollingFlag = true;
+			// 処理が完了した
+			SendNatDnsResponse(v, n);
+
+			// 終了処理
+			n->DisconnectNow = true;
+		}
+	}
+}
+
+// NAT DNS エントリの作成
+NAT_ENTRY *CreateNatDns(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port,
+				  UINT transaction_id, bool dns_get_ip_from_host, char *dns_target_host_name)
+{
+	NAT_ENTRY *n;
+	// 引数チェック
+	if (v == NULL || dns_target_host_name == NULL)
+	{
+		return NULL;
+	}
+
+	if (CanCreateNewNatEntry(v) == false)
+	{
+		return NULL;
+	}
+
+	n = ZeroMalloc(sizeof(NAT_ENTRY));
+	n->Id = Inc(v->Counter);
+	n->v = v;
+	n->lock = NewLock();
+	n->Protocol = NAT_DNS;
+	n->SrcIp = src_ip;
+	n->SrcPort = src_port;
+	n->DestIp = dest_ip;
+	n->DestPort = dest_port;
+	n->DnsTransactionId = transaction_id;
+	n->CreatedTime = n->LastCommTime = v->Now;
+	n->DisconnectNow = false;
+
+	n->DnsGetIpFromHost = false;
+	n->DnsTargetHostName = CopyStr(dns_target_host_name);
+
+	Add(v->NatTable, n);
+
+#if	1
+	{
+		IP ip1, ip2;
+		char s1[MAX_SIZE], s2[MAX_SIZE];
+		UINTToIP(&ip1, src_ip);
+		UINTToIP(&ip2, dest_ip);
+		IPToStr(s1, 0, &ip1);
+		IPToStr(s2, 0, &ip2);
+		Debug("NAT_ENTRY: CreateNatDns %s %u -> %s %u\n", s1, src_port, s2, dest_port);
+	}
+#endif
+
+
+	return n;
+}
+
+// 次のバイトを取得
+UCHAR GetNextByte(BUF *b)
+{
+	UCHAR c = 0;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return 0;
+	}
+
+	if (ReadBuf(b, &c, 1) != 1)
+	{
+		return 0;
+	}
+
+	return c;
+}
+
+// DNS クエリの解釈
+bool ParseDnsQuery(char *name, UINT name_size, void *data, UINT data_size)
+{
+	BUF *b;
+	char tmp[257];
+	bool ok = true;
+	USHORT val;
+	// 引数チェック
+	if (name == NULL || data == NULL || data_size == 0)
+	{
+		return false;
+	}
+	StrCpy(name, name_size, "");
+
+	b = NewBuf();
+	WriteBuf(b, data, data_size);
+	SeekBuf(b, 0, 0);
+
+	while (true)
+	{
+		UINT next_len = (UINT)GetNextByte(b);
+		if (next_len > 0)
+		{
+			// 指定した文字だけ読む
+			Zero(tmp, sizeof(tmp));
+			if (ReadBuf(b, tmp, next_len) != next_len)
+			{
+				ok = false;
+				break;
+			}
+			// 追記
+			if (StrLen(name) != 0)
+			{
+				StrCat(name, name_size, ".");
+			}
+			StrCat(name, name_size, tmp);
+		}
+		else
+		{
+			// すべて読み終えた
+			break;
+		}
+	}
+
+	if (ReadBuf(b, &val, sizeof(val)) != sizeof(val))
+	{
+		ok = false;
+	}
+	else
+	{
+		if (Endian16(val) != 0x01 && Endian16(val) != 0x0c)
+		{
+			ok = false;
+		}
+	}
+
+	if (ReadBuf(b, &val, sizeof(val)) != sizeof(val))
+	{
+		ok = false;
+	}
+	else
+	{
+		if (Endian16(val) != 0x01)
+		{
+			ok = false;
+		}
+	}
+
+	FreeBuf(b);
+
+	if (ok == false || StrLen(name) == 0)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+// DNS プロキシとして動作する
+void DnsProxy(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+	// 引数チェック
+	if (v == NULL || data == NULL || size == 0)
+	{
+		return;
+	}
+
+	// まず DNS クエリを解釈することができるかどうか試してみる
+	//if (ParseDnsPacket(v, src_ip, src_port, dest_ip, dest_port, data, size) == false)
+	{
+		// うまくいかない場合は要求をそのまま投げる
+		UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, data, size, true);
+	}
+}
+
+// 仮想ホストへの UDP パケットの処理
+void UdpRecvForMe(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+	// 引数チェック
+	if (data == NULL || v == NULL)
+	{
+		return;
+	}
+
+	if (dest_port == NAT_DNS_PROXY_PORT)
+	{
+		// DNS プロキシ起動
+		DnsProxy(v, src_ip, src_port, dest_ip, dest_port, data, size);
+	}
+}
+
+// ブロードキャスト UDP パケットの処理
+void UdpRecvForBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+	// 引数チェック
+	if (data == NULL || v == NULL)
+	{
+		return;
+	}
+}
+
+// UDP パケットを受信した
+void VirtualUdpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, bool mac_broadcast)
+{
+	UDP_HEADER *udp;
+	UINT packet_length;
+	void *buf;
+	UINT buf_size;
+	UINT src_port, dest_port;
+	// 引数チェック
+	if (v == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// ヘッダのチェック
+	udp = (UDP_HEADER *)data;
+	if (size < UDP_HEADER_SIZE)
+	{
+		return;
+	}
+	packet_length = Endian16(udp->PacketLength);
+	if (packet_length != size)
+	{
+		return;
+	}
+	buf = ((UCHAR *)data) + UDP_HEADER_SIZE;
+	buf_size = size - UDP_HEADER_SIZE;
+	src_port = Endian16(udp->SrcPort);
+	dest_port = Endian16(udp->DstPort);
+	// ポート番号をチェック
+	if (dest_port == 0)
+	{
+		// ポート番号が不正
+		return;
+	}
+
+	// 自分宛のパケットまたはブロードキャストパケットかどうか判別する
+	if (dest_ip == v->HostIP)
+	{
+		// 自分宛のパケットが届いた
+		UdpRecvForMe(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
+	}
+	else if (mac_broadcast || dest_ip == 0xffffffff || dest_ip == GetBroadcastAddress(v->HostIP, v->HostMask))
+	{
+		// ブロードキャストパケットが届いた
+		UdpRecvForBroadcast(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
+	}
+	else if (IsInNetwork(dest_ip, v->HostIP, v->HostMask) == false)
+	{
+		// ローカルアドレス以外 (つまりインターネット上) へのパケットが届いた
+		UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size, false);
+	}
+	else
+	{
+		// ローカルアドレスが届いた。無視
+	}
+}
+
+// 指定した IP アドレスの属するサブネットのネットワークアドレスを求める
+UINT GetNetworkAddress(UINT addr, UINT mask)
+{
+	return (addr & mask);
+}
+
+// 指定した IP アドレスの属するサブネットのブロードキャストアドレスを求める
+UINT GetBroadcastAddress(UINT addr, UINT mask)
+{
+	return ((addr & mask) | (~mask));
+}
+
+// 指定した IP アドレスが別の指定したアドレスとサブネットマスクによって表現される
+// サブネットワークに所属しているかどうか判別する
+bool IsInNetwork(UINT uni_addr, UINT network_addr, UINT mask)
+{
+	if (GetNetworkAddress(uni_addr, mask) == GetNetworkAddress(network_addr, mask))
+	{
+		return true;
+	}
+	return false;
+}
+
+// UDP パケットの送信
+void SendUdp(VH *v, UINT dest_ip, UINT dest_port, UINT src_ip, UINT src_port, void *data, UINT size)
+{
+	UDPV4_PSEUDO_HEADER *vh;
+	UDP_HEADER *udp;
+	UINT udp_packet_length = UDP_HEADER_SIZE + size;
+	USHORT checksum;
+	// 引数チェック
+	if (v == NULL || data == NULL)
+	{
+		return;
+	}
+	if (udp_packet_length > 65536)
+	{
+		return;
+	}
+
+	// 仮想ヘッダを生成
+	vh = Malloc(sizeof(UDPV4_PSEUDO_HEADER) + size);
+	udp = (UDP_HEADER *)(((UCHAR *)vh) + 12);
+
+	vh->SrcIP = src_ip;
+	vh->DstIP = dest_ip;
+	vh->Reserved = 0;
+	vh->Protocol = IP_PROTO_UDP;
+	vh->PacketLength1 = Endian16((USHORT)udp_packet_length);
+	udp->SrcPort = Endian16((USHORT)src_port);
+	udp->DstPort = Endian16((USHORT)dest_port);
+	udp->PacketLength = Endian16((USHORT)udp_packet_length);
+	udp->Checksum = 0;
+
+	// データをコピー
+	Copy(((UCHAR *)udp) + UDP_HEADER_SIZE, data, size);
+
+	// チェックサムを計算
+	checksum = IpChecksum(vh, udp_packet_length + 12);
+	if (checksum == 0x0000)
+	{
+		checksum = 0xffff;
+	}
+	udp->Checksum = checksum;
+
+	// パケットを送信
+	SendIp(v, dest_ip, src_ip, IP_PROTO_UDP, udp, udp_packet_length);
+
+	// メモリ解放
+	Free(vh);
+}
+
+// IP 結合オブジェクトのポーリング
+void PollingIpCombine(VH *v)
+{
+	LIST *o;
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// 古い結合オブジェクトを破棄する
+	o = NULL;
+	for (i = 0;i < LIST_NUM(v->IpCombine);i++)
+	{
+		IP_COMBINE *c = LIST_DATA(v->IpCombine, i);
+
+		if (c->Expire < v->Now)
+		{
+			if (o == NULL)
+			{
+				o = NewListFast(NULL);
+			}
+			Add(o, c);
+		}
+	}
+
+	if (o != NULL)
+	{
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			IP_COMBINE *c = LIST_DATA(o, i);
+
+			// リストから削除
+			Delete(v->IpCombine, c);
+
+			// メモリ解放
+			FreeIpCombine(v, c);
+		}
+		ReleaseList(o);
+	}
+}
+
+// ICMP パケットを送信する
+void VirtualIcmpSend(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size)
+{
+	ICMP_HEADER *icmp;
+	void *data_buf;
+	// 引数チェック
+	if (v == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// ヘッダ組み立て
+	icmp = ZeroMalloc(sizeof(ICMP_HEADER) + size);
+	// データコピー
+	data_buf = ((UCHAR *)icmp) + sizeof(ICMP_HEADER);
+	Copy(data_buf, data, size);
+	// その他
+	icmp->Checksum = 0;
+	icmp->Code = 0;
+	icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
+	// チェックサム
+	icmp->Checksum = IpChecksum(icmp, sizeof(ICMP_HEADER) + size);
+
+	// IP パケット送信
+	SendIp(v, dst_ip, src_ip, IP_PROTO_ICMPV4, icmp, sizeof(ICMP_HEADER) + size);
+
+	// メモリ解放
+	Free(icmp);
+}
+
+// ICMP Echo Response パケットを送信する
+void VirtualIcmpEchoSendResponse(VH *v, UINT src_ip, UINT dst_ip, USHORT id, USHORT seq_no, void *data, UINT size)
+{
+	ICMP_ECHO *e;
+	// 引数チェック
+	if (v == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// ヘッダ組み立て
+	e = ZeroMalloc(sizeof(ICMP_ECHO) + size);
+	e->Identifier = Endian16(id);
+	e->SeqNo = Endian16(seq_no);
+
+	// データコピー
+	Copy(((UCHAR *)e) + sizeof(ICMP_ECHO), data, size);
+
+	// ICMP 送信
+	VirtualIcmpSend(v, src_ip, dst_ip, e, sizeof(ICMP_ECHO) + size);
+
+	// メモリ解放
+	Free(e);
+}
+
+// ICMP Echo Request パケットを受信した
+void VirtualIcmpEchoRequestReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size)
+{
+	ICMP_ECHO *echo;
+	UINT data_size;
+	void *data_buf;
+	USHORT id, seq_no;
+	// 引数チェック
+	if (v == NULL || data == NULL)
+	{
+		return;
+	}
+
+	echo = (ICMP_ECHO *)data;
+
+	// エコーサイズチェック
+	if (size < sizeof(ICMP_ECHO))
+	{
+		// データが足らない
+		return;
+	}
+
+	id = Endian16(echo->Identifier);
+	seq_no = Endian16(echo->SeqNo);
+
+	// データサイズ
+	data_size = size - sizeof(ICMP_ECHO);
+
+	// データ本体
+	data_buf = ((UCHAR *)data) + sizeof(ICMP_ECHO);
+
+	// ICMP Echo Response を返す
+	VirtualIcmpEchoSendResponse(v, dst_ip, src_ip, id, seq_no, data_buf, data_size);
+}
+
+// ICMP パケットを受信した
+void VirtualIcmpReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size)
+{
+	ICMP_HEADER *icmp;
+	UINT msg_size;
+	USHORT checksum_calc, checksum_original;
+	// 引数チェック
+	if (v == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// サイズチェック
+	if (size < sizeof(ICMP_HEADER))
+	{
+		return;
+	}
+
+	// ICMP ヘッダ
+	icmp = (ICMP_HEADER *)data;
+
+	// ICMP メッセージサイズの取得
+	msg_size = size - sizeof(ICMP_HEADER);
+
+	// ICMP ヘッダのチェックサムをチェックする
+	checksum_original = icmp->Checksum;
+	icmp->Checksum = 0;
+	checksum_calc = IpChecksum(data, size);
+	icmp->Checksum = checksum_original;
+
+	if (checksum_calc != checksum_original)
+	{
+		// チェックサムが不正
+		Debug("ICMP CheckSum Failed.\n");
+		return;
+	}
+
+	// オペコードによって識別
+	switch (icmp->Type)
+	{
+	case ICMP_TYPE_ECHO_REQUEST:	// ICMP Echo 要求
+		VirtualIcmpEchoRequestReceived(v, src_ip, dst_ip, ((UCHAR *)data) + sizeof(ICMP_HEADER), msg_size);
+		break;
+
+	case ICMP_TYPE_ECHO_RESPONSE:	// ICMP Echo 応答
+		// 何もしない
+		break;
+	}
+}
+
+// IP パケットを受信した
+void IpReceived(VH *v, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size, bool mac_broadcast)
+{
+	// 引数チェック
+	if (v == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// サポートされている上位プロトコルにデータを渡す
+	switch (protocol)
+	{
+	case IP_PROTO_ICMPV4:	// ICMPv4
+		VirtualIcmpReceived(v, src_ip, dest_ip, data, size);
+		break;
+
+	case IP_PROTO_TCP:		// TCP
+		if (mac_broadcast == false)
+		{
+			VirtualTcpReceived(v, src_ip, dest_ip, data, size);
+		}
+		break;
+
+	case IP_PROTO_UDP:		// UDP
+		VirtualUdpReceived(v, src_ip, dest_ip, data, size, mac_broadcast);
+		break;
+	}
+}
+
+// IP ヘッダのチェックサムを確認する
+bool IpCheckChecksum(IPV4_HEADER *ip)
+{
+	UINT header_size;
+	USHORT checksum_original, checksum_calc;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	header_size = IPV4_GET_HEADER_LEN(ip) * 4;
+	checksum_original = ip->Checksum;
+	ip->Checksum = 0;
+	checksum_calc = IpChecksum(ip, header_size);
+	ip->Checksum = checksum_original;
+
+	if (checksum_original == checksum_calc)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// チェックサムを計算する
+USHORT IpChecksum(void *buf, UINT size)
+{
+	int sum = 0;
+	USHORT *addr = (USHORT *)buf;
+	int len = (int)size;
+	USHORT *w = addr;
+	int nleft = len;
+	USHORT answer = 0;
+
+	while (nleft > 1)
+	{
+		sum += *w++;
+		nleft -= 2;
+	}
+
+	if (nleft == 1)
+	{
+		*(UCHAR *)(&answer) = *(UCHAR *)w;
+		sum += answer;
+	}
+
+	sum = (sum >> 16) + (sum & 0xffff);
+	sum += (sum >> 16);
+
+	answer = ~sum;
+	
+	return answer;
+}
+
+// IP 結合オブジェクトに新しく受信した IP パケットを結合する
+void CombineIp(VH *v, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet)
+{
+	UINT i;
+	IP_PART *p;
+	UINT need_size;
+	UINT data_size_delta;
+	// 引数チェック
+	if (c == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// オフセットとサイズをチェック
+	if ((offset + size) > 65535)
+	{
+		// 64Kbytes を超えるパケットは処理しない
+		return;
+	}
+
+	if (last_packet == false && c->Size != 0)
+	{
+		if ((offset + size) > c->Size)
+		{
+			// パケットサイズより大きいパケットは処理しない
+			return;
+		}
+	}
+
+	need_size = offset + size;
+	data_size_delta = c->DataReserved;
+	// バッファが不足している場合は十分確保する
+	while (c->DataReserved < need_size)
+	{
+		c->DataReserved = c->DataReserved * 4;
+		c->Data = ReAlloc(c->Data, c->DataReserved);
+	}
+	data_size_delta = c->DataReserved - data_size_delta;
+	v->CurrentIpQuota += data_size_delta;
+
+	// データをバッファに上書きする
+	Copy(((UCHAR *)c->Data) + offset, data, size);
+
+	if (last_packet)
+	{
+		// No More Flagment パケットが届いた場合、このデータグラムのサイズが確定する
+		c->Size = offset + size;
+	}
+
+	// オフセットとサイズによって表現されている領域と既存の受信済みリストの
+	// オフセットとサイズによって表現されている領域との間の重複をチェックする
+	for (i = 0;i < LIST_NUM(c->IpParts);i++)
+	{
+		UINT moving_size;
+		IP_PART *p = LIST_DATA(c->IpParts, i);
+
+		// 先頭領域と既存領域との重複をチェック
+		if ((p->Offset <= offset) && ((p->Offset + p->Size) > offset))
+		{
+			// このパケットと既存パケットとの間で先頭部分に重複が見つかったので
+			// このパケットのオフセットを後方に圧縮する
+
+			if ((offset + size) <= (p->Offset + p->Size))
+			{
+				// このパケットは既存のパケットの中に埋もれている
+				size = 0;
+			}
+			else
+			{
+				// 後方領域は重なっていない
+				moving_size = p->Offset + p->Size - offset;
+				offset += moving_size;
+				size -= moving_size;
+			}
+		}
+		if ((p->Offset < (offset + size)) && ((p->Offset + p->Size) >= (offset + size)))
+		{
+			// このパケットと既存パケットとの間で後方部分に重複が見つかったので
+			// このパケットのサイズを前方に圧縮する
+
+			moving_size = p->Offset + p->Size - offset - size;
+			size -= moving_size;
+		}
+
+		if ((p->Offset >= offset) && ((p->Offset + p->Size) <= (offset + size)))
+		{
+			// このパケットが既存のパケットを完全に覆いかぶさるように上書きされた
+			p->Size = 0;
+		}
+	}
+
+	if (size != 0)
+	{
+		// このパケットを登録する
+		p = ZeroMalloc(sizeof(IP_PART));
+
+		p->Offset = offset;
+		p->Size = size;
+
+		Add(c->IpParts, p);
+	}
+
+	if (c->Size != 0)
+	{
+		// すでに受信したデータ部分リストの合計サイズを取得する
+		UINT total_size = 0;
+		UINT i;
+
+		for (i = 0;i < LIST_NUM(c->IpParts);i++)
+		{
+			IP_PART *p = LIST_DATA(c->IpParts, i);
+
+			total_size += p->Size;
+		}
+
+		if (total_size == c->Size)
+		{
+			// IP パケットをすべて受信した
+			IpReceived(v, c->SrcIP, c->DestIP, c->Protocol, c->Data, c->Size, c->MacBroadcast);
+
+			// 結合オブジェクトの解放
+			FreeIpCombine(v, c);
+
+			// 結合オブジェクトをリストから削除
+			Delete(v->IpCombine, c);
+		}
+	}
+}
+
+// IP 結合オブジェクトの解放
+void FreeIpCombine(VH *v, IP_COMBINE *c)
+{
+	UINT i;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	// データ解放
+	v->CurrentIpQuota -= c->DataReserved;
+	Free(c->Data);
+
+	// 部分リスト解放
+	for (i = 0;i < LIST_NUM(c->IpParts);i++)
+	{
+		IP_PART *p = LIST_DATA(c->IpParts, i);
+
+		Free(p);
+	}
+
+	ReleaseList(c->IpParts);
+	Free(c);
+}
+
+// IP 結合リストを検索
+IP_COMBINE *SearchIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol)
+{
+	IP_COMBINE *c, t;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	t.DestIP = dest_ip;
+	t.SrcIP = src_ip;
+	t.Id = id;
+	t.Protocol = protocol;
+
+	c = Search(v->IpCombine, &t);
+
+	return c;
+}
+
+// IP 結合リストに新しいオブジェクトを作成して挿入
+IP_COMBINE *InsertIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast)
+{
+	IP_COMBINE *c;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	// クォータを調べる
+	if ((v->CurrentIpQuota + IP_COMBINE_INITIAL_BUF_SIZE) > IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA)
+	{
+		// これ以上 IP パケットを格納できない
+		return NULL;
+	}
+
+	c = ZeroMalloc(sizeof(IP_COMBINE));
+	c->DestIP = dest_ip;
+	c->SrcIP = src_ip;
+	c->Id = id;
+	c->Expire = v->Now + (UINT64)IP_COMBINE_TIMEOUT;
+	c->Size = 0;
+	c->IpParts = NewList(NULL);
+	c->Protocol = protocol;
+	c->MacBroadcast = mac_broadcast;
+
+	// メモリを確保
+	c->DataReserved = IP_COMBINE_INITIAL_BUF_SIZE;
+	c->Data = Malloc(c->DataReserved);
+	v->CurrentIpQuota += c->DataReserved;
+
+	Insert(v->IpCombine, c);
+
+	return c;
+}
+
+// IP 結合リストの初期化
+void InitIpCombineList(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	v->IpCombine = NewList(CompareIpCombine);
+}
+
+// IP 結合リストの解放
+void FreeIpCombineList(VH *v)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(v->IpCombine);i++)
+	{
+		IP_COMBINE *c = LIST_DATA(v->IpCombine, i);
+
+		FreeIpCombine(v, c);
+	}
+
+	ReleaseList(v->IpCombine);
+}
+
+// IP 結合リストの比較
+int CompareIpCombine(void *p1, void *p2)
+{
+	IP_COMBINE *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(IP_COMBINE **)p1;
+	c2 = *(IP_COMBINE **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+	if (c1->Id > c2->Id)
+	{
+		return 1;
+	}
+	else if (c1->Id < c2->Id)
+	{
+		return -1;
+	}
+	else if (c1->DestIP > c2->DestIP)
+	{
+		return 1;
+	}
+	else if (c1->DestIP < c2->DestIP)
+	{
+		return -1;
+	}
+	else if (c1->SrcIP > c2->SrcIP)
+	{
+		return 1;
+	}
+	else if (c1->SrcIP < c2->SrcIP)
+	{
+		return -1;
+	}
+	else if (c1->Protocol > c2->Protocol)
+	{
+		return 1;
+	}
+	else if (c1->Protocol < c2->Protocol)
+	{
+		return -1;
+	}
+	return 0;
+}
+
+// IP パケットを受信した
+void VirtualIpReceived(VH *v, PKT *packet)
+{
+	IPV4_HEADER *ip;
+	void *data;
+	UINT data_size_recved;
+	UINT size;
+	UINT ipv4_header_size;
+	bool last_packet;
+	// 引数チェック
+	if (v == NULL || packet == NULL)
+	{
+		return;
+	}
+
+	ip = packet->L3.IPv4Header;
+
+	// IPv4 ヘッダのサイズを取得する
+	ipv4_header_size = IPV4_GET_HEADER_LEN(packet->L3.IPv4Header) * 4;
+
+	// IPv4 ヘッダのチェックサムを計算する
+	if (IpCheckChecksum(ip) == false)
+	{
+		return;
+	}
+
+	// データへのポインタを取得する
+	data = ((UCHAR *)packet->L3.PointerL3) + ipv4_header_size;
+
+	// ARP テーブルに登録しておく
+	ArpIpWasKnown(v, packet->L3.IPv4Header->SrcIP, packet->MacAddressSrc);
+
+	// データサイズを取得する
+	size = Endian16(ip->TotalLength);
+	if (size <= ipv4_header_size)
+	{
+		// データが無い
+		return;
+	}
+	size -= ipv4_header_size;
+
+	// 実際に受信したデータサイズを取得する
+	data_size_recved = packet->PacketSize - (ipv4_header_size + MAC_HEADER_SIZE);
+	if (data_size_recved < size)
+	{
+		// データが足りない (途中で欠落しているかも知れない)
+		return;
+	}
+
+	if (IPV4_GET_OFFSET(ip) == 0 && (IPV4_GET_FLAGS(ip) & 0x01) == 0)
+	{
+		// このパケットは分割されていないので直ちに上位層に渡すことができる
+		IpReceived(v, ip->SrcIP, ip->DstIP, ip->Protocol, data, size, packet->BroadcastPacket);
+	}
+	else
+	{
+		// このパケットは分割されているので結合する必要がある
+
+		UINT offset = IPV4_GET_OFFSET(ip) * 8;
+		IP_COMBINE *c = SearchIpCombine(v, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol);
+
+		last_packet = ((IPV4_GET_FLAGS(ip) & 0x01) == 0 ? true : false);
+
+		if (c != NULL)
+		{
+			// 2 個目移行のパケットである
+			CombineIp(v, c, offset, data, size, last_packet);
+		}
+		else
+		{
+			// 最初のパケットなので結合オブジェクトを作成する
+			c = InsertIpCombine(
+				v, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol, packet->BroadcastPacket);
+			if (c != NULL)
+			{
+				CombineIp(v, c, offset, data, size, last_packet);
+			}
+		}
+	}
+}
+
+// 待機している IP パケットのうち指定した IP アドレスからのものを送信する
+void SendWaitingIp(VH *v, UCHAR *mac, UINT dest_ip)
+{
+	UINT i;
+	LIST *o = NULL;
+	// 引数チェック
+	if (v == NULL || mac == NULL)
+	{
+		return;
+	}
+
+	// 対象リストを取得する
+	for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
+	{
+		IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
+
+		if (w->DestIP == dest_ip)
+		{
+			if (o == NULL)
+			{
+				o = NewListFast(NULL);
+			}
+			Add(o, w);
+		}
+	}
+
+	// 対象となったパケットを一気に送信する
+	if (o != NULL)
+	{
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			IP_WAIT *w = LIST_DATA(o, i);
+
+			// 送信処理
+			VirtualIpSend(v, mac, w->Data, w->Size);
+
+			// リストから削除
+			Delete(v->IpWaitTable, w);
+
+			// メモリ解放
+			Free(w->Data);
+			Free(w);
+		}
+
+		ReleaseList(o);
+	}
+}
+
+// 古い IP 待ちテーブルを削除する
+void DeleteOldIpWaitTable(VH *v)
+{
+	UINT i;
+	LIST *o = NULL;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// 削除対象リストを取得する
+	for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
+	{
+		IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
+
+		if (w->Expire < v->Now)
+		{
+			if (o == NULL)
+			{
+				o = NewListFast(NULL);
+			}
+			Add(o, w);
+		}
+	}
+
+	// 一気に削除する
+	if (o != NULL)
+	{
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			IP_WAIT *w = LIST_DATA(o, i);
+
+			// リストから削除
+			Delete(v->IpWaitTable, w);
+
+			// メモリ解放
+			Free(w->Data);
+			Free(w);
+		}
+		ReleaseList(o);
+	}
+}
+
+// IP 待ちテーブルのポーリング
+void PollingIpWaitTable(VH *v)
+{
+	// 古いテーブルの削除
+	DeleteOldIpWaitTable(v);
+}
+
+// IP 待ちテーブルに IP パケットを挿入する
+void InsertIpWaitTable(VH *v, UINT dest_ip, UINT src_ip, void *data, UINT size)
+{
+	IP_WAIT *w;
+	// 引数チェック
+	if (v == NULL || data == NULL || size == 0)
+	{
+		return;
+	}
+
+	w = ZeroMalloc(sizeof(IP_WAIT));
+	w->Data = data;
+	w->Size = size;
+	w->SrcIP = src_ip;
+	w->DestIP = dest_ip;
+	w->Expire = v->Now + (UINT64)IP_WAIT_FOR_ARP_TIMEOUT;
+
+	Add(v->IpWaitTable, w);
+}
+
+// IP 待ちテーブルを初期化する
+void InitIpWaitTable(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	v->IpWaitTable = NewList(NULL);
+}
+
+// IP 待ちテーブルを解放する
+void FreeIpWaitTable(VH *v)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
+	{
+		IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
+
+		Free(w->Data);
+		Free(w);
+	}
+
+	ReleaseList(v->IpWaitTable);
+}
+
+// ARP Response が到着するなどして IP アドレスに対する MAC アドレスが判明した
+void ArpIpWasKnown(VH *v, UINT ip, UCHAR *mac)
+{
+	// 引数チェック
+	if (v == NULL || mac == NULL)
+	{
+		return;
+	}
+
+	// ARP 待ち行列にこの IP アドレスに対する問い合わせがあった場合は削除する
+	DeleteArpWaitTable(v, ip);
+
+	// ARP テーブルに登録または更新する
+	InsertArpTable(v, mac, ip);
+
+	// IP 待機リストで待機している IP パケットを送信する
+	SendWaitingIp(v, mac, ip);
+}
+
+// ARP 待ちリストをチェックし適時 ARP を再発行する
+void PollingArpWaitTable(VH *v)
+{
+	UINT i;
+	LIST *o;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// 削除リストの初期化
+	o = NULL;
+
+	// すべての ARP 待ちリストを走査
+	for (i = 0;i < LIST_NUM(v->ArpWaitTable);i++)
+	{
+		ARP_WAIT *w = LIST_DATA(v->ArpWaitTable, i);
+
+		if (w->GiveupTime < v->Now || (w->GiveupTime - 100 * 1000) > v->Now)
+		{
+			// ARP の送信を諦める
+			if (o == NULL)
+			{
+				o = NewListFast(NULL);
+			}
+			Add(o, w);
+		}
+		else
+		{
+			if (w->TimeoutTime < v->Now)
+			{
+				// ARP を再度送信する
+				VirtualArpSendRequest(v, w->IpAddress);
+
+				// 次のタイムアウト時刻をセット
+				w->TimeoutTime = v->Now + (UINT64)w->NextTimeoutTimeValue;
+				// 2 回目以降の ARP 送信間隔は増やしていく
+				w->NextTimeoutTimeValue = w->NextTimeoutTimeValue + ARP_REQUEST_TIMEOUT;
+			}
+		}
+	}
+
+	// 削除対象の ARP 待ちレコードがある場合は削除する
+	if (o != NULL)
+	{
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			ARP_WAIT *w = LIST_DATA(o, i);
+
+			DeleteArpWaitTable(v, w->IpAddress);
+		}
+		ReleaseList(o);
+	}
+}
+
+// ARP を発行する
+void SendArp(VH *v, UINT ip)
+{
+	ARP_WAIT *w;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// まず ARP 待ちリストに宛先 IP アドレスが登録されているかどうか調べる
+	w = SearchArpWaitTable(v, ip);
+	if (w != NULL)
+	{
+		// すでに登録されているので何もしない
+		return;
+	}
+
+	// まず ARP パケットを送信する
+	VirtualArpSendRequest(v, ip);
+
+	// ARP 待ちリストに登録する
+	w = ZeroMalloc(sizeof(ARP_WAIT));
+	w->GiveupTime = v->Now + (UINT64)ARP_REQUEST_GIVEUP;
+	w->TimeoutTime = v->Now + (UINT64)ARP_REQUEST_TIMEOUT;
+	w->NextTimeoutTimeValue = ARP_REQUEST_TIMEOUT;
+	w->IpAddress = ip;
+
+	InsertArpWaitTable(v, w);
+}
+
+// ARP 待ちテーブルの削除
+void DeleteArpWaitTable(VH *v, UINT ip)
+{
+	ARP_WAIT *w;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	w = SearchArpWaitTable(v, ip);
+	if (w == NULL)
+	{
+		return;
+	}
+	Delete(v->ArpWaitTable, w);
+
+	Free(w);
+}
+
+// ARP 待ちテーブルの検索
+ARP_WAIT *SearchArpWaitTable(VH *v, UINT ip)
+{
+	ARP_WAIT *w, t;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	t.IpAddress = ip;
+	w = Search(v->ArpWaitTable, &t);
+
+	return w;
+}
+
+// ARP 待ちテーブルに登録
+void InsertArpWaitTable(VH *v, ARP_WAIT *w)
+{
+	// 引数チェック
+	if (v == NULL || w == NULL)
+	{
+		return;
+	}
+
+	Add(v->ArpWaitTable, w);
+}
+
+// ARP 待ちテーブルの初期化
+void InitArpWaitTable(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	v->ArpWaitTable = NewList(CompareArpWaitTable);
+}
+
+// ARP 待ちテーブルの解放
+void FreeArpWaitTable(VH *v)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(v->ArpWaitTable);i++)
+	{
+		ARP_WAIT *w = LIST_DATA(v->ArpWaitTable, i);
+
+		Free(w);
+	}
+
+	ReleaseList(v->ArpWaitTable);
+}
+
+// MAC アドレスが不正かどうかチェック
+bool IsMacInvalid(UCHAR *mac)
+{
+	UINT i;
+	// 引数チェック
+	if (mac == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < 6;i++)
+	{
+		if (mac[i] != 0x00)
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+// MAC アドレスがブロードキャストアドレスかどうかチェック
+bool IsMacBroadcast(UCHAR *mac)
+{
+	UINT i;
+	// 引数チェック
+	if (mac == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < 6;i++)
+	{
+		if (mac[i] != 0xff)
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+// ARP テーブルにエントリを挿入する
+void InsertArpTable(VH *v, UCHAR *mac, UINT ip)
+{
+	ARP_ENTRY *e, t;
+	// 引数チェック
+	if (v == NULL || mac == NULL || ip == 0 || ip == 0xffffffff || IsMacBroadcast(mac) || IsMacInvalid(mac))
+	{
+		return;
+	}
+
+	// すでに同じ IP アドレスが登録されていないかどうかチェック
+	t.IpAddress = ip;
+	e = Search(v->ArpTable, &t);
+	if (e != NULL)
+	{
+		// 登録されていたのでこれを上書きするだけ
+		if (Cmp(e->MacAddress, mac, 6) != 0)
+		{
+			e->Created = v->Now;
+			Copy(e->MacAddress, mac, 6);
+		}
+		e->Expire = v->Now + (UINT64)ARP_ENTRY_EXPIRES;
+	}
+	else
+	{
+		// 新しくエントリを作成する
+		e = ZeroMalloc(sizeof(ARP_ENTRY));
+
+		e->Created = v->Now;
+		e->Expire = v->Now + (UINT64)ARP_ENTRY_EXPIRES;
+		Copy(e->MacAddress, mac, 6);
+		e->IpAddress = ip;
+
+		Add(v->ArpTable, e);
+	}
+}
+
+// ARP テーブルのポーリング
+void PollingArpTable(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	if (v->Now > v->NextArpTablePolling)
+	{
+		v->NextArpTablePolling = v->Now + (UINT64)ARP_ENTRY_POLLING_TIME;
+		RefreshArpTable(v);
+	}
+}
+
+// 古い ARP エントリを削除する
+void RefreshArpTable(VH *v)
+{
+	UINT i;
+	LIST *o;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	o = NewListFast(NULL);
+	for (i = 0;i < LIST_NUM(v->ArpTable);i++)
+	{
+		ARP_ENTRY *e = LIST_DATA(v->ArpTable, i);
+
+		// 有効期限が切れたものを調べる
+		if (e->Expire < v->Now)
+		{
+			// 有効期限が切れている
+			Add(o, e);
+		}
+	}
+
+	// 有効期限が切れているものを一括して削除する
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		ARP_ENTRY *e = LIST_DATA(o, i);
+
+		Delete(v->ArpTable, e);
+		Free(e);
+	}
+
+	ReleaseList(o);
+}
+
+// ARP テーブルの検索
+ARP_ENTRY *SearchArpTable(VH *v, UINT ip)
+{
+	ARP_ENTRY *e, t;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	t.IpAddress = ip;
+	e = Search(v->ArpTable, &t);
+
+	return e;
+}
+
+// ARP テーブルの初期化
+void InitArpTable(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	v->ArpTable = NewList(CompareArpTable);
+}
+
+// ARP テーブルの解放
+void FreeArpTable(VH *v)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// すべてのエントリを削除する
+	for (i = 0;i < LIST_NUM(v->ArpTable);i++)
+	{
+		ARP_ENTRY *e = LIST_DATA(v->ArpTable, i);
+		Free(e);
+	}
+	ReleaseList(v->ArpTable);
+}
+
+// ARP 待ちテーブルの比較
+int CompareArpWaitTable(void *p1, void *p2)
+{
+	ARP_WAIT *e1, *e2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	e1 = *(ARP_WAIT **)p1;
+	e2 = *(ARP_WAIT **)p2;
+	if (e1 == NULL || e2 == NULL)
+	{
+		return 0;
+	}
+
+	if (e1->IpAddress > e2->IpAddress)
+	{
+		return 1;
+	}
+	else if (e1->IpAddress < e2->IpAddress)
+	{
+		return -1;
+	}
+	return 0;
+}
+
+// ARP テーブルの比較
+int CompareArpTable(void *p1, void *p2)
+{
+	ARP_ENTRY *e1, *e2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	e1 = *(ARP_ENTRY **)p1;
+	e2 = *(ARP_ENTRY **)p2;
+	if (e1 == NULL || e2 == NULL)
+	{
+		return 0;
+	}
+
+	if (e1->IpAddress > e2->IpAddress)
+	{
+		return 1;
+	}
+	else if (e1->IpAddress < e2->IpAddress)
+	{
+		return -1;
+	}
+	return 0;
+}
+
+// 仮想ホストの初期化
+bool VirtualInit(VH *v)
+{
+	// ログ初期化
+	v->Logger = NULL;
+
+	LockVirtual(v);
+	{
+		// 初期化
+		v->Cancel = NewCancel();
+		v->SendQueue = NewQueue();
+	}
+	UnlockVirtual(v);
+
+	// カウンタリセット
+	v->Counter->c = 0;
+	v->DhcpId = 0;
+
+	// ARP テーブルの初期化
+	InitArpTable(v);
+
+	// ARP 待ちテーブルの初期化
+	InitArpWaitTable(v);
+
+	// IP 待ちテーブルの初期化
+	InitIpWaitTable(v);
+
+	// IP 結合リストの初期化
+	InitIpCombineList(v);
+
+	// NAT の初期化
+	InitNat(v);
+
+	// DHCP サーバーの初期化
+	InitDhcpServer(v);
+
+	// その他初期化
+	v->flag1 = false;
+	v->NextArpTablePolling = Tick64() + (UINT64)ARP_ENTRY_POLLING_TIME;
+	v->CurrentIpQuota = 0;
+	v->Active = true;
+
+	return true;
+}
+bool VirtualPaInit(SESSION *s)
+{
+	VH *v;
+	// 引数チェック
+	if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+	{
+		return false;
+	}
+
+	return VirtualInit(v);
+}
+
+// 仮想ホストのキャンセルオブジェクトを取得
+CANCEL *VirtualPaGetCancel(SESSION *s)
+{
+	VH *v;
+	// 引数チェック
+	if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+	{
+		return NULL;
+	}
+
+	AddRef(v->Cancel->ref);
+	return v->Cancel;
+}
+
+// 仮想ホストから次のパケットを取得
+UINT VirtualGetNextPacket(VH *v, void **data)
+{
+	UINT ret = 0;
+
+START:
+	// 送信キューを調べる
+	LockQueue(v->SendQueue);
+	{
+		BLOCK *block = GetNext(v->SendQueue);
+
+		if (block != NULL)
+		{
+			// パケットがあった
+			ret = block->Size;
+			*data = block->Buf;
+			// 構造体は破棄する
+			Free(block);
+		}
+	}
+	UnlockQueue(v->SendQueue);
+
+	if (ret == 0)
+	{
+		LockVirtual(v);
+		{
+			v->Now = Tick64();
+			// ポーリング処理
+			VirtualPolling(v);
+		}
+		UnlockVirtual(v);
+		if (v->SendQueue->num_item != 0)
+		{
+			goto START;
+		}
+	}
+
+	return ret;
+}
+UINT VirtualPaGetNextPacket(SESSION *s, void **data)
+{
+	VH *v;
+	// 引数チェック
+	if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+	{
+		return INFINITE;
+	}
+
+	return VirtualGetNextPacket(v, data);
+}
+
+// ポーリング処理 (SessionMain ループ中に 1 回必ず呼ばれる)
+void VirtualPolling(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// DHCP ポーリング
+	PollingDhcpServer(v);
+
+	// NAT ポーリング
+	PoolingNat(v);
+
+	// 古い ARP テーブルの清掃
+	PollingArpTable(v);
+
+	// ARP 待ちリストのポーリング
+	PollingArpWaitTable(v);
+
+	// IP 待ちリストのポーリング
+	PollingIpWaitTable(v);
+
+	// IP 結合リストのポーリング
+	PollingIpCombine(v);
+
+	// ビーコン送信プロシージャ
+	PollingBeacon(v);
+}
+
+// ビーコン送信プロシージャ
+void PollingBeacon(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	if (v->LastSendBeacon == 0 ||
+		((v->LastSendBeacon + BEACON_SEND_INTERVAL) <= Tick64()))
+	{
+		v->LastSendBeacon = Tick64();
+
+		SendBeacon(v);
+	}
+}
+
+// Layer-2 パケットを送信する
+void VirtualLayer2Send(VH *v, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)
+{
+	MAC_HEADER *mac_header;
+	UCHAR *buf;
+	BLOCK *block;
+	// 引数チェック
+	if (v == NULL || dest_mac == NULL || src_mac == NULL || data == NULL || size > (MAX_PACKET_SIZE - sizeof(MAC_HEADER)))
+	{
+		return;
+	}
+
+	// バッファ生成
+	buf = Malloc(MAC_HEADER_SIZE + size);
+
+	// MAC ヘッダ
+	mac_header = (MAC_HEADER *)&buf[0];
+	Copy(mac_header->DestAddress, dest_mac, 6);
+	Copy(mac_header->SrcAddress, src_mac, 6);
+	mac_header->Protocol = Endian16(protocol);
+
+	// データのコピー
+	Copy(&buf[sizeof(MAC_HEADER)], data, size);
+
+	// サイズ
+	size += sizeof(MAC_HEADER);
+
+	// パケット生成
+	block = NewBlock(buf, size, 0);
+
+	// キューに挿入する
+	LockQueue(v->SendQueue);
+	{
+		InsertQueue(v->SendQueue, block);
+	}
+	UnlockQueue(v->SendQueue);
+
+	// キャンセル
+	Cancel(v->Cancel);
+}
+
+// IP パケットを送信する (自動的に分割処理を行う)
+void SendIp(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size)
+{
+	UINT mss;
+	UCHAR *buf;
+	USHORT offset;
+	USHORT id;
+	USHORT total_size;
+	UINT size_of_this_packet;
+	// 引数チェック
+	if (v == NULL || data == NULL || size == 0 || size > MAX_IP_DATA_SIZE_TOTAL)
+	{
+		return;
+	}
+
+	// 最大セグメントサイズ
+	mss = v->IpMss;
+
+	// バッファ
+	buf = (UCHAR *)data;
+
+	// ID
+	id = (v->NextId++);
+
+	// 合計サイズ
+	total_size = (USHORT)size;
+
+	// 分割作業を開始
+	offset = 0;
+
+	while (true)
+	{
+		bool last_packet = false;
+		// このパケットのサイズを取得
+		size_of_this_packet = MIN((USHORT)mss, (total_size - offset));
+		if ((offset + (USHORT)size_of_this_packet) == total_size)
+		{
+			last_packet = true;
+		}
+
+		// 分割されたパケットの送信処理
+		SendFragmentedIp(v, dest_ip, src_ip, id,
+			total_size, offset, protocol, buf + offset, size_of_this_packet, NULL);
+		if (last_packet)
+		{
+			break;
+		}
+
+		offset += (USHORT)size_of_this_packet;
+	}
+}
+
+// 分割済みの IP パケットを送信予約する
+void SendFragmentedIp(VH *v, UINT dest_ip, UINT src_ip, USHORT id, USHORT total_size, USHORT offset, UCHAR protocol, void *data, UINT size, UCHAR *dest_mac)
+{
+	UCHAR *buf;
+	IPV4_HEADER *ip;
+	ARP_ENTRY *arp;
+	// 引数チェック
+	if (v == NULL || data == NULL || size == 0)
+	{
+		return;
+	}
+
+	// メモリ確保
+	buf = Malloc(size + IP_HEADER_SIZE);
+	ip = (IPV4_HEADER *)&buf[0];
+
+	// IP ヘッダ構築
+	ip->VersionAndHeaderLength = 0;
+	IPV4_SET_VERSION(ip, 4);
+	IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
+	ip->TypeOfService = DEFAULT_IP_TOS;
+	ip->TotalLength = Endian16((USHORT)(size + IP_HEADER_SIZE));
+	ip->Identification = Endian16(id);
+	ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
+	IPV4_SET_OFFSET(ip, (offset / 8));
+	if ((offset + size) >= total_size)
+	{
+		IPV4_SET_FLAGS(ip, 0x00);
+	}
+	else
+	{
+		IPV4_SET_FLAGS(ip, 0x01);
+	}
+	ip->TimeToLive = DEFAULT_IP_TTL;
+	ip->Protocol = protocol;
+	ip->Checksum = 0;
+	ip->SrcIP = src_ip;
+	ip->DstIP = dest_ip;
+
+	// チェックサム計算
+	ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
+
+	// データコピー
+	Copy(buf + IP_HEADER_SIZE, data, size);
+
+	if (dest_mac == NULL)
+	{
+		if (ip->DstIP == 0xffffffff ||
+			(IsInNetwork(ip->DstIP, v->HostIP, v->HostMask) && (ip->DstIP & (~v->HostMask)) == (~v->HostMask)))
+		{
+			// ブロードキャストアドレス
+			dest_mac = broadcast;
+		}
+		else
+		{
+			// 宛先 MAC アドレスが不明な場合は ARP 問い合わせ
+			arp = SearchArpTable(v, dest_ip);
+			if (arp != NULL)
+			{
+				dest_mac = arp->MacAddress;
+			}
+		}
+	}
+	if (dest_mac != NULL)
+	{
+		// 直ちにパケットを送信する
+		VirtualIpSend(v, dest_mac, buf, size + IP_HEADER_SIZE);
+
+		// パケットデータは解放して良い
+		Free(buf);
+	}
+	else
+	{
+		// このパケットはまだ転送できないので IP 待ちテーブルに追加する
+		InsertIpWaitTable(v, dest_ip, src_ip, buf, size + IP_HEADER_SIZE);
+
+		// ARP を発行する
+		SendArp(v, dest_ip);
+	}
+}
+
+// IP パケット (分割済み) を送信する
+void VirtualIpSend(VH *v, UCHAR *dest_mac, void *data, UINT size)
+{
+	// 引数チェック
+	if (v == NULL || dest_mac == NULL || data == NULL || size == 0)
+	{
+		return;
+	}
+
+	// 送信
+	VirtualLayer2Send(v, dest_mac, v->MacAddress, MAC_PROTO_IPV4, data, size);
+}
+
+// ARP リクエストパケットを送信する
+void VirtualArpSendRequest(VH *v, UINT dest_ip)
+{
+	ARPV4_HEADER arp;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// ARP ヘッダを構築
+	arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+	arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+	arp.HardwareSize = 6;
+	arp.ProtocolSize = 4;
+	arp.Operation = Endian16(ARP_OPERATION_REQUEST);
+	Copy(arp.SrcAddress, v->MacAddress, 6);
+	arp.SrcIP = v->HostIP;
+	Zero(&arp.TargetAddress, 6);
+	arp.TargetIP = dest_ip;
+
+	// 送信
+	VirtualLayer2Send(v, broadcast, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// ARP レスポンスパケットを送信する
+void VirtualArpSendResponse(VH *v, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)
+{
+	ARPV4_HEADER arp;
+	// 引数チェック
+	if (v == NULL || dest_mac == NULL)
+	{
+		return;
+	}
+
+	// ARP ヘッダを構築
+	arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+	arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+	arp.HardwareSize = 6;
+	arp.ProtocolSize = 4;
+	arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+	Copy(arp.SrcAddress, v->MacAddress, 6);
+	Copy(arp.TargetAddress, dest_mac, 6);
+	arp.SrcIP = src_ip;
+	arp.TargetIP = dest_ip;
+
+	// 送信
+	VirtualLayer2Send(v, dest_mac, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(ARPV4_HEADER));
+}
+
+// ARP リクエストパケットを受信した
+void VirtualArpResponseRequest(VH *v, PKT *packet)
+{
+	ARPV4_HEADER *arp;
+	// 引数チェック
+	if (v == NULL || packet == NULL)
+	{
+		return;
+	}
+
+	arp = packet->L3.ARPv4Header;
+
+	// 相手のホスト IP アドレスと MAC アドレスを既知の情報とする
+	ArpIpWasKnown(v, arp->SrcIP, arp->SrcAddress);
+
+	// 自分のホスト IP アドレスと一致するかどうか検索
+	if (v->HostIP == arp->TargetIP)
+	{
+		// 一致したので応答する
+		VirtualArpSendResponse(v, arp->SrcAddress, arp->SrcIP, v->HostIP);
+		return;
+	}
+	// 一致しない場合は何もしない
+}
+
+// ARP レスポンスパケットを受信した
+void VirtualArpResponseReceived(VH *v, PKT *packet)
+{
+	ARPV4_HEADER *arp;
+	// 引数チェック
+	if (v == NULL || packet == NULL)
+	{
+		return;
+	}
+
+	arp = packet->L3.ARPv4Header;
+
+	// この情報を既知の情報とする
+	ArpIpWasKnown(v, arp->SrcIP, arp->SrcAddress);
+}
+
+// ARP パケットを受信した
+void VirtualArpReceived(VH *v, PKT *packet)
+{
+	ARPV4_HEADER *arp;
+	// 引数チェック
+	if (v == NULL || packet == NULL)
+	{
+		return;
+	}
+
+	arp = packet->L3.ARPv4Header;
+
+	if (Endian16(arp->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET)
+	{
+		// ハードウェア種類が Ethernet 以外の場合は無視
+		return;
+	}
+	if (Endian16(arp->ProtocolType) != MAC_PROTO_IPV4)
+	{
+		// プロトコル種類が IPv4 以外の場合は無視
+		return;
+	}
+	if (arp->HardwareSize != 6 || arp->ProtocolSize != 4)
+	{
+		// ハードウェアアドレスまたはプロトコルアドレスのサイズが不正なので無視
+		return;
+	}
+	// 送信元 MAC アドレスをチェック
+	if (Cmp(arp->SrcAddress, packet->MacAddressSrc, 6) != 0)
+	{
+		// ARP パケットの MAC アドレスと MAC ヘッダの MAC アドレスが異なる
+		return;
+	}
+
+	switch (Endian16(arp->Operation))
+	{
+	case ARP_OPERATION_REQUEST:		// ARP リクエスト
+		VirtualArpResponseRequest(v, packet);
+		break;
+
+	case ARP_OPERATION_RESPONSE:	// ARP レスポンス
+		VirtualArpResponseReceived(v, packet);
+		break;
+	}
+}
+
+// DHCP サーバーの解放
+void FreeDhcpServer(VH *v)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// すべてのリースエントリを削除する
+	for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
+	{
+		DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
+		FreeDhcpLease(d);
+	}
+
+	ReleaseList(v->DhcpLeaseList);
+	v->DhcpLeaseList = NULL;
+}
+
+// DHCP サーバーの初期化
+void InitDhcpServer(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// リスト作成
+	v->DhcpLeaseList = NewList(CompareDhcpLeaseList);
+}
+
+// DHCP リース項目を IP アドレスで検索
+DHCP_LEASE *SearchDhcpLeaseByIp(VH *v, UINT ip)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
+	{
+		DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
+		if (d->IpAddress == ip)
+		{
+			return d;
+		}
+	}
+
+	return NULL;
+}
+
+// DHCP リース項目を MAC アドレスで検索
+DHCP_LEASE *SearchDhcpLeaseByMac(VH *v, UCHAR *mac)
+{
+	DHCP_LEASE *d, t;
+	// 引数チェック
+	if (v == NULL || mac == NULL)
+	{
+		return NULL;
+	}
+
+	Copy(&t.MacAddress, mac, 6);
+	d = Search(v->DhcpLeaseList, &t);
+
+	return d;
+}
+
+// DHCP リース項目の解放
+void FreeDhcpLease(DHCP_LEASE *d)
+{
+	// 引数チェック
+	if (d == NULL)
+	{
+		return;
+	}
+
+	Free(d->Hostname);
+	Free(d);
+}
+
+// DHCP リース項目の作成
+DHCP_LEASE *NewDhcpLease(UINT expire, UCHAR *mac_address, UINT ip, UINT mask, char *hostname)
+{
+	DHCP_LEASE *d;
+	// 引数チェック
+	if (mac_address == NULL || hostname == NULL)
+	{
+		return NULL;
+	}
+
+	d = ZeroMalloc(sizeof(DHCP_LEASE));
+	d->LeasedTime = (UINT64)Tick64();
+	if (expire == INFINITE)
+	{
+		d->ExpireTime = INFINITE;
+	}
+	else
+	{
+		d->ExpireTime = d->LeasedTime + (UINT64)expire;
+	}
+	d->IpAddress = ip;
+	d->Mask = mask;
+	d->Hostname = CopyStr(hostname);
+	Copy(d->MacAddress, mac_address, 6);
+
+
+	return d;
+}
+
+// DHCP リストの項目の比較
+int CompareDhcpLeaseList(void *p1, void *p2)
+{
+	DHCP_LEASE *d1, *d2;
+	// 引数チェック
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	d1 = *(DHCP_LEASE **)p1;
+	d2 = *(DHCP_LEASE **)p2;
+	if (d1 == NULL || d2 == NULL)
+	{
+		return 0;
+	}
+
+	return Cmp(d1->MacAddress, d2->MacAddress, 6);
+}
+
+// DHCP サーバーのポーリング
+void PollingDhcpServer(VH *v)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	if (v->LastDhcpPolling != 0)
+	{
+		if ((v->LastDhcpPolling + (UINT64)DHCP_POLLING_INTERVAL) < v->Now ||
+			v->LastDhcpPolling > v->Now)
+		{
+			return;
+		}
+	}
+	v->LastDhcpPolling = v->Now;
+
+	// 有効期限の切れたエントリを削除
+FIRST_LIST:
+	for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
+	{
+		DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
+
+		if (d->ExpireTime < v->Now)
+		{
+			FreeDhcpLease(d);
+			Delete(v->DhcpLeaseList, d);
+			goto FIRST_LIST;
+		}
+	}
+}
+
+// DHCP REQUEST に対応する
+UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip)
+{
+	UINT ret;
+	// 引数チェック
+	if (v == NULL || mac == NULL)
+	{
+		return 0;
+	}
+
+	ret = ServeDhcpDiscover(v, mac, request_ip);
+	if (ret != request_ip)
+	{
+		if (request_ip != 0)
+		{
+			// 要求されている IP アドレスを割り当てることができない場合はエラー
+			return 0;
+		}
+	}
+
+	return ret;
+}
+
+// DHCP DISCOVER に対応する
+UINT ServeDhcpDiscover(VH *v, UCHAR *mac, UINT request_ip)
+{
+	UINT ret = 0;
+	// 引数チェック
+	if (v == NULL || mac == NULL)
+	{
+		return 0;
+	}
+
+	if (request_ip != 0)
+	{
+		// IP アドレスが指定されている
+		DHCP_LEASE *d = SearchDhcpLeaseByIp(v, request_ip);
+		if (d != NULL)
+		{
+			// 同じ IP アドレスのエントリがすでに存在している場合は
+			// 同じ MAC アドレスからの要求であることを調べる
+			if (Cmp(mac, d->MacAddress, 6) == 0)
+			{
+				// 指定された IP アドレスが割り当て範囲内にあるかどうか調べる
+				if (Endian32(v->DhcpIpStart) <= Endian32(request_ip) &&
+					Endian32(request_ip) <= Endian32(v->DhcpIpEnd))
+				{
+					// 範囲内にあるなら承諾する
+					ret = request_ip;
+				}
+			}
+		}
+		else
+		{
+			// 指定された IP アドレスが割り当て範囲内にあるかどうか調べる
+			if (Endian32(v->DhcpIpStart) <= Endian32(request_ip) &&
+				Endian32(request_ip) <= Endian32(v->DhcpIpEnd))
+			{
+				// 範囲内にあるなら承諾する
+				ret = request_ip;
+			}
+			else
+			{
+				// 範囲外であるが Discover なので範囲内の IP を 1 つ提案する
+			}
+		}
+	}
+
+	if (ret == 0)
+	{
+		// すでに登録されているエントリで同じ MAC アドレスのものがあれば
+		// それを優先して使用する
+		DHCP_LEASE *d = SearchDhcpLeaseByMac(v, mac);
+		if (d != NULL)
+		{
+			// 見つかった IP アドレスが割り当て範囲内にあるかどうか調べる
+			if (Endian32(v->DhcpIpStart) <= Endian32(d->IpAddress) &&
+				Endian32(d->IpAddress) <= Endian32(v->DhcpIpEnd))
+			{
+				// 範囲内にあるなら見つかったIPアドレスを使用する
+				ret = d->IpAddress;
+			}
+		}
+	}
+
+	if (ret == 0)
+	{
+		// 新しく割り当てることが可能な IP アドレスを適当に取る
+		ret = GetFreeDhcpIpAddress(v);
+	}
+
+	return ret;
+}
+
+// 新しく割り当てることが可能な IP アドレスを適当に 1 つ取る
+UINT GetFreeDhcpIpAddress(VH *v)
+{
+	UINT ip_start, ip_end;
+	UINT i;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return 0;
+	}
+
+	ip_start = Endian32(v->DhcpIpStart);
+	ip_end = Endian32(v->DhcpIpEnd);
+
+	for (i = ip_start; i <= ip_end;i++)
+	{
+		UINT ip = Endian32(i);
+		if (SearchDhcpLeaseByIp(v, ip) == NULL)
+		{
+			// 空き IP アドレスを発見した
+			return ip;
+		}
+	}
+
+	// 空きが無い
+	return 0;
+}
+
+// 仮想 DHCP サーバー
+void VirtualDhcpServer(VH *v, PKT *p)
+{
+	DHCPV4_HEADER *dhcp;
+	UCHAR *data;
+	UINT size;
+	UINT dhcp_header_size;
+	UINT dhcp_data_offset;
+	UINT tran_id;
+	UINT magic_cookie = Endian32(DHCP_MAGIC_COOKIE);
+	bool ok;
+	DHCP_OPTION_LIST *opt;
+	// 引数チェック
+	if (v == NULL || p == NULL)
+	{
+		return;
+	}
+
+	dhcp = p->L7.DHCPv4Header;
+
+	tran_id = Endian32(dhcp->TransactionId);
+
+	// DHCP データとサイズを取得する
+	dhcp_header_size = sizeof(DHCPV4_HEADER);
+	dhcp_data_offset = (UINT)(((UCHAR *)p->L7.DHCPv4Header) - ((UCHAR *)p->MacHeader) + dhcp_header_size);
+	data = ((UCHAR *)dhcp) + dhcp_header_size;
+	size = p->PacketSize - dhcp_data_offset;
+	if (dhcp_header_size < 5)
+	{
+		// データサイズが不正
+		return;
+	}
+
+	// Magic Cookie を検索する
+	ok = false;
+	while (size >= 5)
+	{
+		if (Cmp(data, &magic_cookie, sizeof(magic_cookie)) == 0)
+		{
+			// 発見
+			data += 4;
+			size -= 4;
+			ok = true;
+			break;
+		}
+		data++;
+		size--;
+	}
+
+	if (ok == false)
+	{
+		// パケット不正
+		return;
+	}
+
+	// DHCP オプションリストのパース
+	opt = ParseDhcpOptionList(data, size);
+	if (opt == NULL)
+	{
+		// パケット不正
+		return;
+	}
+
+	if (dhcp->OpCode == 1 && (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST))
+	{
+		// サーバーとしての動作を行う
+		UINT ip;
+		if (opt->RequestedIp == 0)
+		{
+			opt->RequestedIp = p->L3.IPv4Header->SrcIP;
+		}
+		if (opt->Opcode == DHCP_DISCOVER)
+		{
+			// 利用できる IP アドレスを 1 つ返す
+			ip = ServeDhcpDiscover(v, p->MacAddressSrc, opt->RequestedIp);
+		}
+		else
+		{
+			// IP アドレスを確定する
+			ip = ServeDhcpRequest(v, p->MacAddressSrc, opt->RequestedIp);
+		}
+		if (ip != 0)
+		{
+			// 提供可能な IP アドレスがある場合は応答してやる
+
+			if (opt->Opcode == DHCP_REQUEST)
+			{
+				DHCP_LEASE *d;
+				char mac[MAX_SIZE];
+				char str[MAX_SIZE];
+				// 同じ IP アドレスで古いレコードがあれば削除する
+				d = SearchDhcpLeaseByIp(v, ip);
+				if (d != NULL)
+				{
+					FreeDhcpLease(d);
+					Delete(v->DhcpLeaseList, d);
+				}
+
+				// 新しいエントリを作成する
+				d = NewDhcpLease(v->DhcpExpire, p->MacAddressSrc,
+					ip, v->DhcpMask,
+					opt->Hostname);
+				d->Id = ++v->DhcpId;
+				Add(v->DhcpLeaseList, d);
+				MacToStr(mac, sizeof(mac), d->MacAddress);
+
+				IPToStr32(str, sizeof(str), d->IpAddress);
+
+				NLog(v, "LH_NAT_DHCP_CREATED", d->Id, mac, str, d->Hostname, v->DhcpExpire / 1000);
+			}
+
+			// 応答する
+			if (ip != 0)
+			{
+				DHCP_OPTION_LIST ret;
+				LIST *o;
+				Zero(&ret, sizeof(ret));
+
+				ret.Opcode = (opt->Opcode == DHCP_DISCOVER ? DHCP_OFFER : DHCP_ACK);
+				ret.ServerAddress = v->HostIP;
+				if (v->DhcpExpire == INFINITE)
+				{
+					ret.LeaseTime = INFINITE;
+				}
+				else
+				{
+					ret.LeaseTime = Endian32(v->DhcpExpire / 1000);
+				}
+				StrCpy(ret.DomainName, sizeof(ret.DomainName), v->DhcpDomain);
+				ret.SubnetMask = v->DhcpMask;
+				ret.DnsServer = v->DhcpDns;
+				ret.Gateway = v->DhcpGateway;
+
+				if (1)
+				{
+					char client_mac[MAX_SIZE];
+					char client_ip[64];
+					IP ips;
+					BinToStr(client_mac, sizeof(client_mac), p->MacAddressSrc, 6);
+					UINTToIP(&ips, ip);
+					IPToStr(client_ip, sizeof(client_ip), &ips);
+					Debug("DHCP %s : %s given %s\n",
+						ret.Opcode == DHCP_OFFER ? "DHCP_OFFER" : "DHCP_ACK",
+						client_mac, client_ip);
+				}
+
+				// DHCP オプションのビルド
+				o = BuildDhcpOption(&ret);
+				if (o != NULL)
+				{
+					BUF *b = BuildDhcpOptionsBuf(o);
+					if (b != NULL)
+					{
+						UINT dest_ip = p->L3.IPv4Header->SrcIP;
+						if (dest_ip == 0)
+						{
+							dest_ip = 0xffffffff;
+						}
+						// 送信
+						VirtualDhcpSend(v, tran_id, dest_ip, Endian16(p->L4.UDPHeader->SrcPort),
+							ip, dhcp->ClientMacAddress, b);
+
+						// メモリ解放
+						FreeBuf(b);
+					}
+					FreeDhcpOptions(o);
+				}
+			}
+		}
+		else
+		{
+			// 提供できる IP アドレスが無い
+			DHCP_OPTION_LIST ret;
+			LIST *o;
+			Zero(&ret, sizeof(ret));
+
+			ret.Opcode = DHCP_NACK;
+			ret.ServerAddress = v->HostIP;
+			StrCpy(ret.DomainName, sizeof(ret.DomainName), v->DhcpDomain);
+			ret.SubnetMask = v->DhcpMask;
+
+			// DHCP オプションのビルド
+			o = BuildDhcpOption(&ret);
+			if (o != NULL)
+			{
+				BUF *b = BuildDhcpOptionsBuf(o);
+				if (b != NULL)
+				{
+					UINT dest_ip = p->L3.IPv4Header->SrcIP;
+					if (dest_ip == 0)
+					{
+						dest_ip = 0xffffffff;
+					}
+					// 送信
+					VirtualDhcpSend(v, tran_id, dest_ip, Endian16(p->L4.UDPHeader->SrcPort),
+						ip, dhcp->ClientMacAddress, b);
+
+					// メモリ解放
+					FreeBuf(b);
+				}
+				FreeDhcpOptions(o);
+			}
+		}
+	}
+
+	// メモリ解放
+	Free(opt);
+}
+
+// DHCP 応答パケットの送信
+void VirtualDhcpSend(VH *v, UINT tran_id, UINT dest_ip, UINT dest_port,
+					 UINT new_ip, UCHAR *client_mac, BUF *b)
+{
+	UINT blank_size = 128 + 64;
+	UINT dhcp_packet_size;
+	UINT magic = Endian32(DHCP_MAGIC_COOKIE);
+	DHCPV4_HEADER *dhcp;
+	void *magic_cookie_addr;
+	void *buffer_addr;
+	// 引数チェック
+	if (v == NULL || b == NULL)
+	{
+		return;
+	}
+
+	// DHCP パケットサイズを求める
+	dhcp_packet_size = blank_size + sizeof(DHCPV4_HEADER) + sizeof(magic) + b->Size;
+
+	// ヘッダ作成
+	dhcp = ZeroMalloc(dhcp_packet_size);
+
+	dhcp->OpCode = 2;
+	dhcp->HardwareType = 1;
+	dhcp->HardwareAddressSize = 6;
+	dhcp->Hops = 0;
+	dhcp->TransactionId = Endian32(tran_id);
+	dhcp->Seconds = 0;
+	dhcp->Flags = 0;
+	dhcp->YourIP = new_ip;
+	dhcp->ServerIP = v->HostIP;
+	Copy(dhcp->ClientMacAddress, client_mac, 6);
+
+	// アドレスを求める
+	magic_cookie_addr = (((UCHAR *)dhcp) + sizeof(DHCPV4_HEADER) + blank_size);
+	buffer_addr = ((UCHAR *)magic_cookie_addr) + sizeof(magic);
+
+	// Magic Cookie
+	Copy(magic_cookie_addr, &magic, sizeof(magic));
+
+	// Buffer
+	Copy(buffer_addr, b->Buf, b->Size);
+
+	// 送信
+	SendUdp(v, dest_ip, dest_port, v->HostIP, NAT_DHCP_SERVER_PORT, dhcp, dhcp_packet_size);
+
+	Free(dhcp);
+}
+
+// DHCP オプション リストをバッファに変換する
+BUF *BuildDhcpOptionsBuf(LIST *o)
+{
+	BUF *b;
+	UINT i;
+	UCHAR id;
+	UCHAR sz;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		DHCP_OPTION *d = LIST_DATA(o, i);
+		id = (UCHAR)d->Id;
+		sz = (UCHAR)d->Size;
+		WriteBuf(b, &id, 1);
+		WriteBuf(b, &sz, 1);
+		WriteBuf(b, d->Data, d->Size);
+	}
+
+	id = 0xff;
+	WriteBuf(b, &id, 1);
+
+	return b;
+}
+
+// DHCP オプション リストを DHCP オプションに変換する
+LIST *BuildDhcpOption(DHCP_OPTION_LIST *opt)
+{
+	LIST *o;
+	UCHAR opcode;
+	// 引数チェック
+	if (opt == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(NULL);
+
+	// オペコード
+	opcode = (UCHAR)opt->Opcode;
+	Add(o, NewDhcpOption(DHCP_ID_MESSAGE_TYPE, &opcode, sizeof(opcode)));
+	Add(o, NewDhcpOption(DHCP_ID_SERVER_ADDRESS, &opt->ServerAddress, sizeof(opt->ServerAddress)));
+	Add(o, NewDhcpOption(DHCP_ID_LEASE_TIME, &opt->LeaseTime, sizeof(opt->LeaseTime)));
+	if (StrLen(opt->DomainName) != 0 && opt->DnsServer != 0)
+	{
+		Add(o, NewDhcpOption(DHCP_ID_DOMAIN_NAME, opt->DomainName, StrLen(opt->DomainName)));
+	}
+	if (opt->SubnetMask != 0)
+	{
+		Add(o, NewDhcpOption(DHCP_ID_SUBNET_MASK, &opt->SubnetMask, sizeof(opt->SubnetMask)));
+	}
+	if (opt->Gateway != 0)
+	{
+		Add(o, NewDhcpOption(DHCP_ID_GATEWAY_ADDR, &opt->Gateway, sizeof(opt->Gateway)));
+	}
+	if (opt->DnsServer != 0)
+	{
+		Add(o, NewDhcpOption(DHCP_ID_DNS_ADDR, &opt->DnsServer, sizeof(opt->DnsServer)));
+	}
+
+	return o;
+}
+
+// 新しい DHCP オプション項目の作成
+DHCP_OPTION *NewDhcpOption(UINT id, void *data, UINT size)
+{
+	DHCP_OPTION *ret;
+	if (size != 0 && data == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(DHCP_OPTION));
+	ret->Data = ZeroMalloc(size);
+	Copy(ret->Data, data, size);
+	ret->Size = (UCHAR)size;
+	ret->Id = (UCHAR)id;
+
+	return ret;
+}
+
+// DHCP オプションリストのパース
+DHCP_OPTION_LIST *ParseDhcpOptionList(void *data, UINT size)
+{
+	DHCP_OPTION_LIST *ret;
+	LIST *o;
+	DHCP_OPTION *a;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return NULL;
+	}
+
+	// リストのパース
+	o = ParseDhcpOptions(data, size);
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(DHCP_OPTION_LIST));
+
+	// オペコードの取得
+	a = GetDhcpOption(o, DHCP_ID_MESSAGE_TYPE);
+	if (a != NULL)
+	{
+		if (a->Size == 1)
+		{
+			ret->Opcode = *((UCHAR *)a->Data);
+		}
+	}
+
+	switch (ret->Opcode)
+	{
+	case DHCP_DISCOVER:
+	case DHCP_REQUEST:
+		// クライアント要求なのでより細かくパースする
+		// 要求された IP アドレス
+		a = GetDhcpOption(o, DHCP_ID_REQUEST_IP_ADDRESS);
+		if (a != NULL && a->Size == 4)
+		{
+			Copy(&ret->RequestedIp, a->Data, 4);
+		}
+		// ホスト名
+		a = GetDhcpOption(o, DHCP_ID_HOST_NAME);
+		if (a != NULL)
+		{
+			if (a->Size > 1)
+			{
+				Copy(ret->Hostname, a->Data, MIN(a->Size, sizeof(ret->Hostname) - 1));
+			}
+		}
+		break;
+
+	case DHCP_OFFER:
+	case DHCP_ACK:
+		// 今のところこの 2 つのオプションをパースする必要は無い
+		break;
+	}
+
+	// リストの解放
+	FreeDhcpOptions(o);
+
+	return ret;
+}
+
+// DHCP オプションの検索
+DHCP_OPTION *GetDhcpOption(LIST *o, UINT id)
+{
+	UINT i;
+	DHCP_OPTION *ret = NULL;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		DHCP_OPTION *opt = LIST_DATA(o, i);
+		if (opt->Id == id)
+		{
+			ret = opt;
+		}
+	}
+
+	return ret;
+}
+
+// DHCP オプションの解放
+void FreeDhcpOptions(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		DHCP_OPTION *opt = LIST_DATA(o, i);
+		Free(opt->Data);
+		Free(opt);
+	}
+
+	ReleaseList(o);
+}
+
+// DHCP オプションのパース
+LIST *ParseDhcpOptions(void *data, UINT size)
+{
+	BUF *b;
+	LIST *o;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, data, size);
+	SeekBuf(b, 0, 0);
+
+	o = NewListFast(NULL);
+
+	while (true)
+	{
+		UCHAR c = 0;
+		UCHAR sz = 0;
+		DHCP_OPTION *opt;
+		if (ReadBuf(b, &c, 1) != 1)
+		{
+			break;
+		}
+		if (c == 0xff)
+		{
+			break;
+		}
+		if (ReadBuf(b, &sz, 1) != 1)
+		{
+			break;
+		}
+
+		opt = ZeroMalloc(sizeof(DHCP_OPTION));
+		opt->Id = (UINT)c;
+		opt->Size = (UINT)sz;
+		opt->Data = ZeroMalloc((UINT)sz);
+		ReadBuf(b, opt->Data, sz);
+		Add(o, opt);
+	}
+
+	FreeBuf(b);
+
+	return o;
+}
+
+// 仮想ホスト - Layer2 の処理
+void VirtualLayer2(VH *v, PKT *packet)
+{
+	bool ok;
+	// 引数チェック
+	if (packet == NULL || v == NULL)
+	{
+		return;
+	}
+
+	// パケットフィルタ
+	if (VirtualLayer2Filter(v, packet) == false)
+	{
+		// パケットは無視された
+		return;
+	}
+
+	ok = false;
+	if (packet->TypeL3 == L3_IPV4 && packet->TypeL4 == L4_UDP && packet->TypeL7 == L7_DHCPV4)
+	{
+		if (v->UseDhcp)
+		{
+			// DHCP パケットに関する特殊な処理
+			if (packet->BroadcastPacket || Cmp(packet->MacAddressDest, v->MacAddress, 6) == 0)
+			{
+				// 仮想 DHCP サーバー処理
+				VirtualDhcpServer(v, packet);
+				ok = true;
+			}
+		}
+	}
+
+	if (ok == false)
+	{
+		// サポートしているプロトコルごとに処理
+		switch (packet->TypeL3)
+		{
+		case L3_ARPV4:	// ARPv4
+			VirtualArpReceived(v, packet);
+			break;
+
+		case L3_IPV4:	// IPv4
+			VirtualIpReceived(v, packet);
+			break;
+		}
+	}
+}
+
+// パケットフィルタ (自分以外へのパケットを遮断)
+bool VirtualLayer2Filter(VH *v, PKT *packet)
+{
+	// 引数チェック
+	if (v == NULL || packet == NULL)
+	{
+		return false;
+	}
+
+	// ブロードキャストパケットなら通過
+	if (packet->BroadcastPacket)
+	{
+		return true;
+	}
+
+	// 送信元が自分のパケットなら無視
+	if (Cmp(packet->MacAddressSrc, v->MacAddress, 6) == 0)
+	{
+		return false;
+	}
+	// 自分宛のパケットなら通過
+	if (Cmp(packet->MacAddressDest, v->MacAddress, 6) == 0)
+	{
+		return true;
+	}
+
+	// それ以外のパケットなら破棄
+	return false;
+}
+
+// 仮想ホストにパケットを受信させる
+bool VirtualPutPacket(VH *v, void *data, UINT size)
+{
+	if (data == NULL)
+	{
+		// フラッシュ
+		v->flag1 = false;
+	}
+	else
+	{
+		// 受信したパケットを解釈する
+		PKT *packet = ParsePacket(data, size);
+
+		if (v->flag1 == false)
+		{
+			v->flag1 = true;
+			v->Now = Tick64();
+		}
+
+		// ここの中は仮想マシン全体をロックする
+		LockVirtual(v);
+		{
+			if (packet != NULL)
+			{
+				// Layer-2 の処理を行う
+				VirtualLayer2(v, packet);
+
+				// パケット構造体の解放
+				FreePacket(packet);
+			}
+		}
+		UnlockVirtual(v);
+
+		Free(data);
+	}
+
+	return true;
+}
+bool VirtualPaPutPacket(SESSION *s, void *data, UINT size)
+{
+	VH *v;
+	// 引数チェック
+	if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+	{
+		return false;
+	}
+
+	return VirtualPutPacket(v, data, size);
+}
+
+// 仮想ホストのオプションを取得する
+void GetVirtualHostOption(VH *v, VH_OPTION *o)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	LockVirtual(v);
+	{
+		Zero(o, sizeof(VH_OPTION));
+
+		// MAC アドレス
+		Copy(o->MacAddress, v->MacAddress, 6);
+
+		// ホスト情報
+		UINTToIP(&o->Ip, v->HostIP);
+		UINTToIP(&o->Mask, v->HostMask);
+
+		o->Mtu = v->Mtu;
+
+		// NAT タイムアウト情報
+		o->NatTcpTimeout = v->NatTcpTimeout / 1000;
+		o->NatUdpTimeout = v->NatUdpTimeout / 1000;
+
+		// NAT 使用フラグ
+		o->UseNat = v->UseNat;
+
+		// DHCP 使用フラグ
+		o->UseDhcp = v->UseDhcp;
+
+		// DHCP 配布 IP アドレス範囲
+		UINTToIP(&o->DhcpLeaseIPStart, v->DhcpIpStart);
+		UINTToIP(&o->DhcpLeaseIPEnd, v->DhcpIpEnd);
+
+		// サブネットマスク
+		UINTToIP(&o->DhcpSubnetMask, v->DhcpMask);
+
+		// 有効期限
+		if (v->DhcpExpire != INFINITE)
+		{
+			o->DhcpExpireTimeSpan = v->DhcpExpire / 1000;
+		}
+		else
+		{
+			o->DhcpExpireTimeSpan = INFINITE;
+		}
+
+		// ゲートウェイアドレス
+		UINTToIP(&o->DhcpGatewayAddress, v->DhcpGateway);
+
+		// DNS サーバーアドレス
+		UINTToIP(&o->DhcpDnsServerAddress, v->DhcpDns);
+
+		// ドメイン名
+		StrCpy(o->DhcpDomainName, sizeof(o->DhcpDomainName), v->DhcpDomain);
+
+		// ログの保存
+		o->SaveLog = v->SaveLog;
+	}
+	UnlockVirtual(v);
+}
+
+// 仮想ホストにオプションを設定する
+void SetVirtualHostOption(VH *v, VH_OPTION *vo)
+{
+	UINT i;
+	// 引数チェック
+	if (v == NULL || vo == NULL)
+	{
+		return;
+	}
+
+	LockVirtual(v);
+	{
+		// MAC アドレスを設定する
+		for (i = 0;i < 6;i++)
+		{
+			if (vo->MacAddress[i] != 0)
+			{
+				Copy(v->MacAddress, vo->MacAddress, 6);
+				break;
+			}
+		}
+
+		// ホスト情報リストを設定する
+		v->HostIP = IPToUINT(&vo->Ip);
+		v->HostMask = IPToUINT(&vo->Mask);
+
+		// MTU, MMS を設定する
+		v->Mtu = MIN(vo->Mtu, MAX_L3_DATA_SIZE);
+		if (v->Mtu == 0)
+		{
+			v->Mtu = MAX_L3_DATA_SIZE;
+		}
+		v->Mtu = MAX(v->Mtu, TCP_HEADER_SIZE + IP_HEADER_SIZE + MAC_HEADER_SIZE + 8);
+		v->IpMss = ((v->Mtu - IP_HEADER_SIZE) / 8) * 8;
+		v->TcpMss = ((v->IpMss - TCP_HEADER_SIZE) / 8) * 8;
+		v->UdpMss = ((v->IpMss - UDP_HEADER_SIZE) / 8) * 8;
+
+		if (vo->NatTcpTimeout != 0)
+		{
+			v->NatTcpTimeout = MIN(vo->NatTcpTimeout, 4000000) * 1000;
+		}
+		if (vo->NatUdpTimeout != 0)
+		{
+			v->NatUdpTimeout = MIN(vo->NatUdpTimeout, 4000000) * 1000;
+		}
+		v->NatTcpTimeout = MAKESURE(v->NatTcpTimeout, NAT_TCP_MIN_TIMEOUT, NAT_TCP_MAX_TIMEOUT);
+		v->NatUdpTimeout = MAKESURE(v->NatUdpTimeout, NAT_UDP_MIN_TIMEOUT, NAT_UDP_MAX_TIMEOUT);
+		Debug("Timeout: %d , %d\n", v->NatTcpTimeout, v->NatUdpTimeout);
+
+		// NAT 使用フラグ
+		v->UseNat = vo->UseNat;
+
+		// DHCP 使用フラグ
+		v->UseDhcp = vo->UseDhcp;
+
+		// 有効期限
+		if (vo->DhcpExpireTimeSpan == 0 || vo->DhcpExpireTimeSpan == INFINITE)
+		{
+			v->DhcpExpire = INFINITE;
+		}
+		else
+		{
+			v->DhcpExpire = MAKESURE(DHCP_MIN_EXPIRE_TIMESPAN,
+				MIN(vo->DhcpExpireTimeSpan * 1000, 2000000000),
+				INFINITE);
+		}
+
+		// 配布するアドレス範囲
+		v->DhcpIpStart = IPToUINT(&vo->DhcpLeaseIPStart);
+		v->DhcpIpEnd = IPToUINT(&vo->DhcpLeaseIPEnd);
+		if (Endian32(v->DhcpIpEnd) < Endian32(v->DhcpIpStart))
+		{
+			v->DhcpIpEnd = v->DhcpIpStart;
+		}
+
+		// サブネットマスク
+		v->DhcpMask = IPToUINT(&vo->DhcpSubnetMask);
+
+		// ゲートウェイアドレス
+		v->DhcpGateway = IPToUINT(&vo->DhcpGatewayAddress);
+
+		// DNS サーバーアドレス
+		v->DhcpDns = IPToUINT(&vo->DhcpDnsServerAddress);
+
+		// ドメイン名
+		StrCpy(v->DhcpDomain, sizeof(v->DhcpDomain), vo->DhcpDomainName);
+
+		// ログの保存
+		v->SaveLog = vo->SaveLog;
+	}
+	UnlockVirtual(v);
+}
+
+// 仮想ホストの解放
+void Virtual_Free(VH *v)
+{
+	// DHCP サーバー解放
+	FreeDhcpServer(v);
+
+	// NAT 解放
+	FreeNat(v);
+
+	LockVirtual(v);
+	{
+		// IP 結合リスト解放
+		FreeIpCombineList(v);
+
+		// IP 待ちテーブル解放
+		FreeIpWaitTable(v);
+
+		// ARP 待ちテーブル解放
+		FreeArpWaitTable(v);
+
+		// ARP テーブル解放
+		FreeArpTable(v);
+
+		// 送信キュー解放
+		LockQueue(v->SendQueue);
+		{
+			BLOCK *block;
+
+			// すべてのキューを解放する
+			while (block = GetNext(v->SendQueue))
+			{
+				FreeBlock(block);
+			}
+		}
+		UnlockQueue(v->SendQueue);
+		ReleaseQueue(v->SendQueue);
+		v->SendQueue = NULL;
+
+		// キャンセルオブジェクト解放
+		ReleaseCancel(v->Cancel);
+
+		v->Active = false;
+	}
+	UnlockVirtual(v);
+
+	// ロガー解放
+	FreeLog(v->Logger);
+}
+void VirtualPaFree(SESSION *s)
+{
+	VH *v;
+	// 引数チェック
+	if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+	{
+		return;
+	}
+
+	Virtual_Free(v);
+}
+
+// 仮想ホストの解放
+void ReleaseVirtual(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	if (Release(v->ref) == 0)
+	{
+		CleanupVirtual(v);
+	}
+}
+
+// 仮想ホストのロック
+void LockVirtual(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	Lock(v->lock);
+}
+
+// 仮想ホストのロック解除
+void UnlockVirtual(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	Unlock(v->lock);
+}
+
+// 仮想ホストのクリーンアップ
+void CleanupVirtual(VH *v)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	if (v->Session != NULL)
+	{
+		ReleaseSession(v->Session);
+	}
+
+	DeleteCounter(v->Counter);
+	DeleteLock(v->lock);
+
+	Free(v);
+}
+
+// 仮想ホストの停止
+void StopVirtualHost(VH *v)
+{
+	SESSION *s;
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	// 仮想ホストに対応したセッションの取得
+	LockVirtual(v);
+	{
+		s = v->Session;
+		if (s != NULL)
+		{
+			AddRef(s->ref);
+		}
+	}
+	UnlockVirtual(v);
+
+	if (s == NULL)
+	{
+		// すでにこのセッションは停止している
+		return;
+	}
+
+	// セッションの停止
+	StopSession(s);
+
+	ReleaseSession(s);
+}
+
+// 新しい仮想ホストの作成
+VH *NewVirtualHost(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option)
+{
+	return NewVirtualHostEx(cedar, option, auth, vh_option, NULL);
+}
+VH *NewVirtualHostEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option, NAT *nat)
+{
+	VH *v;
+	// 引数チェック
+	if (vh_option == NULL)
+	{
+		return NULL;
+	}
+
+	// VH の作成
+	v = ZeroMalloc(sizeof(VH));
+	v->ref = NewRef();
+	v->lock = NewLock();
+	v->Counter = NewCounter();
+
+	v->nat = nat;
+
+	// オプションの設定
+	SetVirtualHostOption(v, vh_option);
+
+	return v;
+}
+
+// ランダムな MAC アドレスを生成する
+void GenMacAddress(UCHAR *mac)
+{
+	UCHAR rand_data[32];
+	UINT64 now;
+	BUF *b;
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (mac == NULL)
+	{
+		return;
+	}
+
+	// 現在時刻を取得
+	now = SystemTime64();
+
+	// 乱数を生成
+	Rand(rand_data, sizeof(rand_data));
+
+	// バッファに追加
+	b = NewBuf();
+	WriteBuf(b, &now, sizeof(now));
+	WriteBuf(b, rand_data, sizeof(rand_data));
+
+	// ハッシュ
+	Hash(hash, b->Buf, b->Size, true);
+
+	// MAC アドレスを生成
+	mac[0] = 0x00;
+	mac[1] = 0xAC;		// AC 万歳
+	mac[2] = hash[0];
+	mac[3] = hash[1];
+	mac[4] = hash[2];
+	mac[5] = hash[3];
+
+	FreeBuf(b);
+}
+
+// 仮想ホストのパケットアダプタを取得
+PACKET_ADAPTER *VirtualGetPacketAdapter()
+{
+	return NewPacketAdapter(VirtualPaInit, VirtualPaGetCancel,
+		VirtualPaGetNextPacket, VirtualPaPutPacket, VirtualPaFree);
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Virtual.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Virtual.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Virtual.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,504 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Virtual.h
+// Virtual.c のヘッダ
+
+#ifndef	VIRTUAL_H
+#define	VIRTUAL_H
+
+
+// ARP エントリ
+struct ARP_ENTRY
+{
+	UINT IpAddress;					// IP アドレス
+	UCHAR MacAddress[6];			// MAC アドレス
+	UCHAR Padding[2];
+	UINT64 Created;					// 作成日時
+	UINT64 Expire;					// 有効期限
+};
+
+// ARP 待機リスト
+struct ARP_WAIT
+{
+	UINT IpAddress;					// 解決しようとしている IP アドレス
+	UINT NextTimeoutTimeValue;		// 次にタイムアウトするまでの時間
+	UINT64 TimeoutTime;				// 現在の送信のタイムアウト時刻
+	UINT64 GiveupTime;				// 送信を諦める時刻
+};
+
+// IP 待機リスト
+struct IP_WAIT
+{
+	UINT DestIP;					// 宛先 IP アドレス
+	UINT SrcIP;						// 送信元 IP アドレス
+	UINT64 Expire;					// 保管期限
+	void *Data;						// データ
+	UINT Size;						// サイズ
+};
+
+// IP 部分リスト
+struct IP_PART
+{
+	UINT Offset;					// オフセット
+	UINT Size;						// サイズ
+};
+
+// IP 復元リスト
+struct IP_COMBINE
+{
+	UINT DestIP;					// 宛先 IP アドレス
+	UINT SrcIP;						// 送信元 IP アドレス
+	USHORT Id;						// IP パケット ID
+	UINT64 Expire;					// 保管期限
+	void *Data;						// パケットデータ
+	UINT DataReserved;				// データ用に確保された領域
+	UINT Size;						// パケットサイズ (トータル)
+	LIST *IpParts;					// IP 部分リスト
+	UCHAR Protocol;					// プロトコル番号
+	bool MacBroadcast;				// MAC レベルでのブロードキャストパケット
+};
+
+#define	IP_COMBINE_INITIAL_BUF_SIZE		(MAX_IP_DATA_SIZE)		// 初期バッファサイズ
+
+// NAT セッションテーブル
+struct NAT_ENTRY
+{
+	// TCP | UDP 共通項目
+	struct VH *v;					// 仮想マシン
+	UINT Id;						// ID
+	LOCK *lock;						// ロック
+	UINT Protocol;					// プロトコル
+	UINT SrcIp;						// 接続元 IP アドレス
+	UINT SrcPort;					// 接続元ポート番号
+	UINT DestIp;					// 接続先 IP アドレス
+	UINT DestPort;					// 接続先ポート番号
+	UINT PublicIp;					// 公衆 IP アドレス
+	UINT PublicPort;				// 公衆ポート番号
+	UINT64 CreatedTime;				// 接続時刻
+	UINT64 LastCommTime;			// 最終通信時刻
+	SOCK *Sock;						// ソケット
+	bool DisconnectNow;				// すぐに停止せよフラグ
+	UINT tag1;
+	bool ProxyDns;					// プロキシ DNS
+	UINT DestIpProxy;				// プロキシ DNS アドレス
+
+	// DNS NAT 項目
+	THREAD *DnsThread;				// DNS 問い合わせ用スレッド
+	bool DnsGetIpFromHost;			// 逆引きフラグ
+	char *DnsTargetHostName;		// ターゲットホスト名
+	IP DnsResponseIp;				// 応答 IP アドレス
+	char *DnsResponseHostName;		// 応答ホスト名
+	UINT DnsTransactionId;			// DNS トランザクション ID
+	bool DnsFinished;				// DNS 問い合わせ完了フラグ
+	bool DnsOk;						// DNS 成功フラグ
+	bool DnsPollingFlag;			// DNS ポーリング完了フラグ
+
+	// UDP 項目
+	QUEUE *UdpSendQueue;			// UDP 送信キュー
+	QUEUE *UdpRecvQueue;			// UDP 受信キュー
+	bool UdpSocketCreated;			// UDP のソケットが作成されたかどうか
+
+	// TCP 項目
+	FIFO *SendFifo;					// 送信 FIFO
+	FIFO *RecvFifo;					// 受信 FIFO
+	UINT TcpStatus;					// TCP 状態
+	THREAD *NatTcpConnectThread;	// TCP ソケット接続スレッド
+	bool TcpMakeConnectionFailed;	// 接続スレッドによる接続に失敗した
+	bool TcpMakeConnectionSucceed;	// 接続スレッドによる接続に成功した
+	UINT TcpSendMaxSegmentSize;		// 最大送信セグメントサイズ
+	UINT TcpRecvMaxSegmentSize;		// 最大受信セグメントサイズ
+	UINT64 LastSynAckSentTime;		// 最後に SYN + ACK を送信した時刻
+	UINT SynAckSentCount;			// SYN + ACK 送信回数
+	UINT TcpSendWindowSize;			// 送信ウインドウサイズ
+	UINT TcpSendCWnd;				// 送信用輻輳ウインドウサイズ (/mss)
+	UINT TcpRecvWindowSize;			// 受信ウインドウサイズ
+	UINT TcpSendTimeoutSpan;		// 送信タイムアウト時間
+	UINT64 TcpLastSentTime;			// TCP で最後に送信を行った時刻
+	UINT64 LastSentKeepAliveTime;	// 最後にキープアライブ ACK を送信した時刻
+	FIFO *TcpRecvWindow;			// TCP 受信ウインドウ
+	LIST *TcpRecvList;				// TCP 受信リスト
+	bool SendAckNext;				// 次の送信時に ACK を送信する
+	UINT LastSentWindowSize;		// 最後に送信した自分のウインドウサイズ
+
+	UINT64 SendSeqInit;				// 初期送信シーケンス番号
+	UINT64 SendSeq;					// 送信シーケンス番号
+	UINT64 RecvSeqInit;				// 初期受信シーケンス番号
+	UINT64 RecvSeq;					// 受信シーケンス番号
+
+	bool CurrentSendingMission;		// バースト送信実施中
+	UINT SendMissionSize;			// 今回の送信サイズ
+	bool RetransmissionUsedFlag;	// 再送信使用記録フラグ
+
+	UINT CurrentRTT;				// 現在の RTT 値
+	UINT64 CalcRTTStartTime;		// RTT 測定開始時刻
+	UINT64 CalcRTTStartValue;		// RTT 測定開始値
+
+	bool TcpFinished;				// TCP のデータ通信終了フラグ
+	UINT64 FinSentTime;				// 最後に FIN を送信した時刻
+	UINT FinSentCount;				// FIN 送信回数
+};
+
+
+// TCP オプション
+struct TCP_OPTION
+{
+	UINT MaxSegmentSize;			// 最大セグメントサイズ
+	UINT WindowScaling;				// ウインドウスケーリング
+};
+
+// 仮想ホスト構造体
+struct VH
+{
+	REF *ref;						// 参照カウンタ
+	LOCK *lock;						// ロック
+	SESSION *Session;				// セッション
+	CANCEL *Cancel;					// キャンセルオブジェクト
+	QUEUE *SendQueue;				// 送信キュー
+	bool Active;					// アクティブフラグ
+	volatile bool HaltNat;			// NAT 停止フラグ
+	LIST *ArpTable;					// ARP テーブル
+	LIST *ArpWaitTable;				// ARP 待ちテーブル
+	LIST *IpWaitTable;				// IP 待ちテーブル
+	LIST *IpCombine;				// IP 結合テーブル
+	UINT64 Now;						// 現在時刻
+	UINT64 NextArpTablePolling;		// 次に ARP テーブルをポーリングする時刻
+	UINT Mtu;						// MTU 値
+	UINT IpMss;						// IP 最大データサイズ
+	UINT TcpMss;					// TCP 最大データサイズ
+	UINT UdpMss;					// UDP 最大データサイズ
+	bool flag1;						// フラグ 1
+	bool flag2;						// フラグ 2
+	USHORT NextId;					// IP パケットの ID
+	UINT CurrentIpQuota;			// IP パケットメモリクォータ
+	LIST *NatTable;					// NAT テーブル
+	SOCK_EVENT *SockEvent;			// ソケットイベント
+	THREAD *NatThread;				// NAT 用スレッド
+	void *TmpBuf;					// 一時的に使用できるバッファ
+	bool NatDoCancelFlag;			// キャンセルを叩くかどうかのフラグ
+	UCHAR MacAddress[6];			// MAC アドレス
+	UCHAR Padding[2];
+	UINT HostIP;					// ホスト IP
+	UINT HostMask;					// ホストサブネットマスク
+	UINT NatTcpTimeout;				// NAT TCP タイムアウト秒数
+	UINT NatUdpTimeout;				// NAT UDP タイムアウト秒数
+	bool UseNat;					// NAT 使用フラグ
+	bool UseDhcp;					// DHCP 使用フラグ
+	UINT DhcpIpStart;				// 配布開始アドレス
+	UINT DhcpIpEnd;					// 配布終了アドレス
+	UINT DhcpMask;					// サブネットマスク
+	UINT DhcpExpire;				// アドレス配布有効期限
+	UINT DhcpGateway;				// ゲートウェイアドレス
+	UINT DhcpDns;					// DNS サーバーアドレス
+	char DhcpDomain[MAX_HOST_NAME_LEN + 1];	// 割り当てドメイン名
+	LIST *DhcpLeaseList;			// DHCP リースリスト
+	UINT64 LastDhcpPolling;			// 最後に DHCP リストをポーリングした時刻
+	bool SaveLog;					// ログの保存
+	COUNTER *Counter;				// セッションカウンタ
+	UINT DhcpId;					// DHCP ID
+	UINT64 LastSendBeacon;			// 最後にビーコンを発信した時刻
+	LOG *Logger;					// ロガー
+	NAT *nat;						// NAT オブジェクトへの参照
+};
+
+// 仮想ホストオプション
+struct VH_OPTION
+{
+	char HubName[MAX_HUBNAME_LEN + 1];	// 操作対象の仮想 HUB 名
+	UCHAR MacAddress[6];			// MAC アドレス
+	UCHAR Padding[2];
+	IP Ip;							// IP アドレス
+	IP Mask;						// サブネットマスク
+	bool UseNat;					// NAT 機能の使用フラグ
+	UINT Mtu;						// MTU 値
+	UINT NatTcpTimeout;				// NAT TCP タイムアウト秒数
+	UINT NatUdpTimeout;				// NAT UDP タイムアウト秒数
+	bool UseDhcp;					// DHCP 機能の使用フラグ
+	IP DhcpLeaseIPStart;			// DHCP 配布 IP 開始アドレス
+	IP DhcpLeaseIPEnd;				// DHCP 配布 IP 終了アドレス
+	IP DhcpSubnetMask;				// DHCP サブネットマスク
+	UINT DhcpExpireTimeSpan;		// DHCP 有効期限
+	IP DhcpGatewayAddress;			// 割り当てゲートウェイアドレス
+	IP DhcpDnsServerAddress;		// 割り当て DNS サーバーアドレス
+	char DhcpDomainName[MAX_HOST_NAME_LEN + 1];	// 割り当てドメイン名
+	bool SaveLog;					// ログの保存
+};
+
+// DHCP オプション
+struct DHCP_OPTION
+{
+	UINT Id;						// ID
+	UINT Size;						// サイズ
+	void *Data;						// データ
+};
+
+// DHCP オプションリスト
+struct DHCP_OPTION_LIST
+{
+	// 共通項目
+	UINT Opcode;					// DHCP オペコード
+
+	// クライアント要求
+	UINT RequestedIp;				// 要求された IP アドレス
+	char Hostname[MAX_HOST_NAME_LEN + 1]; // ホスト名
+
+	// サーバー応答
+	UINT ServerAddress;				// DHCP サーバーアドレス
+	UINT LeaseTime;					// リース時間
+	char DomainName[MAX_HOST_NAME_LEN + 1];	// ドメイン名
+	UINT SubnetMask;				// サブネットマスク
+	UINT Gateway;					// ゲートウェイアドレス
+	UINT DnsServer;					// DNS サーバーアドレス
+};
+
+
+// DHCP リース エントリ
+struct DHCP_LEASE
+{
+	UINT Id;						// ID
+	UINT64 LeasedTime;				// リースした時刻
+	UINT64 ExpireTime;				// 有効期限
+	UCHAR MacAddress[6];			// MAC アドレス
+	UCHAR Padding[2];				// Padding
+	UINT IpAddress;					// IP アドレス
+	UINT Mask;						// サブネットマスク
+	char *Hostname;					// ホスト名
+};
+
+// DNS 問い合わせ
+typedef struct NAT_DNS_QUERY
+{
+	REF *ref;						// 参照カウンタ
+	char Hostname[256];				// ホスト名
+	bool Ok;						// 結果の成功フラグ
+	IP Ip;							// 結果 IP アドレス
+} NAT_DNS_QUERY;
+
+
+// 仮想ホストの仮想 LAN カード
+PACKET_ADAPTER *VirtualGetPacketAdapter();
+bool VirtualPaInit(SESSION *s);
+CANCEL *VirtualPaGetCancel(SESSION *s);
+UINT VirtualPaGetNextPacket(SESSION *s, void **data);
+bool VirtualPaPutPacket(SESSION *s, void *data, UINT size);
+void VirtualPaFree(SESSION *s);
+
+bool VirtualInit(VH *v);
+UINT VirtualGetNextPacket(VH *v, void **data);
+bool VirtualPutPacket(VH *v, void *data, UINT size);
+void Virtual_Free(VH *v);
+
+VH *NewVirtualHost(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option);
+VH *NewVirtualHostEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option, NAT *nat);
+void LockVirtual(VH *v);
+void UnlockVirtual(VH *v);
+void ReleaseVirtual(VH *v);
+void CleanupVirtual(VH *v);
+void StopVirtualHost(VH *v);
+void SetVirtualHostOption(VH *v, VH_OPTION *vo);
+void GenMacAddress(UCHAR *mac);
+void GetVirtualHostOption(VH *v, VH_OPTION *o);
+
+void VirtualLayer2(VH *v, PKT *packet);
+bool VirtualLayer2Filter(VH *v, PKT *packet);
+void VirtualArpReceived(VH *v, PKT *packet);
+void VirtualArpResponseRequest(VH *v, PKT *packet);
+void VirtualArpResponseReceived(VH *v, PKT *packet);
+void VirtualArpSendResponse(VH *v, UCHAR *dest_mac, UINT dest_ip, UINT src_ip);
+void VirtualArpSendRequest(VH *v, UINT dest_ip);
+void VirtualIpSend(VH *v, UCHAR *dest_mac, void *data, UINT size);
+void VirtualLayer2Send(VH *v, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size);
+void VirtualPolling(VH *v);
+void InitArpTable(VH *v);
+void FreeArpTable(VH *v);
+int CompareArpTable(void *p1, void *p2);
+ARP_ENTRY *SearchArpTable(VH *v, UINT ip);
+void RefreshArpTable(VH *v);
+void PollingArpTable(VH *v);
+void InsertArpTable(VH *v, UCHAR *mac, UINT ip);
+bool IsMacBroadcast(UCHAR *mac);
+bool IsMacInvalid(UCHAR *mac);
+void InitArpWaitTable(VH *v);
+void FreeArpWaitTable(VH *v);
+int CompareArpWaitTable(void *p1, void *p2);
+ARP_WAIT *SearchArpWaitTable(VH *v, UINT ip);
+void DeleteArpWaitTable(VH *v, UINT ip);
+void SendArp(VH *v, UINT ip);
+void InsertArpWaitTable(VH *v, ARP_WAIT *w);
+void PollingArpWaitTable(VH *v);
+void ArpIpWasKnown(VH *v, UINT ip, UCHAR *mac);
+void InitIpWaitTable(VH *v);
+void FreeIpWaitTable(VH *v);
+void InsertIpWaitTable(VH *v, UINT dest_ip, UINT src_ip, void *data, UINT size);
+void SendFragmentedIp(VH *v, UINT dest_ip, UINT src_ip, USHORT id, USHORT total_size, USHORT offset, UCHAR protocol, void *data, UINT size, UCHAR *dest_mac);
+void SendIp(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size);
+void PollingIpWaitTable(VH *v);
+void DeleteOldIpWaitTable(VH *v);
+void SendWaitingIp(VH *v, UCHAR *mac, UINT dest_ip);
+void VirtualIpReceived(VH *v, PKT *packet);
+void InitIpCombineList(VH *v);
+void FreeIpCombineList(VH *v);
+int CompareIpCombine(void *p1, void *p2);
+void CombineIp(VH *v, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet);
+void IpReceived(VH *v, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size, bool mac_broadcast);
+void FreeIpCombine(VH *v, IP_COMBINE *c);
+void PollingIpCombine(VH *v);
+IP_COMBINE *InsertIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast);
+IP_COMBINE *SearchIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol);
+USHORT IpChecksum(void *buf, UINT size);
+bool IpCheckChecksum(IPV4_HEADER *ip);
+void VirtualIcmpReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size);
+void VirtualIcmpEchoRequestReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size);
+void VirtualIcmpEchoSendResponse(VH *v, UINT src_ip, UINT dst_ip, USHORT id, USHORT seq_no, void *data, UINT size);
+void VirtualIcmpSend(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size);
+void VirtualUdpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, bool mac_broadcast);
+void SendUdp(VH *v, UINT dest_ip, UINT dest_port, UINT src_ip, UINT src_port, void *data, UINT size);
+UINT GetNetworkAddress(UINT addr, UINT mask);
+UINT GetBroadcastAddress(UINT addr, UINT mask);
+bool IsInNetwork(UINT uni_addr, UINT network_addr, UINT mask);
+void UdpRecvForMe(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+void UdpRecvForBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+void UdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy);
+void InitNat(VH *v);
+void FreeNat(VH *v);
+int CompareNat(void *p1, void *p2);
+NAT_ENTRY *SearchNat(VH *v, NAT_ENTRY *target);
+void SetNat(NAT_ENTRY *n, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT public_ip, UINT public_port);
+void DeleteNatTcp(VH *v, NAT_ENTRY *n);
+void DeleteNatUdp(VH *v, NAT_ENTRY *n);
+NAT_ENTRY *CreateNatUdp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT dns_proxy_ip);
+void NatThread(THREAD *t, void *param);
+void NatThreadMain(VH *v);
+bool NatTransactUdp(VH *v, NAT_ENTRY *n);
+void PoolingNat(VH *v);
+void PoolingNatUdp(VH *v, NAT_ENTRY *n);
+void VirtualTcpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size);
+void TcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *tcp, void *data, UINT size);
+NAT_ENTRY *CreateNatTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port);
+bool NatTransactTcp(VH *v, NAT_ENTRY *n);
+void CreateNatTcpConnectThread(VH *v, NAT_ENTRY *n);
+void NatTcpConnectThread(THREAD *t, void *p);
+void PollingNatTcp(VH *v, NAT_ENTRY *n);
+void ParseTcpOption(TCP_OPTION *o, void *data, UINT size);
+void SendTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss, void *data, UINT size);
+void DnsProxy(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+bool ParseDnsPacket(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+bool ParseDnsQuery(char *name, UINT name_size, void *data, UINT data_size);
+UCHAR GetNextByte(BUF *b);
+bool NatTransactDns(VH *v, NAT_ENTRY *n);
+void NatDnsThread(THREAD *t, void *param);
+bool NatGetIP(IP *ip, char *hostname);
+void NatGetIPThread(THREAD *t, void *param);
+NAT_ENTRY *CreateNatDns(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port,
+				  UINT transaction_id, bool dns_get_ip_from_host, char *dns_target_host_name);
+void PollingNatDns(VH *v, NAT_ENTRY *n);
+void SendNatDnsResponse(VH *v, NAT_ENTRY *n);
+void BuildDnsQueryPacket(BUF *b, char *hostname, bool ptr);
+void BuildDnsResponsePacketA(BUF *b, IP *ip);
+void BuildDnsResponsePacketPtr(BUF *b, char *hostname);
+bool ArpaToIP(IP *ip, char *str);
+BUF *BuildDnsHostName(char *hostname);
+bool CanCreateNewNatEntry(VH *v);
+void VirtualDhcpServer(VH *v, PKT *p);
+LIST *ParseDhcpOptions(void *data, UINT size);
+void FreeDhcpOptions(LIST *o);
+DHCP_OPTION *GetDhcpOption(LIST *o, UINT id);
+DHCP_OPTION_LIST *ParseDhcpOptionList(void *data, UINT size);
+void InitDhcpServer(VH *v);
+void FreeDhcpServer(VH *v);
+void PollingDhcpServer(VH *v);
+int CompareDhcpLeaseList(void *p1, void *p2);
+DHCP_LEASE *NewDhcpLease(UINT expire, UCHAR *mac_address, UINT ip, UINT mask, char *hostname);
+void FreeDhcpLease(DHCP_LEASE *d);
+DHCP_LEASE *SearchDhcpLeaseByMac(VH *v, UCHAR *mac);
+DHCP_LEASE *SearchDhcpLeaseByIp(VH *v, UINT ip);
+UINT ServeDhcpDiscover(VH *v, UCHAR *mac, UINT request_ip);
+UINT GetFreeDhcpIpAddress(VH *v);
+UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip);
+LIST *BuildDhcpOption(DHCP_OPTION_LIST *opt);
+DHCP_OPTION *NewDhcpOption(UINT id, void *data, UINT size);
+BUF *BuildDhcpOptionsBuf(LIST *o);
+void VirtualDhcpSend(VH *v, UINT tran_id, UINT dest_ip, UINT dest_port,
+					 UINT new_ip, UCHAR *client_mac, BUF *b);
+void VLog(VH *v, char *str);
+void SendBeacon(VH *v);
+void PollingBeacon(VH *v);
+
+
+#endif	// VIRTUAL_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Win32Html.cpp
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Win32Html.cpp	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Win32Html.cpp	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,731 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Win32Html.c
+// Win32 用 HTML 表示モジュール
+
+// Q. ソースコード名が「HTML」となっているが、どう見ても HTML に関係のない処理
+//    が入っているように見える。
+// A. はい。
+
+#ifdef	WIN32
+
+#define	WIN32HTML_CPP
+
+//#define	_WIN32_WINNT		0x0502
+//#define	WINVER				0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <comdef.h>
+#include <Mshtmhst.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+extern "C"
+{
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+}
+#include "../PenCore/resource.h"
+
+typedef struct FOLDER_DLG_INNER_DATA
+{
+	wchar_t *default_dir;
+} FOLDER_DLG_INNER_DATA;
+
+int CALLBACK FolderDlgInnerCallbackA(HWND hWnd, UINT msg, LPARAM lParam, LPARAM lData)
+{
+	FOLDER_DLG_INNER_DATA *data = (FOLDER_DLG_INNER_DATA *)lData;
+	LPITEMIDLIST pidl;
+
+	switch (msg)
+	{
+	case BFFM_INITIALIZED:
+		if (data->default_dir != NULL)
+		{
+			char *default_dir_a = CopyUniToStr(data->default_dir);
+
+			SendMessage(hWnd, BFFM_SETSELECTIONA, true, (LPARAM)default_dir_a);
+
+			Free(default_dir_a);
+		}
+		break;
+
+	case BFFM_SELCHANGED:
+		pidl = (LPITEMIDLIST)lParam;
+
+		if (pidl)
+		{
+			char tmp[MAX_PATH];
+
+			Zero(tmp, sizeof(tmp));
+			if (SHGetPathFromIDListA(pidl, tmp))
+			{
+				SendMessage(hWnd, BFFM_ENABLEOK, 0, 1);
+			}
+			else
+			{
+				SendMessage(hWnd, BFFM_ENABLEOK, 0, 0);
+			}
+		}
+		break;
+	}
+
+	return 0;
+}
+
+char *FolderDlgInnerA(HWND hWnd, wchar_t *title, char *default_dir)
+{
+	BROWSEINFOA info;
+	char display_name[MAX_PATH];
+	FOLDER_DLG_INNER_DATA data;
+	LPMALLOC pMalloc;
+	char *ret = NULL;
+	char *title_a;
+	if (UniIsEmptyStr(title))
+	{
+		title = NULL;
+	}
+	if (IsEmptyStr(default_dir))
+	{
+		default_dir = NULL;
+	}
+
+	Zero(&data, sizeof(data));
+	data.default_dir = CopyStrToUni(default_dir);
+
+	Zero(display_name, sizeof(display_name));
+	Zero(&info, sizeof(info));
+	info.hwndOwner = hWnd;
+	info.pidlRoot = NULL;
+	info.pszDisplayName = display_name;
+	title_a = CopyUniToStr(title);
+	info.lpszTitle = title_a;
+	info.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_SHAREABLE;
+	info.lpfn = FolderDlgInnerCallbackA;
+	info.lParam = (LPARAM)&data;
+
+	if (SUCCEEDED(SHGetMalloc(&pMalloc)))
+	{
+		LPITEMIDLIST pidl;
+
+		pidl = SHBrowseForFolderA(&info);
+
+		if (pidl)
+		{
+			char tmp[MAX_PATH];
+
+			if (SHGetPathFromIDListA(pidl, tmp))
+			{
+				ret = CopyStr(tmp);
+			}
+
+			pMalloc->Free(pidl);
+		}
+
+		pMalloc->Release();
+	}
+
+	Free(data.default_dir);
+	Free(title_a);
+
+	return ret;
+}
+
+int CALLBACK FolderDlgInnerCallbackW(HWND hWnd, UINT msg, LPARAM lParam, LPARAM lData)
+{
+	FOLDER_DLG_INNER_DATA *data = (FOLDER_DLG_INNER_DATA *)lData;
+	LPITEMIDLIST pidl;
+
+	switch (msg)
+	{
+	case BFFM_INITIALIZED:
+		if (data->default_dir != NULL)
+		{
+			SendMessage(hWnd, BFFM_SETSELECTIONW, true, (LPARAM)data->default_dir);
+		}
+		break;
+
+	case BFFM_SELCHANGED:
+		pidl = (LPITEMIDLIST)lParam;
+
+		if (pidl)
+		{
+			wchar_t tmp[MAX_PATH];
+
+			Zero(tmp, sizeof(tmp));
+			if (SHGetPathFromIDListW(pidl, tmp))
+			{
+				SendMessage(hWnd, BFFM_ENABLEOK, 0, 1);
+			}
+			else
+			{
+				SendMessage(hWnd, BFFM_ENABLEOK, 0, 0);
+			}
+		}
+		break;
+	}
+
+	return 0;
+}
+
+wchar_t *FolderDlgInnerW(HWND hWnd, wchar_t *title, wchar_t *default_dir)
+{
+	BROWSEINFOW info;
+	wchar_t display_name[MAX_PATH];
+	FOLDER_DLG_INNER_DATA data;
+	LPMALLOC pMalloc;
+	wchar_t *ret = NULL;
+	if (UniIsEmptyStr(title))
+	{
+		title = NULL;
+	}
+	if (UniIsEmptyStr(default_dir))
+	{
+		default_dir = NULL;
+	}
+
+	Zero(&data, sizeof(data));
+	data.default_dir = default_dir;
+
+	Zero(display_name, sizeof(display_name));
+	Zero(&info, sizeof(info));
+	info.hwndOwner = hWnd;
+	info.pidlRoot = NULL;
+	info.pszDisplayName = display_name;
+	info.lpszTitle = title;
+	info.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_SHAREABLE;
+	info.lpfn = FolderDlgInnerCallbackW;
+	info.lParam = (LPARAM)&data;
+
+	if (SUCCEEDED(SHGetMalloc(&pMalloc)))
+	{
+		LPITEMIDLIST pidl;
+
+		pidl = SHBrowseForFolderW(&info);
+
+		if (pidl)
+		{
+			wchar_t tmp[MAX_PATH];
+
+			if (SHGetPathFromIDListW(pidl, tmp))
+			{
+				ret = CopyUniStr(tmp);
+			}
+
+			pMalloc->Free(pidl);
+		}
+
+		pMalloc->Release();
+	}
+
+	return ret;
+}
+
+
+class CModule
+{
+public:
+    CModule()
+    {
+        m_hInstLib = NULL;
+    }
+    CModule( HINSTANCE hInstLib )
+    {
+        m_hInstLib = NULL;
+        this->Attach( hInstLib );
+    }
+    CModule( LPCTSTR pszModuleName )
+    {
+        m_hInstLib = NULL;
+        this->LoadLibrary( pszModuleName );
+    }
+    virtual ~CModule()
+    {
+        this->FreeLibrary();
+    }
+
+public:
+    BOOL Attach( HINSTANCE hInstLib )
+    {
+        this->FreeLibrary();
+        m_hInstLib = hInstLib;
+       
+        return TRUE;
+    }
+    BOOL Detach()
+    {
+        m_hInstLib = NULL;
+       
+        return TRUE;
+    }
+
+public:
+    HMODULE GetHandle()
+    {
+        return m_hInstLib;
+    }
+    // ＤＬＬのロード
+    HINSTANCE LoadLibrary( LPCTSTR pszModuleName )
+    {
+        this->FreeLibrary();
+        m_hInstLib = ::LoadLibrary( pszModuleName );
+       
+        return m_hInstLib;
+    }
+    // ＤＬＬの開放
+    BOOL FreeLibrary()
+    {
+        if (m_hInstLib == NULL)
+        {
+            return FALSE;
+        }
+       
+        BOOL bResult = ::FreeLibrary( m_hInstLib );
+        m_hInstLib = NULL;
+       
+        return bResult;
+    }
+    // 関数のアドレスの取得
+    FARPROC GetProcAddress( LPCTSTR pszProcName )
+    {
+        if (m_hInstLib == NULL)
+        {
+            return NULL;
+        }
+       
+        return ::GetProcAddress(m_hInstLib, pszProcName);
+    }
+    // 指定されたタイプおよび名前を持つリソースの情報ブロックのハンドルを取得
+    HRSRC FindResource(LPCTSTR lpName, LPCTSTR lpType)
+    {
+        if (m_hInstLib == NULL)
+        {
+            return NULL;
+        }
+       
+        return ::FindResource(m_hInstLib, lpName, lpType);
+    }
+    // 指定されたリソースのロード
+    HGLOBAL LoadResource(HRSRC hResInfo)
+    {
+        if (m_hInstLib == NULL)
+        {
+            return NULL;
+        }
+       
+        return ::LoadResource(m_hInstLib, hResInfo);
+    }
+
+protected:
+    HINSTANCE m_hInstLib;
+};
+
+
+
+static HRESULT _ShowHTMLDialog(
+    HWND hwndParent,
+    IMoniker* pMk,
+    VARIANT* pvarArgIn = NULL,
+    WCHAR* pchOptions = NULL,
+    VARIANT* pvarArgOut = NULL)
+{
+    HRESULT hr = S_OK;
+   
+    try
+    {
+        CModule Module("MSHTML.DLL");
+        if (Module.GetHandle() == NULL)
+        {
+            return E_FAIL;
+        }
+       
+        SHOWHTMLDIALOGFN* fnShowHTMLDialog =
+            (SHOWHTMLDIALOGFN*)Module.GetProcAddress("ShowHTMLDialog");
+        if (fnShowHTMLDialog == NULL)
+        {
+            return E_FAIL;
+        }
+       
+        hr = (*fnShowHTMLDialog)(hwndParent, pMk, pvarArgIn, pchOptions, pvarArgOut);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+    catch (...)
+    {
+        return E_FAIL;
+    }
+   
+    return hr;
+}
+
+HRESULT ShowHTMLDialogFromURL(HWND hwndParent,wchar_t *szURL,VARIANT* pvarArgIn,WCHAR* pchOptions,VARIANT* pvarArgOut)
+{
+    HRESULT hr = S_OK;
+   
+    try
+    {
+        IMonikerPtr spMoniker;
+        hr = ::CreateURLMoniker(NULL, szURL, &spMoniker);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+       
+        hr = ::_ShowHTMLDialog(hwndParent, spMoniker, pvarArgIn, pchOptions, pvarArgOut);
+        if (FAILED(hr))
+        {
+            return hr;
+        }
+    }
+    catch (...)
+    {
+        return E_FAIL;
+    }
+   
+    return hr;
+}
+
+// ショートカットの作成
+bool CreateLinkInnerA(char *filename, char *target, char *workdir, char *args,
+				     char *comment, char *icon, UINT icon_index)
+{
+	HRESULT r;
+	wchar_t tmp[MAX_SIZE];
+	IShellLinkA* pShellLink;
+	IPersistFile* pPersistFile;
+
+	r = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, (void **)&pShellLink);
+	if (FAILED(r))
+	{
+		return false;
+	}
+
+	r = pShellLink->QueryInterface(IID_IPersistFile,(void **)&pPersistFile);
+	if (FAILED(r))
+	{
+		pShellLink->Release();
+		return false;
+	}
+
+	r = pShellLink->SetPath(target);
+	if (FAILED(r))
+	{
+		pShellLink->Release();
+		pPersistFile->Release();
+		return false;
+	}
+
+	if (workdir != NULL)
+	{
+		r = pShellLink->SetWorkingDirectory(workdir);
+		if (FAILED(r))
+		{
+			pShellLink->Release();
+			pPersistFile->Release();
+			return false;
+		}
+	}
+
+	if (args != NULL)
+	{
+		r = pShellLink->SetArguments(args);
+		if (FAILED(r))
+		{
+			pShellLink->Release();
+			pPersistFile->Release();
+			return false;
+		}
+	}
+
+	if (comment != NULL)
+	{
+		r = pShellLink->SetDescription(comment);
+		if (FAILED(r))
+		{
+			pShellLink->Release();
+			pPersistFile->Release();
+			return false;
+		}
+	}
+
+	if (icon != NULL)
+	{
+		r = pShellLink->SetIconLocation(icon, icon_index);
+		if (FAILED(r))
+		{
+			pShellLink->Release();
+			pPersistFile->Release();
+			return false;
+		}
+	}
+
+	StrToUni(tmp, sizeof(tmp), filename);
+	r = pPersistFile->Save(tmp, true);
+	if (FAILED(r))
+	{
+		pShellLink->Release();
+		pPersistFile->Release();
+		return false;
+	}
+
+	pShellLink->Release();
+	pPersistFile->Release();
+	return true;
+}
+bool CreateLinkInner(wchar_t *filename, wchar_t *target, wchar_t *workdir, wchar_t *args,
+				     wchar_t *comment, wchar_t *icon, UINT icon_index)
+{
+	HRESULT r;
+	bool ret;
+	IShellLinkW* pShellLink;
+	IPersistFile* pPersistFile;
+
+	if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+	{
+		char *a1, *a2, *a3, *a4, *a5, *a6;
+		a1 = CopyUniToStr(filename);
+		a2 = CopyUniToStr(target);
+		a3 = CopyUniToStr(workdir);
+		a4 = CopyUniToStr(args);
+		a5 = CopyUniToStr(icon);
+		a6 = CopyUniToStr(comment);
+
+		ret = CreateLinkInnerA(a1, a2, a3, a4, a6, a5, icon_index);
+
+		Free(a1);
+		Free(a2);
+		Free(a3);
+		Free(a4);
+		Free(a5);
+		Free(a6);
+
+		return ret;
+	}
+
+	r = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void **)&pShellLink);
+	if (FAILED(r))
+	{
+		return false;
+	}
+
+	r = pShellLink->QueryInterface(IID_IPersistFile,(void **)&pPersistFile);
+	if (FAILED(r))
+	{
+		pShellLink->Release();
+		return false;
+	}
+
+	r = pShellLink->SetPath(target);
+	if (FAILED(r))
+	{
+		pShellLink->Release();
+		pPersistFile->Release();
+		return false;
+	}
+
+	if (workdir != NULL)
+	{
+		r = pShellLink->SetWorkingDirectory(workdir);
+		if (FAILED(r))
+		{
+			pShellLink->Release();
+			pPersistFile->Release();
+			return false;
+		}
+	}
+
+	if (comment != NULL)
+	{
+		r = pShellLink->SetDescription(comment);
+		if (FAILED(r))
+		{
+			pShellLink->Release();
+			pPersistFile->Release();
+			return false;
+		}
+	}
+
+	if (args != NULL)
+	{
+		r = pShellLink->SetArguments(args);
+		if (FAILED(r))
+		{
+			pShellLink->Release();
+			pPersistFile->Release();
+			return false;
+		}
+	}
+
+	if (icon != NULL)
+	{
+		r = pShellLink->SetIconLocation(icon, icon_index);
+		if (FAILED(r))
+		{
+			pShellLink->Release();
+			pPersistFile->Release();
+			return false;
+		}
+	}
+
+	r = pPersistFile->Save(filename, true);
+	if (FAILED(r))
+	{
+		pShellLink->Release();
+		pPersistFile->Release();
+		return false;
+	}
+
+	pShellLink->Release();
+	pPersistFile->Release();
+	return true;
+}
+
+extern "C"
+{
+
+// フォルダ選択ダイアログの表示
+wchar_t *FolderDlgW(HWND hWnd, wchar_t *title, wchar_t *default_dir)
+{
+	wchar_t *ret;
+
+	if (MsIsNt() == false)
+	{
+		char *default_dir_a = CopyUniToStr(default_dir);
+		char *ret_a = FolderDlgA(hWnd, title, default_dir_a);
+
+		ret = CopyStrToUni(ret_a);
+		Free(ret_a);
+		Free(default_dir_a);
+
+		return ret;
+	}
+
+	ret = FolderDlgInnerW(hWnd, title, default_dir);
+
+	return ret;
+}
+char *FolderDlgA(HWND hWnd, wchar_t *title, char *default_dir)
+{
+	char *ret;
+
+	ret = FolderDlgInnerA(hWnd, title, default_dir);
+
+	return ret;
+}
+
+// ショートカットの作成
+bool CreateLink(wchar_t *filename, wchar_t *target, wchar_t *workdir, wchar_t *args,
+				wchar_t *comment, wchar_t *icon, UINT icon_index)
+{
+	if (filename == NULL || target == NULL)
+	{
+		return false;
+	}
+
+	return CreateLinkInner(filename, target, workdir, args, comment, icon, icon_index);
+}
+
+// HTML の表示
+void ShowHtml(HWND hWnd, char *url, wchar_t *option)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (url == NULL || option == NULL)
+	{
+		return;
+	}
+
+	StrToUni(tmp, sizeof(tmp), url);
+
+	ShowHTMLDialogFromURL(hWnd, tmp, NULL, option, NULL);
+}
+
+}
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Win32Html.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Win32Html.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Win32Html.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,247 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Win32Html.h
+// Win32Html.c のヘッダ
+
+#ifndef	WIN32HTML_H
+#define	WIN32HTML_H
+
+#ifdef	WIN32HTML_CPP
+
+// 内部向け関数
+
+#endif	// WIN32HTML_CPP
+
+// 外部向け関数
+
+#pragma comment(lib,"htmlhelp.lib")
+#pragma comment(lib,"Urlmon.lib")
+
+#if	defined(__cplusplus)
+extern "C"
+{
+#endif
+
+	void ShowHtml(HWND hWnd, char *url, wchar_t *option);
+	bool CreateLink(wchar_t *filename, wchar_t *target, wchar_t *workdir, wchar_t *args,
+		wchar_t *comment, wchar_t *icon, UINT icon_index);
+	wchar_t *FolderDlgW(HWND hWnd, wchar_t *title, wchar_t *default_dir);
+	char *FolderDlgA(HWND hWnd, wchar_t *title, char *default_dir);
+
+	//////////////////////////////////////////////////////////////////////////
+	//JumpList
+
+
+	typedef void* JL_PCustomDestinationList;
+	typedef void* JL_PObjectArray;
+	typedef void* JL_PShellLink;
+	typedef void* JL_PObjectCollection;
+	typedef long JL_HRESULT;
+
+	JL_HRESULT JL_CreateCustomDestinationList(JL_PCustomDestinationList* poc, wchar_t* appID);
+	JL_HRESULT JL_ReleaseCustomDestinationList(JL_PCustomDestinationList poc);
+
+	JL_HRESULT JL_BeginList(JL_PCustomDestinationList poc, JL_PObjectArray* oaRemoved);
+	JL_HRESULT JL_CommitList(JL_PCustomDestinationList cdl);
+
+
+	JL_HRESULT JL_CreateObjectCollection(JL_PObjectCollection* poc);
+	JL_HRESULT JL_ReleaseObjectCollection(JL_PObjectCollection poc);
+	JL_HRESULT JL_ObjectCollectionAddShellLink(JL_PObjectCollection poc, JL_PShellLink ppsl);
+
+	JL_HRESULT JL_AddCategoryToList(JL_PCustomDestinationList pcdl, 
+		JL_PObjectCollection poc, 
+		wchar_t* categoryName,
+		JL_PObjectArray poaRemoved);
+	JL_HRESULT JL_DeleteJumpList(JL_PCustomDestinationList jpcdl,wchar_t* appID);
+
+
+	JL_HRESULT JL_CreateShellLink(
+		wchar_t* pszPath, 
+		wchar_t* pszArguments, 
+		wchar_t* pszTitle, 
+		wchar_t* iconLocation,
+		int iconIndex,
+		wchar_t* description, JL_PShellLink *ppsl);
+	JL_HRESULT JL_ReleaseShellLink(JL_PShellLink ppsl);
+
+
+	//SetApplicationID for Windows 7
+	JL_HRESULT JL_SetCurrentProcessExplicitAppUserModelID(wchar_t* appID);
+
+#if	defined(__cplusplus)
+}
+#endif
+
+
+#if defined(__cplusplus)
+
+// 注意: このあたりの宣言文は Windows SDK からのコピーである。
+//       しかし創作性に乏しい (単なる宣言であるため) ので GPL のコード中にペーストしても
+//       支障はないと解釈している。
+
+#ifndef	__IObjectArray_INTERFACE_DEFINED__
+#define	__IObjectArray_INTERFACE_DEFINED__
+
+MIDL_INTERFACE("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")
+IObjectArray : public IUnknown
+{
+public:
+	virtual HRESULT STDMETHODCALLTYPE GetCount( 
+		/* [out] */ __RPC__out UINT *pcObjects) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE GetAt( 
+		/* [in] */ UINT uiIndex,
+		/* [in] */ __RPC__in REFIID riid,
+		/* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
+
+};
+
+MIDL_INTERFACE("5632b1a4-e38a-400a-928a-d4cd63230295")
+IObjectCollection : public IObjectArray
+{
+public:
+	virtual HRESULT STDMETHODCALLTYPE AddObject( 
+		/* [in] */ __RPC__in_opt IUnknown *punk) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE AddFromArray( 
+		/* [in] */ __RPC__in_opt IObjectArray *poaSource) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE RemoveObjectAt( 
+		/* [in] */ UINT uiIndex) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE Clear( void) = 0;
+
+};
+
+#endif	// __IObjectArray_INTERFACE_DEFINED__
+
+#ifndef	__ICustomDestinationList_INTERFACE_DEFINED__
+#define	__ICustomDestinationList_INTERFACE_DEFINED__
+
+typedef /* [v1_enum] */ 
+enum KNOWNDESTCATEGORY
+{	
+	KDC_FREQUENT	= 1,
+	KDC_RECENT	= ( KDC_FREQUENT + 1 ) 
+} 	KNOWNDESTCATEGORY;
+
+MIDL_INTERFACE("6332debf-87b5-4670-90c0-5e57b408a49e")
+ICustomDestinationList : public IUnknown
+{
+public:
+	virtual HRESULT STDMETHODCALLTYPE SetAppID( 
+		/* [string][in] */ __RPC__in_string LPCWSTR pszAppID) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE BeginList( 
+		/* [out] */ __RPC__out UINT *pcMinSlots,
+		/* [in] */ __RPC__in REFIID riid,
+		/* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE AppendCategory( 
+		/* [string][in] */ __RPC__in_string LPCWSTR pszCategory,
+		/* [in] */ __RPC__in_opt IObjectArray *poa) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE AppendKnownCategory( 
+		/* [in] */ KNOWNDESTCATEGORY category) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE AddUserTasks( 
+		/* [in] */ __RPC__in_opt IObjectArray *poa) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE CommitList( void) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE GetRemovedDestinations( 
+		/* [in] */ __RPC__in REFIID riid,
+		/* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE DeleteList( 
+		/* [string][unique][in] */ __RPC__in_opt_string LPCWSTR pszAppID) = 0;
+
+	virtual HRESULT STDMETHODCALLTYPE AbortList( void) = 0;
+
+};
+
+
+#endif	// __ICustomDestinationList_INTERFACE_DEFINED__
+
+
+#endif //defined(__cplusplus)
+
+
+
+#endif	// WIN32HTML_H
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinJumpList.cpp
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinJumpList.cpp	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinJumpList.cpp	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,440 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// WinJumpList.cpp
+// Windows7用　ジャンプリスト ソースコード
+
+// Q. このソースコードだけ他と違ってコメントが少ないように見える。
+// A. はい。
+
+#ifdef	WIN32
+
+//#define NTDDI_WIN7                          0x06010000
+//#define	_WIN32_WINNT	_WIN32_WINNT_VISTA
+//#define NTDDI_VERSION NTDDI_VISTA  // Specifies that the minimum required platform is Windows 7.
+#define WIN32_LEAN_AND_MEAN       // Exclude rarely-used stuff from Windows headers
+#define STRICT_TYPED_ITEMIDS      // Utilize strictly typed IDLists
+
+//#include <objectarray.h>
+#include <shobjidl.h>
+#include <propkey.h>
+#include <propvarutil.h>
+//#include <knownfolders.h>
+//#include <shlobj.h>
+
+
+#ifdef StrCpy
+#undef StrCpy
+#endif
+
+#ifdef StrCat
+#undef StrCat
+#endif
+
+#ifdef StrCmp
+#undef StrCmp
+#endif
+
+
+#define	WIN32HTML_CPP
+
+//#define	_WIN32_WINNT		0x0502
+//#define	WINVER				0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <comdef.h>
+#include <Mshtmhst.h>
+//#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+
+extern "C"
+{
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+}
+#include "../PenCore/resource.h"
+
+extern "C"
+{
+
+	//////////////////////////////////////////////////////////////////////////
+	//JumpList
+	// 注意: このあたりのコードは Win32 ヘッダファイル等からコピーした部分がある。
+	//       ただしコピーしたのは単純な部分のみであり、創造的かつ複雑な部分ではないので
+	//       GPL のコードの一部としてペーストしてあっても問題にはならないものと解釈
+	//       している。
+
+	#define CREATE_PROPERTYKEY(l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) { { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }, pid }
+
+
+	JL_HRESULT JL_CreateCustomDestinationList(JL_PCustomDestinationList* poc, wchar_t* appID)
+	{
+		ICustomDestinationList *pcdl;
+
+		//CLSID_DestinationList = 6332DEBF-87B5-4670-90C0-5E57-B408-A49E
+
+		GUID destList;
+
+		destList.Data1 = 2012286192;
+		destList.Data2 = 15797;
+		destList.Data3 = 18790;
+
+		destList.Data4[0] = 181;
+		destList.Data4[1] = 32;
+		destList.Data4[2] = 183;
+		destList.Data4[3] = 197;
+		destList.Data4[4] = 79;
+		destList.Data4[5] = 211;
+		destList.Data4[6] = 94;
+		destList.Data4[7] = 214;
+
+		HRESULT hr = CoCreateInstance(destList, 
+			NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcdl));
+
+		if (SUCCEEDED(hr))
+		{
+			pcdl->SetAppID(appID);
+			(*poc) = (void*)pcdl;
+		}
+		else
+		{
+			(*poc) = NULL;
+		}
+
+		return hr;
+	}
+
+	JL_HRESULT JL_ReleaseCustomDestinationList(JL_PCustomDestinationList poc)
+	{
+		ICustomDestinationList *pcdl = (ICustomDestinationList*)poc;
+		if(pcdl != NULL)
+		{
+			pcdl->Release();
+		}
+
+		return 0;
+	}
+
+	JL_HRESULT JL_BeginList(JL_PCustomDestinationList poc, JL_PObjectArray* oaRemoved)
+	{
+		UINT cMinSlots;
+		IObjectArray *poaRemoved;
+
+		ICustomDestinationList *pcdl = (ICustomDestinationList*)poc;
+
+		HRESULT hr = pcdl->BeginList(&cMinSlots, IID_PPV_ARGS(&poaRemoved));
+
+		(*oaRemoved) = poaRemoved;
+
+		return hr;
+	}
+
+	JL_HRESULT JL_CommitList(JL_PCustomDestinationList cdl)
+	{
+		ICustomDestinationList *pcdl = (ICustomDestinationList*)cdl;
+
+		return pcdl->CommitList();
+	}
+
+	JL_HRESULT JL_CreateObjectCollection(JL_PObjectCollection* jpoc)
+	{
+
+		//CLSID_EnumerableObjectCollection = 2D3468C1-36A7-43B6-AC24-D3F0-2FD9-607A
+
+
+		GUID enumObjCol;
+
+		enumObjCol.Data1 = 758409409;
+		enumObjCol.Data2 = 13991;
+		enumObjCol.Data3 = 17334;
+
+		enumObjCol.Data4[0] = 172;
+		enumObjCol.Data4[1] = 36;
+		enumObjCol.Data4[2] = 211;
+		enumObjCol.Data4[3] = 240;
+		enumObjCol.Data4[4] = 47;
+		enumObjCol.Data4[5] = 217;
+		enumObjCol.Data4[6] = 96;
+		enumObjCol.Data4[7] = 122;
+
+		IObjectCollection *poc;
+		HRESULT hr = CoCreateInstance(enumObjCol,
+			NULL, CLSCTX_INPROC, IID_PPV_ARGS(&poc));
+
+		if (SUCCEEDED(hr))
+		{
+			(*jpoc) = poc;
+		}
+		else{
+			(*jpoc) = NULL;
+		}
+		return hr;
+	}
+
+	JL_HRESULT JL_ReleaseObjectCollection(JL_PObjectCollection jpoc)
+	{
+		IObjectCollection *poc = (IObjectCollection *)jpoc;
+		if(poc != NULL)
+		{
+			return poc->Release();
+		}
+
+		return 0;
+	}
+
+	JL_HRESULT JL_ObjectCollectionAddShellLink(JL_PObjectCollection jpoc, JL_PShellLink jpsl)
+	{
+		IObjectCollection *poc = (IObjectCollection *)jpoc;
+		IShellLink *psl = (IShellLink *) jpsl;
+
+		return poc->AddObject(psl);
+
+	}
+
+
+	JL_HRESULT JL_AddCategoryToList(JL_PCustomDestinationList jpcdl, 
+		JL_PObjectCollection jpoc, 
+		wchar_t* categoryName,
+		JL_PObjectArray jpoaRemoved)
+	{
+		ICustomDestinationList *pcdl = (ICustomDestinationList*)jpcdl;
+		IObjectCollection *poc = (IObjectCollection *)jpoc;
+		 IObjectArray *poaRemoved = (IObjectArray*)jpoaRemoved;
+
+		IObjectArray *poa;
+		HRESULT hr = poc->QueryInterface(IID_PPV_ARGS(&poa));
+		if (SUCCEEDED(hr))
+		{
+		
+			hr = pcdl->AppendCategory(categoryName, poa);
+			poa->Release();
+
+			if (SUCCEEDED(hr))
+			{
+			}
+			else
+			{
+				Print("Failed AppendCategory\n");
+			}
+		}
+		else
+		{
+			Print("Failed QueryInterface\n");
+		}
+		
+
+		return hr;
+	}
+
+
+
+	JL_HRESULT JL_CreateShellLink(
+		wchar_t* pszPath, 
+		wchar_t* pszArguments, 
+		wchar_t* pszTitle, 
+		wchar_t* iconLocation,
+		int iconIndex, 
+		wchar_t* description, JL_PShellLink *ppsl)
+	{
+		IShellLinkW *psl;
+		HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&psl));
+		if (SUCCEEDED(hr))
+		{
+			psl->SetPath(pszPath);
+			psl->SetArguments(pszArguments);
+			if(iconLocation != NULL)
+			{
+				psl->SetIconLocation(iconLocation,iconIndex);
+			}
+
+			if(description != NULL)
+			{
+				psl->SetDescription(description);
+			}
+				if (SUCCEEDED(hr))
+				{
+					IPropertyStore *pps;
+					hr = psl->QueryInterface(IID_PPV_ARGS(&pps));
+					if (SUCCEEDED(hr))
+					{
+						PROPVARIANT propvar;
+						hr = InitPropVariantFromString(pszTitle, &propvar);
+						if (SUCCEEDED(hr))
+						{
+
+							PROPERTYKEY pkey_title = 
+								CREATE_PROPERTYKEY(0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 2);
+
+							hr = pps->SetValue(pkey_title, propvar);
+
+
+							if (SUCCEEDED(hr))
+							{
+								hr = pps->Commit();
+								if (SUCCEEDED(hr))
+								{
+									IShellLink *tpsl;
+									hr = psl->QueryInterface(IID_PPV_ARGS(&tpsl));
+									(*ppsl) = tpsl;
+								}
+							}
+							PropVariantClear(&propvar);
+						}
+						pps->Release();
+					}
+				}
+			psl->Release();
+		}
+		return hr;
+	}
+
+	JL_HRESULT JL_ReleaseShellLink(JL_PShellLink jpsl)
+	{
+		IShellLink *psl = (IShellLink *) jpsl;
+
+		if(psl != NULL)
+		{
+			return psl->Release();
+		}
+
+		return 0;
+	}
+
+	JL_HRESULT JL_DeleteJumpList(JL_PCustomDestinationList jpcdl,wchar_t* appID)
+	{
+		ICustomDestinationList *pcdl = (ICustomDestinationList *)jpcdl;
+
+		HRESULT	hr = pcdl->DeleteList(appID);
+
+
+		return hr;
+	}
+
+
+
+	//////////////////////////////////////////////////////////////////////////
+	//SetApplicationID for Windows 7
+	JL_HRESULT JL_SetCurrentProcessExplicitAppUserModelID(wchar_t* appID)
+	{
+#ifdef UNICODE
+		HMODULE hModule = LoadLibraryW( L"shell32.dll");
+#else
+		HMODULE hModule = LoadLibraryA( "shell32.dll");
+#endif
+		HRESULT (__stdcall *SetAppID) (PCWSTR);
+
+		if( hModule == NULL )
+		{
+			Print("Not Found shell32.dll");
+		}
+		else
+		{
+			SetAppID = (HRESULT (__stdcall *)(PCWSTR))
+				GetProcAddress( hModule, "SetCurrentProcessExplicitAppUserModelID" );
+			if( SetAppID != NULL )
+			{
+				FreeLibrary( hModule );
+				return SetAppID(appID);
+			}
+			else
+			{
+				Print("Not Found SetCurrentProcessExplicitAppUserModelID");
+
+			}
+
+			FreeLibrary( hModule );
+		}
+		return 0;
+
+
+	}
+
+
+
+}
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinUi.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinUi.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinUi.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,9920 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// WinUi.c
+// Win32 用ユーザーインターフェースコード
+
+#ifdef	WIN32
+
+#define	WINUI_C
+
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <Iphlpapi.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "../PenCore/resource.h"
+
+char cached_pin_code[MAX_SIZE] = {0};
+UINT64 cached_pin_code_expires = 0;
+
+static HINSTANCE hDll = NULL;
+static wchar_t *title_bar = NULL;
+static char *font_name = NULL;
+static UINT font_size = 9;
+static HIMAGELIST large_image_list = NULL, small_image_list = NULL;
+static LIST *icon_list = NULL;
+static HINSTANCE hMsHtml = NULL;
+static UINT init_winui_counter = 0;
+static bool new_style_mode = false;
+
+bool UseAlpha = false;
+UINT AlphaValue = 100;
+
+static THREAD *led_thread = NULL;
+static bool thread_stop = false;
+static bool g_led_special = false;
+static bool g_tcpip_topmost = false;
+
+typedef struct GDI_CACHE
+{
+	bool IsInited;
+	COLORREF BackgroundColor;
+	COLORREF ForegroundColor;
+	COLORREF TextBoxBackgroundColor;
+	HBRUSH BlackBrush;
+	HBRUSH WhiteBrush;
+	HBRUSH BackgroundColorBrush;
+	HBRUSH ForegroundColorBrush;
+	HBRUSH TextBoxBackgroundColorBrush;
+} GDI_CACHE;
+
+static GDI_CACHE gdi_cache = { false, };
+
+// スプラッシュウインドウデータ
+typedef struct SPLASH
+{
+	HWND hWnd;
+	HWND hWndParent;
+	WINBMP *Bmp;
+	void *Param;
+	UINT64 Ticks;
+	UINT64 StartTick;
+	char *Title;
+	wchar_t *Caption;
+	HPEN LinePen;
+	WINMEMDC *BackDC;
+} SPLASH;
+
+// 画面がフルカラーモードかどうか取得
+bool IsFullColor()
+{
+	bool ret = false;
+	HDC hDC = CreateCompatibleDC(0);
+
+	if (GetDeviceCaps(hDC, BITSPIXEL) >= 16)
+	{
+		ret = true;
+	}
+
+	DeleteDC(hDC);
+
+	return ret;
+}
+
+// リストビューの背景に画像を表示する
+void LvSetBkImage(HWND hWnd, UINT id, char *bmp_file_name)
+{
+	LVBKIMAGE t;
+	char *tmp;
+	// 引数チェック
+	if (hWnd == NULL || bmp_file_name == NULL)
+	{
+		return;
+	}
+	if (IsFullColor() == false)
+	{
+		// 256 色モードの場合は表示しない
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+
+	tmp = MsCreateTempFileNameByExt(".bmp");
+
+	FileCopy(bmp_file_name, tmp);
+
+	t.ulFlags = LVBKIF_SOURCE_URL | LVBKIF_STYLE_NORMAL;
+	t.pszImage = tmp;
+	t.xOffsetPercent = 100;
+	t.yOffsetPercent = 100;
+
+	ListView_SetBkImage(DlgItem(hWnd, id), &t);
+
+	Free(tmp);
+}
+
+// メモリ DC を解放する
+void FreeMemDC(WINMEMDC *m)
+{
+	// 引数チェック
+	if (m == NULL)
+	{
+		return;
+	}
+
+	DeleteDC(m->hDC);
+	DeleteObject(m->hBitmap);
+
+	Free(m);
+}
+
+// メモリ DC を作成する
+WINMEMDC *NewMemDC(UINT width, UINT height)
+{
+	WINMEMDC *m = ZeroMalloc(sizeof(WINMEMDC));
+	BITMAPINFOHEADER h;
+	BITMAPINFO bi;
+
+	m->Width = width;
+	m->Height = height;
+
+	m->hDC = CreateCompatibleDC(0);
+
+	Zero(&h, sizeof(h));
+	h.biSize = sizeof(h);
+	h.biWidth = width;
+	h.biHeight = height;
+	h.biPlanes = 1;
+	h.biBitCount = 24;
+	h.biXPelsPerMeter = 2834;
+	h.biYPelsPerMeter = 2834;
+
+	Zero(&bi, sizeof(bi));
+	Copy(&bi.bmiHeader, &h, sizeof(BITMAPINFOHEADER));
+
+	m->hBitmap = CreateDIBSection(m->hDC, &bi, DIB_RGB_COLORS,
+		&m->Data, NULL, 0);
+
+	SelectObject(m->hDC, m->hBitmap);
+
+	return m;
+}
+
+// スプラッシュ画面を表示する (毎回絵が変わる)
+void ShowSplashEx(HWND hWndParent, char *software_name, UINT ticks, UINT line_color)
+{
+	wchar_t tmp[MAX_SIZE];
+	wchar_t caption[MAX_SIZE];
+	UINT id = MsRegReadInt(REG_CURRENT_USER, SPLASH_BMP_REGKEY, SPLASH_BMP_REGVALUE);
+	id++;
+	if (id > 20)
+	{
+		id = 1;
+	}
+	MsRegWriteInt(REG_CURRENT_USER, SPLASH_BMP_REGKEY, SPLASH_BMP_REGVALUE, id);
+
+	UniFormat(tmp, sizeof(tmp), L"|Splash%02u.bmp", id);
+
+	StrToUni(caption, sizeof(caption), software_name);
+
+	ShowSplash(hWndParent, tmp, software_name, caption, ticks, line_color, NULL);
+}
+
+// フォント描画
+void DrawFont(HDC hDC, wchar_t *text, UINT x, UINT y, HFONT font, UINT fore_color,
+			  UINT back_color, UINT back_width)
+{
+	int i, j;
+
+	SelectObject(hDC, font);
+	SetBkMode(hDC, TRANSPARENT);
+
+	// 背景の描画
+	SetTextColor(hDC, back_color);
+	for (i = -((int)back_width);i <= (int)back_width;i++)
+	{
+		for (j = -((int)back_width); j <= (int)back_width;j++)
+		{
+			if (i != 0 || j != 0)
+			{
+				TextOutW(hDC, (int)x + i, (int)y + j, text, UniStrLen(text));
+			}
+		}
+	}
+
+	// 文字の描画
+	SetTextColor(hDC, fore_color);
+	TextOutW(hDC, x, y, text, UniStrLen(text));
+}
+
+// スプラッシュウインドウを開く
+LRESULT CALLBACK SplashProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	SPLASH *splash;
+	CREATESTRUCT *cs = (CREATESTRUCT *)lParam;
+	UINT64 now = Tick64();
+	UINT64 current_span = 0;
+	UINT a;
+	UINT fade = 8;
+
+	if (msg == WM_CREATE)
+	{
+		splash = (SPLASH *)cs->lpCreateParams;
+		current_span = 0;
+	}
+	else
+	{
+		splash = (SPLASH *)GetWindowLongPtrA(hWnd, GWLP_USERDATA);
+		if (splash != NULL)
+		{
+			current_span = now - splash->StartTick;
+		}
+	}
+
+	switch (msg)
+	{
+	case WM_CREATE:
+		SetWindowLongPtrA(hWnd, GWLP_USERDATA, (LONG_PTR)splash);
+
+		CenterParent(hWnd);
+
+		if (splash->Ticks != 0)
+		{
+			SetTimer(hWnd, 1, 1, NULL);
+
+			splash->StartTick = now;
+
+			SetAplha(hWnd, 0);
+
+			Top(hWnd);
+		}
+
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			a = 0;
+
+			if (current_span < (splash->Ticks / fade))
+			{
+				// フェードイン
+				a = (UINT)((double)current_span * 255.0 / (double)(splash->Ticks / fade));
+			}
+			else if (current_span < (splash->Ticks * (fade - 1) / fade))
+			{
+				// 通常表示
+				a = 255;
+			}
+			else if (current_span < splash->Ticks)
+			{
+				// フェードアウト
+				a = 255 - (UINT)(((double)(current_span - (splash->Ticks * (fade - 1) / fade))) * 255.0 / (double)(splash->Ticks / fade));
+			}
+			else
+			{
+				// 閉じる
+				goto LABEL_CLOSE;
+			}
+
+			SetAplha(hWnd, a);
+
+			SetTimer(hWnd, 1, 1, NULL);
+			break;
+		}
+		break;
+
+	case WM_PAINT:
+		if (true)
+		{
+			PAINTSTRUCT ps;
+			HDC hDC, hWndDC;
+
+			Zero(&ps, sizeof(ps));
+			hWndDC = BeginPaint(hWnd, &ps);
+			if (hWndDC != NULL)
+			{
+				POINT points[5];
+				wchar_t tmp[MAX_SIZE];
+
+				hDC = splash->BackDC->hDC;
+
+				// ビットマップ画像
+				BitBlt(hDC, 0, 0, splash->Bmp->Width, splash->Bmp->Height,
+					splash->Bmp->hDC, 0, 0, SRCCOPY);
+
+				// 線
+				Zero(points, sizeof(points));
+				points[0].x = 0; points[0].y = 0;
+				points[1].x = splash->Bmp->Width - 1; points[1].y = 0;
+				points[2].x = splash->Bmp->Width - 1; points[2].y = splash->Bmp->Height - 1;
+				points[3].x = 0; points[3].y = splash->Bmp->Height - 1;
+				points[4].x = 0; points[4].y = 0;
+
+				SelectObject(hDC, splash->LinePen);
+				Polyline(hDC, points, 5);
+
+				// ソフトウェアのタイトルの描画
+				DrawFont(hDC, splash->Caption, 114, 136,
+					GetFont("Arial", 36, true, false, false, false),
+					RGB(0, 0, 0),
+					RGB(255, 255, 255),
+					3);
+
+				// ソフトウェアのバージョン情報の描画
+				UniFormat(tmp, sizeof(tmp),
+					L"Version %u.%02u Build %u, Compiled in %04u/%02u/%02u.",
+					CEDAR_VER / 100, CEDAR_VER - (CEDAR_VER / 100) * 100,
+					CEDAR_BUILD, BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D);
+				DrawFont(hDC, tmp, 200, 202,
+					GetFont("Arial", 8, true, false, false, false),
+					RGB(0, 0, 0),
+					RGB(255, 255, 255),
+					1);
+
+				// 画面に描画
+				BitBlt(hWndDC, 0, 0, splash->Bmp->Width, splash->Bmp->Height,
+					hDC, 0, 0, SRCCOPY);
+
+				EndPaint(hWnd, &ps);
+			}
+		}
+		break;
+
+	case WM_CLOSE:
+		if (splash->Ticks != 0)
+		{
+			return 0;
+		}
+LABEL_CLOSE:
+		if (splash->hWndParent != NULL)
+		{
+			Enable(splash->hWndParent, 0);
+		}
+		DestroyWindow(hWnd);
+		return 0;
+
+	case WM_KEYDOWN:
+		switch (wParam)
+		{
+		case VK_ESCAPE:
+		case VK_RETURN:
+		case VK_SPACE:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_LBUTTONUP:
+	case WM_RBUTTONUP:
+	case WM_MBUTTONUP:
+		Close(hWnd);
+		break;
+
+	case WM_DESTROY:
+		if (splash->hWndParent != NULL)
+		{
+			Enable(splash->hWndParent, 0);
+		}
+		PostQuitMessage(0);
+		return 0;
+	}
+
+	return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+// スプラッシュウインドウ
+void ShowSplash(HWND hWndParent, wchar_t *bmp_file_name, char *title, wchar_t *caption, UINT ticks, UINT line_color, void *param)
+{
+	SPLASH *p;
+	WNDCLASSA wc;
+	char wndclass_name[MAX_SIZE];
+	// 引数チェック
+	if (bmp_file_name == NULL)
+	{
+		return;
+	}
+	if (IsEmptyStr(title))
+	{
+		title = "Splash Window";
+	}
+
+	p = ZeroMalloc(sizeof(SPLASH));
+
+	p->Bmp = LoadBmpFromFileW(bmp_file_name);
+	if (p->Bmp == NULL)
+	{
+		Free(p);
+		return;
+	}
+
+	p->BackDC = NewMemDC(p->Bmp->Width, p->Bmp->Height);
+
+	p->LinePen = CreatePen(PS_SOLID, 1, line_color);
+
+	p->hWndParent = hWndParent;
+
+	p->Title = title;
+	p->Caption = caption;
+	p->Ticks = ticks;
+
+	p->Param = param;
+
+	Zero(&wc, sizeof(wc));
+	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+	wc.hCursor = LoadCursor(NULL, ticks == 0 ? IDC_ARROW : IDC_APPSTARTING);
+	wc.hInstance = GetModuleHandleA(NULL);
+	wc.lpfnWndProc = SplashProc;
+
+	Format(wndclass_name, sizeof(wndclass_name), "WINUI_SPLASH_CLASS_%I64u", Rand64());
+	wc.lpszClassName = wndclass_name;
+
+	RegisterClassA(&wc);
+
+	p->hWnd = CreateWindowA(wndclass_name, title,
+		WS_POPUP, 0, 0,
+		p->Bmp->Width, p->Bmp->Height,
+		hWndParent, NULL, GetModuleHandleA(NULL), p);
+	if (p->hWnd == NULL)
+	{
+		Debug("CreateWindowA Error: %u\n", GetLastError());
+	}
+
+	if (hWndParent != NULL)
+	{
+		Disable(hWndParent, 0);
+	}
+
+	ShowWindow(p->hWnd, SW_SHOW);
+
+	if (p->hWnd != NULL)
+	{
+		MSG msg;
+
+		while (true)
+		{
+			Zero(&msg, sizeof(msg));
+
+			if (GetMessageA(&msg, NULL, 0, 0) == 0)
+			{
+				break;
+			}
+
+			TranslateMessage(&msg);
+			DispatchMessageA(&msg);
+		}
+	}
+
+	if (hWndParent != NULL)
+	{
+		Enable(hWndParent, 0);
+		SetActiveWindow(hWndParent);
+		BringWindowToTop(hWndParent);
+	}
+
+	UnregisterClassA(wndclass_name, GetModuleHandleA(NULL));
+
+	FreeMemDC(p->BackDC);
+
+	FreeBmp(p->Bmp);
+
+	DeleteObject(p->LinePen);
+
+	Free(p);
+}
+
+// GDI オブジェクトのキャッシュがまだ作成されていない場合は作成する
+void InitGdiCache()
+{
+	if (gdi_cache.IsInited)
+	{
+		return;
+	}
+
+	gdi_cache.BlackBrush = GetStockObject(BLACK_BRUSH);
+	gdi_cache.WhiteBrush = GetStockObject(WHITE_BRUSH);
+
+	gdi_cache.BackgroundColor = RGB(247, 238, 255);
+	gdi_cache.BackgroundColorBrush = CreateSolidBrush(gdi_cache.BackgroundColor);
+
+	gdi_cache.ForegroundColor = RGB(0, 0, 0);
+	gdi_cache.ForegroundColorBrush = CreateSolidBrush(gdi_cache.ForegroundColor);
+
+	gdi_cache.TextBoxBackgroundColor = RGB(255, 255, 255);
+	gdi_cache.TextBoxBackgroundColorBrush = CreateSolidBrush(gdi_cache.TextBoxBackgroundColor);
+
+	gdi_cache.IsInited = true;
+}
+
+// ビットマップをリソースから読む
+WINBMP *LoadBmpFromResource(UINT id)
+{
+	HANDLE h;
+	// 引数チェック
+	if (id == 0)
+	{
+		return NULL;
+	}
+
+	h = LoadImageA(hDll, MAKEINTRESOURCEA(id), IMAGE_BITMAP, 0, 0,
+		LR_CREATEDIBSECTION | LR_VGACOLOR);
+
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	return LoadBmpMain(h);
+}
+
+// ビットマップをファイルから読む
+WINBMP *LoadBmpFromFileW(wchar_t *filename)
+{
+	wchar_t tmp[MAX_SIZE];
+	char *tmpa;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	// 一時ファイルにコピー
+	tmpa = MsCreateTempFileNameByExt("bmp");
+
+	StrToUni(tmp, sizeof(tmp), tmpa);
+
+	Free(tmpa);
+
+	if (FileCopyW(filename, tmp) == false)
+	{
+		return NULL;
+	}
+
+	return LoadBmpFromFileInnerW(tmp);
+}
+WINBMP *LoadBmpFromFileInnerW(wchar_t *filename)
+{
+	HANDLE h;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	if (MsIsNt())
+	{
+		h = LoadImageW(NULL, filename, IMAGE_BITMAP, 0, 0,
+			LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_VGACOLOR);
+	}
+	else
+	{
+		char tmp[MAX_SIZE];
+
+		UniToStr(tmp, sizeof(tmp), filename);
+
+		h = LoadImageA(NULL, tmp, IMAGE_BITMAP, 0, 0,
+			LR_CREATEDIBSECTION | LR_LOADFROMFILE | LR_VGACOLOR);
+	}
+
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	return LoadBmpMain(h);
+}
+WINBMP *LoadBmpFromFileA(char *filename)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	StrToUni(tmp, sizeof(tmp), filename);
+
+	return LoadBmpFromFileW(tmp);
+}
+
+// ビットマップ読み込みメイン
+WINBMP *LoadBmpMain(void *hBitmap)
+{
+	WINBMP *b;
+	BITMAP d;
+	HDC hDC;
+	// 引数チェック
+	if (hBitmap == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&d, sizeof(d));
+
+	if (GetObject((HANDLE)hBitmap, sizeof(d), &d) == 0)
+	{
+		DeleteObject((HANDLE)hBitmap);
+		return NULL;
+	}
+
+	b = ZeroMalloc(sizeof(WINBMP));
+	b->Bits = d.bmBitsPixel;
+	b->hBitmap = hBitmap;
+	b->Height = d.bmHeight;
+	b->Width = d.bmWidth;
+
+	hDC = CreateCompatibleDC(0);
+
+	SelectObject(hDC, hBitmap);
+
+	b->hDC = hDC;
+
+	return b;
+}
+
+// ビットマップを解放する
+void FreeBmp(WINBMP *b)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	DeleteDC(b->hDC);
+	DeleteObject(b->hBitmap);
+
+	Free(b);
+}
+
+// 新しいスタイルを開始
+void EnableNewStyleMode()
+{
+	InitGdiCache();
+
+	new_style_mode = true;
+}
+
+// 新しいスタイルを終了
+void DisableNewStyleMode()
+{
+	new_style_mode = false;
+}
+
+// 新しいスタイルが有効になっているかどうかチェック
+bool IsNewStyleModeEnabled()
+{
+	return new_style_mode;
+}
+
+// NIC 情報ダイアログプロシージャ
+UINT NicInfoProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UI_NICINFO *info = (UI_NICINFO *)param;
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		NicInfoInit(hWnd, info);
+
+		SetTimer(hWnd, 1, 50, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+
+			NicInfoOnTimer(hWnd, info);
+
+			SetTimer(hWnd, 1, 50, NULL);
+			break;
+
+		case 2:
+			KillTimer(hWnd, 2);
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		KillTimer(hWnd, 1);
+		KillTimer(hWnd, 2);
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+void NicInfoCloseAfterTime(HWND hWnd, UI_NICINFO *info, UINT tick)
+{
+	UINT64 now;
+	UINT64 closetime;
+	// 引数チェック
+	if (hWnd == NULL || info == NULL)
+	{
+		return;
+	}
+
+	now = Tick64();
+	closetime = now + (UINT64)tick;
+
+	if (info->CloseAfterTime == 0 || info->CloseAfterTime >= closetime)
+	{
+		info->CloseAfterTime = closetime;
+		KillTimer(hWnd, 2);
+		SetTimer(hWnd, 2, tick, NULL);
+	}
+}
+void NicInfoShowStatus(HWND hWnd, UI_NICINFO *info, wchar_t *msg1, wchar_t *msg2, UINT icon, bool animate)
+{
+	// 引数チェック
+	if (hWnd == NULL || info == NULL)
+	{
+		return;
+	}
+	if (icon == 0)
+	{
+		icon = ICO_TEST;
+	}
+	if (msg1 == NULL)
+	{
+		msg1 = L"";
+	}
+	if (msg2 == NULL)
+	{
+		msg2 = L"";
+	}
+
+	if (info->CurrentIcon != icon)
+	{
+		SetIcon(hWnd, S_ICON, icon);
+		info->CurrentIcon = icon;
+	}
+
+	SetText(hWnd, S_STATUS1, msg1);
+	SetText(hWnd, S_STATUS2, msg2);
+
+	SetShow(hWnd, P_BAR, animate && MsIsWinXPOrWinVista());
+}
+void NicInfoRefresh(HWND hWnd, UI_NICINFO *info)
+{
+	MS_ADAPTER *a;
+	IP ip;
+	char ip_str[MAX_SIZE];
+	char title[MAX_SIZE];
+	UINT i;
+	wchar_t tmp[MAX_SIZE];
+	bool has_ip = false;
+	// 引数チェック
+	if (hWnd == NULL || info == NULL)
+	{
+		return;
+	}
+
+	Format(title, sizeof(title), VLAN_ADAPTER_NAME_TAG, info->NicName);
+
+	a = MsGetAdapter(title);
+	if (a == NULL)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	// IP アドレスが割り当てら割れているかどうかチェック
+	Zero(&ip, sizeof(ip));
+	for (i = 0;i < MAX_MS_ADAPTER_IP_ADDRESS;i++)
+	{
+		if (IsZeroIP(&a->IpAddresses[i]) == false)
+		{
+			Copy(&ip, &a->IpAddresses[i], sizeof(IP));
+
+			if (!(ip.addr[0] == 169 && ip.addr[1] == 254))
+			{
+				has_ip = true;
+			}
+		}
+	}
+	IPToStr(ip_str, sizeof(ip_str), &ip);
+
+	if (has_ip == false)
+	{
+		if (a->UseDhcp)
+		{
+			NicInfoShowStatus(hWnd, info, _UU("NICINFO_1"), _UU("NICINFO_1_1"), ICO_NIC_OFFLINE, true);
+		}
+		else
+		{
+			NicInfoShowStatus(hWnd, info, _UU("NICINFO_1"), _UU("NICINFO_1_2"), ICO_NIC_OFFLINE, true);
+		}
+	}
+	else
+	{
+		if (a->UseDhcp)
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("NICINFO_2_1"), ip_str);
+			NicInfoShowStatus(hWnd, info, _UU("NICINFO_2"), tmp, ICO_NIC_ONLINE, false);
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), _UU("NICINFO_3_1"), ip_str);
+			NicInfoShowStatus(hWnd, info, _UU("NICINFO_3"), tmp, ICO_NIC_ONLINE, false);
+		}
+
+		NicInfoCloseAfterTime(hWnd, info, NICINFO_AUTOCLOSE_TIME_2);
+	}
+
+	MsFreeAdapter(a);
+}
+void NicInfoInit(HWND hWnd, UI_NICINFO *info)
+{
+	// 引数チェック
+	if (hWnd == NULL || info == NULL)
+	{
+		return;
+	}
+
+	if (MsIsWinXPOrWinVista())
+	{
+		// Windows XP 以降の場合はプログレスバーを表示する
+		SendMsg(hWnd, P_BAR, PBM_SETMARQUEE, TRUE, 150);
+		SetStyle(hWnd, P_BAR, PBS_MARQUEE);
+	}
+
+	DlgFont(hWnd, S_STATUS1, 9, false);
+	DlgFont(hWnd, S_STATUS2, 11, false);
+
+	SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+
+	FormatText(hWnd, 0, info->NicName);
+
+	NicInfoRefresh(hWnd, info);
+
+	NicInfoCloseAfterTime(hWnd, info, NICINFO_AUTOCLOSE_TIME_1);
+}
+void NicInfoOnTimer(HWND hWnd, UI_NICINFO *info)
+{
+	// 引数チェック
+	if (hWnd == NULL || info == NULL)
+	{
+		return;
+	}
+
+	if (info->Halt)
+	{
+		Close(hWnd);
+		return;
+	}
+
+	if (info->RouteChange != NULL &&
+		IsRouteChanged(info->RouteChange) == false)
+	{
+		return;
+	}
+
+	NicInfoRefresh(hWnd, info);
+}
+
+// NIC 情報ダイアログの表示
+void NicInfo(UI_NICINFO *info)
+{
+	// 引数チェック
+	if (info == NULL)
+	{
+		return;
+	}
+
+	info->RouteChange = NewRouteChange();
+
+	DialogEx2(NULL, D_NICINFO, NicInfoProc, info, true, true);
+
+	FreeRouteChange(info->RouteChange);
+	info->RouteChange = NULL;
+}
+
+// TCP 接続スレッド
+void WinConnectDlgThread(THREAD *thread, void *param)
+{
+	SOCK *s;
+	WINCONNECT_DLG_DATA *d = (WINCONNECT_DLG_DATA *)param;
+	// 引数チェック
+	if (d == NULL || thread == NULL)
+	{
+		return;
+	}
+
+	// ソケット接続
+	s = ConnectEx2(d->hostname, d->port, d->timeout, &d->cancel);
+
+	d->ret_sock = s;
+
+	PostMessageA(d->hWnd, WM_APP + 68, 0, 0);
+}
+
+// TCP 接続ダイアログプロシージャ
+UINT WinConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	WINCONNECT_DLG_DATA *d = (WINCONNECT_DLG_DATA *)param;
+	// 引数チェック
+	if (hWnd == NULL || d == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// UI 設定
+		CenterParent(hWnd);
+		SetText(hWnd, 0, d->caption);
+		SetText(hWnd, S_INFO, d->info);
+		SetIcon(hWnd, S_ICON, d->icon_id);
+		d->hWnd = hWnd;
+
+		if (MsIsWinXPOrWinVista())
+		{
+			// Windows XP 以降の場合はプログレスバーを表示する
+			SendMsg(hWnd, IDC_PROGRESS1, PBM_SETMARQUEE, TRUE, 100);
+			SetStyle(hWnd, IDC_PROGRESS1, PBS_MARQUEE);
+		}
+		else
+		{
+			// Windows 2000 以前の場合はプログレスバーを非表示にする
+			Hide(hWnd, IDC_PROGRESS1);
+		}
+
+		// スレッドの作成
+		d->thread = NewThread(WinConnectDlgThread, d);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_APP + 68:
+	case WM_CLOSE:
+		if (d->cancel == false)
+		{
+			d->cancel = true;
+			Disable(hWnd, IDCANCEL);
+			if (d->ret_sock == NULL)
+			{
+				SetText(hWnd, S_INFO, _UU("CONNECTDLG_CANCELING"));
+			}
+			DoEvents(hWnd);
+			Refresh(hWnd);
+			WaitThread(d->thread, INFINITE);
+			ReleaseThread(d->thread);
+			EndDialog(hWnd, 0);
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// TCP 接続を UI を表示しながら実施
+SOCK *WinConnectEx2(HWND hWnd, char *server, UINT port, UINT timeout, UINT icon_id, wchar_t *caption, wchar_t *info)
+{
+	wchar_t tmp[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	WINCONNECT_DLG_DATA d;
+	// 引数チェック
+	if (server == NULL || port == 0)
+	{
+		return NULL;
+	}
+	if (icon_id == 0)
+	{
+		icon_id = ICO_USER_ADMIN;
+	}
+	if (caption == NULL)
+	{
+		if (hWnd == NULL)
+		{
+			caption = _UU("CONNECTDLG_CAPTION");
+		}
+		else
+		{
+			GetTxt(hWnd, 0, tmp2, sizeof(tmp2));
+			caption = tmp2;
+		}
+	}
+	if (info == NULL)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CONNECTDLG_MESSAGE"), server, port);
+
+		info = tmp;
+	}
+
+	Zero(&d, sizeof(d));
+
+	d.cancel = false;
+	d.caption = caption;
+	d.icon_id = icon_id;
+	d.info = info;
+	d.timeout = timeout;
+	d.hostname = server;
+	d.port = port;
+
+	Dialog(hWnd, D_CONNECT, WinConnectDlgProc, &d);
+
+	return d.ret_sock;
+}
+
+// Windows ネットワーク設定画面の表示
+bool ShowWindowsNetworkConnectionDialog()
+{
+	wchar_t exe_name[MAX_SIZE];
+	void *proc;
+
+	CombinePathW(exe_name, sizeof(exe_name), MsGetSystem32DirW(), L"control.exe");
+
+	proc = Win32RunEx2W(exe_name, L"netconnections", false, NULL);
+
+	if (proc == NULL)
+	{
+		return false;
+	}
+
+	Win32CloseProcess(proc);
+
+	return true;
+}
+
+// メイリオフォントの取得
+HFONT GetMeiryoFont()
+{
+	return GetMeiryoFontEx(0);
+}
+HFONT GetMeiryoFontEx(UINT font_size)
+{
+	// 少し適当な処理。日本語版では Meiryo, 中文版では Microsoft YaHei を使用する。
+	if (_GETLANG() == 0)
+	{
+		return GetFont("Meiryo", font_size, false, false, false, false);
+	}
+	else if (_GETLANG() == 2)
+	{
+		return GetFont("Microsoft YaHei", font_size, false, false, false, false);
+	}
+	else
+	{
+		return GetFont(NULL, font_size, false, false, false, false);
+	}
+}
+
+// メイリオフォントに設定
+void SetFontMeiryo(HWND hWnd, UINT id)
+{
+	SetFont(hWnd, id, GetMeiryoFont());
+}
+
+// デフォルトフォントに設定
+void SetFontDefault(HWND hWnd, UINT id)
+{
+	SetFont(hWnd, id, GetDialogDefaultFont());
+}
+
+// 悪いプロセスに関する警告メッセージの表示
+void ShowBadProcessWarning(HWND hWnd, BAD_PROCESS *bad)
+{
+	wchar_t title[MAX_SIZE];
+	wchar_t message[8192];
+	// 引数チェック
+	if (bad == NULL)
+	{
+		return;
+	}
+
+	UniFormat(title, sizeof(title), _UU("BAD_PROCESS_TITLE"), bad->Title);
+	UniFormat(message, sizeof(message), _UU("BAD_PROCESS_MESSAGE"),
+		bad->Title, bad->Title, bad->Title, bad->Title);
+
+	OnceMsg(hWnd, title, message, true, ICO_WARNING);
+}
+
+// 競合するアンチウイルスソフトの一覧を検索し、該当するものがあれば表示する
+bool CheckBadProcesses(HWND hWnd)
+{
+	bool ret = true;
+	UINT i;
+	LIST *o;
+
+	o = MsGetProcessList();
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		MS_PROCESS *p = LIST_DATA(o, i);
+		char exe[MAX_PATH];
+		BAD_PROCESS *bad;
+
+		GetFileNameFromFilePath(exe, sizeof(exe), p->ExeFilename);
+
+		bad = IsBadProcess(exe);
+
+		if (bad != NULL)
+		{
+			// 悪いプロセスを発見したのでメッセージを表示する
+			ret = false;
+
+			ShowBadProcessWarning(hWnd, bad);
+		}
+	}
+
+	MsFreeProcessList(o);
+
+	return ret;
+}
+
+// 指定したプロセス名が悪いプロセスに該当するかどうか検索する
+BAD_PROCESS *IsBadProcess(char *exe)
+{
+	UINT i;
+	// 引数チェック
+	if (exe == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < num_bad_processes;i++)
+	{
+		BAD_PROCESS *bad = &bad_processes[i];
+
+		if (StrCmpi(bad->ExeName, exe) == 0)
+		{
+			return bad;
+		}
+	}
+
+	return NULL;
+}
+
+// メッセージ表示プロシージャ
+UINT OnceMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	ONCEMSG_DLG *d = (ONCEMSG_DLG *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetText(hWnd, 0, d->Title);
+		SetText(hWnd, E_TEXT, d->Message);
+		SetShow(hWnd, C_DONTSHOWAGAIN, d->ShowCheckbox);
+		//DisableClose(hWnd);
+		Focus(hWnd, IDCANCEL);
+		if (d->Icon != 0)
+		{
+			SetIcon(hWnd, 0, d->Icon);
+		}
+
+		if (MsIsVista())
+		{
+			SetFont(hWnd, E_TEXT, GetMeiryoFont());
+		}
+		else
+		{
+			DlgFont(hWnd, E_TEXT, 11, false);
+		}
+
+		SetTimer(hWnd, 1, 50, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			if (*d->halt)
+			{
+				Close(hWnd);
+			}
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		KillTimer(hWnd, 1);
+		d->Checked = IsChecked(hWnd, C_DONTSHOWAGAIN);
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// メッセージを表示する
+void OnceMsg(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon)
+{
+	OnceMsgEx(hWnd, title, message, show_checkbox, icon, NULL);
+}
+void OnceMsgEx(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon, bool *halt)
+{
+	ONCEMSG_DLG d;
+	UINT hash;
+	char valuename[MAX_PATH];
+	bool b_dummy = false;
+	// 引数チェック
+	if (title == NULL)
+	{
+		title = title_bar;
+	}
+	if (message == NULL)
+	{
+		message = L"message";
+	}
+	if (halt == NULL)
+	{
+		halt = &b_dummy;
+	}
+
+	Zero(&d, sizeof(d));
+	d.Message = message;
+	d.Title = title;
+	d.ShowCheckbox = show_checkbox;
+	d.Icon = icon;
+	d.halt = halt;
+
+	hash = GetOnceMsgHash(title, message);
+	Format(valuename, sizeof(valuename), ONCE_MSG_REGVALUE, hash);
+
+	if (MsRegReadInt(REG_CURRENT_USER, ONCE_MSG_REGKEY, valuename) == 0)
+	{
+		switch (icon)
+		{
+		case ICO_WARNING:
+			MessageBeep(MB_ICONEXCLAMATION);
+			break;
+
+		case ICO_INFORMATION:
+			MessageBeep(MB_ICONASTERISK);
+			break;
+		}
+
+		Dialog(hWnd, D_ONCEMSG, OnceMsgProc, &d);
+
+		if (show_checkbox)
+		{
+			if (d.Checked)
+			{
+				MsRegWriteInt(REG_CURRENT_USER, ONCE_MSG_REGKEY, valuename, 1);
+			}
+		}
+	}
+}
+
+// メッセージハッシュの取得
+UINT GetOnceMsgHash(wchar_t *title, wchar_t *message)
+{
+	BUF *b;
+	UCHAR hash[SHA1_SIZE];
+	UINT ret;
+	// 引数チェック
+	if (title == NULL)
+	{
+		title = title_bar;
+	}
+	if (message == NULL)
+	{
+		message = L"message";
+	}
+
+	b = NewBuf();
+	WriteBuf(b, title, UniStrSize(title));
+	WriteBuf(b, message, UniStrSize(message));
+	HashSha1(hash, b->Buf, b->Size);
+	FreeBuf(b);
+
+	Copy(&ret, hash, sizeof(UINT));
+
+	return ret;
+}
+
+// Windows Vista のテーマを設定する
+void InitVistaWindowTheme(HWND hWnd)
+{
+	static HINSTANCE hInstDll = NULL;
+	HRESULT (WINAPI *_SetWindowTheme)(HWND, LPCWSTR, LPCWSTR) = NULL;
+
+	if (MsIsVista() == false)
+	{
+		return;
+	}
+
+	if (hInstDll == NULL)
+	{
+		hInstDll = LoadLibraryA("uxtheme.dll");
+	}
+
+	if (hInstDll == NULL)
+	{
+		return;
+	}
+
+	if (_SetWindowTheme == NULL)
+	{
+		_SetWindowTheme = (HRESULT (WINAPI *)(HWND,LPCWSTR,LPCWSTR))GetProcAddress(hInstDll, "SetWindowTheme");
+	}
+
+	if (_SetWindowTheme == NULL)
+	{
+		return;
+	}
+
+	_SetWindowTheme(hWnd, L"explorer", NULL);
+}
+
+// 現在のディレクトリに存在する可能性のある Windows ファイアウォールに登録すべき
+// すべてのアプリケーションを登録する
+// Q. 行儀が悪いのではないか?
+// A. 確かに行儀が悪いが、Windows Firewall でブロックされていることが原因で
+//    VPN ソフトウェアが使用できないという苦情メールがよく来ていたので
+//    やむを得ずこのように行うことにした。
+//    なお、Microsoft 純正のサーバーソフトや他社のサーバーソフト等もこのように
+//    して対応しているようであるから、良いのではないか。
+void RegistWindowsFirewallAll()
+{
+	MsRegistWindowsFirewallEx2(CEDAR_CLIENT_STR, "utvpnclient.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_CLIENT_STR, "utvpnclient_x64.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_CLIENT_STR, "utvpnclient_ia64.exe");
+
+	MsRegistWindowsFirewallEx2(CEDAR_CLIENT_MANAGER_STR, "utvpncmgr.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_CLIENT_MANAGER_STR, "utvpncmgr_x64.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_CLIENT_MANAGER_STR, "utvpncmgr_ia64.exe");
+
+	MsRegistWindowsFirewallEx2(CEDAR_SERVER_STR, "utvpnserver.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_SERVER_STR, "utvpnserver_x64.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_SERVER_STR, "utvpnserver_ia64.exe");
+
+	MsRegistWindowsFirewallEx2(CEDAR_CUI_STR, "utvpncmd.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_CUI_STR, "utvpncmd_x64.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_CUI_STR, "utvpncmd_ia64.exe");
+
+	MsRegistWindowsFirewallEx2(CEDAR_PRODUCT_STR, "ham.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_PRODUCT_STR, "ham_x64.exe");
+	MsRegistWindowsFirewallEx2(CEDAR_PRODUCT_STR, "ham_ia64.exe");
+}
+
+// すでに通知サービスが動作しているかどうかチェックする
+bool Win32CnCheckAlreadyExists(bool lock)
+{
+	char tmp[MAX_SIZE];
+	HANDLE hMutex;
+
+	HashInstanceNameLocal(tmp, sizeof(tmp), CLIENT_NOTIFY_SERVICE_INSTANCENAME);
+
+	hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, tmp);
+	if (hMutex != NULL)
+	{
+		CloseHandle(hMutex);
+		return true;
+	}
+
+	if (lock == false)
+	{
+		return false;
+	}
+
+	hMutex = CreateMutex(NULL, FALSE, tmp);
+	if (hMutex == NULL)
+	{
+		CloseHandle(hMutex);
+		return true;
+	}
+
+	return false;
+}
+
+// hamcore 内の EXE の実行
+bool ExecuteHamcoreExe(char *name)
+{
+	BUF *b;
+	wchar_t tmp[MAX_PATH];
+	char tmp2[MAX_PATH];
+	UCHAR hash[MD5_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	b = ReadDump(name);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	Hash(hash, name, StrLen(name), false);
+	BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
+	UniFormat(tmp, sizeof(tmp), L"%s\\tmp_%S.exe", MsGetMyTempDirW(), tmp2);
+	SeekBuf(b, 0, 0);
+	DumpBufW(b, tmp);
+
+	FreeBuf(b);
+
+	return RunW(tmp, NULL, false, false);
+}
+
+// イースターエッグの表示
+void ShowEasterEgg(HWND hWnd)
+{
+}
+
+void KakushiThread(THREAD *thread, void *param)
+{
+	KAKUSHI *k;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	k = (KAKUSHI *)param;
+
+	k->Thread = thread;
+	AddRef(k->Thread->ref);
+	NoticeThreadInit(thread);
+
+	Dialog(NULL, D_CM_KAKUSHI, KakushiDlgProc, k);
+	k->hWnd = NULL;
+}
+
+KAKUSHI *InitKakushi()
+{
+	THREAD *t;
+	KAKUSHI *k = ZeroMalloc(sizeof(KAKUSHI));
+
+	t = NewThread(KakushiThread, k);
+
+	WaitThreadInit(t);
+	ReleaseThread(t);
+
+	return k;
+}
+
+UINT KakushiDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	KAKUSHI *k = (KAKUSHI *)param;
+	UINT64 now;
+	bool b;
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetText(hWnd, S_INFO, _UU("CM_VLAN_CREATING"));
+
+		b = false;
+
+		if (MsIsVista())
+		{
+			if (_GETLANG() == 0)
+			{
+				SetFont(hWnd, S_INFO, GetFont("Meiryo", 11, false, false, false, false));
+				b = true;
+			}
+			else if (_GETLANG() == 2)
+			{
+				SetFont(hWnd, S_INFO, GetFont("Microsoft YaHei", 11, false, false, false, false));
+				b = true;
+			}
+		}
+
+		if (b == false)
+		{
+			DlgFont(hWnd, S_INFO, 11, false);
+		}
+
+		SetTimer(hWnd, 1, 50, NULL);
+		k->hWnd = hWnd;
+
+		k->Span = 20 * 1000;
+		k->StartTick = Tick64();
+
+		SetRange(hWnd, P_PROGRESS, 0, (UINT)k->Span);
+
+	case WM_APP + 9821:
+		now = Tick64();
+
+		if (((k->StartTick + k->Span) <= now) || k->Halt)
+		{
+			EndDialog(hWnd, 0);
+			break;
+		}
+
+		SetPos(hWnd, P_PROGRESS, (UINT)(now - k->StartTick));
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			AllowSetForegroundWindow(ASFW_ANY);
+			SetForegroundWindow(hWnd);
+			SetActiveWindow(hWnd);
+
+			now = Tick64();
+
+			if (((k->StartTick + k->Span) <= now) || k->Halt)
+			{
+				EndDialog(hWnd, 0);
+				break;
+			}
+
+			SetPos(hWnd, P_PROGRESS, (UINT)(now - k->StartTick));
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		return 1;
+	}
+
+	return 0;
+}
+
+// 隠し画面解放
+void FreeKakushi(KAKUSHI *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	k->Halt = true;
+
+	if (k->hWnd != NULL)
+	{
+		PostMessage(k->hWnd, WM_APP + 9821, 0, 0);
+	}
+
+	WaitThread(k->Thread, INFINITE);
+	ReleaseThread(k->Thread);
+
+	Free(k);
+}
+
+// TCP/IP 最適化選択ダイアログプロシージャ
+UINT TcpMsgDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetIcon(hWnd, 0, ICO_SETUP);
+		//DlgFont(hWnd, R_OPTIMIZE, 0, true);
+
+		Check(hWnd, R_NO, true);
+
+		if (g_tcpip_topmost)
+		{
+			Top(hWnd);
+		}
+
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			ret = 1;
+			if (IsChecked(hWnd, R_MANUAL))
+			{
+				ret = 2;
+			}
+			else if (IsChecked(hWnd, R_NO))
+			{
+				ret = 0;
+			}
+
+			EndDialog(hWnd, ret);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		return 1;
+	}
+
+	return 0;
+}
+
+// ダイアログ初期化
+void TcpIpDlgInit(HWND hWnd)
+{
+	MS_TCP tcp;
+
+	SetIcon(hWnd, 0, ICO_SETUP);
+
+	MsGetTcpConfig(&tcp);
+
+	Check(hWnd, R_RECV_DISABLE, tcp.RecvWindowSize == 0);
+	Check(hWnd, R_RECV_ENABLE, tcp.RecvWindowSize != 0);
+	SetInt(hWnd, E_RECV, tcp.RecvWindowSize != 0 ? tcp.RecvWindowSize : DEFAULT_TCP_MAX_WINDOW_SIZE_RECV);
+
+	Check(hWnd, R_SEND_DISABLE, tcp.SendWindowSize == 0);
+	Check(hWnd, R_SEND_ENABLE, tcp.SendWindowSize != 0);
+	SetInt(hWnd, E_SEND, tcp.SendWindowSize != 0 ? tcp.SendWindowSize : DEFAULT_TCP_MAX_WINDOW_SIZE_SEND);
+
+	TcpIpDlgUpdate(hWnd);
+}
+
+// ダイアログ更新
+void TcpIpDlgUpdate(HWND hWnd)
+{
+	bool ok = true;
+
+	SetEnable(hWnd, E_RECV, IsChecked(hWnd, R_RECV_ENABLE));
+	SetEnable(hWnd, S_RECV, IsChecked(hWnd, R_RECV_ENABLE));
+	SetEnable(hWnd, E_SEND, IsChecked(hWnd, R_SEND_ENABLE));
+	SetEnable(hWnd, S_SEND, IsChecked(hWnd, R_SEND_ENABLE));
+
+	if (IsChecked(hWnd, R_RECV_ENABLE) && GetInt(hWnd, E_RECV) < 1454)
+	{
+		ok = false;
+	}
+
+	if (IsChecked(hWnd, R_SEND_ENABLE) && GetInt(hWnd, E_SEND) < 1454)
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// TCP/IP ダイアログプロシージャ
+UINT TcpIpDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	MS_TCP tcp, old;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		TcpIpDlgInit(hWnd);
+
+		if (g_tcpip_topmost)
+		{
+			Top(hWnd);
+		}
+
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_RECV_DISABLE:
+		case R_RECV_ENABLE:
+		case R_SEND_DISABLE:
+		case R_SEND_ENABLE:
+		case E_RECV:
+		case E_SEND:
+			TcpIpDlgUpdate(hWnd);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			Zero(&tcp, sizeof(tcp));
+
+			if (IsChecked(hWnd, R_RECV_ENABLE))
+			{
+				tcp.RecvWindowSize = GetInt(hWnd, E_RECV);
+			}
+
+			if (IsChecked(hWnd, R_SEND_ENABLE))
+			{
+				tcp.SendWindowSize = GetInt(hWnd, E_SEND);
+			}
+
+			MsGetTcpConfig(&old);
+
+			MsSetTcpConfig(&tcp);
+			MsSaveTcpConfigReg(&tcp);
+
+			EndDialog(hWnd, true);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+
+		case R_RECV_ENABLE:
+			FocusEx(hWnd, E_RECV);
+			break;
+
+		case R_SEND_ENABLE:
+			FocusEx(hWnd, E_SEND);
+			break;
+
+		case B_RECV:
+			SetInt(hWnd, E_RECV, DEFAULT_TCP_MAX_WINDOW_SIZE_RECV);
+			Check(hWnd, R_RECV_DISABLE, false);
+			Check(hWnd, R_RECV_ENABLE, true);
+			TcpIpDlgUpdate(hWnd);
+			FocusEx(hWnd, E_RECV);
+			break;
+
+		case B_SEND:
+			SetInt(hWnd, E_SEND, DEFAULT_TCP_MAX_WINDOW_SIZE_SEND);
+			Check(hWnd, R_SEND_DISABLE, false);
+			Check(hWnd, R_SEND_ENABLE, true);
+			TcpIpDlgUpdate(hWnd);
+			FocusEx(hWnd, E_SEND);
+			break;
+
+		case B_DELETE:
+			Zero(&tcp, sizeof(tcp));
+			MsSetTcpConfig(&tcp);
+			MsDeleteTcpConfigReg();
+			EndDialog(hWnd, 0);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 64 bit に関する警告ダイアログ
+UINT Cpu64DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetIcon(hWnd, 0, ICO_WARNING);
+		DlgFont(hWnd, S_BOLD, 9, true);
+		SetTimer(hWnd, 1, 30 * 1000, NULL);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			Command(hWnd, IDOK);
+			break;
+		}
+
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// 64 bit に関する警告ダイアログの表示
+void ShowCpu64Warning()
+{
+	Dialog(NULL, D_CPU64_WARNING, Cpu64DlgProc, NULL);
+}
+
+// TCP/IP 設定ユーティリティの表示
+void ShowTcpIpConfigUtil(HWND hWnd, bool util_mode)
+{
+	if (MsIsTcpConfigSupported() == false)
+	{
+		if (util_mode)
+		{
+			// 現在の OS ではサポートされていない旨のメッセージを表示
+			if (MsIsAdmin() == false)
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("TCPOPT_NOT_ADMIN"));
+			}
+			else
+			{
+				MsgBox(hWnd, MB_ICONINFORMATION, _UU("TCPOPT_NOT_SUPPORTED"));
+			}
+		}
+		return;
+	}
+
+	if (util_mode == false)
+	{
+		// utvpncmd を起動してすぐに終了する
+		wchar_t tmp[MAX_PATH];
+		wchar_t exedir[MAX_PATH];
+		HANDLE h;
+
+		GetExeDirW(exedir, sizeof(exedir));
+
+		if (IsX64())
+		{
+			UniFormat(tmp, sizeof(tmp), L"%s\\utvpncmd_x64.exe", exedir);
+		}
+		else if (IsIA64())
+		{
+			UniFormat(tmp, sizeof(tmp), L"%s\\utvpncmd_ia64.exe", exedir);
+		}
+		else
+		{
+			UniFormat(tmp, sizeof(tmp), L"%s\\utvpncmd.exe", exedir);
+		}
+
+		if (IsFileW(tmp))
+		{
+			RunW(tmp, L"/tool /cmd:exit", true, false);
+		}
+
+		// netsh によるタスクオフローディングの無効化
+		if (MsIsVista())
+		{
+			char netsh_exe[MAX_SIZE];
+			DIRLIST *dl;
+			UINT i;
+			bool b = false;
+
+			dl = EnumDirW(exedir);
+
+			for (i = 0;i < dl->NumFiles;i++)
+			{
+				if (UniInStr(dl->File[i]->FileNameW, L"utvpnbridge") || 
+					UniInStr(dl->File[i]->FileNameW, L"utvpnserver"))
+				{
+					b = true;
+				}
+			}
+
+			FreeDir(dl);
+
+			if (b)
+			{
+				CombinePath(netsh_exe, sizeof(netsh_exe), MsGetSystem32Dir(), "netsh.exe");
+
+				Run(netsh_exe, "netsh int ipv6 set global taskoffload=disabled", true, false);
+				Run(netsh_exe, "netsh int ipv4 set global taskoffload=disabled", true, false);
+			}
+		}
+
+		// Windows Firewall 登録
+		RegistWindowsFirewallAll();
+
+		SleepThread(1000);
+
+		// utvpnclient.exe /uihelp の起動
+		h = CmExecUiHelperMain();
+		if (h != NULL)
+		{
+			CloseHandle(h);
+		}
+
+		if (Is64() == false)
+		{
+			if (MsIs64BitWindows())
+			{
+				// 32 bit 版を 64 bit Windows 上で使用している場合は
+				// 警告メッセージを表示する
+				ShowCpu64Warning();
+			}
+		}
+
+		if (MsIsAdmin())
+		{
+			if (MsIsVista())
+			{
+				// Windows Vista でインストールする場合は
+				// MMCSS のネットワーク制限を解除する
+				if (MsIsMMCSSNetworkThrottlingEnabled())
+				{
+					MsSetMMCSSNetworkThrottlingEnable(false);
+				}
+			}
+		}
+	}
+
+	if (util_mode == false && MsIsShouldShowTcpConfigApp() == false)
+	{
+		return;
+	}
+
+	if (util_mode == false)
+	{
+		// 2006.07.04 nobori
+		// インストーラ上では TCP/IP 最適化ユーティリティは表示しないことにした
+		return;
+	}
+
+	g_tcpip_topmost = util_mode ? false : true;
+
+	if (util_mode == false)
+	{
+		UINT ret = Dialog(hWnd, D_TCP_MSG, TcpMsgDlgProc, NULL);
+
+		if (ret == 0)
+		{
+			MS_TCP tcp;
+
+			Zero(&tcp, sizeof(tcp));
+			MsGetTcpConfig(&tcp);
+			MsSaveTcpConfigReg(&tcp);
+			return;
+		}
+		else if (ret == 1)
+		{
+			MS_TCP tcp;
+
+			Zero(&tcp, sizeof(tcp));
+
+			tcp.RecvWindowSize = DEFAULT_TCP_MAX_WINDOW_SIZE_RECV;
+			tcp.SendWindowSize = DEFAULT_TCP_MAX_WINDOW_SIZE_SEND;
+			MsSetTcpConfig(&tcp);
+			MsSaveTcpConfigReg(&tcp);
+
+			return;
+		}
+	}
+
+	Dialog(hWnd, D_TCP, TcpIpDlgProc, NULL);
+}
+
+// メニューの国際化対応処理を行う (Unicode)
+void InitMenuInternationalUni(HMENU hMenu, char *prefix)
+{
+	UINT i, num;
+	// 引数チェック
+	if (hMenu == NULL || prefix == NULL)
+	{
+		return;
+	}
+
+	// メニューの項目数を取得する
+	num = GetMenuItemCount(hMenu);
+
+	// メニューを列挙する
+	for (i = 0;i < num;i++)
+	{
+		HMENU hSubMenu = GetSubMenu(hMenu, i);
+		MENUITEMINFOW info;
+		wchar_t tmp[MAX_SIZE];
+
+		if (hSubMenu != NULL)
+		{
+			// サブメニューがある場合再帰呼び出しする
+			InitMenuInternational(hSubMenu, prefix);
+		}
+
+		// メニュー項目を取得する
+		Zero(&info, sizeof(info));
+		info.cbSize = sizeof(info);
+		info.cch = sizeof(tmp);
+		info.dwTypeData = tmp;
+		info.fMask = MIIM_STRING;
+		Zero(tmp, sizeof(tmp));
+
+		if (GetMenuItemInfoW(hMenu, i, true, &info))
+		{
+			if (tmp[0] == L'@')
+			{
+				char name[256];
+				wchar_t *ret;
+
+				Format(name, sizeof(name), "%s@%S", prefix, &tmp[1]);
+
+				ret = _UU(name);
+				if (UniIsEmptyStr(ret) == false)
+				{
+					UniStrCpy(tmp, sizeof(tmp), ret);
+					info.cch = UniStrLen(tmp);
+
+					SetMenuItemInfoW(hMenu, i, true, &info);
+				}
+			}
+		}
+	}
+}
+
+// メニューの国際化対応処理を行う
+void InitMenuInternational(HMENU hMenu, char *prefix)
+{
+	UINT i, num;
+	// 引数チェック
+	if (hMenu == NULL || prefix == NULL)
+	{
+		return;
+	}
+
+	if (MsIsNt())
+	{
+		InitMenuInternationalUni(hMenu, prefix);
+		return;
+	}
+
+	// メニューの項目数を取得する
+	num = GetMenuItemCount(hMenu);
+
+	// メニューを列挙する
+	for (i = 0;i < num;i++)
+	{
+		HMENU hSubMenu = GetSubMenu(hMenu, i);
+		MENUITEMINFO info;
+		char tmp[MAX_SIZE];
+
+		if (hSubMenu != NULL)
+		{
+			// サブメニューがある場合再帰呼び出しする
+			InitMenuInternational(hSubMenu, prefix);
+		}
+
+		// メニュー項目を取得する
+		Zero(&info, sizeof(info));
+		info.cbSize = sizeof(info);
+		info.cch = sizeof(tmp);
+		info.dwTypeData = tmp;
+		info.fMask = MIIM_STRING;
+		Zero(tmp, sizeof(tmp));
+
+		if (GetMenuItemInfo(hMenu, i, true, &info))
+		{
+			if (tmp[0] == '@')
+			{
+				char name[256];
+				char *ret;
+
+				Format(name, sizeof(name), "%s@%s", prefix, &tmp[1]);
+
+				ret = _SS(name);
+				if (IsEmptyStr(ret) == false)
+				{
+					StrCpy(tmp, sizeof(tmp), ret);
+					info.cch = StrLen(tmp);
+
+					SetMenuItemInfo(hMenu, i, true, &info);
+				}
+			}
+		}
+	}
+}
+
+// ダイアログボックス用のデフォルトのフォントを取得する
+HFONT GetDialogDefaultFont()
+{
+	return GetDialogDefaultFontEx(false);
+}
+HFONT GetDialogDefaultFontEx(bool meiryo)
+{
+	char *default_font_name = _SS("DEFAULT_FONT");
+	UINT default_font_size = _II("DEFAULT_FONT_SIZE");
+
+	if (meiryo)
+	{
+		if (_GETLANG() == 2)
+		{
+			default_font_name = "Microsoft YaHei";
+		}
+		else
+		{
+			default_font_name = "Meiryo";
+		}
+	}
+
+	if (IsEmptyStr(default_font_name))
+	{
+		default_font_name = font_name;
+	}
+
+	if (default_font_size == 0)
+	{
+		default_font_size = 9;
+	}
+
+	return GetFont(default_font_name, default_font_size, false, false, false, false);
+}
+
+// ウインドウサイズとコントロールサイズを調整する
+void AdjustWindowAndControlSize(HWND hWnd)
+{
+	HFONT hDlgFont;
+	UINT dlgfont_x, dlgfont_y;
+	RECT rect, rect2;
+	LIST *o;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// 現在のウインドウのフォントを取得する
+	hDlgFont = (HFONT)SendMsg(hWnd, 0, WM_GETFONT, 0, 0);
+
+	// 現在のウインドウのフォントの幅と高さを取得する
+	CalcFontSize(hDlgFont, &dlgfont_x, &dlgfont_y);
+
+	if ((dlgfont_x == WINUI_DEFAULT_DIALOG_UNIT_X) &&
+		(dlgfont_y == WINUI_DEFAULT_DIALOG_UNIT_Y))
+	{
+		// 調整する必要が無い
+		return;
+	}
+
+	// ウインドウのサイズを調整する
+	if (GetWindowRect(hWnd, &rect))
+	{
+		if (GetClientRect(hWnd, &rect2))
+		{
+			UINT width = rect2.right - rect2.left;
+			UINT height = rect2.bottom - rect2.top;
+
+			AdjustDialogXY(&width, &height, dlgfont_x, dlgfont_y);
+
+			width += (rect.right - rect.left) - (rect2.right - rect2.left);
+			height += (rect.bottom - rect.top) - (rect2.bottom - rect2.top);
+
+			if (true)
+			{
+				HWND hParent = GetParent(hWnd);
+
+				if (hParent != NULL)
+				{
+					RECT r;
+
+					Zero(&r, sizeof(r));
+
+					if (GetWindowRect(hParent, &r))
+					{
+						RECT r2;
+
+						rect.top = r.top + GetSystemMetrics(SM_CYCAPTION);
+
+						Zero(&r2, sizeof(r2));
+						if (SystemParametersInfo(SPI_GETWORKAREA, 0, &r2, 0))
+						{
+							if (r2.bottom < (rect.top + (int)height))
+							{
+								rect.top -= (rect.top + (int)height) - r2.bottom;
+
+								if (rect.top < 0)
+								{
+									rect.top = 0;
+								}
+							}
+						}
+					}
+				}
+			}
+
+			MoveWindow(hWnd, rect.left, rect.top, width, height, false);
+		}
+	}
+
+	// 子ウインドウを列挙する
+	o = EnumAllChildWindowEx(hWnd, false, true, true);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		// 子ウインドウのサイズを調整する
+		HWND h = *((HWND *)LIST_DATA(o, i));
+		HWND hWndParent = GetParent(h);
+		RECT current_rect;
+		char class_name[MAX_PATH];
+		bool is_image = false;
+
+		// クラス名を取得
+		Zero(class_name, sizeof(class_name));
+		GetClassNameA(h, class_name, sizeof(class_name));
+
+		if (StrCmpi(class_name, "static") == 0)
+		{
+			if (SendMsg(h, 0, STM_GETIMAGE, IMAGE_BITMAP, 0) != 0 ||
+				SendMsg(h, 0, STM_GETIMAGE, IMAGE_ICON, 0) != 0 ||
+				SendMsg(h, 0, STM_GETICON, 0, 0) != 0)
+			{
+				is_image = true;
+			}
+		}
+
+		// 位置を取得
+		if (GetWindowRect(h, &current_rect))
+		{
+			// クライアント座標に変換
+			POINT p1, p2;
+
+			p1.x = current_rect.left;
+			p1.y = current_rect.top;
+
+			p2.x = current_rect.right;
+			p2.y = current_rect.bottom;
+
+			ScreenToClient(hWndParent, &p1);
+			ScreenToClient(hWndParent, &p2);
+
+			// 位置を調整
+			AdjustDialogXY(&p1.x, &p1.y, dlgfont_x, dlgfont_y);
+			AdjustDialogXY(&p2.x, &p2.y, dlgfont_x, dlgfont_y);
+
+			if (is_image)
+			{
+				p2.x = p1.x + (current_rect.right - current_rect.left);
+				p2.y = p1.y + (current_rect.bottom - current_rect.top);
+			}
+
+			// 移動
+			MoveWindow(h, p1.x, p1.y, p2.x - p1.x, p2.y - p1.y, false);
+		}
+	}
+
+	FreeWindowList(o);
+}
+
+// x と y の値をフォントに応じて調整する
+void AdjustDialogXY(UINT *x, UINT *y, UINT dlgfont_x, UINT dlgfont_y)
+{
+	if (x != NULL)
+	{
+		*x = (UINT)(((double)*x) * (double)WINUI_DEFAULT_DIALOG_UNIT_X / (double)dlgfont_x);
+	}
+
+	if (y != NULL)
+	{
+		*y = (UINT)(((double)*y) * (double)WINUI_DEFAULT_DIALOG_UNIT_Y / (double)dlgfont_y);
+	}
+}
+
+// ダイアログボックスの国際化対応処理を行う
+void InitDialogInternational(HWND hWnd, void *param)
+{
+	LIST *o;
+	UINT i;
+	bool is_managed_dialog = false;
+	char caption[MAX_PATH];
+	char *dialog_name;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	AdjustWindowAndControlSize(hWnd);
+
+	GetTxtA(hWnd, 0, caption, sizeof(caption));
+	if (caption[0] == '@')
+	{
+		dialog_name = &caption[1];
+
+		is_managed_dialog = true;
+	}
+
+	// すべてのウインドウハンドルを列挙する
+	o = EnumAllChildWindow(hWnd);
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		HWND hControl = *((HWND *)LIST_DATA(o, i));
+
+		if (hControl != NULL)
+		{
+			HFONT hFont = GetDialogDefaultFontEx(param && ((DIALOG_PARAM *)param)->meiryo);
+
+			SetFont(hControl, 0, hFont);
+
+			if (MsIsVista())
+			{
+				char classname[MAX_PATH];
+				GetClassNameA(hControl, classname, sizeof(classname));
+
+				if (StrCmpi(classname, "syslistview32") == 0)
+				{
+					InitVistaWindowTheme(hControl);
+				}
+			}
+
+			if (is_managed_dialog)
+			{
+				char str[MAX_PATH];
+
+				GetTxtA(hControl, 0, str, sizeof(str));
+				if (str[0] == '@')
+				{
+					char *control_name = &str[1];
+					char tmp[MAX_PATH];
+					wchar_t *ret;
+
+					StrCpy(tmp, sizeof(tmp), dialog_name);
+					StrCat(tmp, sizeof(tmp), "@");
+
+					if (hWnd == hControl)
+					{
+						StrCat(tmp, sizeof(tmp), "CAPTION");
+					}
+					else
+					{
+						StrCat(tmp, sizeof(tmp), control_name);
+					}
+
+					ret = _UU(tmp);
+
+					if (ret != NULL && UniIsEmptyStr(ret) == false)
+					{
+						SetText(hControl, 0, ret);
+					}
+				}
+			}
+		}
+	}
+
+	FreeWindowList(o);
+}
+
+// 子ウインドウ列挙プロシージャ
+// ダイアログ初期化
+void StringDlgInit(HWND hWnd, STRING_DLG *s)
+{
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	SetText(hWnd, E_STRING, s->String);
+
+	SetIcon(hWnd, S_ICON, s->Icon);
+	SetText(hWnd, S_INFO, s->Info);
+	SetText(hWnd, 0, s->Title);
+
+	FocusEx(hWnd, E_STRING);
+
+	StringDlgUpdate(hWnd, s);
+}
+
+// ダイアログコントロール更新
+void StringDlgUpdate(HWND hWnd, STRING_DLG *s)
+{
+	wchar_t *tmp;
+	bool b = true;
+	// 引数チェック
+	if (hWnd == NULL || s == NULL)
+	{
+		return;
+	}
+
+	tmp = GetText(hWnd, E_STRING);
+
+	if (tmp != NULL)
+	{
+		if (s->AllowEmpty == false)
+		{
+			if (UniIsEmptyStr(tmp))
+			{
+				b = false;
+			}
+		}
+
+		if (s->AllowUnsafe == false)
+		{
+			if (IsSafeUniStr(tmp) == false)
+			{
+				b = false;
+			}
+		}
+
+		Free(tmp);
+	}
+
+	SetEnable(hWnd, IDOK, b);
+}
+
+// 文字列ダイアログプロシージャ
+UINT StringDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	STRING_DLG *s = (STRING_DLG *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		StringDlgInit(hWnd, s);
+		break;
+
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case E_STRING:
+			StringDlgUpdate(hWnd, s);
+			break;
+		}
+
+		switch (wParam)
+		{
+		case IDOK:
+			GetTxt(hWnd, E_STRING, s->String, sizeof(s->String));
+			EndDialog(hWnd, true);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 文字列ダイアログを表示する
+wchar_t *StringDlg(HWND hWnd, wchar_t *title, wchar_t *info, wchar_t *def, UINT icon, bool allow_empty, bool allow_unsafe)
+{
+	STRING_DLG s;
+	// 引数チェック
+	if (title == NULL)
+	{
+		title = _UU("DLG_STRING_DEFTITLE");
+	}
+	if (info == NULL)
+	{
+		info = _UU("DLG_STRING_DEFINFO");
+	}
+	if (def == NULL)
+	{
+		def = L"";
+	}
+	if (icon == 0)
+	{
+		icon = ICO_NULL;
+	}
+
+	Zero(&s, sizeof(s));
+	s.Icon = icon;
+	s.Info = info;
+	s.Title = title;
+	s.Icon = icon;
+	UniStrCpy(s.String, sizeof(s.String), def);
+	s.AllowEmpty = allow_empty;
+	s.AllowUnsafe = allow_unsafe;
+
+	if (Dialog(hWnd, D_STRING, StringDlgProc, &s) == false)
+	{
+		return NULL;
+	}
+	else
+	{
+		return CopyUniStr(s.String);
+	}
+}
+char *StringDlgA(HWND hWnd, wchar_t *title, wchar_t *info, char *def, UINT icon, bool allow_empty, bool allow_unsafe)
+{
+	wchar_t unidef[MAX_SIZE];
+	wchar_t *tmp;
+	char *ret;
+	if (def == NULL)
+	{
+		def = "";
+	}
+
+	StrToUni(unidef, sizeof(unidef), def);
+
+	tmp = StringDlg(hWnd, title, info, unidef, icon, allow_empty, allow_unsafe);
+	if (tmp == NULL)
+	{
+		return NULL;
+	}
+
+	ret = CopyUniToStr(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// 再起動ダイアログ
+UINT Win9xRebootDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	WIN9X_REBOOT_DLG *d = (WIN9X_REBOOT_DLG *)param;
+	UINT64 now;
+	wchar_t tmp[MAX_PATH];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		d->StartTime = Tick64();
+		SetRange(hWnd, P_PROGRESS, 0, d->TotalTime);
+		SetTimer(hWnd, 1, 100, NULL);
+		goto UPDATE;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+UPDATE:
+			now = Tick64();
+			if ((d->StartTime + (UINT64)d->TotalTime) <= now)
+			{
+				KillTimer(hWnd, 1);
+				UniStrCpy(tmp, sizeof(tmp), _UU("DLG_REBOOT_INFO_2"));
+				SetText(hWnd, S_INFO, tmp);
+				if (MsShutdown(true, false) == false)
+				{
+					MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_REBOOT_ERROR"));
+				}
+				EndDialog(hWnd, 0);
+			}
+			else
+			{
+				SetPos(hWnd, P_PROGRESS, (UINT)(now - d->StartTime));
+				UniFormat(tmp, sizeof(tmp), _UU("DLG_REBOOT_INFO"),
+					(UINT)((UINT64)d->TotalTime - (now - d->StartTime)) / 1000 + 1);
+				SetText(hWnd, S_INFO, tmp);
+			}
+
+			break;
+		}
+		break;
+	}
+	return 0;
+}
+
+// 再起動用スレッド
+void Win9xRebootThread(THREAD *t, void *p)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	Win9xReboot(NULL);
+}
+
+// 自動的に再起動する
+void Win9xReboot(HWND hWnd)
+{
+	WIN9X_REBOOT_DLG d;
+
+	Zero(&d, sizeof(d));
+	d.TotalTime = 10 * 1000;
+
+	Dialog(hWnd, D_WIN9X_REBOOT, Win9xRebootDlgProc, &d);
+}
+
+// バージョン情報の初期化
+void AboutDlgInit(HWND hWnd, WINUI_ABOUT *a)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || a == NULL)
+	{
+		return;
+	}
+
+	UniFormat(tmp, sizeof(tmp), _UU("ABOUT_CAPTION"), a->ProductName);
+	SetText(hWnd, 0, tmp);
+
+	SetFont(hWnd, S_VERSION, GetFont(NULL, 15, true, false, false, false));
+
+	SetTextA(hWnd, S_VERSION, a->ProductName);
+
+	SetFont(hWnd, S_VERSION2, GetFont("Verdana", 13, false, false, false, false));
+	UniFormat(tmp, sizeof(tmp),
+		L"Version %u.%02u Build %u ",
+		a->Cedar->Version / 100, a->Cedar->Version % 100,
+		a->Cedar->Build);
+	SetText(hWnd, S_VERSION2, tmp);
+
+	SetFont(hWnd, S_BUILD, GetFont("Verdana", 11, false, false, true, false));
+	SetTextA(hWnd, S_BUILD, a->Cedar->BuildInfo);
+
+	SendMsg(hWnd, S_LOGO, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)LoadBitmap(hDll, MAKEINTRESOURCE(a->Bitmap)));
+}
+
+// バージョン情報プロシージャ
+UINT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	WINUI_ABOUT *a = (WINUI_ABOUT *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		AboutDlgInit(hWnd, a);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			if ((GetKeyState(VK_SHIFT) & 0x8000) &&
+				(GetKeyState(VK_CONTROL) & 0x8000) &&
+				(GetKeyState(VK_MENU) & 0x8000))
+			{
+				ShowEasterEgg(hWnd);
+			}
+			EndDialog(hWnd, true);
+			break;
+		case B_WEB:
+			ShellExecute(hWnd, "open", _SS("SE_COMPANY_URL"), NULL, NULL, SW_SHOW);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// バージョン情報 (古い形式)
+void About(HWND hWnd, CEDAR *cedar, char *product_name, UINT bitmap)
+{
+	WINUI_ABOUT a;
+	// 引数チェック
+	if (cedar == NULL || product_name == NULL || bitmap == 0)
+	{
+		return;
+	}
+
+	Zero(&a, sizeof(a));
+	a.Bitmap = bitmap;
+	a.Cedar = cedar;
+	a.ProductName = product_name;
+
+	Dialog(hWnd, D_ABOUT, AboutDlgProc, &a);
+}
+
+// テスト
+void UiTest()
+{
+}
+
+// IP アドレスが入力されているフィルード数を調べる
+UINT IpGetFilledNum(HWND hWnd, UINT id)
+{
+	UINT ret;
+	DWORD value;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
+
+	return ret;
+}
+
+// IP アドレスが入力されているかどうか調べる
+bool IpIsFilled(HWND hWnd, UINT id)
+{
+	UINT ret;
+	DWORD value;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
+
+	if (ret != 4)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+// IP アドレスのクリア
+void IpClear(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, IPM_CLEARADDRESS, 0, 0);
+}
+
+// IP アドレスの取得
+UINT IpGet(HWND hWnd, UINT id)
+{
+	UINT ret;
+	DWORD value;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
+
+	if (ret != 4)
+	{
+		return 0;
+	}
+	else
+	{
+		return Endian32((UINT)value);
+	}
+}
+
+// IP アドレスのセット
+void IpSet(HWND hWnd, UINT id, UINT ip)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, IPM_SETADDRESS, 0, Endian32(ip));
+}
+
+// レジストリに候補を書き込む
+void WriteCandidateToReg(UINT root, char *key, LIST *o, char *name)
+{
+	BUF *b;
+	// 引数チェック
+	if (key == NULL || o == NULL || name == NULL)
+	{
+		return;
+	}
+
+	b = CandidateToBuf(o);
+	if (b == NULL)
+	{
+		return;
+	}
+
+	MsRegWriteBin(root, key, name, b->Buf, b->Size);
+
+	FreeBuf(b);
+}
+
+// レジストリから候補を読み込む
+LIST *ReadCandidateFromReg(UINT root, char *key, char *name)
+{
+	BUF *b;
+	// 引数チェック
+	if (key == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	b = MsRegReadBin(root, key, name);
+	if (b == NULL)
+	{
+		return NewCandidateList();
+	}
+	else
+	{
+		LIST *o = BufToCandidate(b);
+		FreeBuf(b);
+
+		return o;
+	}
+}
+
+// リモート接続ダイアログ初期化
+void RemoteDlgInit(HWND hWnd, WINUI_REMOTE *r)
+{
+	LIST *o;
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	SetIcon(hWnd, 0, r->Icon);
+
+	SetText(hWnd, 0, r->Caption);
+	SetText(hWnd, S_TITLE, r->Title);
+	SetIcon(hWnd, S_ICON, r->Icon);
+
+	// 候補を読み込む
+	o = ReadCandidateFromReg(REG_CURRENT_USER, r->RegKeyName, "RemoteHostCandidate");
+	r->CandidateList = o;
+
+	// 候補を表示する
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		CANDIDATE *c = LIST_DATA(o, i);
+		CbAddStr(hWnd, C_HOSTNAME, c->Str, 0);
+	}
+
+	if (r->DefaultHostname != NULL)
+	{
+		SetTextA(hWnd, C_HOSTNAME, r->DefaultHostname);
+	}
+
+	FocusEx(hWnd, C_HOSTNAME);
+
+	RemoteDlgRefresh(hWnd, r);
+}
+
+// リモート接続ダイアログ更新
+void RemoteDlgRefresh(HWND hWnd, WINUI_REMOTE *r)
+{
+	char *s;
+	bool ok = true;
+	bool localhost_mode = false;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	s = GetTextA(hWnd, C_HOSTNAME);
+	if (s != NULL)
+	{
+		Trim(s);
+		if (StrCmpi(s, "localhost") == 0 || StartWith(s, "127."))
+		{
+			localhost_mode = true;
+		}
+		Free(s);
+	}
+
+	if (localhost_mode == false)
+	{
+		Enable(hWnd, C_HOSTNAME);
+		Enable(hWnd, S_HOSTNAME);
+		Check(hWnd, R_LOCAL, false);
+	}
+	else
+	{
+		if (r->Title != _UU("NM_CONNECT_TITLE"))
+		{
+			Disable(hWnd, C_HOSTNAME);
+			Disable(hWnd, S_HOSTNAME);
+		}
+		Check(hWnd, R_LOCAL, true);
+		SetTextA(hWnd, C_HOSTNAME, "localhost");
+
+		if (r->flag1 == false)
+		{
+			Focus(hWnd, IDOK);
+		}
+	}
+
+	if (IsEmpty(hWnd, C_HOSTNAME))
+	{
+		ok = false;
+	}
+
+	SetEnable(hWnd, IDOK, ok);
+
+	r->flag1 = true;
+}
+
+// リモート接続ダイアログ OK ボタン
+void RemoteDlgOnOk(HWND hWnd, WINUI_REMOTE *r)
+{
+	char *hostname;
+	wchar_t *s;
+	LIST *o;
+	// 引数チェック
+	if (hWnd == NULL || r == NULL)
+	{
+		return;
+	}
+
+	// 入力されているホスト名を取得
+	hostname = GetTextA(hWnd, C_HOSTNAME);
+	if (hostname == NULL)
+	{
+		return;
+	}
+	Trim(hostname);
+
+	// 候補を追加
+	o = r->CandidateList;
+	s = CopyStrToUni(hostname);
+	AddCandidate(o, s, 64);
+	Free(s);
+
+	// 候補を書き込む
+	WriteCandidateToReg(REG_CURRENT_USER, r->RegKeyName, o, "RemoteHostCandidate");
+	FreeCandidateList(o);
+
+	r->Hostname = hostname;
+
+	EndDialog(hWnd, true);
+}
+
+// リモート接続ダイアログプロシージャ
+UINT RemoteDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	WINUI_REMOTE *r = (WINUI_REMOTE *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		RemoteDlgInit(hWnd, r);
+		SetTimer(hWnd, 1, 100, NULL);
+		break;
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			RemoteDlgRefresh(hWnd, r);
+			SetTimer(hWnd, 1, 100, NULL);
+			break;
+		}
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case R_LOCAL:
+			if (IsChecked(hWnd, R_LOCAL) == false)
+			{
+				SetTextA(hWnd, C_HOSTNAME, "");
+				RemoteDlgRefresh(hWnd, r);
+				FocusEx(hWnd, C_HOSTNAME);
+			}
+			else
+			{
+				SetTextA(hWnd, C_HOSTNAME, "localhost");
+				RemoteDlgRefresh(hWnd, r);
+				Focus(hWnd, IDOK);
+			}
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		case IDOK:
+			RemoteDlgOnOk(hWnd, r);
+			break;
+		}
+		switch (LOWORD(wParam))
+		{
+		case R_LOCAL:
+		case C_HOSTNAME:
+			RemoteDlgRefresh(hWnd, r);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		FreeCandidateList(r->CandidateList);
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// リモート接続ダイアログ
+char *RemoteDlg(HWND hWnd, char *regkey, UINT icon, wchar_t *caption, wchar_t *title, char *default_host)
+{
+	WINUI_REMOTE r;
+	// 引数チェック
+	if (regkey == NULL)
+	{
+		regkey = "Software\\SoftEther Corporation\\SoftEther UT-VPN\\WinUI Common Module";
+	}
+	if (caption == NULL)
+	{
+		caption = _UU("REMOTE_DEF_CAPTION");
+	}
+	if (title == NULL)
+	{
+		title = _UU("REMOTE_DEF_TITLE");
+	}
+	if (icon == 0)
+	{
+		icon = ICO_INTERNET;
+	}
+
+	Zero(&r, sizeof(r));
+	r.RegKeyName = regkey;
+	r.Caption = caption;
+	r.Title = title;
+	r.Icon = icon;
+	r.DefaultHostname = default_host;
+
+	if (Dialog(hWnd, D_REMOTE, RemoteDlgProc, &r) == false)
+	{
+		return NULL;
+	}
+
+	return r.Hostname;
+}
+
+// ウインドウの検索プロシージャ
+bool CALLBACK SearchWindowEnumProc(HWND hWnd, LPARAM lParam)
+{
+	if (hWnd != NULL && lParam != 0)
+	{
+		wchar_t *s = GetText(hWnd, 0);
+		SEARCH_WINDOW_PARAM *p = (SEARCH_WINDOW_PARAM *)lParam;
+		if (s != NULL)
+		{
+			if (UniStrCmpi(p->caption, s) == 0)
+			{
+				p->hWndFound = hWnd;
+			}
+			Free(s);
+		}
+	}
+	return true;
+}
+
+// ウインドウの検索
+HWND SearchWindow(wchar_t *caption)
+{
+	SEARCH_WINDOW_PARAM p;
+	// 引数チェック
+	if (caption == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&p, sizeof(p));
+	p.caption = caption;
+	p.hWndFound = NULL;
+
+	EnumWindows(SearchWindowEnumProc, (LPARAM)&p);
+
+	return p.hWndFound;
+}
+
+// 指定したプロセスにフォアグラウンドウインドウになることを許可
+void AllowFGWindow(UINT process_id)
+{
+	if (process_id == 0)
+	{
+		return;
+	}
+
+	if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) &&
+		GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+	{
+		AllowSetForegroundWindow(process_id);
+	}
+}
+
+// アイテムのリネーム
+void LvRename(HWND hWnd, UINT id, UINT pos)
+{
+	// 引数チェック
+	if (hWnd == NULL || pos == INFINITE)
+	{
+		return;
+	}
+
+	ListView_EditLabel(DlgItem(hWnd, id), pos);
+}
+
+// メニューを表示する
+void PrintMenu(HWND hWnd, HMENU hMenu)
+{
+	POINT p;
+	// 引数チェック
+	if (hMenu == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	GetCursorPos(&p);
+
+	TrackPopupMenu(hMenu, TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
+}
+
+// メニューからショートカット文字列を削除する
+void RemoveShortcutKeyStrFromMenu(HMENU hMenu)
+{
+	UINT i, num;
+	// 引数チェック
+	if (hMenu == NULL)
+	{
+		return;
+	}
+
+	num = GetMenuNum(hMenu);
+	for (i = 0;i < num;i++)
+	{
+		wchar_t *str = GetMenuStr(hMenu, i);
+		if (str != NULL)
+		{
+			UINT j, len;
+			len = UniStrLen(str);
+			for (j = 0;j < len;j++)
+			{
+				if (str[j] == L'\t')
+				{
+					str[j] = 0;
+				}
+			}
+			SetMenuStr(hMenu, i, str);
+			Free(str);
+		}
+	}
+}
+
+// メニュー内の項目数を取得する
+UINT GetMenuNum(HMENU hMenu)
+{
+	UINT ret;
+	// 引数チェック
+	if (hMenu == NULL)
+	{
+		return 0;
+	}
+
+	ret = GetMenuItemCount(hMenu);
+	if (ret == INFINITE)
+	{
+		return 0;
+	}
+	else
+	{
+		return ret;
+	}
+}
+
+// メニュー内の文字列を設定する
+void SetMenuStr(HMENU hMenu, UINT pos, wchar_t *str)
+{
+	MENUITEMINFOW info;
+	// 引数チェック
+	if (hMenu == NULL || pos == INFINITE || str == NULL)
+	{
+		return;
+	}
+
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(str);
+		SetMenuStrA(hMenu, pos, s);
+		Free(s);
+		return;
+	}
+
+	Zero(&info, sizeof(info));
+	info.cbSize = sizeof(info);
+	info.fMask = MIIM_STRING;
+	info.dwTypeData = str;
+	SetMenuItemInfoW(hMenu, pos, true, &info);
+}
+void SetMenuStrA(HMENU hMenu, UINT pos, char *str)
+{
+	MENUITEMINFOA info;
+	// 引数チェック
+	if (hMenu == NULL || pos == INFINITE || str == NULL)
+	{
+		return;
+	}
+
+	Zero(&info, sizeof(info));
+	info.cbSize = sizeof(info);
+	info.fMask = MIIM_STRING;
+	info.dwTypeData = str;
+	SetMenuItemInfoA(hMenu, pos, true, &info);
+}
+
+// メニュー内の文字列を取得する
+wchar_t *GetMenuStr(HMENU hMenu, UINT pos)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hMenu == NULL || pos == INFINITE)
+	{
+		return NULL;
+	}
+	if (MsIsNt() == false)
+	{
+		char *s = GetMenuStrA(hMenu, pos);
+		if (s == NULL)
+		{
+			return NULL;
+		}
+		else
+		{
+			wchar_t *ret = CopyStrToUni(s);
+			Free(s);
+			return ret;
+		}
+	}
+
+	if (GetMenuStringW(hMenu, pos, tmp, sizeof(tmp), MF_BYPOSITION) == 0)
+	{
+		return NULL;
+	}
+
+	return UniCopyStr(tmp);
+}
+char *GetMenuStrA(HMENU hMenu, UINT pos)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hMenu == NULL || pos == INFINITE)
+	{
+		return NULL;
+	}
+
+	if (GetMenuString(hMenu, pos, tmp, sizeof(tmp), MF_BYPOSITION) == 0)
+	{
+		return NULL;
+	}
+
+	return CopyStr(tmp);
+}
+
+// メニュー項目を太字にする
+void SetMenuItemBold(HMENU hMenu, UINT pos, bool bold)
+{
+	MENUITEMINFO info;
+	// 引数チェック
+	if (hMenu == NULL || pos == INFINITE)
+	{
+		return;
+	}
+
+	Zero(&info, sizeof(info));
+	info.cbSize = sizeof(info);
+	info.fMask = MIIM_STATE;
+
+	if (GetMenuItemInfo(hMenu, pos, true, &info) == false)
+	{
+		return;
+	}
+
+	if (bold)
+	{
+		info.fState |= MFS_DEFAULT;
+	}
+	else
+	{
+		info.fState = info.fState & ~MFS_DEFAULT;
+	}
+
+	SetMenuItemInfo(hMenu, pos, true, &info);
+}
+
+// メニュー項目を有効 / 無効にする
+void SetMenuItemEnable(HMENU hMenu, UINT pos, bool enable)
+{
+	MENUITEMINFO info;
+	// 引数チェック
+	if (hMenu == NULL || pos == INFINITE)
+	{
+		return;
+	}
+
+	Zero(&info, sizeof(info));
+	info.cbSize = sizeof(info);
+	info.fMask = MIIM_STATE;
+
+	if (GetMenuItemInfo(hMenu, pos, true, &info) == false)
+	{
+		return;
+	}
+
+	if (enable)
+	{
+		info.fState |= MFS_ENABLED;
+		info.fState = info.fState & ~MFS_DISABLED;
+	}
+	else
+	{
+		info.fState |= MFS_DISABLED;
+		info.fState = info.fState & ~MFS_ENABLED;
+	}
+
+	SetMenuItemInfo(hMenu, pos, true, &info);
+}
+
+// メニュー項目を削除する
+void DeleteMenuItem(HMENU hMenu, UINT pos)
+{
+	// 引数チェック
+	if (hMenu == NULL || pos == INFINITE)
+	{
+		return;
+	}
+
+	DeleteMenu(hMenu, pos, MF_BYPOSITION);
+}
+
+// メニュー内の ID から位置を取得する
+UINT GetMenuItemPos(HMENU hMenu, UINT id)
+{
+	UINT num, i;
+	// 引数チェック
+	if (hMenu == NULL)
+	{
+		return INFINITE;
+	}
+
+	num = GetMenuItemCount(hMenu);
+	if (num == INFINITE)
+	{
+		return INFINITE;
+	}
+
+	for (i = 0;i < num;i++)
+	{
+		if (GetMenuItemID(hMenu, i) == id)
+		{
+			return i;
+		}
+	}
+
+	return INFINITE;
+}
+
+// サブメニューを取得
+HMENU LoadSubMenu(UINT menu_id, UINT pos, HMENU *parent_menu)
+{
+	HMENU h = LoadMenu(hDll, MAKEINTRESOURCE(menu_id));
+	HMENU ret;
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	ret = GetSubMenu(h, pos);
+
+	if (parent_menu != NULL)
+	{
+		*parent_menu = h;
+	}
+
+	return ret;
+}
+
+// ユーザーインターフェイスの DLL を取得
+HINSTANCE GetUiDll()
+{
+	return hDll;
+}
+
+// 接続エラーダイアログプロシージャ
+UINT ConnectErrorDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UI_CONNECTERROR_DLG *p = (UI_CONNECTERROR_DLG *)param;
+	wchar_t tmp[1024];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		if (p->Err == ERR_DISCONNECTED || p->Err == ERR_SESSION_TIMEOUT)
+		{
+			// 接続が切断された旨のメッセージ
+			SetText(hWnd, S_TITLE, _UU("ERRDLG_DISCONNECTED_MSG"));
+		}
+		if (p->HideWindow)
+		{
+			Hide(hWnd, R_HIDE);
+		}
+		FormatText(hWnd, 0, p->AccountName);
+		FormatText(hWnd, S_TITLE, p->ServerName);
+		UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_ERRMSG"), p->Err, _E(p->Err));
+		SetText(hWnd, E_ERROR, tmp);
+
+		SetIcon(hWnd, 0, ICO_SERVER_OFFLINE);
+
+		if (p->RetryIntervalSec == 0)
+		{
+			SetText(hWnd, S_COUNTDOWN, _UU("ERRDLG_INFORMATION"));
+			Hide(hWnd, P_PROGRESS);
+			Hide(hWnd, S_RETRYINFO);
+		}
+		else
+		{
+			if (p->RetryLimit != INFINITE)
+			{
+				UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRY_INFO_1"), p->CurrentRetryCount, p->RetryLimit);
+			}
+			else
+			{
+				UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRY_INFO_2"), p->CurrentRetryCount);
+			}
+			SetText(hWnd, S_RETRYINFO, tmp);
+			SetRange(hWnd, P_PROGRESS, 0, p->RetryIntervalSec);
+			SetPos(hWnd, P_PROGRESS, 0);
+			SetTimer(hWnd, 1, 10, NULL);
+			p->StartTick = Tick64();
+		}
+		SetTimer(hWnd, 2, 10, NULL);
+		Focus(hWnd, IDOK);
+		break;
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			if (p->RetryIntervalSec != 0)
+			{
+				UINT64 start, end, now;
+				now = Tick64();
+				start = p->StartTick;
+				end = start + (UINT64)p->RetryIntervalSec;
+
+				if (end > now)
+				{
+					SetPos(hWnd, P_PROGRESS, (UINT)(now - start));
+					UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRYCOUNT"), ((UINT)(end - now)) / 1000);
+					SetText(hWnd, S_COUNTDOWN, tmp);
+				}
+				else
+				{
+					Command(hWnd, IDOK);
+				}
+			}
+			break;
+		case 2:
+			if (p->CancelEvent != NULL)
+			{
+				if (WaitForSingleObject((HANDLE)p->CancelEvent->pData, 0) != WAIT_TIMEOUT)
+				{
+					// 強制キャンセル
+					Close(hWnd);
+				}
+			}
+			break;
+		}
+		break;
+	case WM_COMMAND:
+		switch (LOWORD(wParam))
+		{
+		case R_HIDE:
+			p->HideWindow = IsChecked(hWnd, R_HIDE);
+			break;
+		}
+		switch (wParam)
+		{
+		case IDOK:
+			EndDialog(hWnd, true);
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 接続エラーダイアログを表示
+bool ConnectErrorDlg(UI_CONNECTERROR_DLG *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	return DialogEx2(NULL, D_CONNECTERROR, ConnectErrorDlgProc, p, true, true);
+}
+
+// 証明書の内容を表示する
+void PrintCheckCertInfo(HWND hWnd, UI_CHECKCERT *p)
+{
+	wchar_t tmp[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	UCHAR md5[MD5_SIZE];
+	UCHAR sha1[SHA1_SIZE];
+	X *x;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	x = p->x;
+
+	GetAllNameFromNameEx(tmp, sizeof(tmp), x->subject_name);
+	SetText(hWnd, E_SUBJECT, tmp);
+
+	GetAllNameFromNameEx(tmp, sizeof(tmp), x->issuer_name);
+	SetText(hWnd, E_ISSUER, tmp);
+
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
+	SetText(hWnd, E_EXPIRES, tmp);
+
+	GetXDigest(x, md5, false);
+	BinToStr(tmp2, sizeof(tmp2), md5, sizeof(md5));
+	SetTextA(hWnd, E_MD5, tmp2);
+
+	GetXDigest(x, sha1, true);
+	BinToStr(tmp2, sizeof(tmp2), sha1, sizeof(sha1));
+	SetTextA(hWnd, E_SHA1, tmp2);
+
+	SetFont(hWnd, E_MD5, GetFont("Arial", 8, false, false, false, false));
+	SetFont(hWnd, E_SHA1, GetFont("Arial", 8, false, false, false, false));
+}
+
+// 証明書が相違する旨を警告する
+void ShowDlgDiffWarning(HWND hWnd, UI_CHECKCERT *p)
+{
+	UCHAR sha1_new[SHA1_SIZE], sha1_old[SHA1_SIZE];
+	UCHAR md5_new[MD5_SIZE], md5_old[MD5_SIZE];
+	char sha1_new_str[MAX_SIZE], sha1_old_str[MAX_SIZE];
+	char md5_new_str[MAX_SIZE], md5_old_str[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || p->x == NULL || p->old_x == NULL)
+	{
+		return;
+	}
+
+	GetXDigest(p->x, sha1_new, true);
+	GetXDigest(p->x, md5_new, false);
+
+	GetXDigest(p->old_x, sha1_old, true);
+	GetXDigest(p->old_x, md5_old, false);
+
+	BinToStrEx(sha1_new_str, sizeof(sha1_new_str), sha1_new, sizeof(sha1_new));
+	BinToStrEx(md5_new_str, sizeof(md5_new_str), md5_new, sizeof(md5_new));
+	BinToStrEx(sha1_old_str, sizeof(sha1_old_str), sha1_old, sizeof(sha1_old));
+	BinToStrEx(md5_old_str, sizeof(md5_old_str), md5_old, sizeof(md5_old));
+
+	MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("CC_DANGEROUS_MSG"),
+		p->ServerName, md5_old_str, sha1_old_str, md5_new_str, sha1_new_str);
+}
+
+// [OK] ボタンが押された
+void CheckCertDialogOnOk(HWND hWnd, UI_CHECKCERT *p)
+{
+	UCHAR sha1_new[SHA1_SIZE];
+	UCHAR md5_new[MD5_SIZE];
+	char sha1_new_str[MAX_SIZE];
+	char md5_new_str[MAX_SIZE];
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	GetXDigest(p->x, sha1_new, true);
+	GetXDigest(p->x, md5_new, false);
+	BinToStrEx(sha1_new_str, sizeof(sha1_new_str), sha1_new, sizeof(sha1_new));
+	BinToStrEx(md5_new_str, sizeof(md5_new_str), md5_new, sizeof(md5_new));
+
+	ret = MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON2,
+		_UU("CC_WARNING_MSG"),
+		p->AccountName, sha1_new_str, md5_new_str);
+
+	if (ret == IDYES)
+	{
+		p->SaveServerCert = true;
+	}
+
+	if (ret == IDCANCEL)
+	{
+		return;
+	}
+
+	p->Ok = true;
+	EndDialog(hWnd, true);
+}
+
+// 証明書ダイアログプロシージャ
+UINT CheckCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UI_CHECKCERT *p = (UI_CHECKCERT *)param;
+	// 引数チェック
+	if (hWnd == NULL || param == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		FormatText(hWnd, 0, p->AccountName);
+		FormatText(hWnd, S_TITLE, p->ServerName);
+		FormatText(hWnd, S_MSG1, p->ServerName);
+
+		PrintCheckCertInfo(hWnd, p);
+
+		Focus(hWnd, IDCANCEL);
+
+		SetIcon(hWnd, 0, ICO_WARNING);
+
+		if (p->DiffWarning)
+		{
+			SetTimer(hWnd, 1, 1, NULL);
+		}
+
+		SetTimer(hWnd, 2, 100, NULL);
+
+		break;
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			ShowDlgDiffWarning(hWnd, p);
+			break;
+		case 2:
+			if ((p->Session != NULL && p->Session->Halt) ||
+				(p->Halt))
+			{
+				p->Ok = false;
+				EndDialog(hWnd, false);
+			}
+			break;
+		}
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_SHOW:
+			CertDlg(hWnd, p->x, p->parent_x, false);
+			break;
+		case IDOK:
+			CheckCertDialogOnOk(hWnd, p);
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		p->Ok = false;
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// 証明書のチェックダイアログ
+void CheckCertDlg(UI_CHECKCERT *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	Dialog(NULL, D_CHECKCERT, CheckCertDlgProc, p);
+}
+
+// アイコン ID からイメージリスト ID を取得する
+UINT GetIcon(UINT icon_id)
+{
+	IMAGELIST_ICON *c, t;
+	t.id = icon_id;
+
+	c = Search(icon_list, &t);
+	if (c == NULL)
+	{
+		if (icon_id != ICO_NULL)
+		{
+			return GetIcon(ICO_NULL);
+		}
+		else
+		{
+			return INFINITE;
+		}
+	}
+	else
+	{
+		return c->Index;
+	}
+}
+
+// イメージリスト用にアイコンをロードする
+IMAGELIST_ICON *LoadIconForImageList(UINT id)
+{
+	IMAGELIST_ICON *ret = ZeroMalloc(sizeof(IMAGELIST_ICON));
+	HICON small_icon, large_icon;
+
+	ret->id = id;
+
+	large_icon = LoadLargeIcon(id);
+	if (large_icon == NULL)
+	{
+		large_icon = LoadSmallIcon(id);
+	}
+
+	small_icon = LoadSmallIcon(id);
+	if (small_icon == NULL)
+	{
+		small_icon = LoadLargeIcon(id);
+	}
+
+	ret->hSmallImage = small_icon;
+	ret->hLargeImage = large_icon;
+	ret->Index = ImageList_AddIcon(large_image_list, large_icon);
+	ImageList_AddIcon(small_image_list, small_icon);
+
+	return ret;
+}
+
+// イメージリストアイコンの比較
+int CompareImageListIcon(void *p1, void *p2)
+{
+	IMAGELIST_ICON *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(IMAGELIST_ICON **)p1;
+	c2 = *(IMAGELIST_ICON **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+
+	if (c1->id > c2->id)
+	{
+		return 1;
+	}
+	else if (c1->id < c2->id)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// イメージリストの初期化
+void InitImageList()
+{
+	large_image_list = ImageList_Create(32, 32, ILC_COLOR32 | ILC_MASK, 1, 0);
+	ImageList_SetBkColor(large_image_list, RGB(255, 255, 255));
+	small_image_list = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 1, 0);
+	ImageList_SetBkColor(small_image_list, RGB(255, 255, 255));
+	icon_list = NewList(CompareImageListIcon);
+
+	// 列挙
+	EnumResourceNames(hDll, RT_GROUP_ICON, EnumResNameProc, 0);
+}
+
+// アイコンリソース列挙プロシージャ
+BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
+{
+	if (IS_INTRESOURCE(lpszName))
+	{
+		UINT icon_id = (UINT)lpszName;
+		IMAGELIST_ICON *img = LoadIconForImageList(icon_id);
+
+		Add(icon_list, img);
+	}
+
+	return TRUE;
+}
+
+// イメージリストの解放
+void FreeImageList()
+{
+	UINT i;
+	ImageList_Destroy(large_image_list);
+	ImageList_Destroy(small_image_list);
+	large_image_list = small_image_list = NULL;
+
+	for (i = 0;i < LIST_NUM(icon_list);i++)
+	{
+		IMAGELIST_ICON *c = LIST_DATA(icon_list, i);
+		Free(c);
+	}
+
+	ReleaseList(icon_list);
+	icon_list = NULL;
+}
+
+// カラムの横幅の取得
+UINT LvGetColumnWidth(HWND hWnd, UINT id, UINT index)
+{
+	return ListView_GetColumnWidth(DlgItem(hWnd, id), index);
+}
+
+// カラムの挿入
+void LvInsertColumn(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT width)
+{
+	LVCOLUMNW c;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return;
+	}
+
+	Zero(&c, sizeof(c));
+	c.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+
+	c.pszText = str;
+	c.iSubItem = index;
+	c.cx = width;
+
+	SendMsg(hWnd, id, LVM_INSERTCOLUMNW, index, (LPARAM)&c);
+}
+
+// すべてのアイテムを削除
+void LvReset(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	ListView_DeleteAllItems(DlgItem(hWnd, id));
+}
+
+// リストビューを初期化
+void LvInitEx(HWND hWnd, UINT id, bool no_image)
+{
+	LvInitEx2(hWnd, id, no_image, false);
+}
+void LvInitEx2(HWND hWnd, UINT id, bool no_image, bool large_icon)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	ListView_SetUnicodeFormat(DlgItem(hWnd, id), true);
+
+	if (no_image == false)
+	{
+		ListView_SetImageList(DlgItem(hWnd, id), large_image_list, LVSIL_NORMAL);
+		ListView_SetImageList(DlgItem(hWnd, id), large_icon ? large_image_list : small_image_list, LVSIL_SMALL);
+	}
+
+	ListView_SetExtendedListViewStyle(DlgItem(hWnd, id), LVS_EX_FULLROWSELECT);
+
+	if (MsIsVista())
+	{
+		LvSetStyle(hWnd, id, LVS_EX_DOUBLEBUFFER);
+	}
+}
+void LvInit(HWND hWnd, UINT id)
+{
+	LvInitEx(hWnd, id, false);
+}
+
+// バッチ追加処理完了 (高速)
+void LvInsertEnd(LVB *b, HWND hWnd, UINT id)
+{
+	LvInsertEndEx(b, hWnd, id, false);
+}
+void LvInsertEndEx(LVB *b, HWND hWnd, UINT id, bool force_reset)
+{
+	UINT i, num;
+	LIST *new_list, *exist_list;
+	wchar_t *last_selected = NULL;
+	// 引数チェック
+	if (b == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	new_list = NewListFast(CompareUniStr);
+
+	for (i = 0;i < LIST_NUM(b->ItemList);i++)
+	{
+		LVB_ITEM *t = LIST_DATA(b->ItemList, i);
+		Add(new_list, t->Strings[0]);
+	}
+
+	Sort(new_list);
+
+	if ((LIST_NUM(b->ItemList) >= LV_INSERT_RESET_ALL_ITEM_MIN) || force_reset)
+	{
+		last_selected = LvGetFocusedStr(hWnd, id, 0);
+		LvReset(hWnd, id);
+	}
+
+	exist_list = NewListFast(CompareUniStr);
+
+	num = LvNum(hWnd, id);
+
+	// 既存項目のうちバッチリスト内に存在していない項目を削除する
+	for (i = 0;i < num;i++)
+	{
+		bool exists = false;
+		wchar_t *s = LvGetStr(hWnd, id, i, 0);
+		if (Search(new_list, s) != NULL)
+		{
+			exists = true;
+		}
+		if (exists == false)
+		{
+			// 追加予定バッチリスト内に存在しない項目はリストビューから削除する
+			LvDeleteItem(hWnd, id, i);
+			num = LvNum(hWnd, id);
+			i--;
+			Free(s);
+		}
+		else
+		{
+			Add(exist_list, s);
+		}
+	}
+
+	Sort(exist_list);
+
+	// バッチ内の項目を 1 つずつ追加していく
+	for (i = 0;i < LIST_NUM(b->ItemList);i++)
+	{
+		LVB_ITEM *t = LIST_DATA(b->ItemList, i);
+		UINT index;
+		UINT j;
+		bool exists = false;
+
+		if (Search(exist_list, t->Strings[0]) != NULL)
+		{
+			index = LvSearchStr(hWnd, id, 0, t->Strings[0]);
+		}
+		else
+		{
+			index = INFINITE;
+		}
+
+		if (index != INFINITE)
+		{
+			UINT j;
+			// 追加しようとする項目と同じ文字列の項目がすでに存在する場合は
+			// 追加ではなく更新を行う
+			for (j = 0;j < t->NumStrings;j++)
+			{
+				LvSetItem(hWnd, id, index, j, t->Strings[j]);
+			}
+			LvSetItemImageByImageListId(hWnd, id, index, t->Image);
+			LvSetItemParam(hWnd, id, index, t->Param);
+		}
+		else
+		{
+			// 新しく追加を行う
+			UINT index = INFINITE;
+			UINT j;
+			for (j = 0;j < t->NumStrings;j++)
+			{
+				if (j == 0)
+				{
+					index = LvInsertItemByImageListId(hWnd, id, t->Image, t->Param, t->Strings[j]);
+				}
+				else
+				{
+					LvSetItem(hWnd, id, index, j, t->Strings[j]);
+				}
+			}
+		}
+
+		// メモリを解放する
+		for (j = 0;j < t->NumStrings;j++)
+		{
+			Free(t->Strings[j]);
+		}
+		Free(t->Strings);
+		Free(t);
+	}
+
+	// リストを解放する
+	ReleaseList(b->ItemList);
+
+	// メモリを解放する
+	Free(b);
+
+	ReleaseList(new_list);
+
+	for (i = 0;i < LIST_NUM(exist_list);i++)
+	{
+		Free(LIST_DATA(exist_list, i));
+	}
+	ReleaseList(exist_list);
+
+	if (last_selected != NULL)
+	{
+		UINT pos = LvSearchStr(hWnd, id, 0, last_selected);
+
+		if (pos != INFINITE)
+		{
+			LvSelect(hWnd, id, pos);
+		}
+
+		Free(last_selected);
+	}
+}
+
+// カラム数の取得
+UINT LvGetColumnNum(HWND hWnd, UINT id)
+{
+	UINT i;
+	LVCOLUMN c;
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	for (i = 0;;i++)
+	{
+		Zero(&c, sizeof(c));
+		c.mask = LVCF_SUBITEM;
+		if (ListView_GetColumn(DlgItem(hWnd, id), i, &c) == false)
+		{
+			break;
+		}
+	}
+
+	return i;
+}
+
+// ソート関数
+int CALLBACK LvSortProc(LPARAM param1, LPARAM param2, LPARAM sort_param)
+{
+	WINUI_LV_SORT *sort = (WINUI_LV_SORT *)sort_param;
+	HWND hWnd;
+	UINT id;
+	UINT i1, i2;
+	int ret = 0;
+	wchar_t *s1, *s2;
+	if (sort == NULL)
+	{
+		return 0;
+	}
+
+	hWnd = sort->hWnd;
+	id = sort->id;
+
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	i1 = (UINT)param1;
+	i2 = (UINT)param2;
+
+	s1 = LvGetStr(hWnd, id, i1, sort->subitem);
+	if (s1 == NULL)
+	{
+		return 0;
+	}
+
+	s2 = LvGetStr(hWnd, id, i2, sort->subitem);
+	if (s2 == NULL)
+	{
+		Free(s1);
+		return 0;
+	}
+
+	if (sort->numeric == false)
+	{
+		if (UniStrCmpi(s1, _UU("CM_NEW_ICON")) == 0)
+		{
+			ret = -1;
+		}
+		else if (UniStrCmpi(s1, _UU("CM_ASP")) == 0)
+		{
+			ret = -1;
+		}
+		else if (UniStrCmpi(s2, _UU("CM_NEW_ICON")) == 0)
+		{
+			ret = 1;
+		}
+		else if (UniStrCmpi(s2, _UU("CM_ASP")) == 0)
+		{
+			return 1;
+		}
+		else
+		{
+			ret = UniStrCmpi(s1, s2);
+		}
+	}
+	else
+	{
+		UINT64 v1, v2;
+		v1 = UniToInt64(s1);
+		v2 = UniToInt64(s2);
+		if (v1 > v2)
+		{
+			ret = 1;
+		}
+		else if (v1 < v2)
+		{
+			ret = -1;
+		}
+		else
+		{
+			ret = 0;
+		}
+	}
+
+	Free(s1);
+	Free(s2);
+
+	if (sort->desc)
+	{
+		ret = -ret;
+	}
+
+	return ret;
+}
+
+// 標準的なハンドラ
+void LvStandardHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id)
+{
+	NMHDR *n;
+	NMLVKEYDOWN *key;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	LvSortHander(hWnd, msg, wParam, lParam, id);
+
+	switch (msg)
+	{
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		if (n->idFrom == id)
+		{
+			switch (n->code)
+			{
+			case NM_DBLCLK:
+				Command(hWnd, IDOK);
+				break;
+			case LVN_KEYDOWN:
+				key = (NMLVKEYDOWN *)n;
+				if (key != NULL)
+				{
+					UINT code = key->wVKey;
+					switch (code)
+					{
+					case VK_DELETE:
+						Command(hWnd, B_DELETE);
+						break;
+
+					case VK_RETURN:
+						Command(hWnd, IDOK);
+						break;
+
+					case VK_F5:
+						Command(hWnd, B_REFRESH);
+						break;
+					}
+				}
+				break;
+			}
+		}
+		break;
+	}
+}
+
+// ソートヘッダハンドラ
+void LvSortHander(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id)
+{
+	NMHDR *nmhdr;
+	UINT subitem;
+	bool desc;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	switch (msg)
+	{
+	case WM_NOTIFY:
+		nmhdr = (NMHDR *)lParam;
+
+		if (nmhdr != NULL)
+		{
+			if (nmhdr->idFrom == id)
+			{
+				NMLISTVIEW *v;
+				switch (nmhdr->code)
+				{
+				case LVN_COLUMNCLICK:
+					desc = false;
+					v = (NMLISTVIEW *)lParam;
+					subitem = v->iSubItem;
+
+					if ((GetStyle(hWnd, id) & LVS_SORTDESCENDING) == 0)
+					{
+						desc = true;
+						SetStyle(hWnd, id, LVS_SORTDESCENDING);
+						RemoveStyle(hWnd, id, LVS_SORTASCENDING);
+					}
+					else
+					{
+						SetStyle(hWnd, id, LVS_SORTASCENDING);
+						RemoveStyle(hWnd, id, LVS_SORTDESCENDING);
+					}
+
+					LvSort(hWnd, id, subitem, desc);
+					break;
+				}
+			}
+		}
+		break;
+	}
+}
+
+// ソートを行う
+void LvSort(HWND hWnd, UINT id, UINT subitem, bool desc)
+{
+	UINT i, num;
+	bool numeric = true;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	num = LvNum(hWnd, id);
+	for (i = 0;i < num;i++)
+	{
+		wchar_t *s = LvGetStr(hWnd, id, i, subitem);
+		if (s != NULL)
+		{
+			if (UniIsNum(s) == false)
+			{
+				numeric = false;
+				Free(s);
+				break;
+			}
+			Free(s);
+		}
+		else
+		{
+			numeric = false;
+			break;
+		}
+	}
+
+	LvSortEx(hWnd, id, subitem, desc, numeric);
+}
+
+void LvSortEx(HWND hWnd, UINT id, UINT subitem, bool desc, bool numeric)
+{
+	WINUI_LV_SORT s;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+	if (subitem >= LvGetColumnNum(hWnd, id))
+	{
+		return;
+	}
+
+	Zero(&s, sizeof(s));
+	s.desc = desc;
+	s.numeric = numeric;
+	s.id = id;
+	s.hWnd = hWnd;
+	s.subitem = subitem;
+
+	ListView_SortItemsEx(DlgItem(hWnd, id), LvSortProc, (LPARAM)&s);
+}
+
+// 項目追加バッチへの追加
+void LvInsertAdd(LVB *b, UINT icon, void *param, UINT num_str, ...)
+{
+	UINT i;
+	va_list va;
+	UINT index = 0;
+	LVB_ITEM *t;
+	// 引数チェック
+	if (b == NULL || num_str == 0)
+	{
+		return;
+	}
+
+	t = ZeroMalloc(sizeof(LVB_ITEM));
+
+	va_start(va, num_str);
+
+	t->Strings = (wchar_t **)ZeroMalloc(sizeof(wchar_t *) * num_str);
+	t->NumStrings = num_str;
+
+	for (i = 0;i < num_str;i++)
+	{
+		wchar_t *s = va_arg(va, wchar_t *);
+
+		t->Strings[i] = UniCopyStr(s);
+	}
+
+	t->Param = param;
+	t->Image = GetIcon(icon);
+
+	Add(b->ItemList, t);
+
+	va_end(va);
+}
+
+// 項目追加バッチの開始
+LVB *LvInsertStart()
+{
+	LVB *b = ZeroMalloc(sizeof(LVB));
+	b->ItemList = NewListFast(NULL);
+
+	return b;
+}
+
+// リストビューに項目を追加する
+void LvInsert(HWND hWnd, UINT id, UINT icon, void *param, UINT num_str, ...)
+{
+	UINT i;
+	va_list va;
+	UINT index = 0;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	va_start(va, num_str);
+
+	for (i = 0;i < num_str;i++)
+	{
+		wchar_t *s = va_arg(va, wchar_t *);
+		if (i == 0)
+		{
+			index = LvInsertItem(hWnd, id, icon, param, s);
+		}
+		else
+		{
+			LvSetItem(hWnd, id, index, i, s);
+		}
+	}
+
+	va_end(va);
+}
+
+// アイテムのサイズを自動調整する
+void LvAutoSize(HWND hWnd, UINT id)
+{
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	i = 0;
+	while (true)
+	{
+		if (ListView_SetColumnWidth(DlgItem(hWnd, id), i, LVSCW_AUTOSIZE) == false)
+		{
+			break;
+		}
+		i++;
+	}
+}
+
+// アイテムを追加する
+UINT LvInsertItem(HWND hWnd, UINT id, UINT icon, void *param, wchar_t *str)
+{
+	return LvInsertItemByImageListId(hWnd, id, GetIcon(icon), param, str);
+}
+UINT LvInsertItemByImageListId(HWND hWnd, UINT id, UINT image, void *param, wchar_t *str)
+{
+	LVITEMW t;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(str);
+		UINT ret;
+		ret = LvInsertItemByImageListIdA(hWnd, id, image, param, s);
+		Free(s);
+		return ret;
+	}
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
+	t.pszText = str;
+	t.iImage = image;
+	t.lParam = (LPARAM)param;
+	t.iItem = LvNum(hWnd, id);
+
+	return SendMsg(hWnd, id, LVM_INSERTITEMW, 0, (LPARAM)&t);
+}
+UINT LvInsertItemByImageListIdA(HWND hWnd, UINT id, UINT image, void *param, char *str)
+{
+	LVITEM t;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
+	t.pszText = str;
+	t.iImage = image;
+	t.lParam = (LPARAM)param;
+	t.iItem = LvNum(hWnd, id);
+
+	return SendMsg(hWnd, id, LVM_INSERTITEM, 0, (LPARAM)&t);
+}
+
+// イメージを変更する
+void LvSetItemImage(HWND hWnd, UINT id, UINT index, UINT icon)
+{
+	LvSetItemImageByImageListId(hWnd, id, index, GetIcon(icon));
+}
+void LvSetItemImageByImageListId(HWND hWnd, UINT id, UINT index, UINT image)
+{
+	LVITEM t;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_IMAGE;
+	t.iImage = image;
+	t.iItem = index;
+
+	SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
+}
+
+// アイテムのパラメータを設定する
+void LvSetItemParam(HWND hWnd, UINT id, UINT index, void *param)
+{
+	LvSetItemParamEx(hWnd, id, index, 0, param);
+}
+void LvSetItemParamEx(HWND hWnd, UINT id, UINT index, UINT subitem, void *param)
+{
+	LVITEM t;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_PARAM;
+	t.iItem = index;
+	t.iSubItem = subitem;
+	t.lParam = (LPARAM)param;
+
+	SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
+}
+
+// アイテムを設定する
+void LvSetItem(HWND hWnd, UINT id, UINT index, UINT pos, wchar_t *str)
+{
+	LVITEMW t;
+	wchar_t *old_str;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return;
+	}
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(str);
+		LvSetItemA(hWnd, id, index, pos, s);
+		Free(s);
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_TEXT;
+	t.pszText = str;
+	t.iItem = index;
+	t.iSubItem = pos;
+
+	old_str = LvGetStr(hWnd, id, index, pos);
+
+	if (UniStrCmp(old_str, str) != 0)
+	{
+		SendMsg(hWnd, id, LVM_SETITEMW, 0, (LPARAM)&t);
+	}
+
+	Free(old_str);
+}
+void LvSetItemA(HWND hWnd, UINT id, UINT index, UINT pos, char *str)
+{
+	LVITEM t;
+	wchar_t *old_str;
+	char *old_str_2;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return;
+	}
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_TEXT;
+	t.pszText = str;
+	t.iItem = index;
+	t.iSubItem = pos;
+
+	old_str = LvGetStr(hWnd, id, index, pos);
+	old_str_2 = CopyUniToStr(old_str);
+
+	if (StrCmp(old_str_2, str) != 0)
+	{
+		SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
+	}
+
+	Free(old_str_2);
+	Free(old_str);
+}
+
+// リストボックスのビューを設定
+void LvSetView(HWND hWnd, UINT id, bool details)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (details)
+	{
+		RemoveStyle(hWnd, id, LVS_ICON);
+		SetStyle(hWnd, id, LVS_REPORT);
+	}
+	else
+	{
+		RemoveStyle(hWnd, id, LVS_REPORT);
+		SetStyle(hWnd, id, LVS_ICON);
+	}
+}
+
+// 指定したアイテムが必ず表示されるようにする
+void LvShow(HWND hWnd, UINT id, UINT index)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	ListView_EnsureVisible(DlgItem(hWnd, id), index, false);
+}
+
+// 現在選択されている項目が存在するかどうかを取得する
+bool LvIsSelected(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	if (LvGetSelected(hWnd, id) == INFINITE)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 現在選択されている項目を取得する
+UINT LvGetFocused(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	return ListView_GetNextItem(DlgItem(hWnd, id), -1, LVNI_FOCUSED);
+}
+
+// 現在選択されている文字列を取得する
+wchar_t *LvGetFocusedStr(HWND hWnd, UINT id, UINT pos)
+{
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	i = LvGetFocused(hWnd, id);
+	if (i == INFINITE)
+	{
+		return NULL;
+	}
+
+	return LvGetStr(hWnd, id, i, pos);
+}
+
+// 現在選択されている項目を取得する
+UINT LvGetSelected(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	return ListView_GetNextItem(DlgItem(hWnd, id), -1, LVNI_FOCUSED | LVNI_SELECTED);
+}
+
+// 現在選択されている文字列を取得する
+wchar_t *LvGetSelectedStr(HWND hWnd, UINT id, UINT pos)
+{
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	i = LvGetSelected(hWnd, id);
+	if (i == INFINITE)
+	{
+		return NULL;
+	}
+
+	return LvGetStr(hWnd, id, i, pos);
+}
+char *LvGetSelectedStrA(HWND hWnd, UINT id, UINT pos)
+{
+	char *ret;
+	wchar_t *tmp = LvGetSelectedStr(hWnd, id, pos);
+	if (tmp == NULL)
+	{
+		return NULL;
+	}
+	ret = CopyUniToStr(tmp);
+	Free(tmp);
+	return ret;
+}
+
+// 2 つ以上の項目がマスクされているかどうかを取得する
+bool LvIsMultiMasked(HWND hWnd, UINT id)
+{
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	i = INFINITE;
+	i = LvGetNextMasked(hWnd, id, i);
+	if (i != INFINITE)
+	{
+		if (LvGetNextMasked(hWnd, id, i) != INFINITE)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// ただ 1 つの項目だけが選択されているかどうか調べる
+bool LvIsSingleSelected(HWND hWnd, UINT id)
+{
+	return LvIsSelected(hWnd, id) && (LvIsMultiMasked(hWnd, id) == false);
+}
+
+// 現在マスクされている項目が存在するかどうかを取得する
+bool LvIsMasked(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	if (LvGetNextMasked(hWnd, id, INFINITE) == INFINITE)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 現在マスクされている項目数を取得する
+UINT LvGetMaskedNum(HWND hWnd, UINT id)
+{
+	UINT i = INFINITE;
+	UINT num = 0;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	while (true)
+	{
+		i = LvGetNextMasked(hWnd, id, i);
+		if (i == INFINITE)
+		{
+			break;
+		}
+
+		num++;
+	}
+
+	return num;
+}
+
+// 現在マスクされている項目を取得する
+UINT LvGetNextMasked(HWND hWnd, UINT id, UINT start)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	return ListView_GetNextItem(DlgItem(hWnd, id), start, LVNI_SELECTED);
+}
+
+// 指定した文字列を持つ項目を検索する
+UINT LvSearchStr_(HWND hWnd, UINT id, UINT pos, wchar_t *str)
+{
+	UINT ret;
+	LVFINDINFOW t;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	Zero(&t, sizeof(t));
+	t.flags = LVFI_STRING;
+	t.psz = str;
+	t.vkDirection = VK_DOWN;
+
+	ret = SendMsg(hWnd, id, LVM_FINDITEMW, -1, (LPARAM)&t);
+
+	return ret;
+}
+
+// 指定した文字列を持つ項目を検索する
+UINT LvSearchStr(HWND hWnd, UINT id, UINT pos, wchar_t *str)
+{
+	UINT i, num;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	num = LvNum(hWnd, id);
+
+	for (i = 0;i < num;i++)
+	{
+		wchar_t *s = LvGetStr(hWnd, id, i, pos);
+		if (s != NULL)
+		{
+			if (UniStrCmpi(s, str) == 0)
+			{
+				Free(s);
+				return i;
+			}
+			else
+			{
+				Free(s);
+			}
+		}
+	}
+
+	return INFINITE;
+}
+UINT LvSearchStrA(HWND hWnd, UINT id, UINT pos, char *str)
+{
+	wchar_t *tmp = CopyStrToUni(str);
+	UINT ret = LvSearchStr(hWnd, id, pos, tmp);
+	Free(tmp);
+	return ret;
+}
+
+// 指定した param を持つ項目を検索する
+UINT LvSearchParam(HWND hWnd, UINT id, void *param)
+{
+	UINT i, num;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	num = LvNum(hWnd, id);
+
+	for (i = 0;i < num;i++)
+	{
+		if (LvGetParam(hWnd, id, i) == param)
+		{
+			return i;
+		}
+	}
+
+	return INFINITE;
+}
+
+// 項目数を取得する
+UINT LvNum(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	return ListView_GetItemCount(DlgItem(hWnd, id));
+}
+
+// 項目を削除する
+void LvDeleteItem(HWND hWnd, UINT id, UINT index)
+{
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	ListView_DeleteItem(DlgItem(hWnd, id), index);
+
+	i = LvGetSelected(hWnd, id);
+	if (i != INFINITE)
+	{
+		LvSelect(hWnd, id, i);
+	}
+}
+
+// 項目からデータを取得する
+void *LvGetParam(HWND hWnd, UINT id, UINT index)
+{
+	return LvGetParamEx(hWnd, id, index, 0);
+}
+void *LvGetParamEx(HWND hWnd, UINT id, UINT index, UINT subitem)
+{
+	LVITEM t;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+	if (index == INFINITE)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_PARAM;
+	t.iItem = index;
+	t.iSubItem = subitem;
+
+	if (ListView_GetItem(DlgItem(hWnd, id), &t) == false)
+	{
+		return NULL;
+	}
+
+	return (void *)t.lParam;
+}
+
+// 項目の文字列を取得する
+wchar_t *LvGetStr(HWND hWnd, UINT id, UINT index, UINT pos)
+{
+	wchar_t *tmp;
+	UINT size;
+	LVITEMW t;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+	if (MsIsNt() == false)
+	{
+		char *s = LvGetStrA(hWnd, id, index, pos);
+		if (s == NULL)
+		{
+			return NULL;
+		}
+		else
+		{
+			wchar_t *ret = CopyStrToUni(s);
+			Free(s);
+
+			return ret;
+		}
+	}
+
+	size = 65536;
+	tmp = Malloc(size);
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_TEXT;
+	t.iItem = index;
+	t.iSubItem = pos;
+	t.pszText = tmp;
+	t.cchTextMax = size;
+
+	if (SendMsg(hWnd, id, LVM_GETITEMTEXTW, index, (LPARAM)&t) <= 0)
+	{
+		Free(tmp);
+		return UniCopyStr(L"");
+	}
+	else
+	{
+		wchar_t *ret = UniCopyStr(tmp);
+		Free(tmp);
+		return ret;
+	}
+}
+char *LvGetStrA(HWND hWnd, UINT id, UINT index, UINT pos)
+{
+	char *tmp;
+	UINT size;
+	LVITEM t;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	size = 65536;
+	tmp = Malloc(size);
+
+	Zero(&t, sizeof(t));
+	t.mask = LVIF_TEXT;
+	t.iItem = index;
+	t.iSubItem = pos;
+	t.pszText = tmp;
+	t.cchTextMax = size;
+
+	if (SendMsg(hWnd, id, LVM_GETITEMTEXT, index, (LPARAM)&t) <= 0)
+	{
+		Free(tmp);
+		return CopyStr("");
+	}
+	else
+	{
+		char *ret = CopyStr(tmp);
+		Free(tmp);
+		return ret;
+	}
+}
+
+// スタイルを設定する
+void LvSetStyle(HWND hWnd, UINT id, UINT style)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if ((ListView_GetExtendedListViewStyle(DlgItem(hWnd, id)) & style) == 0)
+	{
+		ListView_SetExtendedListViewStyleEx(DlgItem(hWnd, id), style, style);
+	}
+}
+
+// スタイルを削除する
+void LvRemoveStyle(HWND hWnd, UINT id, UINT style)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if ((ListView_GetExtendedListViewStyle(DlgItem(hWnd, id)) & style) != 0)
+	{
+		ListView_SetExtendedListViewStyleEx(DlgItem(hWnd, id), style, 0);
+	}
+}
+
+// 項目の選択を反転する
+void LvSwitchSelect(HWND hWnd, UINT id)
+{
+	UINT i, num;
+	bool *states;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	num = LvNum(hWnd, id);
+	states = ZeroMalloc(sizeof(bool) * num);
+
+	i = INFINITE;
+	while (true)
+	{
+		i = LvGetNextMasked(hWnd, id, i);
+		if (i == INFINITE)
+		{
+			break;
+		}
+
+		states[i] = true;
+	}
+
+	for (i = 0;i < num;i++)
+	{
+		if (states[i] == false)
+		{
+			ListView_SetItemState(DlgItem(hWnd, id), i, LVIS_SELECTED, LVIS_SELECTED);
+		}
+		else
+		{
+			ListView_SetItemState(DlgItem(hWnd, id), i, 0, LVIS_SELECTED);
+		}
+	}
+
+	Free(states);
+}
+
+// すべての項目を選択する
+void LvSelectAll(HWND hWnd, UINT id)
+{
+	UINT i, num;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	num = LvNum(hWnd, id);
+	for (i = 0;i < num;i++)
+	{
+		ListView_SetItemState(DlgItem(hWnd, id), i, LVIS_SELECTED, LVIS_SELECTED);
+	}
+}
+
+// 項目を選択する
+void LvSelect(HWND hWnd, UINT id, UINT index)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (index == INFINITE)
+	{
+		UINT i, num;
+		// すべて選択解除する
+		num = LvNum(hWnd, id);
+		for (i = 0;i < num;i++)
+		{
+			ListView_SetItemState(DlgItem(hWnd, id), i, 0, LVIS_SELECTED);
+		}
+	}
+	else
+	{
+		// 選択する
+		ListView_SetItemState(DlgItem(hWnd, id), index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
+		ListView_EnsureVisible(DlgItem(hWnd, id), index, true);
+	}
+}
+
+// 証明書情報を表示する
+void PrintCertInfo(HWND hWnd, CERT_DLG *p)
+{
+	X *x;
+	char *serial_tmp;
+	UINT serial_size;
+	wchar_t *wchar_tmp;
+	wchar_t tmp[1024 * 5];
+	UCHAR md5[MD5_SIZE];
+	UCHAR sha1[SHA1_SIZE];
+	char *s_tmp;
+	K *k;
+	// 引数チェック
+	if (p == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	x = p->x;
+
+	// シリアル番号
+	if (x->serial != NULL)
+	{
+		serial_size = x->serial->size * 3 + 1;
+		serial_tmp = ZeroMalloc(serial_size);
+		BinToStrEx(serial_tmp, serial_size, x->serial->data, x->serial->size);
+		wchar_tmp = CopyStrToUni(serial_tmp);
+		Free(serial_tmp);
+	}
+	else
+	{
+		wchar_tmp = CopyUniStr(_UU("CERT_NO_SERIAL"));
+	}
+	LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_SERIAL"), wchar_tmp);
+
+	// 発行者
+	GetAllNameFromName(tmp, sizeof(tmp), x->issuer_name);
+	LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_ISSUER"), tmp);
+
+	// サブジェクト
+	GetAllNameFromName(tmp, sizeof(tmp), x->subject_name);
+	LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_SUBJECT"), tmp);
+
+	// 有効期限の開始
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notBefore), NULL);
+	LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_NOT_BEFORE"), tmp);
+
+	// 有効期限の終了
+	GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
+	LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_NOT_AFTER"), tmp);
+
+	// ビット数
+	if (x->is_compatible_bit)
+	{
+		UniFormat(tmp, sizeof(tmp), _UU("CERT_BITS_FORMAT"), x->bits);
+		LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_BITS"), tmp);
+	}
+
+	// 公開鍵
+	k = GetKFromX(x);
+	if (k != NULL)
+	{
+		BUF *b = KToBuf(k, false, NULL);
+		s_tmp = CopyBinToStrEx(b->Buf, b->Size);
+		StrToUni(tmp, sizeof(tmp), s_tmp);
+		Free(s_tmp);
+		LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_PUBLIC_KEY"), tmp);
+		FreeBuf(b);
+	}
+	FreeK(k);
+
+	GetXDigest(x, md5, false);
+	GetXDigest(x, sha1, true);
+
+	// ダイジェスト (MD5)
+	s_tmp = CopyBinToStrEx(md5, sizeof(md5));
+	StrToUni(tmp, sizeof(tmp), s_tmp);
+	Free(s_tmp);
+	LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_DIGEST_MD5"), tmp);
+
+	// ダイジェスト (SHA-1)
+	s_tmp = CopyBinToStrEx(sha1, sizeof(sha1));
+	StrToUni(tmp, sizeof(tmp), s_tmp);
+	Free(s_tmp);
+	LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_DIGEST_SHA1"), tmp);
+
+	Free(wchar_tmp);
+
+	LvSelect(hWnd, L_CERTINFO, 0);
+}
+
+// 表示の更新
+void CertDlgUpdate(HWND hWnd, CERT_DLG *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (LvIsSelected(hWnd, L_CERTINFO) == false)
+	{
+		SetText(hWnd, E_DETAIL, L"");
+	}
+	else
+	{
+		UINT i = LvGetSelected(hWnd, L_CERTINFO);
+		wchar_t *tmp = LvGetStr(hWnd, L_CERTINFO, i, 1);
+		SetText(hWnd, E_DETAIL, tmp);
+		Free(tmp);
+	}
+}
+
+// 証明書の保存
+void CertDlgSave(HWND hWnd, CERT_DLG *p)
+{
+	wchar_t *name;
+	X *x;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// 保存
+	name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), NULL, L".cer");
+	x = p->x;
+	if (name != NULL)
+	{
+		char str[MAX_SIZE];
+		UniToStr(str, sizeof(str), name);
+		if (XToFile(x, str, true))
+		{
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_CERT_SAVE_OK"));
+		}
+		else
+		{
+			MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
+		}
+		Free(name);
+	}
+}
+
+// 証明書表示ダイアログプロシージャ
+UINT CertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	CERT_DLG *p = (CERT_DLG *)param;
+	X *x;
+	wchar_t tmp[MAX_SIZE];
+	NMHDR *n;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetIcon(hWnd, 0, ICO_CERT);
+		x = p->x;
+		GetAllNameFromNameEx(tmp, sizeof(tmp), x->subject_name);
+		SetText(hWnd, E_SUBJECT, tmp);
+		GetAllNameFromNameEx(tmp, sizeof(tmp), x->issuer_name);
+		SetText(hWnd, E_ISSUER, tmp);
+		GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
+		SetText(hWnd, E_EXPIRES, tmp);
+		SetFont(hWnd, E_SUBJECT, Font(0, 1));
+		SetFont(hWnd, E_ISSUER, Font(0, 1));
+		SetFont(hWnd, E_EXPIRES, Font(0, 1));
+		SetIcon(hWnd, B_PARENT, ICO_CERT);
+		if (x->root_cert)
+		{
+			// ルート証明書
+			Hide(hWnd, S_WARNING_ICON);
+			SetText(hWnd, S_PARENT, _UU("CERT_ROOT"));
+			Hide(hWnd, B_PARENT);
+			Hide(hWnd, S_PARENT_BUTTON_STR);
+		}
+		else if (p->issuer_x != NULL)
+		{
+			// 親証明書がある
+			Hide(hWnd, S_WARNING_ICON);
+		}
+		else
+		{
+			// 親証明書が無い
+			Hide(hWnd, S_CERT_ICON);
+			Hide(hWnd, B_PARENT);
+			Hide(hWnd, S_PARENT_BUTTON_STR);
+			SetText(hWnd, S_PARENT, _UU("CERT_NOT_FOUND"));
+			if (p->ManagerMode)
+			{
+				Hide(hWnd, IDC_STATIC1);
+				Hide(hWnd, S_PARENT);
+				Hide(hWnd, S_WARNING_ICON);
+				Hide(hWnd, S_CERT_ICON);
+				Hide(hWnd, B_PARENT);
+				Hide(hWnd, S_PARENT_BUTTON_STR);
+			}
+		}
+
+
+		LvInit(hWnd, L_CERTINFO);
+		LvInsertColumn(hWnd, L_CERTINFO, 0, _UU("CERT_LV_C1"), 130);
+		LvInsertColumn(hWnd, L_CERTINFO, 1, _UU("CERT_LV_C2"), 250);
+
+		PrintCertInfo(hWnd, p);
+		Focus(hWnd, L_CERTINFO);
+
+		CertDlgUpdate(hWnd, p);
+
+		if (p->ManagerMode)
+		{
+			Show(hWnd, B_SAVE);
+		}
+		else
+		{
+			// セキュリティのため非表示にする
+			Hide(hWnd, B_SAVE);
+		}
+
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		case B_PARENT:
+			CertDlg(hWnd, p->issuer_x, NULL, p->ManagerMode);
+			break;
+		case B_SAVE:
+			// ファイルに保存
+			CertDlgSave(hWnd, p);
+			break;
+		}
+		break;
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	case WM_NOTIFY:
+		n = (NMHDR *)lParam;
+		switch (n->idFrom)
+		{
+		case L_CERTINFO:
+			switch (n->code)
+			{
+			case LVN_ITEMCHANGED:
+				CertDlgUpdate(hWnd, p);
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	LvSortHander(hWnd, msg, wParam, lParam, L_CERTINFO);
+
+	return 0;
+}
+
+// 証明書表示ダイアログ
+void CertDlg(HWND hWnd, X *x, X *issuer_x, bool manager)
+{
+	CERT_DLG p;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return;
+	}
+
+	Zero(&p, sizeof(p));
+	p.x = x;
+	if (CompareX(x, issuer_x) == false)
+	{
+		p.issuer_x = issuer_x;
+	}
+	p.ManagerMode = manager;
+	Dialog(hWnd, D_CERT, CertDlgProc, &p);
+}
+
+// ステータスウインドウダイアログ
+UINT StatusPrinterWindowDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	STATUS_WINDOW_PARAM *p = (STATUS_WINDOW_PARAM *)param;
+	PACK *pack;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		// 初期化
+		SetIcon(hWnd, 0, ICO_SERVER_ONLINE);
+		RemoveExStyle(hWnd, 0, WS_EX_APPWINDOW);
+		p->hWnd = hWnd;
+		NoticeThreadInit(p->Thread);
+		FormatText(hWnd, 0, p->AccountName);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+		case IDCANCEL:
+			// キャンセルボタン
+			Close(hWnd);
+			break;
+		}
+
+		break;
+
+	case WM_APP + 1:
+		// 文字列を設定
+		SetText(hWnd, S_STATUS, (wchar_t *)lParam);
+		break;
+
+	case WM_APP + 2:
+		// このウインドウを閉じる
+		EndDialog(hWnd, false);
+		break;
+
+	case WM_CLOSE:
+		// セッションを終了する
+		pack = NewPack();
+		SendPack(p->Sock, pack);
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// ステータスウインドウ制御用スレッド
+void StatusPrinterWindowThread(THREAD *thread, void *param)
+{
+	STATUS_WINDOW_PARAM *p = (STATUS_WINDOW_PARAM *)param;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	p->Thread = thread;
+	DialogEx2(NULL, D_STATUS, StatusPrinterWindowDlg, p, true, true);
+
+	Free(p);
+}
+
+// ステータスウインドウにメッセージを表示する
+void StatusPrinterWindowPrint(STATUS_WINDOW *sw, wchar_t *str)
+{
+	// 引数チェック
+	if (sw == NULL)
+	{
+		return;
+	}
+
+	SendMessage(sw->hWnd, WM_APP + 1, 0, (LPARAM)str);
+}
+
+// ステータスウインドウの終了と解放
+void StatusPrinterWindowStop(STATUS_WINDOW *sw)
+{
+	// 引数チェック
+	if (sw == NULL)
+	{
+		return;
+	}
+
+	// 停止メッセージを送信
+	SendMessage(sw->hWnd, WM_APP + 2, 0, 0);
+
+	// スレッド停止まで待機
+	WaitThread(sw->Thread, INFINITE);
+
+	// メモリ解放
+	ReleaseThread(sw->Thread);
+	Free(sw);
+}
+
+// ステータスウインドウの初期化
+STATUS_WINDOW *StatusPrinterWindowStart(SOCK *s, wchar_t *account_name)
+{
+	STATUS_WINDOW_PARAM *p;
+	STATUS_WINDOW *sw;
+	THREAD *t;
+	// 引数チェック
+	if (s == NULL || account_name == NULL)
+	{
+		return NULL;
+	}
+
+	p = ZeroMalloc(sizeof(STATUS_WINDOW_PARAM));
+	p->Sock = s;
+	UniStrCpy(p->AccountName, sizeof(p->AccountName), account_name);
+
+	// スレッド作成
+	t = NewThread(StatusPrinterWindowThread, p);
+	WaitThreadInit(t);
+
+	sw = ZeroMalloc(sizeof(STATUS_WINDOW));
+	sw->hWnd = p->hWnd;
+	sw->Thread = t;
+
+	return sw;
+}
+
+// 文字列を取得
+wchar_t *LbGetStr(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	return GetText(hWnd, id);
+}
+
+// 文字列検索
+UINT LbFindStr(HWND hWnd, UINT id, wchar_t *str)
+{
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, LB_FINDSTRING, -1, (LPARAM)str);
+
+	return ret;
+}
+
+// 項目数を取得
+UINT LbNum(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	return SendMsg(hWnd, id, LB_GETCOUNT, 0, 0);
+}
+
+// 文字列追加
+UINT LbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data)
+{
+	UINT ret;
+
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(str);
+		ret = LbAddStrA(hWnd, id, s, data);
+		Free(s);
+		return ret;
+	}
+
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, LB_ADDSTRING, 0, (LPARAM)str);
+	SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
+
+	if (LbNum(hWnd, id) == 1)
+	{
+		LbSelectIndex(hWnd, id, 0);
+	}
+
+	return ret;
+}
+UINT LbAddStrA(HWND hWnd, UINT id, char *str, UINT data)
+{
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, LB_ADDSTRING, 0, (LPARAM)str);
+	SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
+
+	if (LbNum(hWnd, id) == 1)
+	{
+		LbSelectIndex(hWnd, id, 0);
+	}
+
+	return ret;
+}
+
+// 文字列挿入
+UINT LbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data)
+{
+	UINT ret;
+
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(str);
+		ret = LbInsertStrA(hWnd, id, index, s, data);
+		Free(s);
+		return ret;
+	}
+
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, LB_INSERTSTRING, index, (LPARAM)str);
+	SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
+
+	if (LbNum(hWnd, id) == 1)
+	{
+		LbSelect(hWnd, id, 0);
+	}
+
+	return ret;
+}
+UINT LbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
+{
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, LB_INSERTSTRING, index, (LPARAM)str);
+	SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
+
+	if (LbNum(hWnd, id) == 1)
+	{
+		LbSelect(hWnd, id, 0);
+	}
+
+	return ret;
+}
+
+// すべて削除
+void LbReset(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, LB_RESETCONTENT, 0, 0);
+}
+
+// インデックスを指定して選択
+void LbSelectIndex(HWND hWnd, UINT id, UINT index)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, LB_SETCURSEL, index, 0);
+}
+
+// データを取得
+UINT LbGetData(HWND hWnd, UINT id, UINT index)
+{
+	// 引数チェック
+	if (hWnd == NULL || index == INFINITE)
+	{
+		return INFINITE;
+	}
+
+	return SendMsg(hWnd, id, LB_GETITEMDATA, index, 0);
+}
+
+// データを検索
+UINT LbFindData(HWND hWnd, UINT id, UINT data)
+{
+	UINT i, num;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	num = LbNum(hWnd, id);
+	if (num == INFINITE)
+	{
+		return INFINITE;
+	}
+
+	for (i = 0;i < num;i++)
+	{
+		if (LbGetData(hWnd, id, i) == data)
+		{
+			return i;
+		}
+	}
+
+	return INFINITE;
+}
+
+// アイテムの高さを設定
+void LbSetHeight(HWND hWnd, UINT id, UINT value)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, LB_SETITEMHEIGHT, 0, value);
+}
+
+// データを指定して検索
+void LbSelect(HWND hWnd, UINT id, int data)
+{
+	UINT index;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (data == INFINITE)
+	{
+		// 最初の項目を取得
+		LbSelectIndex(hWnd, id, 0);
+		return;
+	}
+
+	index = LbFindData(hWnd, id, data);
+	if (index == INFINITE)
+	{
+		// 発見できなかった
+		return;
+	}
+
+	// 選択する
+	LbSelectIndex(hWnd, id, index);
+}
+
+// 現在選択されている項目を取得
+UINT LbGetSelectIndex(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	return SendMsg(hWnd, id, LB_GETCURSEL, 0, 0);
+}
+
+// 現在選択されている値を取得
+UINT LbGetSelect(HWND hWnd, UINT id)
+{
+	UINT index;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	index = LbGetSelectIndex(hWnd, id);
+	if (index == INFINITE)
+	{
+		return INFINITE;
+	}
+
+	return LbGetData(hWnd, id, index);
+}
+
+// パスワード入力ダイアログ状態変化
+void PasswordDlgProcChange(HWND hWnd, UI_PASSWORD_DLG *p)
+{
+	bool b;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	b = true;
+	if (IsEmpty(hWnd, E_USERNAME))
+	{
+		b = false;
+	}
+
+	SetEnable(hWnd, IDOK, b);
+
+	p->StartTick = Tick64();
+	if (p->RetryIntervalSec)
+	{
+		KillTimer(hWnd, 1);
+		Hide(hWnd, P_PROGRESS);
+		Hide(hWnd, S_COUNTDOWN);
+	}
+}
+
+// 文字列を取得
+wchar_t *CbGetStr(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	return GetText(hWnd, id);
+}
+
+// 文字列検索
+UINT CbFindStr(HWND hWnd, UINT id, wchar_t *str)
+{
+	UINT ret;
+	if (MsIsNt() == false)
+	{
+		char *tmp = CopyUniToStr(str);
+		ret = CbFindStr9xA(hWnd, id, tmp);
+		Free(tmp);
+		return ret;
+	}
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, CB_FINDSTRINGEXACT, -1, (LPARAM)str);
+
+	return ret;
+}
+UINT CbFindStr9xA(HWND hWnd, UINT id, char *str)
+{
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, CB_FINDSTRINGEXACT, -1, (LPARAM)str);
+
+	return ret;
+}
+
+// 項目数を取得
+UINT CbNum(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	return SendMsg(hWnd, id, CB_GETCOUNT, 0, 0);
+}
+
+// 文字列追加
+UINT CbAddStrA(HWND hWnd, UINT id, char *str, UINT data)
+{
+	wchar_t *tmp;
+	UINT ret;
+	// 引く数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+	tmp = CopyStrToUni(str);
+	ret = CbAddStr(hWnd, id, tmp, data);
+	Free(tmp);
+	return ret;
+}
+UINT CbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data)
+{
+	UINT ret;
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(str);
+		ret = CbAddStr9xA(hWnd, id, s, data);
+		Free(s);
+		return ret;
+	}
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, CB_ADDSTRING, 0, (LPARAM)str);
+	SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
+
+	if (CbNum(hWnd, id) == 1)
+	{
+		wchar_t tmp[MAX_SIZE];
+		GetTxt(hWnd, id, tmp, sizeof(tmp));
+		if (UniStrLen(tmp) == 0)
+		{
+			CbSelectIndex(hWnd, id, 0);
+		}
+	}
+
+	return ret;
+}
+UINT CbAddStr9xA(HWND hWnd, UINT id, char *str, UINT data)
+{
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, CB_ADDSTRING, 0, (LPARAM)str);
+	SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
+
+	if (CbNum(hWnd, id) == 1)
+	{
+		wchar_t tmp[MAX_SIZE];
+		GetTxt(hWnd, id, tmp, sizeof(tmp));
+		if (UniStrLen(tmp) == 0)
+		{
+			CbSelectIndex(hWnd, id, 0);
+		}
+	}
+
+	return ret;
+}
+
+// 文字列挿入
+UINT CbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
+{
+	wchar_t *tmp;
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+	tmp = CopyStrToUni(str);
+	ret = CbInsertStr(hWnd, id, index, tmp, data);
+	Free(tmp);
+	return ret;
+}
+UINT CbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data)
+{
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(str);
+		ret = CbInsertStr9xA(hWnd, id, index, s, data);
+		Free(s);
+		return ret;
+	}
+
+	ret = SendMsg(hWnd, id, CB_INSERTSTRING, index, (LPARAM)str);
+	SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
+
+	if (CbNum(hWnd, id) == 1)
+	{
+		CbSelect(hWnd, id, 0);
+	}
+
+	return ret;
+}
+UINT CbInsertStr9xA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
+{
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return INFINITE;
+	}
+
+	ret = SendMsg(hWnd, id, CB_INSERTSTRING, index, (LPARAM)str);
+	SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
+
+	if (CbNum(hWnd, id) == 1)
+	{
+		CbSelect(hWnd, id, 0);
+	}
+
+	return ret;
+}
+
+// すべて削除
+void CbReset(HWND hWnd, UINT id)
+{
+	wchar_t *s;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	s = GetText(hWnd, id);
+
+	SendMsg(hWnd, id, CB_RESETCONTENT, 0, 0);
+
+	if (s != NULL)
+	{
+		SetText(hWnd, id, s);
+		Free(s);
+	}
+}
+
+// インデックスを指定して選択
+void CbSelectIndex(HWND hWnd, UINT id, UINT index)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, CB_SETCURSEL, index, 0);
+}
+
+// データを取得
+UINT CbGetData(HWND hWnd, UINT id, UINT index)
+{
+	// 引数チェック
+	if (hWnd == NULL || index == INFINITE)
+	{
+		return INFINITE;
+	}
+
+	return SendMsg(hWnd, id, CB_GETITEMDATA, index, 0);
+}
+
+// データを検索
+UINT CbFindData(HWND hWnd, UINT id, UINT data)
+{
+	UINT i, num;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	num = CbNum(hWnd, id);
+	if (num == INFINITE)
+	{
+		return INFINITE;
+	}
+
+	for (i = 0;i < num;i++)
+	{
+		if (CbGetData(hWnd, id, i) == data)
+		{
+			return i;
+		}
+	}
+
+	return INFINITE;
+}
+
+// アイテムの高さを設定
+void CbSetHeight(HWND hWnd, UINT id, UINT value)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, CB_SETITEMHEIGHT, 0, value);
+}
+
+// データを指定して検索
+void CbSelect(HWND hWnd, UINT id, int data)
+{
+	UINT index;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (data == INFINITE)
+	{
+		// 最初の項目を取得
+		CbSelectIndex(hWnd, id, 0);
+		return;
+	}
+
+	index = CbFindData(hWnd, id, data);
+	if (index == INFINITE)
+	{
+		// 発見できなかった
+		return;
+	}
+
+	// 選択する
+	CbSelectIndex(hWnd, id, index);
+}
+
+// 現在選択されている項目を取得
+UINT CbGetSelectIndex(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	return SendMsg(hWnd, id, CB_GETCURSEL, 0, 0);
+}
+
+// 現在選択されている値を取得
+UINT CbGetSelect(HWND hWnd, UINT id)
+{
+	UINT index;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return INFINITE;
+	}
+
+	index = CbGetSelectIndex(hWnd, id);
+	if (index == INFINITE)
+	{
+		return INFINITE;
+	}
+
+	return CbGetData(hWnd, id, index);
+}
+
+// OK ボタンが押された
+void PasswordDlgOnOk(HWND hWnd, UI_PASSWORD_DLG *p)
+{
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	GetTxtA(hWnd, E_USERNAME, p->Username, sizeof(p->Username));
+	GetTxtA(hWnd, E_PASSWORD, p->Password, sizeof(p->Password));
+	p->Type = CbGetSelect(hWnd, C_TYPE);
+
+	if (p->ShowNoSavePassword)
+	{
+		p->NoSavePassword = IsChecked(hWnd, R_NO_SAVE_PASSWORD);
+	}
+
+	EndDialog(hWnd, true);
+}
+
+// パスワード入力ダイアログプロシージャ
+UINT PasswordDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	UI_PASSWORD_DLG *p = (UI_PASSWORD_DLG *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		SetIcon(hWnd, 0, ICO_KEY);
+		CbSetHeight(hWnd, C_TYPE, 18);
+		if (p->ServerName != NULL)
+		{
+			FormatText(hWnd, 0, p->ServerName);
+		}
+		else
+		{
+			SetText(hWnd, 0, _UU("PW_LOGIN_DLG_TITLE"));
+		}
+
+		if (p->ProxyServer == false)
+		{
+			FormatText(hWnd, S_TITLE, p->ServerName == NULL ? "" : p->ServerName);
+		}
+		else
+		{
+			wchar_t tmp[MAX_SIZE];
+			UniFormat(tmp, sizeof(tmp), _UU("PW_MSG_PROXY"), p->ServerName == NULL ? "" : p->ServerName);
+			SetText(hWnd, S_TITLE, tmp);
+		}
+
+		// 接続方法の列挙
+		SendMsg(hWnd, C_TYPE, CBEM_SETUNICODEFORMAT, true, 0);
+
+		if (StrCmpi(p->Username, WINUI_PASSWORD_NULL_USERNAME) != 0)
+		{
+			SetTextA(hWnd, E_USERNAME, p->Username);
+			SetTextA(hWnd, E_PASSWORD, p->Password);
+		}
+		else
+		{
+			p->RetryIntervalSec = 0;
+			SetTextA(hWnd, E_USERNAME, "");
+			SetTextA(hWnd, E_PASSWORD, "");
+		}
+
+		if (p->AdminMode == false)
+		{
+			if (p->ProxyServer == false)
+			{
+				CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_1"), CLIENT_AUTHTYPE_PASSWORD);
+				CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_2"), CLIENT_AUTHTYPE_PLAIN_PASSWORD);
+			}
+			else
+			{
+				CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_PROXY"), 0);
+				Disable(hWnd, C_TYPE);
+			}
+
+			CbSelect(hWnd, C_TYPE, p->Type);
+		}
+		else
+		{
+			CbAddStr(hWnd, C_TYPE, _UU("SM_PASSWORD_TYPE_STR"), 0);
+			Disable(hWnd, C_TYPE);
+			SetTextA(hWnd, E_USERNAME, "Administrator");
+			Disable(hWnd, E_USERNAME);
+		}
+
+		if (IsEmpty(hWnd, E_USERNAME))
+		{
+			FocusEx(hWnd, E_USERNAME);
+		}
+		else
+		{
+			FocusEx(hWnd, E_PASSWORD);
+		}
+		LimitText(hWnd, E_USERNAME, MAX_USERNAME_LEN);
+		LimitText(hWnd, E_PASSWORD, MAX_PASSWORD_LEN);
+
+		PasswordDlgProcChange(hWnd, p);
+
+		if (p->RetryIntervalSec != 0)
+		{
+			SetTimer(hWnd, 1, 50, NULL);
+			FormatText(hWnd, S_COUNTDOWN, p->RetryIntervalSec);
+			Show(hWnd, S_COUNTDOWN);
+			Show(hWnd, P_PROGRESS);
+			SetRange(hWnd, P_PROGRESS, 0, p->RetryIntervalSec * 1000);
+		}
+		else
+		{
+			Hide(hWnd, S_COUNTDOWN);
+			Hide(hWnd, P_PROGRESS);
+		}
+
+		if (p->ShowNoSavePassword)
+		{
+			Show(hWnd, R_NO_SAVE_PASSWORD);
+			Check(hWnd, R_NO_SAVE_PASSWORD, p->NoSavePassword);
+		}
+		else
+		{
+			Hide(hWnd, R_NO_SAVE_PASSWORD);
+		}
+
+		p->StartTick = Tick64();
+
+		if (p->CancelEvent != NULL)
+		{
+			SetTimer(hWnd, 2, 50, NULL);
+		}
+
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			if (p->RetryIntervalSec != 0)
+			{
+				wchar_t tmp[MAX_SIZE];
+				UINT64 end, now, start;
+				start = p->StartTick;
+				end = p->StartTick + (UINT64)(p->RetryIntervalSec * 1000);
+				now = Tick64();
+
+				if (now <= end)
+				{
+					UniFormat(tmp, sizeof(tmp), _UU("PW_RETRYCOUNT"), (UINT)((end - now) / 1000));
+					SetText(hWnd, S_COUNTDOWN, tmp);
+					SetPos(hWnd, P_PROGRESS, (UINT)(now - start));
+				}
+				else
+				{
+					EndDialog(hWnd, true);
+				}
+			}
+			break;
+
+		case 2:
+			if (p->CancelEvent != NULL)
+			{
+				// 終了イベントを待機する
+				HANDLE hEvent = (HANDLE)p->CancelEvent->pData;
+				UINT ret = WaitForSingleObject(hEvent, 0);
+				if (ret != WAIT_TIMEOUT)
+				{
+					// 強制終了イベントがセットされた
+					Close(hWnd);
+				}
+			}
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			PasswordDlgOnOk(hWnd, p);
+			break;
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		switch (HIWORD(wParam))
+		{
+		case EN_CHANGE:
+			switch (LOWORD(wParam))
+			{
+			case E_USERNAME:
+			case E_PASSWORD:
+				PasswordDlgProcChange(hWnd, p);
+				break;
+			}
+			break;
+		case CBN_SELCHANGE:
+			switch (LOWORD(wParam))
+			{
+			case C_TYPE:
+				PasswordDlgProcChange(hWnd, p);
+				if (IsEmpty(hWnd, E_USERNAME))
+				{
+					FocusEx(hWnd, E_USERNAME);
+				}
+				else
+				{
+					FocusEx(hWnd, E_PASSWORD);
+				}
+				break;
+			}
+			break;
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// プログレスバーの位置を設定
+void SetPos(HWND hWnd, UINT id, UINT pos)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, PBM_SETPOS, pos, 0);
+}
+
+// プログレスバーの範囲を設定
+void SetRange(HWND hWnd, UINT id, UINT start, UINT end)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, PBM_SETRANGE32, start, end);
+}
+
+// パスワード入力ダイアログ
+bool PasswordDlg(HWND hWnd, UI_PASSWORD_DLG *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	p->StartTick = Tick64();
+
+	return Dialog(hWnd, D_PASSWORD, PasswordDlgProc, p);
+}
+
+// パスフレーズ入力ダイアログ
+bool PassphraseDlg(HWND hWnd, char *pass, UINT pass_size, BUF *buf, bool p12)
+{
+	PASSPHRASE_DLG p;
+	// 引数チェック
+	if (pass == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	Zero(&p, sizeof(PASSPHRASE_DLG));
+
+	p.buf = buf;
+	p.p12 = p12;
+
+	// まず暗号化されているかどうかを調べる
+	if (p12 == false)
+	{
+		// 秘密鍵
+		if (IsEncryptedK(buf, true) == false)
+		{
+			// 暗号化されていない
+			StrCpy(pass, pass_size, "");
+			return true;
+		}
+	}
+	else
+	{
+		// PKCS#12
+		P12 *p12 = BufToP12(buf);
+		if (p12 == NULL)
+		{
+			// 不明な形式だが暗号化されていない
+			StrCpy(pass, pass_size, "");
+			return true;
+		}
+
+		if (IsEncryptedP12(p12) == false)
+		{
+			// 暗号化されていない
+			StrCpy(pass, pass_size, "");
+			FreeP12(p12);
+			return true;
+		}
+		FreeP12(p12);
+	}
+
+	// ダイアログ表示
+	if (Dialog(hWnd, D_PASSPHRASE, PassphraseDlgProc, &p) == false)
+	{
+		// キャンセル
+		return false;
+	}
+
+	StrCpy(pass, pass_size, p.pass);
+
+	return true;
+}
+
+// WM_COMMAND ハンドラ
+void PassphraseDlgProcCommand(HWND hWnd, PASSPHRASE_DLG *p)
+{
+	char *pass;
+	bool ok;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return;
+	}
+
+	pass = GetTextA(hWnd, E_PASSPHRASE);
+	if (pass == NULL)
+	{
+		return;
+	}
+
+	ok = false;
+
+	if (p->p12 == false)
+	{
+		K *k;
+		k = BufToK(p->buf, true, true, pass);
+		if (k != NULL)
+		{
+			ok = true;
+			FreeK(k);
+		}
+	}
+	else
+	{
+		X *x;
+		K *k;
+		P12 *p12;
+		p12 = BufToP12(p->buf);
+		if (p12 != NULL)
+		{
+			if (ParseP12(p12, &x, &k, pass))
+			{
+				FreeX(x);
+				FreeK(k);
+				ok = true;
+			}
+			FreeP12(p12);
+		}
+	}
+
+	Free(pass);
+
+	SetEnable(hWnd, IDOK, ok);
+}
+
+// パスフレーズ入力ダイアログプロシージャ
+UINT PassphraseDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	PASSPHRASE_DLG *p = (PASSPHRASE_DLG *)param;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		PassphraseDlgProcCommand(hWnd, p);
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			GetTxtA(hWnd, E_PASSPHRASE, p->pass, sizeof(p->pass));
+			EndDialog(hWnd, true);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+
+		switch (LOWORD(wParam))
+		{
+		case E_PASSPHRASE:
+			PassphraseDlgProcCommand(hWnd, p);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, false);
+		break;
+	}
+
+	return 0;
+}
+
+// PKCS ユーティリティ
+void PkcsUtil()
+{
+	InitWinUi(_UU("PKCS_UTIL_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+	Dialog(NULL, D_PKCSUTIL, PkcsUtilProc, NULL);
+	FreeWinUi();
+}
+
+// PKCS 書き込み
+void PkcsUtilWrite(HWND hWnd)
+{
+	wchar_t *filename;
+	BUF *in_buf;
+	char filename_ansi[MAX_SIZE];
+	char pass[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	filename = OpenDlg(hWnd, _UU("DLG_PKCS12_FILTER"), _UU("PKCS_UTIL_SAVEDLG_TITLE"));
+	if (filename == NULL)
+	{
+		return;
+	}
+
+	UniToStr(filename_ansi, sizeof(filename_ansi), filename);
+
+	in_buf = ReadDump(filename_ansi);
+
+	if (in_buf == NULL)
+	{
+		MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("PKCS_UTIL_READ_ERROR"), filename);
+	}
+	else
+	{
+		if (PassphraseDlg(hWnd, pass, sizeof(pass), in_buf, true))
+		{
+			P12 *p12 = BufToP12(in_buf);
+			if (p12 == NULL)
+			{
+				MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("PKCS_UTIL_BAD_FILE"));
+			}
+			else
+			{
+				X *x = NULL;
+				K *k = NULL;
+				BUF *b;
+				ParseP12(p12, &x, &k, pass);
+				FreeP12(p12);
+				p12 = NewP12(x, k, NULL);
+				FreeX(x);
+				FreeK(k);
+				b = P12ToBuf(p12);
+				FreeP12(p12);
+				if (b != NULL)
+				{
+					// バッチ処理
+					WINUI_SECURE_BATCH batch[] =
+					{
+						{WINUI_SECURE_WRITE_DATA, _SS("PKCS_UTIL_SECA_FILENAME"), false,
+							b, NULL, NULL, NULL, NULL, NULL},
+					};
+
+					if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), 2, 0))
+					{
+						MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("PKCS_UTIL_WRITE_OK_MSG"), filename);
+					}
+				}
+				FreeBuf(b);
+			}
+		}
+
+		FreeBuf(in_buf);
+	}
+
+	Free(filename);
+}
+
+// PKCS 消去
+void PkcsUtilErase(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+		_UU("PKCS_MAKE_SURE")) == IDYES)
+	{
+		// バッチ処理
+		WINUI_SECURE_BATCH batch[] =
+		{
+			{WINUI_SECURE_DELETE_OBJECT, _SS("PKCS_UTIL_SECA_FILENAME"), false,
+				NULL, NULL, NULL, NULL, NULL, NULL},
+		};
+
+		if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), 2, 0))
+		{
+			MsgBox(hWnd, MB_ICONINFORMATION, _UU("PKCS_UTIL_DELETE_OK_MSG"));
+		}
+	}
+}
+
+// PKCS ユーティリティ ダイアログ
+UINT PkcsUtilProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		DlgFont(hWnd, S_TITLE, 12, true);
+		SetIcon(hWnd, 0, ICO_CERT);
+		SetFont(hWnd, S_COPYRIGHT, GetFont("Arial", 8, false, false, false, false));
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case B_WRITE:
+			PkcsUtilWrite(hWnd);
+			break;
+
+		case B_ERASE:
+			PkcsUtilErase(hWnd);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+
+		break;
+
+	case WM_CLOSE:
+		EndDialog(hWnd, 0);
+		break;
+	}
+
+	return 0;
+}
+
+// [ファイルを保存する] ダイアログ
+wchar_t *SaveDlg(HWND hWnd, wchar_t *filter, wchar_t *title, wchar_t *default_name, wchar_t *default_ext)
+{
+	wchar_t *filter_str;
+	wchar_t tmp[MAX_SIZE];
+	OPENFILENAMEW o;
+
+	if (MsIsNt() == false)
+	{
+		char *ret, *s1, *s2, *s3, *s4;
+		wchar_t *wr;
+		s1 = CopyUniToStr(filter);
+		s2 = CopyUniToStr(title);
+		s3 = CopyUniToStr(default_name);
+		s4 = CopyUniToStr(default_ext);
+		ret = SaveDlgA(hWnd, s1, s2, s3, s4);
+		Free(s1);
+		Free(s2);
+		Free(s3);
+		Free(s4);
+		wr = CopyStrToUni(ret);
+		Free(ret);
+		return wr;
+	}
+
+	// 引数チェック
+	if (filter == NULL)
+	{
+		filter = _UU("DLG_ALL_FILES");
+	}
+
+	filter_str = MakeFilter(filter);
+
+	Zero(&o, sizeof(o));
+	Zero(tmp, sizeof(tmp));
+
+	if (default_name != NULL)
+	{
+		UniStrCpy(tmp, sizeof(tmp), default_name);
+	}
+
+	o.lStructSize = sizeof(o);
+	
+	if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
+	{
+		o.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
+	}
+
+	o.hwndOwner = hWnd;
+	o.hInstance = GetModuleHandleA(NULL);
+	o.lpstrFile = tmp;
+	o.lpstrTitle = title;
+	o.lpstrFilter = filter_str;
+	o.nMaxFile = sizeof(tmp);
+	o.Flags = OFN_OVERWRITEPROMPT;
+	o.lpstrDefExt = default_ext;
+
+	if (GetSaveFileNameW(&o) == false)
+	{
+		Free(filter_str);
+		return NULL;
+	}
+
+	Free(filter_str);
+
+	return UniCopyStr(tmp);
+}
+char *SaveDlgA(HWND hWnd, char *filter, char *title, char *default_name, char *default_ext)
+{
+	char *filter_str;
+	char tmp[MAX_SIZE];
+	OPENFILENAME o;
+	// 引数チェック
+	if (filter == NULL)
+	{
+		filter = _SS("DLG_ALL_FILES");
+	}
+
+	filter_str = MakeFilterA(filter);
+
+	Zero(&o, sizeof(o));
+	Zero(tmp, sizeof(tmp));
+
+	if (default_name != NULL)
+	{
+		StrCpy(tmp, sizeof(tmp), default_name);
+	}
+
+	o.lStructSize = sizeof(o);
+	
+	if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
+	{
+		o.lStructSize = OPENFILENAME_SIZE_VERSION_400A;
+	}
+
+	o.hwndOwner = hWnd;
+	o.hInstance = GetModuleHandleA(NULL);
+	o.lpstrFile = tmp;
+	o.lpstrTitle = title;
+	o.lpstrFilter = filter_str;
+	o.nMaxFile = sizeof(tmp);
+	o.Flags = OFN_OVERWRITEPROMPT;
+	o.lpstrDefExt = default_ext;
+
+	if (GetSaveFileName(&o) == false)
+	{
+		Free(filter_str);
+		return NULL;
+	}
+
+	Free(filter_str);
+
+	return CopyStr(tmp);
+}
+
+// [ファイルを開く] ダイアログ
+wchar_t *OpenDlg(HWND hWnd, wchar_t *filter, wchar_t *title)
+{
+	wchar_t *filter_str;
+	wchar_t tmp[MAX_SIZE];
+	OPENFILENAMEW o;
+
+	if (MsIsNt() == false)
+	{
+		char *ret;
+		char *filter_a;
+		char *title_a;
+		wchar_t *w;
+		filter_a = CopyUniToStr(filter);
+		title_a = CopyUniToStr(title);
+		ret = OpenDlgA(hWnd, filter_a, title_a);
+		Free(filter_a);
+		Free(title_a);
+		w = CopyStrToUni(ret);
+		Free(ret);
+		return w;
+	}
+
+	// 引数チェック
+	if (filter == NULL)
+	{
+		filter = _UU("DLG_ALL_FILES");
+	}
+
+	filter_str = MakeFilter(filter);
+
+	Zero(&o, sizeof(OPENFILENAMEW));
+	Zero(tmp, sizeof(tmp));
+
+	o.lStructSize = sizeof(o);
+
+
+	if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
+	{
+		o.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
+	}
+
+
+	o.hwndOwner = hWnd;
+	o.hInstance = GetModuleHandleA(NULL);
+	o.lpstrFilter = filter_str;
+	o.lpstrFile = tmp;
+	o.nMaxFile = sizeof(tmp);
+	o.lpstrTitle = title;
+	o.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+
+	if (GetOpenFileNameW(&o) == false)
+	{
+		Free(filter_str);
+		return NULL;
+	}
+
+	Free(filter_str);
+
+	return UniCopyStr(tmp);
+}
+char *OpenDlgA(HWND hWnd, char *filter, char *title)
+{
+	char *filter_str;
+	char tmp[MAX_SIZE];
+	OPENFILENAME o;
+	// 引数チェック
+	if (filter == NULL)
+	{
+		filter = _SS("DLG_ALL_FILES");
+	}
+
+	filter_str = MakeFilterA(filter);
+
+	Zero(&o, sizeof(OPENFILENAME));
+	Zero(tmp, sizeof(tmp));
+
+	o.lStructSize = sizeof(o);
+
+	if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
+	{
+		o.lStructSize = OPENFILENAME_SIZE_VERSION_400A;
+	}
+
+	o.hwndOwner = hWnd;
+	o.hInstance = GetModuleHandleA(NULL);
+	o.lpstrFilter = filter_str;
+	o.lpstrFile = tmp;
+	o.nMaxFile = sizeof(tmp);
+	o.lpstrTitle = title;
+	o.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+
+	if (GetOpenFileName(&o) == false)
+	{
+		Free(filter_str);
+		return NULL;
+	}
+
+	Free(filter_str);
+
+	return CopyStr(tmp);
+}
+
+// フィルタ文字列の生成
+wchar_t *MakeFilter(wchar_t *str)
+{
+	UINT i;
+	wchar_t *ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(UniStrSize(str) + 32);
+
+	for (i = 0;i < UniStrLen(str);i++)
+	{
+		if (str[i] == L'|')
+		{
+			ret[i] = L'\0';
+		}
+		else
+		{
+			ret[i] = str[i];
+		}
+	}
+
+	return ret;
+}
+char *MakeFilterA(char *str)
+{
+	UINT i;
+	char *ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(StrSize(str) + 32);
+
+	for (i = 0;i < StrLen(str);i++)
+	{
+		if (str[i] == '|')
+		{
+			ret[i] = '\0';
+		}
+		else
+		{
+			ret[i] = str[i];
+		}
+	}
+
+	return ret;
+}
+
+// バッチの実行
+bool ExecuteSecureDeviceBatch(HWND hWnd, SECURE *sec, SECURE_DEVICE_THREAD *p, SECURE_DEVICE *dev, WINUI_SECURE_BATCH *batch)
+{
+	LIST *o;
+	void *buf;
+	UINT size = 10 * 1024;		// データの最大サイズ
+	UINT type = INFINITE;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || dev == NULL || batch == NULL || sec == NULL)
+	{
+		return false;
+	}
+
+	switch (batch->Type)
+	{
+	case WINUI_SECURE_DELETE_CERT:
+		type = SEC_X;
+		goto DELETE_OBJECT;
+
+	case WINUI_SECURE_DELETE_KEY:
+		type = SEC_K;
+		goto DELETE_OBJECT;
+
+	case WINUI_SECURE_DELETE_DATA:
+		type = SEC_DATA;
+		goto DELETE_OBJECT;
+
+	case WINUI_SECURE_DELETE_OBJECT:
+		// オブジェクトの削除
+DELETE_OBJECT:
+		SetText(hWnd, S_STATUS, _UU("SEC_DELETE"));
+		if (DeleteSecObjectByName(sec, batch->Name, type) == false)
+		{
+			p->ErrorMessage = UniCopyStr(_UU("SEC_ERROR_DELETE"));
+			return false;
+		}
+		break;
+
+	case WINUI_SECURE_ENUM_OBJECTS:
+		// オブジェクトの列挙
+		SetText(hWnd, S_STATUS, _UU("SEC_ENUM"));
+		o = EnumSecObject(sec);
+		if (o == NULL)
+		{
+			p->ErrorMessage = UniCopyStr(_UU("SEC_ERROR_ENUM"));
+			return false;
+		}
+
+		batch->EnumList = o;
+		break;
+
+	case WINUI_SECURE_WRITE_DATA:
+		// データの書き込み
+		SetText(hWnd, S_STATUS, _UU("SEC_WRITE_DATA"));
+		if (WriteSecData(sec, batch->Private, batch->Name, batch->InputData->Buf, batch->InputData->Size) == false)
+		{
+			p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+				_UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
+			return false;
+		}
+		break;
+
+	case WINUI_SECURE_READ_DATA:
+		// データの読み込み
+		SetText(hWnd, S_STATUS, _UU("SEC_READ_DATA"));
+		buf = MallocEx(size, true);
+		size = ReadSecData(sec, batch->Name, buf, size);
+		if (size == 0)
+		{
+			Free(buf);
+			p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+				_UU("SEC_ERROR_NOT_FOUND_1") : _UU("SEC_ERROR_NOT_FOUND_2"));
+			return false;
+		}
+		batch->OutputData = NewBuf();
+		WriteBuf(batch->OutputData, buf, size);
+		SeekBuf(batch->OutputData, 0, 0);
+		Free(buf);
+		break;
+
+	case WINUI_SECURE_WRITE_CERT:
+		// 証明書の書き込み
+		SetText(hWnd, S_STATUS, _UU("SEC_WRITE_CERT"));
+		if (WriteSecCert(sec, batch->Private, batch->Name, batch->InputX) == false)
+		{
+			p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+				_UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
+			return false;
+		}
+		break;
+
+	case WINUI_SECURE_READ_CERT:
+		// 証明書の読み込み
+		SetText(hWnd, S_STATUS, _UU("SEC_READ_CERT"));
+		batch->OutputX = ReadSecCert(sec, batch->Name);
+		if (batch->OutputX == NULL)
+		{
+			p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+				_UU("SEC_ERROR_NOT_FOUND_1") : _UU("SEC_ERROR_NOT_FOUND_2"));
+			return false;
+		}
+		break;
+
+	case WINUI_SECURE_WRITE_KEY:
+		// 秘密鍵の書き込み
+		SetText(hWnd, S_STATUS, _UU("SEC_WRITE_KEY"));
+		if (WriteSecKey(sec, batch->Private, batch->Name, batch->InputK) == false)
+		{
+			p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+				_UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
+			return false;
+		}
+		break;
+
+	case WINUI_SECURE_SIGN_WITH_KEY:
+		// 署名
+		SetText(hWnd, S_STATUS, _UU("SEC_SIGN"));
+		if (SignSec(sec, batch->Name, batch->OutputSign, batch->InputData->Buf, batch->InputData->Size) == false)
+		{
+			p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+				_UU("SEC_ERROR_SIGN_1") : _UU("SEC_ERROR_SIGN_2"));
+			return false;
+		}
+		break;
+	}
+
+	return true;
+}
+
+// セキュアデバイス操作をバッチ処理で実行する
+void SecureDeviceBatch(HWND hWnd, SECURE *sec, SECURE_DEVICE_THREAD *p, SECURE_DEVICE *dev)
+{
+	UINT i;
+	// 引数チェック
+	if (hWnd == NULL || p == NULL || dev == NULL || sec == NULL)
+	{
+		return;
+	}
+
+	// 逐次処理を行う
+	for (i = 0;i < p->w->num_batch;i++)
+	{
+		WINUI_SECURE_BATCH *batch = &p->w->batch[i];
+
+		if (ExecuteSecureDeviceBatch(hWnd, sec, p, dev, batch) == false)
+		{
+			// 1 つでも失敗したら直ちに中断する
+			return;
+		}
+	}
+
+	// すべてのバッチ処理が成功した
+	p->Succeed = true;
+}
+
+// セキュアデバイス操作を行うスレッド
+void SecureDeviceThread(THREAD *t, void *param)
+{
+	SECURE *sec;
+	SECURE_DEVICE_THREAD *p = (SECURE_DEVICE_THREAD *)param;
+	SECURE_DEVICE *dev;
+	HWND hWnd;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	p->Succeed = false;
+	p->ErrorMessage = NULL;
+
+	hWnd = p->hWnd;
+
+	// デバイスを開く
+	dev = GetSecureDevice(p->w->device_id);
+	SetText(hWnd, S_STATUS, _UU("SEC_OPENING"));
+	sec = OpenSec(p->w->device_id);
+	if (sec == NULL)
+	{
+		// デバイスオープン失敗
+		if (p->w->device_id != 9)
+		{
+			p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_DEVICE"), dev->DeviceName);
+		}
+		else
+		{
+			p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_DEVICEEX"), dev->DeviceName);
+		}
+	}
+	else
+	{
+		// セッションを開く
+		SetText(hWnd, S_STATUS, _UU("SEC_OPEN_SESSION"));
+		if (OpenSecSession(sec, 0) == false)
+		{
+			// セッション初期化失敗
+			p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_SESSION"), dev->DeviceName);
+		}
+		else
+		{
+			// ログイン
+			SetText(hWnd, S_STATUS, _UU("SEC_LOGIN"));
+			if (LoginSec(sec, p->pin) == false)
+			{
+				// ログイン失敗
+				p->ErrorMessage =UniCopyStr(_UU("SEC_ERROR_LOGIN"));
+			}
+			else
+			{
+				// バッチ処理メイン
+				SetText(hWnd, S_STATUS, _UU("SEC_INIT_BATCH"));
+				SecureDeviceBatch(hWnd, sec, p, dev);
+
+				// ログアウト
+				SetText(hWnd, S_STATUS, _UU("SEC_LOGOUT"));
+				LogoutSec(sec);
+			}
+
+			// セッションを閉じる
+			SetText(hWnd, S_STATUS, _UU("SEC_CLOSE_SESSION"));
+			CloseSecSession(sec);
+		}
+
+		// デバイスを閉じる
+		SetText(hWnd, S_STATUS, _UU("SEC_CLOSING"));
+		CloseSec(sec);
+	}
+
+	if (p->Succeed)
+	{
+		// 成功した場合は 150ms メッセージを表示する (サービス)
+		SetText(hWnd, S_STATUS, _UU("SEC_FINISHED"));
+		SleepThread(150);
+	}
+
+	SendMessage(p->hWnd, WM_APP + 1, 0, 0);
+}
+
+// セキュアデバイス操作を開始する
+void StartSecureDevice(HWND hWnd, SECURE_DEVICE_WINDOW *w)
+{
+	SECURE_DEVICE_THREAD *p;
+	// 引数チェック
+	if (hWnd == NULL || w == NULL)
+	{
+		return;
+	}
+
+	// コントロールを無効にする
+	EnableSecureDeviceWindowControls(hWnd, false);
+
+	// スレッドを開始する
+	p = ZeroMalloc(sizeof(SECURE_DEVICE_THREAD));
+	p->w = w;
+	p->hWnd = hWnd;
+	w->p = p;
+	p->pin = GetTextA(hWnd, E_PIN);
+	ReleaseThread(NewThread(SecureDeviceThread, p));
+}
+
+// セキュアデバイス操作用ウインドウのコントロールを有効・無効化する
+void EnableSecureDeviceWindowControls(HWND hWnd, bool enable)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (enable)
+	{
+		Show(hWnd, S_PIN_CODE);
+		Show(hWnd, E_PIN);
+		Show(hWnd, S_WARNING);
+	}
+	else
+	{
+		Hide(hWnd, S_PIN_CODE);
+		Hide(hWnd, E_PIN);
+		Hide(hWnd, S_WARNING);
+	}
+
+	SetEnable(hWnd, IDOK, enable);
+	SetEnable(hWnd, IDCANCEL, enable);
+	SetEnable(hWnd, S_TITLE, enable);
+	SetEnable(hWnd, S_DEVICE_INFO, enable);
+	SetEnable(hWnd, S_INSERT_SECURE, enable);
+
+	if (enable == false)
+	{
+		DisableClose(hWnd);
+		SetText(hWnd, S_STATUS, L"");
+		Show(hWnd, S_STATUS);
+		PlayAvi(hWnd, A_PROGRESS, true);
+	}
+	else
+	{
+		EnableClose(hWnd);
+		SetText(hWnd, S_STATUS, L"");
+		Hide(hWnd, S_STATUS);
+		StopAvi(hWnd, A_PROGRESS);
+	}
+}
+
+// セキュアデバイス操作用ウインドウプロシージャ
+UINT SecureDeviceWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+	SECURE_DEVICE_WINDOW *w = (SECURE_DEVICE_WINDOW *)param;
+	SECURE_DEVICE *dev = GetSecureDevice(w->device_id);
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		if (dev == NULL)
+		{
+			MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_ERROR_INVALID_ID"), w->device_id);
+			EndDialog(hWnd, 0);
+			break;
+		}
+
+		if (IsJPKI(dev->Id))
+		{
+			// 住基カード
+			Hide(hWnd, S_IMAGE);
+			Show(hWnd, S_IMAGE2);
+			Hide(hWnd, S_IMAGE_TSUKUBA);
+		}
+		else
+		{
+			// 普通のカード
+			Hide(hWnd, S_IMAGE2);
+
+			if (w->BitmapId != 0)
+			{
+				// 筑波大学用
+				Hide(hWnd, S_IMAGE);
+				Show(hWnd, S_IMAGE_TSUKUBA);
+			}
+			else
+			{
+				// 一般用
+				Show(hWnd, S_IMAGE);
+				Hide(hWnd, S_IMAGE_TSUKUBA);
+			}
+		}
+
+		FormatText(hWnd, 0, dev->Type != SECURE_USB_TOKEN ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN"),
+			dev->DeviceName);
+		FormatText(hWnd, S_TITLE, dev->DeviceName);
+		FormatText(hWnd, S_INSERT_SECURE,
+			dev->Type != SECURE_USB_TOKEN ? _UU("SEC_INIT_MSG_1") : _UU("SEC_INIT_MSG_2"));
+		FormatText(hWnd, S_DEVICE_INFO,
+			dev->DeviceName, dev->Manufacturer, dev->ModuleName);
+
+		DlgFont(hWnd, S_SOFTWARE_TITLE, 11, 0);
+		SetText(hWnd, S_SOFTWARE_TITLE, title_bar);
+
+		DlgFont(hWnd, S_TITLE, 14, true);
+		DlgFont(hWnd, S_DEVICE_INFO, 11, false);
+		DlgFont(hWnd, S_STATUS, 13, true);
+		EnableSecureDeviceWindowControls(hWnd, true);
+		OpenAvi(hWnd, A_PROGRESS, AVI_PROGRESS);
+
+		SetIcon(hWnd, 0, ICO_KEY);
+
+		// 初期 PIN
+		if ((w->default_pin != NULL && StrLen(w->default_pin) != 0) || (cached_pin_code_expires >= Tick64()))
+		{
+			if (w->default_pin != NULL && StrLen(w->default_pin) != 0)
+			{
+				SetTextA(hWnd, E_PIN, w->default_pin);
+			}
+			else
+			{
+				SetTextA(hWnd, E_PIN, cached_pin_code);
+			}
+			SetTimer(hWnd, 1, 1, NULL);
+		}
+
+		break;
+
+	case WM_TIMER:
+		switch (wParam)
+		{
+		case 1:
+			KillTimer(hWnd, 1);
+			Command(hWnd, IDOK);
+			break;
+		}
+		break;
+
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case IDOK:
+			StartSecureDevice(hWnd, w);
+			break;
+
+		case IDCANCEL:
+			Close(hWnd);
+			break;
+		}
+		break;
+
+	case WM_CLOSE:
+		if (IsEnable(hWnd, IDCANCEL))
+		{
+			CloseAvi(hWnd, A_PROGRESS);
+			EndDialog(hWnd, false);
+		}
+		break;
+
+	case WM_APP + 1:
+		// スレッドから応答があった
+		if (w->p != NULL)
+		{
+			if (w->p->Succeed)
+			{
+				// 成功
+				if (w->default_pin != NULL)
+				{
+					StrCpy(w->default_pin, 128, w->p->pin);
+				}
+				StrCpy(cached_pin_code, sizeof(cached_pin_code), w->p->pin);
+				cached_pin_code_expires = Tick64() + (UINT64)WINUI_SECUREDEVICE_PIN_CACHE_TIME;
+				Free(w->p->pin);
+				Free(w->p);
+				EndDialog(hWnd, true);
+			}
+			else
+			{
+				// 失敗
+				cached_pin_code_expires = 0;
+				EnableSecureDeviceWindowControls(hWnd, true);
+				FocusEx(hWnd, E_PIN);
+				MsgBox(hWnd, MB_ICONEXCLAMATION, w->p->ErrorMessage);
+				Free(w->p->pin);
+				Free(w->p->ErrorMessage);
+				Free(w->p);
+			}
+		}
+		break;
+	}
+
+	return 0;
+}
+
+// WM_COMMAND を送信する
+void Command(HWND hWnd, UINT id)
+{
+	SendMessage(hWnd, WM_COMMAND, id, 0);
+}
+
+// セキュアデバイスウインドウを表示する
+bool SecureDeviceWindow(HWND hWnd, WINUI_SECURE_BATCH *batch, UINT num_batch, UINT device_id, UINT bitmap_id)
+{
+	SECURE_DEVICE_WINDOW w;
+	UINT i;
+	// 引数チェック
+	if (batch == NULL || num_batch == 0 || device_id == 0)
+	{
+		return false;
+	}
+
+	// 成功フラグを初期化
+	for (i = 0;i < num_batch;i++)
+	{
+		batch[i].Succeed = false;
+	}
+
+	Zero(&w, sizeof(w));
+	w.batch = batch;
+	w.device_id = device_id;
+	w.num_batch = num_batch;
+	w.BitmapId = bitmap_id;
+
+	// ダイアログを開く
+	return (bool)Dialog(hWnd, D_SECURE, SecureDeviceWindowProc, &w);
+}
+
+// AVI を停止する
+void StopAvi(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	Animate_Stop(DlgItem(hWnd, id));
+	Hide(hWnd, id);
+}
+
+// AVI を再生する
+void PlayAvi(HWND hWnd, UINT id, bool repeat)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	Show(hWnd, id);
+	Animate_Play(DlgItem(hWnd, id), 0, -1, (repeat ? -1 : 0));
+}
+
+// AVI ファイルを閉じる
+void CloseAvi(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	StopAvi(hWnd, id);
+	Animate_Close(DlgItem(hWnd, id));
+}
+
+// AVI ファイルを開く
+void OpenAvi(HWND hWnd, UINT id, UINT avi_id)
+{
+	// 引数チェック
+	if (hWnd == NULL || avi_id == 0)
+	{
+		return;
+	}
+
+	Hide(hWnd, id);
+	Animate_OpenEx(DlgItem(hWnd, id), hDll, MAKEINTRESOURCE(avi_id));
+}
+
+// フォントをコントロールに設定する
+void DlgFont(HWND hWnd, UINT id, UINT size, UINT bold)
+{
+	DIALOG_PARAM *param = (DIALOG_PARAM *)GetParam(hWnd);
+
+	if (param == NULL || param->meiryo == false)
+	{
+		SetFont(hWnd, id, Font(size, bold));
+	}
+	else
+	{
+		SetFont(hWnd, id, GetFont((_GETLANG() == 2 ? "Microsoft YaHei" : "Meiryo"), size, bold, false, false, false));
+	}
+}
+
+// 標準的なフォントを生成する
+HFONT Font(UINT size, UINT bold)
+{
+	return GetFont(NULL, size, bold, false, false, false);
+}
+
+// 内部管理用ダイアログプロシージャ
+UINT CALLBACK InternalDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	DIALOG_PARAM *param = (DIALOG_PARAM *)GetParam(hWnd);
+	void *app_param = NULL;
+	bool white_flag = false;
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	if (msg == WM_INITDIALOG)
+	{
+		DoEvents(hWnd);
+	}
+
+	if (param == NULL)
+	{
+		if (msg == WM_INITDIALOG)
+		{
+			param = (void *)lParam;
+			InitDialogInternational(hWnd, param);
+		}
+	}
+	if (param != NULL)
+	{
+		app_param = param->param;
+		white_flag = param->white;
+	}
+
+	ret = DlgProc(hWnd, msg, wParam, lParam, white_flag);
+	if (ret != 0)
+	{
+		return ret;
+	}
+
+	ret = 0;
+
+	if (param != NULL)
+	{
+		if (param->proc != NULL)
+		{
+			ret = param->proc(hWnd, msg, wParam, lParam, app_param);
+		}
+		else
+		{
+			if (msg == WM_CLOSE)
+			{
+				EndDialog(hWnd, 0);
+			}
+			else if (msg == WM_COMMAND && (wParam == IDOK || wParam == IDCANCEL))
+			{
+				Close(hWnd);
+			}
+		}
+	}
+
+	if (msg == WM_INITDIALOG)
+	{
+		SetForegroundWindow(hWnd);
+		SetActiveWindow(hWnd);
+	}
+
+	return ret;
+}
+
+// ダイアログ ボックスを表示する
+UINT Dialog(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param)
+{
+	bool white = true;
+
+	return DialogEx(hWnd, id, proc, param, white);
+}
+UINT DialogEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white)
+{
+	return DialogEx2(hWnd, id, proc, param, white, false);
+}
+UINT DialogEx2(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white, bool meiryo)
+{
+	UINT ret;
+	DIALOG_PARAM p;
+	// 引数チェック
+	if (id == 0)
+	{
+		return 0;
+	}
+
+	Zero(&p, sizeof(p));
+	p.param = param;
+	p.white = white;
+	p.proc = proc;
+
+	if (MsIsVista())
+	{
+		p.meiryo = meiryo;
+	}
+
+	ret = DialogInternal(hWnd, id, InternalDialogProc, &p);
+
+	return ret;
+}
+
+// モードレスダイアログを作成する
+HWND DialogCreateEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white)
+{
+	HWND ret = NULL;
+	DIALOG_PARAM p;
+	// 引数チェック
+	if (id == 0)
+	{
+		return 0;
+	}
+
+	Zero(&p, sizeof(p));
+	p.param = param;
+	p.white = white;
+	p.proc = proc;
+
+	if (MsIsNt() == false)
+	{
+		// Win9x
+		ret = CreateDialogParamA(hDll, MAKEINTRESOURCEA(id), hWnd,
+			(DLGPROC)proc, (LPARAM)param);
+	}
+	else
+	{
+		// WinNT
+		ret = CreateDialogParamW(hDll, MAKEINTRESOURCEW(id), hWnd,
+			(DLGPROC)proc, (LPARAM)param);
+	}
+
+	return ret;
+}
+
+// ビットマップをボタンに設定する
+void SetBitmap(HWND hWnd, UINT id, UINT bmp_id)
+{
+	HBITMAP bmp;
+	char *class_name;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	bmp = LoadImage(hDll, MAKEINTRESOURCE(bmp_id), IMAGE_BITMAP, 0, 0, (MsIsNt() ? LR_SHARED : 0) | LR_VGACOLOR);
+	if (bmp == NULL)
+	{
+		return;
+	}
+
+	class_name = GetClassA(hWnd, id);
+
+	if (StrCmpi(class_name, "Static") != 0)
+	{
+		SendMsg(hWnd, id, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp);
+	}
+	else
+	{
+		SendMsg(hWnd, id, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp);
+	}
+
+	Free(class_name);
+}
+
+// アイコンキャッシュの初期化
+void InitIconCache()
+{
+	if (icon_cache_list != NULL)
+	{
+		return;
+	}
+
+	icon_cache_list = NewList(NULL);
+}
+
+// アイコンキャッシュの解放
+void FreeIconCache()
+{
+	UINT i;
+	if (icon_cache_list == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(icon_cache_list);i++)
+	{
+		ICON_CACHE *c = LIST_DATA(icon_cache_list, i);
+		DestroyIcon(c->hIcon);
+		Free(c);
+	}
+
+	ReleaseList(icon_cache_list);
+	icon_cache_list = NULL;
+}
+
+// アイコン取得
+HICON LoadIconEx(UINT id, bool small_icon)
+{
+	HICON h = NULL;
+	UINT i;
+	if (icon_cache_list == NULL)
+	{
+		return small_icon == false ? LoadLargeIconInner(id) : LoadSmallIconInner(id);
+	}
+
+	LockList(icon_cache_list);
+	{
+		for (i = 0;i < LIST_NUM(icon_cache_list);i++)
+		{
+			ICON_CACHE *c = LIST_DATA(icon_cache_list, i);
+			if (c->id == id && c->small_icon == small_icon)
+			{
+				h = c->hIcon;
+				break;
+			}
+		}
+
+		if (h == NULL)
+		{
+			h = small_icon == false ? LoadLargeIconInner(id) : LoadSmallIconInner(id);
+			if (h != NULL)
+			{
+				ICON_CACHE *c = ZeroMalloc(sizeof(ICON_CACHE));
+				c->hIcon = h;
+				c->id = id;
+				c->small_icon = small_icon;
+				Add(icon_cache_list, c);
+			}
+		}
+	}
+	UnlockList(icon_cache_list);
+
+	return h;
+}
+
+// 大きいアイコン取得
+HICON LoadLargeIcon(UINT id)
+{
+	return LoadIconEx(id, false);
+}
+
+// 小さいアイコン取得
+HICON LoadSmallIcon(UINT id)
+{
+	return LoadIconEx(id, true);
+}
+
+// 大きいアイコンを取得する
+HICON LoadLargeIconInner(UINT id)
+{
+	HICON ret;
+	ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 32, 32, 0);
+	if (ret == NULL)
+	{
+		ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 32, 32, LR_VGACOLOR);
+		if (ret == NULL)
+		{
+			ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, 0);
+			if (ret == NULL)
+			{
+				ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_VGACOLOR);
+				if (ret == NULL)
+				{
+					ret = LoadIcon(hDll, MAKEINTRESOURCE(id));
+				}
+			}
+		}
+	}
+	return ret;
+}
+
+// 小さいアイコンを取得する
+HICON LoadSmallIconInner(UINT id)
+{
+	HICON ret;
+	ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 16, 16, 0);
+	if (ret == NULL)
+	{
+		ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 16, 16, LR_VGACOLOR);
+		if (ret == NULL)
+		{
+			ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, 0);
+			if (ret == NULL)
+			{
+				ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_VGACOLOR);
+				if (ret == NULL)
+				{
+					ret = LoadLargeIconInner(id);
+				}
+			}
+		}
+	}
+	return ret;
+}
+
+// アイコンをウインドウまたはボタンに設定する
+void SetIcon(HWND hWnd, UINT id, UINT icon_id)
+{
+	HICON icon1, icon2;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	icon1 = LoadLargeIcon(icon_id);
+	if (icon1 == NULL)
+	{
+		return;
+	}
+
+	if (id == 0)
+	{
+		SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon1);
+		icon2 = LoadSmallIcon(icon_id);
+		if (icon2 == NULL)
+		{
+			icon2 = icon1;
+		}
+		SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon2);
+	}
+	else
+	{
+		bool is_btn = true;
+		wchar_t *s = GetClass(hWnd, id);
+		if (s != NULL)
+		{
+			if (UniStrCmpi(s, L"Static") == 0)
+			{
+				is_btn = false;
+			}
+			Free(s);
+		}
+
+		if (is_btn)
+		{
+			SendMsg(hWnd, id, BM_SETIMAGE, IMAGE_ICON, (LPARAM)icon1);
+		}
+		else
+		{
+			SendMsg(hWnd, id, STM_SETICON, (WPARAM)icon1, 0);
+		}
+	}
+}
+
+// ラジオボタンがチェックされているか確認する
+bool IsChecked(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	return IsDlgButtonChecked(hWnd, id) == BST_CHECKED ? true : false;
+}
+
+// ラジオボタンをチェック
+void Check(HWND hWnd, UINT id, bool b)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if ((!(!IsChecked(hWnd, id))) != (!(!b)))
+	{
+		CheckDlgButton(hWnd, id, b ? BST_CHECKED : BST_UNCHECKED);
+	}
+}
+
+// テキストボックスの文字サイズが指定されたサイズ以下であることを確認する
+bool CheckTextSize(HWND hWnd, UINT id, UINT size, bool unicode)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	if (GetTextSize(hWnd, id, unicode) <= size)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// テキストボックスに入っている文字列数が指定された文字列数以下であることを確認する
+bool CheckTextLen(HWND hWnd, UINT id, UINT len, bool unicode)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	if (GetTextLen(hWnd, id, unicode) <= len)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// テキストボックスに入力できる文字数を制限する
+void LimitText(HWND hWnd, UINT id, UINT count)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMsg(hWnd, id, EM_LIMITTEXT, count, 0);
+}
+
+// フォントの設定
+void SetFont(HWND hWnd, UINT id, HFONT hFont)
+{
+	// 引数チェック
+	if (hWnd == NULL || hFont == NULL)
+	{
+		return;
+	}
+
+	SendMessage(DlgItem(hWnd, id), WM_SETFONT, (WPARAM)hFont, true);
+}
+
+// フォントサイズの取得
+bool GetFontSize(HFONT hFont, UINT *x, UINT *y)
+{
+	bool ret = false;
+	UINT xx = 0;
+	UINT yy = 0;
+
+	// フォントハンドルを検索
+	LockList(font_list);
+	{
+		UINT i;
+
+		for (i = 0;i < LIST_NUM(font_list);i++)
+		{
+			FONT *f = LIST_DATA(font_list, i);
+
+			if (f->hFont == hFont)
+			{
+				xx = f->x;
+				yy = f->y;
+
+				ret = true;
+				break;
+			}
+		}
+	}
+	UnlockList(font_list);
+
+	if (ret == false)
+	{
+		ret = CalcFontSize(hFont, &xx, &yy);
+	}
+
+	if (xx == 0 || yy == 0)
+	{
+		xx = 8;
+		yy = 16;
+	}
+
+	if (x != NULL)
+	{
+		*x = xx;
+	}
+
+	if (y != NULL)
+	{
+		*y = yy;
+	}
+
+	return ret;
+}
+
+// フォントサイズの計算
+bool CalcFontSize(HFONT hFont, UINT *x, UINT *y)
+{
+	UINT xx = 0, yy = 0;
+	TEXTMETRIC tm;
+	SIZE sz;
+	bool ret = false;
+	HDC hDC;
+
+	hDC = CreateCompatibleDC(NULL);
+
+	SelectObject(hDC, hFont);
+
+	Zero(&tm, sizeof(tm));
+	Zero(&sz, sizeof(sz));
+
+	if (GetTextMetrics(hDC, &tm))
+	{
+		xx = tm.tmAveCharWidth;
+		yy = tm.tmHeight;
+
+		ret = true;
+
+		if (GetTextExtentPoint32(hDC,
+			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+			52, &sz))
+		{
+			xx = (sz.cx / 26 + 1) / 2;
+		}
+	}
+
+	if (x != NULL)
+	{
+		*x = xx;
+	}
+
+	if (y != NULL)
+	{
+		*y = yy;
+	}
+
+	DeleteDC(hDC);
+
+	return ret;
+}
+
+// フォントの取得
+HFONT GetFont(char *name, UINT size, bool bold, bool italic, bool underline, bool strikeout)
+{
+	HFONT hFont;
+	HDC hDC;
+	// 引数チェック
+	if (name == NULL)
+	{
+		name = font_name;
+	}
+	if (size == 0)
+	{
+		size = font_size;
+		if (size == 0)
+		{
+			size = 9;
+		}
+	}
+
+	// 既存のフォントを探す
+	LockList(font_list);
+	{
+		FONT *f, t;
+		DWORD font_quality = ANTIALIASED_QUALITY;
+		OS_INFO *os = GetOsInfo();
+		UINT x = 0;
+		UINT y = 0;
+		int rotate = 0;
+
+		Zero(&t, sizeof(t));
+		t.Bold = bold;
+		t.Italic = italic;
+		t.Size = size;
+		t.StrikeOut = strikeout;
+		t.UnderLine = underline;
+		t.Name = CopyStr(name);
+		f = Search(font_list, &t);
+		Free(t.Name);
+
+		if (f != NULL)
+		{
+			// フォントを発見した
+			UnlockList(font_list);
+			return f->hFont;
+		}
+
+		// 新しいフォントを作成する
+		hDC = CreateCompatibleDC(NULL);
+
+		// Windows XP 以降では ClearType を指定する
+		if (OS_IS_WINDOWS_NT(os->OsType) && GET_KETA(os->OsType, 100) >= 3)
+		{
+			font_quality = CLEARTYPE_NATURAL_QUALITY;
+			rotate = 3600;
+		}
+
+		// フォント作成
+		hFont = CreateFontA(-MulDiv(size, GetDeviceCaps(hDC, LOGPIXELSY), 72),
+			0, rotate, rotate, (bold == false ? 500 : FW_BOLD),
+			italic, underline, strikeout, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
+			CLIP_DEFAULT_PRECIS, font_quality, DEFAULT_PITCH, name);
+
+		if (hFont == NULL)
+		{
+			// 失敗
+			DeleteDC(hDC);
+			UnlockList(font_list);
+
+			return NULL;
+		}
+
+		CalcFontSize(hFont, &x, &y);
+
+		// テーブルに追加
+		f = ZeroMalloc(sizeof(FONT));
+		f->Bold = bold;
+		f->hFont = hFont;
+		f->Italic = italic;
+		f->Name = CopyStr(name);
+		f->Size = size;
+		f->StrikeOut = strikeout;
+		f->UnderLine = underline;
+		f->x = x;
+		f->y = y;
+
+		Insert(font_list, f);
+
+		DeleteDC(hDC);
+	}
+	UnlockList(font_list);
+
+	return hFont;
+}
+
+// フォントの比較
+int CompareFont(void *p1, void *p2)
+{
+	FONT *f1, *f2;
+	UINT r;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	f1 = *(FONT **)p1;
+	f2 = *(FONT **)p2;
+	if (f1 == NULL || f2 == NULL)
+	{
+		return 0;
+	}
+	r = StrCmpi(f1->Name, f2->Name);
+	if (r != 0)
+	{
+		return r;
+	}
+	else
+	{
+		if (f1->Bold > f2->Bold)
+		{
+			return 1;
+		}
+		else if (f1->Bold < f2->Bold)
+		{
+			return -1;
+		}
+		else if (f1->Italic > f2->Italic)
+		{
+			return 1;
+		}
+		else if (f1->Italic < f2->Italic)
+		{
+			return -1;
+		}
+		else if (f1->Size > f2->Size)
+		{
+			return 1;
+		}
+		else if (f1->Size < f2->Size)
+		{
+			return -1;
+		}
+		else if (f1->StrikeOut > f2->StrikeOut)
+		{
+			return 1;
+		}
+		else if (f1->StrikeOut < f2->StrikeOut)
+		{
+			return -1;
+		}
+		else if (f1->UnderLine > f2->UnderLine)
+		{
+			return 1;
+		}
+		else if (f1->UnderLine < f2->UnderLine)
+		{
+			return -1;
+		}
+		else
+		{
+			return 0;
+		}
+	}
+}
+
+// フォントの初期化
+void InitFont()
+{
+	if (font_list != NULL)
+	{
+		return;
+	}
+	font_list = NewList(CompareFont);
+}
+
+// フォントの解放
+void FreeFont()
+{
+	UINT i;
+	if (font_list == NULL)
+	{
+		return;
+	}
+	for (i = 0;i < LIST_NUM(font_list);i++)
+	{
+		FONT *f = LIST_DATA(font_list, i);
+		Free(f->Name);
+		DeleteObject((HGDIOBJ)f->hFont);
+		Free(f);
+	}
+	ReleaseList(font_list);
+	font_list = NULL;
+}
+
+// ウインドウを閉じるボタンを出す
+void EnableClose(HWND hWnd)
+{
+	HMENU h;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	h = GetSystemMenu(hWnd, false);
+	EnableMenuItem(h, SC_CLOSE, MF_ENABLED);
+	DrawMenuBar(hWnd);
+}
+
+// ウインドウを閉じるボタンを消す
+void DisableClose(HWND hWnd)
+{
+	HMENU h;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	h = GetSystemMenu(hWnd, false);
+	EnableMenuItem(h, SC_CLOSE, MF_GRAYED);
+	DrawMenuBar(hWnd);
+}
+
+// 親ウインドウの中央に移動する
+void CenterParent(HWND hWnd)
+{
+	RECT rp;
+	RECT r;
+	HWND hWndParent = GetParent(hWnd);
+	int win_x, win_y;
+	int x, y;
+
+	if (hWndParent == NULL || IsHide(hWndParent, 0) || IsIconic(hWndParent))
+	{
+		Center(hWnd);
+		return;
+	}
+
+	if (GetWindowRect(hWndParent, &rp) == false)
+	{
+		Center(hWnd);
+		return;
+	}
+
+	GetWindowRect(hWnd, &r);
+
+	win_x = r.right - r.left;
+	win_y = r.bottom - r.top;
+
+	x = (rp.right - rp.left - win_x) / 2 + rp.left;
+	y = (rp.bottom - rp.top - win_y) / 2 + rp.top;
+
+	x = MAX(x, 0);
+	y = MAX(y, 0);
+
+	SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
+}
+
+// ウインドウを中央に移動する
+void Center(HWND hWnd)
+{
+	RECT screen;
+	RECT win;
+	UINT x, y;
+	UINT win_x, win_y;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0) == false)
+	{
+		return;
+	}
+
+	GetWindowRect(hWnd, &win);
+	win_x = win.right - win.left;
+	win_y = win.bottom - win.top;
+
+	if (win_x < (UINT)(screen.right - screen.left))
+	{
+		x = (screen.right - screen.left - win_x) / 2;
+	}
+	else
+	{
+		x = 0;
+	}
+
+	if (win_y < (UINT)(screen.bottom - screen.top))
+	{
+		y = (screen.bottom - screen.top - win_y) / 2;
+	}
+	else
+	{
+		y = 0;
+	}
+
+	SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
+}
+
+// ウインドウを中央に移動する 2
+void Center2(HWND hWnd)
+{
+	RECT screen;
+	RECT win;
+	UINT x, y;
+	UINT win_x, win_y;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0) == false)
+	{
+		return;
+	}
+
+	GetWindowRect(hWnd, &win);
+	win_x = win.right - win.left;
+	win_y = win.bottom - win.top;
+
+	if (win_x < (UINT)(screen.right - screen.left))
+	{
+		x = (screen.right - screen.left - win_x) / 2;
+	}
+	else
+	{
+		x = 0;
+	}
+
+	if (win_y < (UINT)(screen.bottom - screen.top))
+	{
+		y = (screen.bottom - screen.top - win_y) / 4;
+	}
+	else
+	{
+		y = 0;
+	}
+
+	SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
+}
+
+// モニタのサイズを取得する
+void GetMonitorSize(UINT *width, UINT *height)
+{
+	// 引数チェック
+	if (width == NULL || height == NULL)
+	{
+		return;
+	}
+
+	*width = GetSystemMetrics(SM_CXSCREEN);
+	*height = GetSystemMetrics(SM_CYSCREEN);
+}
+
+// ウインドウ内の文字列をフォーマットする
+void FormatText(HWND hWnd, UINT id, ...)
+{
+	va_list args;
+	wchar_t *buf;
+	UINT size;
+	wchar_t *str;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	str = GetText(hWnd, id);
+	if (str == NULL)
+	{
+		return;
+	}
+
+	size = MAX(UniStrSize(str) * 10, MAX_SIZE * 10);
+	buf = MallocEx(size, true);
+
+	va_start(args, id);
+	UniFormatArgs(buf, size, str, args);
+
+	SetText(hWnd, id, buf);
+
+	Free(buf);
+
+	Free(str);
+	va_end(args);
+}
+void FormatTextA(HWND hWnd, UINT id, ...)
+{
+	va_list args;
+	char *buf;
+	UINT size;
+	char *str;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	str = GetTextA(hWnd, id);
+	if (str == NULL)
+	{
+		return;
+	}
+
+	size = MAX(StrSize(str) * 10, MAX_SIZE * 10);
+	buf = MallocEx(size, true);
+
+	va_start(args, id);
+	FormatArgs(buf, size, str, args);
+
+	SetTextA(hWnd, id, buf);
+
+	Free(buf);
+
+	Free(str);
+	va_end(args);
+}
+
+// 可変長引数の文字列をウインドウに設定
+void SetTextEx(HWND hWnd, UINT id, wchar_t *str, ...)
+{
+	va_list args;
+	wchar_t *buf;
+	UINT size;
+	// 引数チェック
+	if (str == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	size = MAX(UniStrSize(str) * 10, MAX_SIZE * 10);
+	buf = MallocEx(size, true);
+
+	va_start(args, str);
+	UniFormatArgs(buf, size, str, args);
+
+	SetText(hWnd, id, buf);
+
+	Free(buf);
+	va_end(args);
+}
+void SetTextExA(HWND hWnd, UINT id, char *str, ...)
+{
+	va_list args;
+	char *buf;
+	UINT size;
+	// 引数チェック
+	if (str == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	size = MAX(StrSize(str) * 10, MAX_SIZE * 10);
+	buf = MallocEx(size, true);
+
+	va_start(args, str);
+	FormatArgs(buf, size, str, args);
+
+	SetTextA(hWnd, id, buf);
+
+	Free(buf);
+	va_end(args);
+}
+
+// 可変長メッセージボックスの表示
+UINT MsgBoxEx(HWND hWnd, UINT flag, wchar_t *msg, ...)
+{
+	va_list args;
+	wchar_t *buf;
+	UINT size;
+	UINT ret;
+	// 引数チェック
+	if (msg == NULL)
+	{
+		msg = L"MessageBox";
+	}
+
+	size = MAX(UniStrSize(msg) * 10, MAX_SIZE * 10);
+	buf = MallocEx(size, true);
+
+	va_start(args, msg);
+	UniFormatArgs(buf, size, msg, args);
+
+	ret = MsgBox(hWnd, flag, buf);
+	Free(buf);
+	va_end(args);
+
+	return ret;
+}
+
+// メッセージボックスの表示
+UINT MsgBox(HWND hWnd, UINT flag, wchar_t *msg)
+{
+	UINT ret;
+	wchar_t *title;
+	// 引数チェック
+	if (msg == NULL)
+	{
+		msg = L"MessageBox";
+	}
+
+	if (title_bar != NULL)
+	{
+		title = CopyUniStr(title_bar);
+	}
+	else
+	{
+		title = CopyStrToUni(CEDAR_PRODUCT_STR);
+	}
+
+	if (hWnd)
+	{
+		// 親ウインドウが最上位ウインドウの場合はメッセージボックスも最上位にする
+		if (GetExStyle(hWnd, 0) & WS_EX_TOPMOST)
+		{
+			flag |= MB_SYSTEMMODAL;
+		}
+	}
+
+	ret = MessageBoxW(hWnd, msg, title, flag);
+
+	Free(title);
+
+	return ret;
+}
+
+// ダイアログの作成 (内部)
+UINT DialogInternal(HWND hWnd, UINT id, DIALOG_PROC *proc, void *param)
+{
+	// 引数チェック
+	if (proc == NULL)
+	{
+		return 0;
+	}
+
+	if (MsIsNt() == false)
+	{
+		// Win9x
+		return (UINT)DialogBoxParam(hDll, MAKEINTRESOURCE(id), hWnd, (DLGPROC)proc, (LPARAM)param);
+	}
+	else
+	{
+		// WinNT
+		return (UINT)DialogBoxParamW(hDll, MAKEINTRESOURCEW(id), hWnd, (DLGPROC)proc, (LPARAM)param);
+	}
+}
+
+// システム設定が更新されたことを通知する
+void NoticeSettingChange()
+{
+	PostMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
+	DoEvents(NULL);
+}
+
+// ウインドウを半透明にする
+void SetAplha(HWND hWnd, UINT value0_255)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	value0_255 = MAKESURE(value0_255, 0, 255);
+
+	if (true)
+	{
+		UINT os_type = GetOsInfo()->OsType;
+		if (OS_IS_WINDOWS_NT(os_type) && GET_KETA(os_type, 100) >= 2)
+		{
+			bool (WINAPI *_SetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD);
+			HINSTANCE hInst;
+
+			hInst = LoadLibrary("user32.dll");
+
+			_SetLayeredWindowAttributes =
+				(bool (__stdcall *)(HWND,COLORREF,BYTE,DWORD))
+				GetProcAddress(hInst, "SetLayeredWindowAttributes");
+
+			if (_SetLayeredWindowAttributes != NULL)
+			{
+				// Windows 2000 以降でのみ対応
+				SetExStyle(hWnd, 0, WS_EX_LAYERED);
+				_SetLayeredWindowAttributes(hWnd, 0, value0_255, LWA_ALPHA);
+			}
+
+			FreeLibrary(hInst);
+		}
+	}
+}
+
+// WinUi が管理するダイアログボックスプロシージャ
+UINT DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, bool white_color)
+{
+	void *param;
+	HWND hWndParent;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	switch (msg)
+	{
+	case WM_INITDIALOG:
+		param = (void *)lParam;
+		SetParam(hWnd, param);
+
+		// 親ウインドウが存在するかどうか調べる
+		hWndParent = GetParent(hWnd);
+		if (hWndParent == NULL || IsShow(hWndParent, 0) == false)
+		{
+			// 存在しない場合は中央に配置する
+			Center(hWnd);
+		}
+
+		if (UseAlpha)
+		{
+			SetAplha(hWnd, AlphaValue * 255 / 100);
+		}
+
+		break;
+	}
+
+	if (white_color)
+	{
+		if (IsNewStyleModeEnabled() == false)
+		{
+			switch (msg)
+			{
+			case WM_CTLCOLORBTN:
+			case WM_CTLCOLORDLG:
+			case WM_CTLCOLOREDIT:
+			case WM_CTLCOLORLISTBOX:
+			case WM_CTLCOLORMSGBOX:
+			case WM_CTLCOLORSCROLLBAR:
+			case WM_CTLCOLORSTATIC:
+				return (UINT)GetStockObject(WHITE_BRUSH);
+			}
+		}
+		else
+		{
+			switch (msg)
+			{
+			case WM_CTLCOLORDLG:
+				// ダイアログの背景色
+				return (UINT)gdi_cache.BackgroundColorBrush;
+
+			case WM_CTLCOLORBTN:
+				// ボタンの背景色
+				SetTextColor((HDC)wParam, gdi_cache.ForegroundColor);
+				SetBkColor((HDC)wParam, gdi_cache.BackgroundColor);
+				return (UINT)gdi_cache.BackgroundColorBrush;
+
+			case WM_CTLCOLORSTATIC:
+				// ラベルの色
+				SetTextColor((HDC)wParam, gdi_cache.ForegroundColor);
+				SetBkColor((HDC)wParam, gdi_cache.BackgroundColor);
+				return (UINT)gdi_cache.BackgroundColorBrush;
+
+			case WM_CTLCOLOREDIT:
+				// エディットコントロールの色
+				return (UINT)gdi_cache.TextBoxBackgroundColorBrush;
+			}
+		}
+	}
+
+	return 0;
+}
+
+// ダイアログボックスのパラメータの設定
+void SetParam(HWND hWnd, void *param)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)param);
+}
+
+// ダイアログボックスのパラメータの取得
+void *GetParam(HWND hWnd)
+{
+	void *ret;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	ret = (void *)GetWindowLongPtr(hWnd, DWLP_USER);
+	return ret;
+}
+
+// ウインドウを最前面でなくする
+void NoTop(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+}
+
+// ウインドウを最前面に表示する
+void Top(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+}
+
+// ウインドウを隠す
+void Hide(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (IsShow(hWnd, id))
+	{
+		ShowWindow(DlgItem(hWnd, id), SW_HIDE);
+	}
+}
+
+// ウインドウを表示する
+void Show(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (IsHide(hWnd, id))
+	{
+		ShowWindow(DlgItem(hWnd, id), SW_SHOW);
+	}
+}
+
+// 表示設定の変更
+void SetShow(HWND hWnd, UINT id, bool b)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (b)
+	{
+		Show(hWnd, id);
+	}
+	else
+	{
+		Hide(hWnd, id);
+	}
+}
+
+// ウインドウが表示されているかどうか取得する
+bool IsShow(HWND hWnd, UINT id)
+{
+	return IsHide(hWnd, id) ? false : true;
+}
+
+// ウインドウが隠れているかどうか取得する
+bool IsHide(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return true;
+	}
+
+	if (GetStyle(hWnd, id) & WS_VISIBLE)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+// ウインドウスタイルを削除する
+void RemoveExStyle(HWND hWnd, UINT id, UINT style)
+{
+	UINT old;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	old = GetExStyle(hWnd, id);
+	if ((old & style) == 0)
+	{
+		return;
+	}
+
+	SetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE, old & ~style);
+	Refresh(DlgItem(hWnd, id));
+}
+
+// ウインドウスタイルを設定する
+void SetExStyle(HWND hWnd, UINT id, UINT style)
+{
+	UINT old;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	old = GetExStyle(hWnd, id);
+	if (old & style)
+	{
+		return;
+	}
+
+	SetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE, old | style);
+	Refresh(DlgItem(hWnd, id));
+}
+
+// ウインドウスタイルを取得する
+UINT GetExStyle(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	return GetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE);
+}
+
+// ウインドウスタイルを削除する
+void RemoveStyle(HWND hWnd, UINT id, UINT style)
+{
+	UINT old;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	old = GetStyle(hWnd, id);
+	if ((old & style) == 0)
+	{
+		return;
+	}
+
+	SetWindowLong(DlgItem(hWnd, id), GWL_STYLE, old & ~style);
+	Refresh(DlgItem(hWnd, id));
+}
+
+// ウインドウスタイルを設定する
+void SetStyle(HWND hWnd, UINT id, UINT style)
+{
+	UINT old;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	old = GetStyle(hWnd, id);
+	if (old & style)
+	{
+		return;
+	}
+
+	SetWindowLong(DlgItem(hWnd, id), GWL_STYLE, old | style);
+	Refresh(DlgItem(hWnd, id));
+}
+
+// ウインドウスタイルを取得する
+UINT GetStyle(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	return GetWindowLong(DlgItem(hWnd, id), GWL_STYLE);
+}
+
+// テキストのバイト数を取得する
+UINT GetTextSize(HWND hWnd, UINT id, bool unicode)
+{
+	UINT len;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	len = GetTextLen(hWnd, id, unicode);
+
+	return len + (unicode ? 2 : 1);
+}
+
+// テキストの文字数を取得する
+UINT GetTextLen(HWND hWnd, UINT id, bool unicode)
+{
+	wchar_t *s;
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	s = GetText(hWnd, id);
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	if (unicode)
+	{
+		ret = UniStrLen(s);
+	}
+	else
+	{
+		char *tmp = CopyUniToStr(s);
+		ret = StrLen(tmp);
+		Free(tmp);
+	}
+
+	Free(s);
+
+	return ret;
+}
+
+// テキストが空白かどうかチェックする
+bool IsEmpty(HWND hWnd, UINT id)
+{
+	bool ret;
+	wchar_t *s;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return true;
+	}
+
+	s = GetText(hWnd, id);
+
+	UniTrim(s);
+	if (UniStrLen(s) == 0)
+	{
+		ret = true;
+	}
+	else
+	{
+		ret = false;
+	}
+
+	Free(s);
+
+	return ret;
+}
+
+// ウインドウクラスを取得する
+wchar_t *GetClass(HWND hWnd, UINT id)
+{
+	wchar_t tmp[MAX_SIZE];
+
+	if (MsIsNt() == false)
+	{
+		wchar_t *ret;
+		char *s;
+		s = GetClassA(hWnd, id);
+		ret = CopyStrToUni(s);
+		Free(s);
+		return ret;
+	}
+
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return CopyUniStr(L"");
+	}
+
+	GetClassNameW(DlgItem(hWnd, id), tmp, sizeof(tmp));
+
+	return UniCopyStr(tmp);
+}
+char *GetClassA(HWND hWnd, UINT id)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return CopyStr("");
+	}
+
+	GetClassName(DlgItem(hWnd, id), tmp, sizeof(tmp));
+
+	return CopyStr(tmp);
+}
+
+// コントロールにメッセージを送信する
+UINT SendMsg(HWND hWnd, UINT id, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	if (MsIsNt())
+	{
+		return (UINT)SendMessageW(DlgItem(hWnd, id), msg, wParam, lParam);
+	}
+	else
+	{
+		return (UINT)SendMessageA(DlgItem(hWnd, id), msg, wParam, lParam);
+	}
+}
+
+// EDIT のテキストをすべて選択する
+void SelectEdit(HWND hWnd, UINT id)
+{
+	wchar_t *class_name;
+
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	class_name = GetClass(hWnd, id);
+
+	if (class_name != NULL)
+	{
+		if (UniStrCmpi(class_name, L"edit") == 0)
+		{
+			SendMsg(hWnd, id, EM_SETSEL, 0, -1);
+		}
+		Free(class_name);
+	}
+}
+
+// EDIT のテキストの選択を解除する
+void UnselectEdit(HWND hWnd, UINT id)
+{
+	wchar_t *class_name;
+
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	class_name = GetClass(hWnd, id);
+
+	if (class_name != NULL)
+	{
+		if (UniStrCmpi(class_name, L"edit") == 0)
+		{
+			SendMsg(hWnd, id, EM_SETSEL, -1, 0);
+		}
+		Free(class_name);
+	}
+}
+
+// EDIT にフォーカスを設定してすべて選択する
+void FocusEx(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (IsEnable(hWnd, id) == false || IsShow(hWnd, id) == false)
+	{
+		return;
+	}
+
+	SelectEdit(hWnd, id);
+
+	Focus(hWnd, id);
+}
+
+// 指定したウインドウがフォーカスを持っているかどうか取得する
+bool IsFocus(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	if (GetFocus() == DlgItem(hWnd, id))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// フォーカスを設定する
+void Focus(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (IsEnable(hWnd, id) == false || IsShow(hWnd, id) == false)
+	{
+		return;
+	}
+
+	SetFocus(DlgItem(hWnd, id));
+}
+
+// int 型の値を設定する
+void SetInt(HWND hWnd, UINT id, UINT value)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	UniToStru(tmp, value);
+	SetText(hWnd, id, tmp);
+}
+void SetIntEx(HWND hWnd, UINT id, UINT value)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (value == 0)
+	{
+		// 0 の場合は空欄にする
+		SetText(hWnd, id, L"");
+	}
+	else
+	{
+		SetInt(hWnd, id, value);
+	}
+}
+
+// int 型の値を取得する
+UINT GetInt(HWND hWnd, UINT id)
+{
+	wchar_t *s;
+	UINT ret;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	s = GetText(hWnd, id);
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	ret = UniToInt(s);
+	Free(s);
+
+	return ret;
+}
+
+// ウインドウ表示を更新する
+void Refresh(HWND hWnd)
+{
+	HWND parent;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	DoEvents(hWnd);
+	UpdateWindow(hWnd);
+	DoEvents(hWnd);
+
+	parent = GetParent(hWnd);
+	if (parent != NULL)
+	{
+		Refresh(parent);
+	}
+}
+
+// イベントを処理する
+void DoEvents(HWND hWnd)
+{
+	MSG msg;
+
+	if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
+	{
+		TranslateMessage(&msg);
+		DispatchMessage(&msg);
+	}
+	UpdateWindow(hWnd);
+
+	if (hWnd)
+	{
+		DoEvents(NULL);
+	}
+}
+
+// ウインドウを閉じる
+void Close(HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	SendMessage(hWnd, WM_CLOSE, 0, 0);
+}
+
+// ウインドウを無効にする
+void Disable(HWND hWnd, UINT id)
+{
+	SetEnable(hWnd, id, false);
+}
+
+// ウインドウを有効にする
+void Enable(HWND hWnd, UINT id)
+{
+	SetEnable(hWnd, id, true);
+}
+
+// ウインドウの有効状態を設定する
+void SetEnable(HWND hWnd, UINT id, bool b)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	if (b == false)
+	{
+		if (IsEnable(hWnd, id))
+		{
+			if (id != 0 && IsFocus(hWnd, id))
+			{
+				Focus(hWnd, IDCANCEL);
+				Focus(hWnd, IDOK);
+			}
+			EnableWindow(DlgItem(hWnd, id), false);
+			Refresh(DlgItem(hWnd, id));
+		}
+	}
+	else
+	{
+		if (IsDisable(hWnd, id))
+		{
+			EnableWindow(DlgItem(hWnd, id), true);
+			Refresh(DlgItem(hWnd, id));
+		}
+	}
+}
+
+// ウインドウが無効かどうか調べる
+bool IsDisable(HWND hWnd, UINT id)
+{
+	return IsEnable(hWnd, id) ? false : true;
+}
+
+// ウインドウが有効かどうか調べる
+bool IsEnable(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return false;
+	}
+
+	return IsWindowEnabled(DlgItem(hWnd, id));
+}
+
+static LOCK *winui_debug_lock = NULL;
+
+// デバッグの初期化
+void WinUiDebugInit()
+{
+	winui_debug_lock = NewLock();
+}
+
+// デバッグの解放
+void WinUiDebugFree()
+{
+	DeleteLock(winui_debug_lock);
+}
+
+// デバッグファイルに文字列を書き込む
+void WinUiDebug(wchar_t *str)
+{
+	wchar_t tmp[1024];
+	char dtstr[256];
+	char *buf;
+	wchar_t exename[MAX_PATH];
+	UINT tid;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	tid = GetCurrentThreadId();
+
+	GetExeNameW(exename, sizeof(exename));
+	GetFileNameFromFilePathW(exename, sizeof(exename), exename);
+
+	GetDateTimeStrMilli64(dtstr, sizeof(dtstr), LocalTime64());
+
+	UniFormat(tmp, sizeof(tmp), L"[%S] (%s:%u) %s\r\n", dtstr, exename, tid, str);
+
+	buf = CopyUniToUtf(tmp);
+
+	Lock(winui_debug_lock);
+	{
+		IO *o = FileOpenEx(WINUI_DEBUG_TEXT, true, true);
+		if (o == NULL)
+		{
+			o = FileCreate(WINUI_DEBUG_TEXT);
+		}
+
+		if (o != NULL)
+		{
+			UINT size = FileSize(o);
+
+			FileSeek(o, FILE_BEGIN, size);
+
+			FileWrite(o, buf, StrLen(buf));
+			FileFlush(o);
+
+			FileClose(o);
+		}
+	}
+	Unlock(winui_debug_lock);
+
+	Free(buf);
+}
+
+
+// テキスト文字列の設定
+void SetText(HWND hWnd, UINT id, wchar_t *str)
+{
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return;
+	}
+
+	SetTextInner(hWnd, id, str);
+}
+void SetTextInner(HWND hWnd, UINT id, wchar_t *str)
+{
+	wchar_t *old;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return;
+	}
+
+	// 古い文字列を取得
+	old = GetText(hWnd, id);
+	if (UniStrCmp(str, old) == 0)
+	{
+		// 同一
+		Free(old);
+		return;
+	}
+
+	Free(old);
+
+	if (MsIsNt())
+	{
+		SetWindowTextW(DlgItem(hWnd, id), str);
+	}
+	else
+	{
+		char *tmp = CopyUniToStr(str);
+
+		if (MsIsNt() == false && StrLen(tmp) >= 32000)
+		{
+			// 32k 以下にきりつめる
+			tmp[32000] = 0;
+		}
+
+		SetWindowTextA(DlgItem(hWnd, id), tmp);
+		Free(tmp);
+	}
+
+	if (id != 0)
+	{
+		Refresh(DlgItem(hWnd, id));
+	}
+}
+void SetTextA(HWND hWnd, UINT id, char *str)
+{
+	wchar_t *s;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return;
+	}
+
+	s = CopyStrToUni(str);
+	if (s == NULL)
+	{
+		return;
+	}
+
+	SetText(hWnd, id, s);
+
+	Free(s);
+}
+
+// テキスト文字列をバッファへ取得
+bool GetTxt(HWND hWnd, UINT id, wchar_t *str, UINT size)
+{
+	wchar_t *s;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	s = GetText(hWnd, id);
+	if (s == NULL)
+	{
+		UniStrCpy(str, size, L"");
+		return false;
+	}
+
+	UniStrCpy(str, size, s);
+	Free(s);
+
+	return true;
+}
+bool GetTxtA(HWND hWnd, UINT id, char *str, UINT size)
+{
+	char *s;
+	// 引数チェック
+	if (hWnd == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	s = GetTextA(hWnd, id);
+	if (s == NULL)
+	{
+		StrCpy(str, size, "");
+		return false;
+	}
+
+	StrCpy(str, size, s);
+	Free(s);
+
+	return true;
+}
+
+// テキスト文字列の取得
+wchar_t *GetText(HWND hWnd, UINT id)
+{
+	wchar_t *ret;
+	UINT size, len;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	if (MsIsNt() == false)
+	{
+		char *s = GetTextA(hWnd, id);
+		ret = CopyStrToUni(s);
+		Free(s);
+
+		return ret;
+	}
+
+	len = GetWindowTextLengthW(DlgItem(hWnd, id));
+	if (len == 0)
+	{
+		return CopyUniStr(L"");
+	}
+
+	size = (len + 1) * 2;
+	ret = ZeroMallocEx(size, true);
+
+	GetWindowTextW(DlgItem(hWnd, id), ret, size);
+
+	return ret;
+}
+char *GetTextA(HWND hWnd, UINT id)
+{
+	char *ret;
+	UINT size, len;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	len = GetWindowTextLengthA(DlgItem(hWnd, id));
+	if (len == 0)
+	{
+		return CopyStr("");
+	}
+
+	size = len + 1;
+	ret = ZeroMallocEx(size, true);
+
+	GetWindowTextA(DlgItem(hWnd, id), ret, size);
+
+	return ret;
+}
+
+// ダイアログ内のアイテムの取得
+HWND DlgItem(HWND hWnd, UINT id)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	if (id == 0)
+	{
+		return hWnd;
+	}
+	else
+	{
+		return GetDlgItem(hWnd, id);
+	}
+}
+
+// タイトルの設定
+void SetWinUiTitle(wchar_t *title)
+{
+	// 引数チェック
+	if (title == NULL)
+	{
+		return;
+	}
+
+	Free(title_bar);
+	title_bar = CopyUniStr(title);
+}
+
+// WinUi の初期化
+void InitWinUi(wchar_t *software_name, char *font, UINT fontsize)
+{
+	if ((init_winui_counter++) != 0)
+	{
+		return;
+	}
+
+	if (hDll != NULL)
+	{
+		return;
+	}
+
+	WinUiDebugInit();
+
+	if (MayaquaIsMinimalMode() == false)
+	{
+		if (Is64())
+		{
+			hDll = MsLoadLibraryAsDataFile(MsGetPenCoreDllFileName());
+		}
+		else
+		{
+			hDll = MsLoadLibrary(MsGetPenCoreDllFileName());
+		}
+
+		if (hDll == NULL)
+		{
+			Alert(PENCORE_DLL_NAME " not found. SoftEther UT-VPN couldn't start.\r\n\r\n"
+				"Please reinstall all files with SoftEther UT-VPN Installer.",
+				NULL);
+			exit(0);
+		}
+	}
+	else
+	{
+		hDll = LoadLibrary(MsGetExeFileName());
+
+		if (hDll == NULL)
+		{
+			Alert("MsLoadLibrary() Error.",
+				NULL);
+			exit(0);
+		}
+	}
+
+	if (software_name != NULL)
+	{
+		title_bar = CopyUniStr(software_name);
+	}
+	else
+	{
+		title_bar = CopyUniStr(L"SoftEther UT-VPN");
+	}
+
+	if (font != NULL)
+	{
+		font_name = CopyStr(font);
+	}
+	else
+	{
+		font_name = CopyStr(_SS("DEFAULT_FONT"));
+	}
+
+	if (fontsize != 0)
+	{
+		font_size = fontsize;
+	}
+	else
+	{
+		font_size = _II("DEFAULT_FONT_SIZE");
+		if (font_size == 0)
+		{
+			font_size = 9;
+		}
+	}
+
+	InitIconCache();
+
+	InitFont();
+
+	InitImageList();
+
+	InitGdiCache();
+
+	EnableNewStyleMode();
+}
+
+// WinUi の解放
+void FreeWinUi()
+{
+	if ((--init_winui_counter) != 0)
+	{
+		return;
+	}
+
+	if (hDll == NULL)
+	{
+		return;
+	}
+
+	FreeImageList();
+
+	FreeFont();
+
+	FreeIconCache();
+
+	FreeLibrary(hDll);
+	hDll = NULL;
+
+	Free(title_bar);
+	title_bar = NULL;
+
+	Free(font_name);
+	font_name = NULL;
+
+	WinUiDebugFree();
+}
+
+#endif	// WIN32
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinUi.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinUi.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Cedar/WinUi.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,774 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// WinUi.h
+// Win32 用ユーザーインターフェースコード
+
+#ifdef	OS_WIN32
+
+#define	WINUI_DEBUG_TEXT							"@winui_debug.txt"
+
+#define	LV_INSERT_RESET_ALL_ITEM_MIN				500
+
+#define WINUI_PASSWORD_NULL_USERNAME				"NULL"
+
+#define WINUI_DEFAULT_DIALOG_UNIT_X					7
+#define WINUI_DEFAULT_DIALOG_UNIT_Y					12
+
+// Windows 用の型が windows.h をインクルードしていなくても使えるようにする
+#ifndef	_WINDEF_
+
+typedef void *HWND;
+typedef void *HFONT;
+typedef void *HICON;
+typedef void *HMENU;
+typedef UINT_PTR WPARAM;
+typedef LONG_PTR LPARAM;
+typedef void *HINSTANCE;
+
+#endif	// _WINDEF_
+
+
+// 定数
+#define	FREE_REGKEY				"Software\\SoftEther Corporation\\UT-VPN Client\\Free Edition Info"
+#define ONCE_MSG_REGKEY			"Software\\SoftEther Corporation\\UT-VPN\\Common"
+#define ONCE_MSG_REGVALUE		"HideMessage_%u"
+
+#define	SPLASH_BMP_REGKEY		"Software\\SoftEther Corporation\\UT-VPN\\SplashScreen"
+#define	SPLASH_BMP_REGVALUE		"LastId"
+
+#define	NICINFO_AUTOCLOSE_TIME_1	(20 * 1000)
+#define	NICINFO_AUTOCLOSE_TIME_2	1800
+
+extern bool UseAlpha;
+extern UINT AlphaValue;
+
+
+// マクロ
+#define	DIALOG			DIALOGEX(false)
+#define	DIALOG_WHITE	DIALOGEX(true)
+#define	DIALOGEX(white)								\
+	void *param = GetParam(hWnd);					\
+	{												\
+		UINT ret;									\
+		ret = DlgProc(hWnd, msg, wParam, lParam, white);	\
+		if (ret != 0) return ret;					\
+	}
+
+typedef UINT (__stdcall DIALOG_PROC)(HWND, UINT, WPARAM, LPARAM);
+
+typedef UINT (WINUI_DIALOG_PROC)(HWND, UINT, WPARAM, LPARAM, void *);
+
+
+// セキュア操作内容
+#define	WINUI_SECURE_ENUM_OBJECTS		1			// オブジェクトの列挙
+#define	WINUI_SECURE_WRITE_DATA			2			// データの書き込み
+#define	WINUI_SECURE_READ_DATA			3			// データの読み込み
+#define	WINUI_SECURE_WRITE_CERT			4			// 証明書の書き込み
+#define	WINUI_SECURE_READ_CERT			5			// 証明書の読み込み
+#define	WINUI_SECURE_WRITE_KEY			6			// 秘密鍵の書き込み
+#define	WINUI_SECURE_SIGN_WITH_KEY		7			// 秘密鍵による署名
+#define	WINUI_SECURE_DELETE_OBJECT		8			// オブジェクトの削除
+#define	WINUI_SECURE_DELETE_CERT		9			// 証明書の削除
+#define	WINUI_SECURE_DELETE_KEY			10			// 秘密鍵の削除
+#define	WINUI_SECURE_DELETE_DATA		11			// データの削除
+
+// セキュア操作構造体
+typedef struct WINUI_SECURE_BATCH
+{
+	UINT Type;										// 動作の種類
+	char *Name;										// 名前
+	bool Private;									// プライベートモード
+	BUF *InputData;									// 入力データ
+	BUF *OutputData;								// 出力データ
+	X *InputX;										// 入力証明書
+	X *OutputX;										// 出力証明書
+	K *InputK;										// 入力秘密鍵
+	LIST *EnumList;									// 列挙リスト
+	UCHAR OutputSign[128];							// 出力署名
+	bool Succeed;									// 成功フラグ
+} WINUI_SECURE_BATCH;
+
+// ステータスウインドウ
+typedef struct STATUS_WINDOW
+{
+	HWND hWnd;
+	THREAD *Thread;
+} STATUS_WINDOW;
+
+// バッチ処理アイテム
+typedef struct LVB_ITEM
+{
+	UINT NumStrings;				// 文字列数
+	wchar_t **Strings;				// 文字列バッファ
+	UINT Image;						// 画像番号
+	void *Param;					// パラメータ
+} LVB_ITEM;
+
+// LV 挿入バッチ処理
+typedef struct LVB
+{
+	LIST *ItemList;					// アイテムリスト
+} LVB;
+
+
+#ifdef	CreateWindow
+
+// 内部用コード
+
+// フォント
+typedef struct FONT
+{
+	UINT Size;						// サイズ
+	bool Bold;						// 太字
+	bool Italic;					// 斜体
+	bool UnderLine;					// 下線
+	bool StrikeOut;					// 取り消し線
+	char *Name;						// フォント名
+	HFONT hFont;					// フォント
+	UINT x, y;						// フォントサイズ
+} FONT;
+
+// フォントキャッシュリスト
+static LIST *font_list = NULL;
+
+// ダイアログ関係
+typedef struct DIALOG_PARAM
+{
+	bool white;
+	void *param;
+	WINUI_DIALOG_PROC *proc;
+	bool meiryo;
+} DIALOG_PARAM;
+
+// セキュアデバイスウインドウ関係
+typedef struct SECURE_DEVICE_WINDOW
+{
+	WINUI_SECURE_BATCH *batch;
+	UINT num_batch;
+	UINT device_id;
+	struct SECURE_DEVICE_THREAD *p;
+	char *default_pin;
+	UINT BitmapId;
+} SECURE_DEVICE_WINDOW;
+
+// スレッド
+typedef struct SECURE_DEVICE_THREAD
+{
+	SECURE_DEVICE_WINDOW *w;
+	HWND hWnd;
+	bool Succeed;
+	wchar_t *ErrorMessage;
+	char *pin;
+} SECURE_DEVICE_THREAD;
+
+void StartSecureDevice(HWND hWnd, SECURE_DEVICE_WINDOW *w);
+
+// パスフレーズ
+typedef struct PASSPHRASE_DLG
+{
+	char pass[MAX_SIZE];
+	BUF *buf;
+	bool p12;
+} PASSPHRASE_DLG;
+
+void PassphraseDlgProcCommand(HWND hWnd, PASSPHRASE_DLG *p);
+
+// ステータスウインドウ
+typedef struct STATUS_WINDOW_PARAM
+{
+	HWND hWnd;
+	SOCK *Sock;
+	THREAD *Thread;
+	wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];
+} STATUS_WINDOW_PARAM;
+
+// 証明書表示ダイアログ
+typedef struct CERT_DLG
+{
+	X *x, *issuer_x;
+	bool ManagerMode;
+} CERT_DLG;
+
+
+typedef struct IMAGELIST_ICON
+{
+	UINT id;
+	HICON hSmallImage;
+	HICON hLargeImage;
+	UINT Index;
+} IMAGELIST_ICON;
+
+typedef struct SEARCH_WINDOW_PARAM
+{
+	wchar_t *caption;
+	HWND hWndFound;
+} SEARCH_WINDOW_PARAM;
+
+// リモート接続画面設定
+typedef struct WINUI_REMOTE
+{
+	bool flag1;
+	char *RegKeyName;					// レジストリキー名
+	UINT Icon;							// アイコン
+	wchar_t *Caption;					// キャプション
+	wchar_t *Title;						// タイトル
+	char *Hostname;						// ホスト名
+	char *DefaultHostname;				// デフォルトホスト名
+	LIST *CandidateList;				// 候補リスト
+} WINUI_REMOTE;
+
+void InitImageList();
+void FreeImageList();
+IMAGELIST_ICON *LoadIconForImageList(UINT id);
+int CompareImageListIcon(void *p1, void *p2);
+BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam);
+void PrintCertInfo(HWND hWnd, CERT_DLG *p);
+void CertDlgUpdate(HWND hWnd, CERT_DLG *p);
+bool CALLBACK SearchWindowEnumProc(HWND hWnd, LPARAM lParam);
+UINT RemoteDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void RemoteDlgInit(HWND hWnd, WINUI_REMOTE *r);
+void RemoteDlgRefresh(HWND hWnd, WINUI_REMOTE *r);
+void RemoteDlgOnOk(HWND hWnd, WINUI_REMOTE *r);
+int CALLBACK LvSortProc(LPARAM param1, LPARAM param2, LPARAM sort_param);
+
+// アイコンキャッシュ
+typedef struct ICON_CACHE
+{
+	UINT id;
+	bool small_icon;
+	HICON hIcon;
+} ICON_CACHE;
+
+static LIST *icon_cache_list = NULL;
+
+// ソート関係
+typedef struct WINUI_LV_SORT
+{
+	HWND hWnd;
+	UINT id;
+	UINT subitem;
+	bool desc;
+	bool numeric;
+} WINUI_LV_SORT;
+
+// バージョン情報
+typedef struct WINUI_ABOUT
+{
+	CEDAR *Cedar;
+	char *ProductName;
+	UINT Bitmap;
+} WINUI_ABOUT;
+
+UINT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void AboutDlgInit(HWND hWnd, WINUI_ABOUT *a);
+
+typedef struct WIN9X_REBOOT_DLG
+{
+	UINT64 StartTime;
+	UINT TotalTime;
+} WIN9X_REBOOT_DLG;
+
+
+
+// STRING
+typedef struct STRING_DLG
+{
+	wchar_t String[MAX_SIZE];
+	wchar_t *Title;
+	wchar_t *Info;
+	UINT Icon;
+	bool AllowEmpty;
+	bool AllowUnsafe;
+} STRING_DLG;
+
+void StringDlgInit(HWND hWnd, STRING_DLG *s);
+void StringDlgUpdate(HWND hWnd, STRING_DLG *s);
+
+// PIN コードは 5 分間キャッシュされる
+#define	WINUI_SECUREDEVICE_PIN_CACHE_TIME		(5 * 60 * 1000)
+extern char cached_pin_code[MAX_SIZE];
+extern UINT64 cached_pin_code_expires;
+
+// TCP 接続ダイアログ関係
+typedef struct WINCONNECT_DLG_DATA
+{
+	wchar_t *caption;
+	wchar_t *info;
+	UINT icon_id;
+	UINT timeout;
+	char *hostname;
+	UINT port;
+	bool cancel;
+	SOCK *ret_sock;
+	THREAD *thread;
+	HWND hWnd;
+} WINCONNECT_DLG_DATA;
+
+#endif	// WINUI_C
+
+// 隠し
+typedef struct KAKUSHI
+{
+	HWND hWnd;
+	THREAD *Thread;
+	volatile bool Halt;
+	UINT64 StartTick, Span;
+} KAKUSHI;
+
+// フリー版に関する情報画面
+typedef struct FREEINFO
+{
+	char ServerName[MAX_SERVER_STR_LEN + 1];
+	HWND hWnd;
+	THREAD *Thread;
+	EVENT *Event;
+} FREEINFO;
+
+// メッセージ
+typedef struct ONCEMSG_DLG
+{
+	UINT Icon;
+	wchar_t *Title;
+	wchar_t *Message;
+	bool ShowCheckbox;
+	bool Checked;
+	UINT MessageHash;
+	bool *halt;
+} ONCEMSG_DLG;
+
+// 悪いプロセスの定義
+typedef struct BAD_PROCESS
+{
+	char *ExeName;
+	char *Title;
+} BAD_PROCESS;
+
+// ビットマップ
+typedef struct WINBMP
+{
+	void *hBitmap;
+	UINT Width, Height, Bits;
+	void *hDC;
+} WINBMP;
+
+// メモリ DC
+typedef struct WINMEMDC
+{
+	void *hDC;
+	UINT Width, Height;
+	void *hBitmap;
+	UCHAR *Data;
+} WINMEMDC;
+
+#ifdef	WINUI_C
+
+// 競合するアンチウイルスソフトのプロセス名一覧
+static BAD_PROCESS bad_processes[] =
+{
+	{"nod32krn.exe", "NOD32 Antivirus",},
+};
+
+static UINT num_bad_processes = sizeof(bad_processes) / sizeof(bad_processes[0]);
+
+#endif	// WINUI_C
+
+// 関数プロトタイプ
+void InitWinUi(wchar_t *software_name, char *font, UINT fontsize);
+void SetWinUiTitle(wchar_t *title);
+void FreeWinUi();
+HWND DlgItem(HWND hWnd, UINT id);
+void SetText(HWND hWnd, UINT id, wchar_t *str);
+void SetTextInner(HWND hWnd, UINT id, wchar_t *str);
+void SetTextA(HWND hWnd, UINT id, char *str);
+wchar_t *GetText(HWND hWnd, UINT id);
+char *GetTextA(HWND hWnd, UINT id);
+bool GetTxt(HWND hWnd, UINT id, wchar_t *str, UINT size);
+bool GetTxtA(HWND hWnd, UINT id, char *str, UINT size);
+bool IsEnable(HWND hWnd, UINT id);
+bool IsDisable(HWND hWnd, UINT id);
+void Enable(HWND hWnd, UINT id);
+void Disable(HWND hWnd, UINT id);
+void SetEnable(HWND hWnd, UINT id, bool b);
+void Close(HWND hWnd);
+void DoEvents(HWND hWnd);
+void Refresh(HWND hWnd);
+UINT GetInt(HWND hWnd, UINT id);
+void SetInt(HWND hWnd, UINT id, UINT value);
+void SetIntEx(HWND hWnd, UINT id, UINT value);
+void Focus(HWND hWnd, UINT id);
+void FocusEx(HWND hWnd, UINT id);
+bool IsFocus(HWND hWnd, UINT id);
+wchar_t *GetClass(HWND hWnd, UINT id);
+char *GetClassA(HWND hWnd, UINT id);
+void SelectEdit(HWND hWnd, UINT id);
+void UnselectEdit(HWND hWnd, UINT id);
+UINT SendMsg(HWND hWnd, UINT id, UINT msg, WPARAM wParam, LPARAM lParam);
+bool IsEmpty(HWND hWnd, UINT id);
+UINT GetTextLen(HWND hWnd, UINT id, bool unicode);
+UINT GetTextSize(HWND hWnd, UINT id, bool unicode);
+UINT GetStyle(HWND hWnd, UINT id);
+void SetStyle(HWND hWnd, UINT id, UINT style);
+void RemoveStyle(HWND hWnd, UINT id, UINT style);
+UINT GetExStyle(HWND hWnd, UINT id);
+void SetExStyle(HWND hWnd, UINT id, UINT style);
+void RemoveExStyle(HWND hWnd, UINT id, UINT style);
+void Hide(HWND hWnd, UINT id);
+void Show(HWND hWnd, UINT id);
+void SetShow(HWND hWnd, UINT id, bool b);
+bool IsHide(HWND hWnd, UINT id);
+bool IsShow(HWND hWnd, UINT id);
+void Top(HWND hWnd);
+void NoTop(HWND hWnd);
+void *GetParam(HWND hWnd);
+void SetParam(HWND hWnd, void *param);
+UINT DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, bool white_color);
+void SetAplha(HWND hWnd, UINT value0_255);
+void NoticeSettingChange();
+void UiTest();
+UINT DialogInternal(HWND hWnd, UINT id, DIALOG_PROC *proc, void *param);
+UINT MsgBox(HWND hWnd, UINT flag, wchar_t *msg);
+UINT MsgBoxEx(HWND hWnd, UINT flag, wchar_t *msg, ...);
+void SetTextEx(HWND hWnd, UINT id, wchar_t *str, ...);
+void SetTextExA(HWND hWnd, UINT id, char *str, ...);
+void FormatText(HWND hWnd, UINT id, ...);
+void FormatTextA(HWND hWnd, UINT id, ...);
+void Center(HWND hWnd);
+void Center2(HWND hWnd);
+void CenterParent(HWND hWnd);
+void GetMonitorSize(UINT *width, UINT *height);
+void DisableClose(HWND hWnd);
+void EnableClose(HWND hWnd);
+void InitFont();
+void FreeFont();
+int CompareFont(void *p1, void *p2);
+HFONT GetFont(char *name, UINT size, bool bold, bool italic, bool underline, bool strikeout);
+bool CalcFontSize(HFONT hFont, UINT *x, UINT *y);
+bool GetFontSize(HFONT hFont, UINT *x, UINT *y);
+void SetFont(HWND hWnd, UINT id, HFONT hFont);
+void LimitText(HWND hWnd, UINT id, UINT count);
+bool CheckTextLen(HWND hWnd, UINT id, UINT len, bool unicode);
+bool CheckTextSize(HWND hWnd, UINT id, UINT size, bool unicode);
+void Check(HWND hWnd, UINT id, bool b);
+bool IsChecked(HWND hWnd, UINT id);
+void SetIcon(HWND hWnd, UINT id, UINT icon_id);
+void SetBitmap(HWND hWnd, UINT id, UINT bmp_id);
+bool SecureDeviceWindow(HWND hWnd, WINUI_SECURE_BATCH *batch, UINT num_batch, UINT device_id, UINT bitmap_id);
+UINT Dialog(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param);
+UINT DialogEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white);
+UINT DialogEx2(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white, bool meiryo);
+HWND DialogCreateEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white);
+UINT __stdcall InternalDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+UINT SecureDeviceWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+HFONT Font(UINT size, UINT bold);
+void DlgFont(HWND hWnd, UINT id, UINT size, UINT bold);
+void OpenAvi(HWND hWnd, UINT id, UINT avi_id);
+void CloseAvi(HWND hWnd, UINT id);
+void PlayAvi(HWND hWnd, UINT id, bool repeat);
+void StopAvi(HWND hWnd, UINT id);
+void EnableSecureDeviceWindowControls(HWND hWnd, bool enable);
+void SecureDeviceThread(THREAD *t, void *param);
+void Command(HWND hWnd, UINT id);
+wchar_t *OpenDlg(HWND hWnd, wchar_t *filter, wchar_t *title);
+char *OpenDlgA(HWND hWnd, char *filter, char *title);
+wchar_t *SaveDlg(HWND hWnd, wchar_t *filter, wchar_t *title, wchar_t *default_name, wchar_t *default_ext);
+char *SaveDlgA(HWND hWnd, char *filter, char *title, char *default_name, char *default_ext);
+wchar_t *MakeFilter(wchar_t *str);
+char *MakeFilterA(char *str);
+void PkcsUtil();
+UINT PkcsUtilProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void PkcsUtilWrite(HWND hWnd);
+void PkcsUtilErase(HWND hWnd);
+bool PassphraseDlg(HWND hWnd, char *pass, UINT pass_size, BUF *buf, bool p12);
+UINT PassphraseDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool PasswordDlg(HWND hWnd, UI_PASSWORD_DLG *p);
+void PasswordDlgOnOk(HWND hWnd, UI_PASSWORD_DLG *p);
+UINT PasswordDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void PasswordDlgProcChange(HWND hWnd, UI_PASSWORD_DLG *p);
+UINT CbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data);
+UINT CbAddStrA(HWND hWnd, UINT id, char *str, UINT data);
+UINT CbAddStr9xA(HWND hWnd, UINT id, char *str, UINT data);
+UINT CbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data);
+UINT CbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data);
+UINT CbInsertStr9xA(HWND hWnd, UINT id, UINT index, char *str, UINT data);
+void CbSelectIndex(HWND hWnd, UINT id, UINT index);
+UINT CbNum(HWND hWnd, UINT id);
+UINT CbFindStr(HWND hWnd, UINT id, wchar_t *str);
+UINT CbFindStr9xA(HWND hWnd, UINT id, char *str);
+wchar_t *CbGetStr(HWND hWnd, UINT id);
+UINT CbFindData(HWND hWnd, UINT id, UINT data);
+UINT CbGetData(HWND hWnd, UINT id, UINT index);
+void CbSelect(HWND hWnd, UINT id, int data);
+void CbReset(HWND hWnd, UINT id);
+void CbSetHeight(HWND hWnd, UINT id, UINT value);
+UINT CbGetSelectIndex(HWND hWnd, UINT id);
+UINT CbGetSelect(HWND hWnd, UINT id);
+void SetRange(HWND hWnd, UINT id, UINT start, UINT end);
+void SetPos(HWND hWnd, UINT id, UINT pos);
+UINT LbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data);
+UINT LbAddStrA(HWND hWnd, UINT id, char *str, UINT data);
+UINT LbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data);
+UINT LbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data);
+void LbSelectIndex(HWND hWnd, UINT id, UINT index);
+UINT LbNum(HWND hWnd, UINT id);
+UINT LbFindStr(HWND hWnd, UINT id, wchar_t *str);
+wchar_t *LbGetStr(HWND hWnd, UINT id);
+UINT LbFindData(HWND hWnd, UINT id, UINT data);
+UINT LbGetData(HWND hWnd, UINT id, UINT index);
+void LbSelect(HWND hWnd, UINT id, int data);
+void LbReset(HWND hWnd, UINT id);
+void LbSetHeight(HWND hWnd, UINT id, UINT value);
+UINT LbGetSelectIndex(HWND hWnd, UINT id);
+UINT LbGetSelect(HWND hWnd, UINT id);
+STATUS_WINDOW *StatusPrinterWindowStart(SOCK *s, wchar_t *account_name);
+void StatusPrinterWindowStop(STATUS_WINDOW *sw);
+void StatusPrinterWindowPrint(STATUS_WINDOW *sw, wchar_t *str);
+void StatusPrinterWindowThread(THREAD *thread, void *param);
+UINT StatusPrinterWindowDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CertDlg(HWND hWnd, X *x, X *issuer_x, bool manager);
+UINT CertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void LvInit(HWND hWnd, UINT id);
+void LvInitEx(HWND hWnd, UINT id, bool no_image);
+void LvInitEx2(HWND hWnd, UINT id, bool no_image, bool large_icon);
+void LvReset(HWND hWnd, UINT id);
+void LvInsertColumn(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT width);
+UINT GetIcon(UINT icon_id);
+void LvInsert(HWND hWnd, UINT id, UINT icon, void *param, UINT num_str, ...);
+UINT LvInsertItem(HWND hWnd, UINT id, UINT icon, void *param, wchar_t *str);
+UINT LvInsertItemByImageListId(HWND hWnd, UINT id, UINT image, void *param, wchar_t *str);
+UINT LvInsertItemByImageListIdA(HWND hWnd, UINT id, UINT image, void *param, char *str);
+void LvSetItem(HWND hWnd, UINT id, UINT index, UINT pos, wchar_t *str);
+void LvSetItemA(HWND hWnd, UINT id, UINT index, UINT pos, char *str);
+void LvSetItemParam(HWND hWnd, UINT id, UINT index, void *param);
+void LvSetItemImage(HWND hWnd, UINT id, UINT index, UINT icon);
+void LvSetItemImageByImageListId(HWND hWnd, UINT id, UINT index, UINT image);
+void LvDeleteItem(HWND hWnd, UINT id, UINT index);
+UINT LvNum(HWND hWnd, UINT id);
+void *LvGetParam(HWND hWnd, UINT id, UINT index);
+wchar_t *LvGetStr(HWND hWnd, UINT id, UINT index, UINT pos);
+char *LvGetStrA(HWND hWnd, UINT id, UINT index, UINT pos);
+void LvShow(HWND hWnd, UINT id, UINT index);
+UINT LvSearchParam(HWND hWnd, UINT id, void *param);
+UINT LvSearchStr(HWND hWnd, UINT id, UINT pos, wchar_t *str);
+UINT LvSearchStrA(HWND hWnd, UINT id, UINT pos, char *str);
+UINT LvGetSelected(HWND hWnd, UINT id);
+UINT LvGetFocused(HWND hWnd, UINT id);
+wchar_t *LvGetFocusedStr(HWND hWnd, UINT id, UINT pos);
+wchar_t *LvGetSelectedStr(HWND hWnd, UINT id, UINT pos);
+char *LvGetSelectedStrA(HWND hWnd, UINT id, UINT pos);
+bool LvIsSelected(HWND hWnd, UINT id);
+UINT LvGetNextMasked(HWND hWnd, UINT id, UINT start);
+bool LvIsMasked(HWND hWnd, UINT id);
+bool LvIsSingleSelected(HWND hWnd, UINT id);
+bool LvIsMultiMasked(HWND hWnd, UINT id);
+UINT LvGetMaskedNum(HWND hWnd, UINT id);
+void LvAutoSize(HWND hWnd, UINT id);
+void LvSelect(HWND hWnd, UINT id, UINT index);
+void LvSelectAll(HWND hWnd, UINT id);
+void LvSwitchSelect(HWND hWnd, UINT id);
+void LvSetView(HWND hWnd, UINT id, bool details);
+UINT LvGetColumnWidth(HWND hWnd, UINT id, UINT index);
+void CheckCertDlg(UI_CHECKCERT *p);
+UINT CheckCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void PrintCheckCertInfo(HWND hWnd, UI_CHECKCERT *p);
+void ShowDlgDiffWarning(HWND hWnd, UI_CHECKCERT *p);
+void CheckCertDialogOnOk(HWND hWnd, UI_CHECKCERT *p);
+bool ConnectErrorDlg(UI_CONNECTERROR_DLG *p);
+UINT ConnectErrorDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+HINSTANCE GetUiDll();
+HICON LoadLargeIconInner(UINT id);
+HICON LoadSmallIconInner(UINT id);
+HICON LoadLargeIcon(UINT id);
+HICON LoadSmallIcon(UINT id);
+HICON LoadIconEx(UINT id, bool small_icon);
+void InitIconCache();
+void FreeIconCache();
+LVB *LvInsertStart();
+void LvInsertAdd(LVB *b, UINT icon, void *param, UINT num_str, ...);
+void LvInsertEnd(LVB *b, HWND hWnd, UINT id);
+void LvInsertEndEx(LVB *b, HWND hWnd, UINT id, bool force_reset);
+void LvSetStyle(HWND hWnd, UINT id, UINT style);
+void LvRemoveStyle(HWND hWnd, UINT id, UINT style);
+HMENU LoadSubMenu(UINT menu_id, UINT pos, HMENU *parent_menu);
+UINT GetMenuItemPos(HMENU hMenu, UINT id);
+void DeleteMenuItem(HMENU hMenu, UINT pos);
+void SetMenuItemEnable(HMENU hMenu, UINT pos, bool enable);
+void SetMenuItemBold(HMENU hMenu, UINT pos, bool bold);
+wchar_t *GetMenuStr(HMENU hMenu, UINT pos);
+char *GetMenuStrA(HMENU hMenu, UINT pos);
+void SetMenuStr(HMENU hMenu, UINT pos, wchar_t *str);
+void SetMenuStrA(HMENU hMenu, UINT pos, char *str);
+void RemoveShortcutKeyStrFromMenu(HMENU hMenu);
+UINT GetMenuNum(HMENU hMenu);
+void PrintMenu(HWND hWnd, HMENU hMenu);
+void LvRename(HWND hWnd, UINT id, UINT pos);
+void AllowFGWindow(UINT process_id);
+HWND SearchWindow(wchar_t *caption);
+char *RemoteDlg(HWND hWnd, char *regkey, UINT icon, wchar_t *caption, wchar_t *title, char *default_host);
+LIST *ReadCandidateFromReg(UINT root, char *key, char *name);
+void WriteCandidateToReg(UINT root, char *key, LIST *o, char *name);
+UINT LvGetColumnNum(HWND hWnd, UINT id);
+void LvSetItemParamEx(HWND hWnd, UINT id, UINT index, UINT subitem, void *param);
+void LvSortEx(HWND hWnd, UINT id, UINT subitem, bool desc, bool numeric);
+void LvSort(HWND hWnd, UINT id, UINT subitem, bool desc);
+void *LvGetParamEx(HWND hWnd, UINT id, UINT index, UINT subitem);
+void LvSortHander(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id);
+void LvStandardHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id);
+void IpSet(HWND hWnd, UINT id, UINT ip);
+UINT IpGet(HWND hWnd, UINT id);
+void IpClear(HWND hWnd, UINT id);
+bool IpIsFilled(HWND hWnd, UINT id);
+UINT IpGetFilledNum(HWND hWnd, UINT id);
+void About(HWND hWnd, CEDAR *cedar, char *product_name, UINT bitmap);
+void Win9xReboot(HWND hWnd);
+void Win9xRebootThread(THREAD *t, void *p);
+UINT Win9xRebootDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+wchar_t *StringDlg(HWND hWnd, wchar_t *title, wchar_t *info, wchar_t *def, UINT icon, bool allow_empty, bool allow_unsafe);
+char *StringDlgA(HWND hWnd, wchar_t *title, wchar_t *info, char *def, UINT icon, bool allow_empty, bool allow_unsafe);
+UINT StringDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void InitDialogInternational(HWND hWnd, void *param);
+void AdjustWindowAndControlSize(HWND hWnd);
+void AdjustDialogXY(UINT *x, UINT *y, UINT dlgfont_x, UINT dlgfont_y);
+HFONT GetDialogDefaultFont();
+HFONT GetDialogDefaultFontEx(bool meiryo);
+void InitMenuInternational(HMENU hMenu, char *prefix);
+void InitMenuInternationalUni(HMENU hMenu, char *prefix);
+void ShowTcpIpConfigUtil(HWND hWnd, bool util_mode);
+void ShowCpu64Warning();
+UINT Cpu64DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT TcpIpDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void TcpIpDlgInit(HWND hWnd);
+void TcpIpDlgUpdate(HWND hWnd);
+UINT TcpMsgDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT KakushiDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void KakushiThread(THREAD *thread, void *param);
+KAKUSHI *InitKakushi();
+void FreeKakushi(KAKUSHI *k);
+void ShowEasterEgg(HWND hWnd);
+bool ExecuteHamcoreExe(char *name);
+bool Win32CnCheckAlreadyExists(bool lock);
+void RegistWindowsFirewallAll();
+void InitVistaWindowTheme(HWND hWnd);
+void WinUiDebug(wchar_t *str);
+void WinUiDebugInit();
+void WinUiDebugFree();
+void OnceMsg(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon);
+void OnceMsgEx(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon, bool *halt);
+UINT GetOnceMsgHash(wchar_t *title, wchar_t *message);
+UINT OnceMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool CheckBadProcesses(HWND hWnd);
+BAD_PROCESS *IsBadProcess(char *exe);
+void ShowBadProcessWarning(HWND hWnd, BAD_PROCESS *bad);
+void SetFontMeiryo(HWND hWnd, UINT id);
+void SetFontDefault(HWND hWnd, UINT id);
+HFONT GetMeiryoFont();
+HFONT GetMeiryoFontEx(UINT font_size);
+bool ShowWindowsNetworkConnectionDialog();
+SOCK *WinConnectEx2(HWND hWnd, char *server, UINT port, UINT timeout, UINT icon_id, wchar_t *caption, wchar_t *info);
+UINT WinConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void WinConnectDlgThread(THREAD *thread, void *param);
+void NicInfo(UI_NICINFO *info);
+UINT NicInfoProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NicInfoInit(HWND hWnd, UI_NICINFO *info);
+void NicInfoOnTimer(HWND hWnd, UI_NICINFO *info);
+void NicInfoRefresh(HWND hWnd, UI_NICINFO *info);
+void NicInfoShowStatus(HWND hWnd, UI_NICINFO *info, wchar_t *msg1, wchar_t *msg2, UINT icon, bool animate);
+void NicInfoCloseAfterTime(HWND hWnd, UI_NICINFO *info, UINT tick);
+bool IsNewStyleModeEnabled();
+void DisableNewStyleMode();
+void EnableNewStyleMode();
+void InitGdiCache();
+WINBMP *LoadBmpFromFileW(wchar_t *filename);
+WINBMP *LoadBmpFromFileInnerW(wchar_t *filename);
+WINBMP *LoadBmpFromFileA(char *filename);
+WINBMP *LoadBmpFromResource(UINT id);
+WINBMP *LoadBmpMain(void *hBitmap);
+void FreeBmp(WINBMP *b);
+void ShowSplash(HWND hWndParent, wchar_t *bmp_file_name, char *title, wchar_t *caption, UINT ticks, UINT line_color, void *param);
+void ShowSplashEx(HWND hWndParent, char *software_name, UINT ticks, UINT line_color);
+WINMEMDC *NewMemDC(UINT width, UINT height);
+void FreeMemDC(WINMEMDC *m);
+void LvSetBkImage(HWND hWnd, UINT id, char *bmp_file_name);
+bool IsFullColor();
+
+#endif	// OS_WIN32
+
+
+
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Ham/Ham.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Ham/Ham.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Ham/Ham.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,525 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Ham.c
+// Hamster テストプログラム
+// (UT-VPN の動作テストを行うための CUI プログラム。)
+
+
+
+#define	HAM_C
+
+#ifdef	WIN32
+#define	HAM_WIN32
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <windows.h>
+#include <DbgHelp.h>
+#include <Iphlpapi.h>
+#include <wtsapi32.h>
+#include "../pencore/resource.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <math.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/engine.h>
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include <openssl/pkcs7.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rc4.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "Ham.h"
+
+// テスト関数一覧定義
+typedef void (TEST_PROC)(UINT num, char **arg);
+
+typedef struct TEST_LIST
+{
+	char *command_str;
+	TEST_PROC *proc;
+} TEST_LIST;
+
+typedef struct TESTST
+{
+	USHORT a:4, b:4;
+} TESTST;
+
+void test(UINT num, char **arg)
+{
+}
+
+// デバッグ
+void debug(UINT num, char **arg)
+{
+	// カーネル状態の表示
+	if (g_debug)
+	{
+		PrintKernelStatus();
+	}
+
+	// デバッグ情報の表示
+	if (g_memcheck)
+	{
+		PrintDebugInformation();
+	}
+}
+
+void client_test(UINT num, char **arg)
+{
+#ifdef	OS_WIN32
+	MsWriteCallingServiceManagerProcessId("utvpnclient", MsGetCurrentProcessId());
+#endif	// OS_WIN32
+
+	Print("Client Test.\n");
+	CtStartClient();
+	GetLine(NULL, 0);
+	CtStopClient();
+
+#ifdef	OS_WIN32
+	MsWriteCallingServiceManagerProcessId("utvpnclient", 0);
+#endif	// OS_WIN32
+}
+
+void server_test(UINT num, char **arg)
+{
+	UINT p[] = {52, 80, 8080, 3128};
+	Print("Server Test.\n");
+
+	if (num != 0)
+	{
+		SERVER_CONFIG_FILE_NAME = "@vpn_member_server.config";
+	}
+
+	StInit();
+
+	StStartServer(false);
+
+	GetLine(NULL, 0);
+
+	if (0 && num != 0)
+	{
+		UINT ports[] = {443, 992};
+		UCHAR password[SHA1_SIZE];
+		Hash(password, "", 0, true);
+		SiSetServerType(StGetServer(), SERVER_TYPE_FARM_MEMBER, 0x0100007f,
+			sizeof(ports) / sizeof(ports[0]), ports, "pc1.sec.softether.co.jp", 5555, password, 0, false);
+		GetLine(NULL, 0);
+	}
+
+	if (0 && num == 0)
+	{
+		HUB *h = GetHub(StGetServer()->Cedar, "DEFAULT");
+		SetHubOffline(h);
+		GetLine(NULL, 0);
+		SetHubOnline(h);
+		GetLine(NULL, 0);
+		ReleaseHub(h);
+	}
+
+	StStopServer();
+
+	StFree();
+}
+
+void disablevlan(UINT num, char **arg)
+{
+#ifdef	OS_WIN32
+	bool ok;
+	if (num < 1)
+	{
+		Print("NO NAME.\n");
+		return;
+	}
+
+	ok = MsDisableVLan(arg[0]);
+
+#ifdef	VISTA_HAM
+	if (ok == false)
+	{
+		_exit(1);
+	}
+	else
+	{
+		_exit(0);
+	}
+#endif
+#endif	// OS_WIN32
+}
+
+void enablevlan(UINT num, char **arg)
+{
+#ifdef	OS_WIN32
+	bool ok;
+	if (num < 1)
+	{
+		Print("NO NAME.\n");
+		return;
+	}
+
+	ok = MsEnableVLan(arg[0]);
+
+#ifdef	VISTA_HAM
+	if (ok == false)
+	{
+		_exit(1);
+	}
+	else
+	{
+		_exit(0);
+	}
+#endif
+#endif	// OS_WIN32
+}
+
+void instvlan(UINT num, char **arg)
+{
+#ifdef	OS_WIN32
+	KAKUSHI *k = NULL;
+	bool ok;
+	if (num < 1)
+	{
+		Print("NO NAME.\n");
+		return;
+	}
+
+	InitWinUi(L"VPN", _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+	if (MsIsNt())
+	{
+		k = InitKakushi();
+	}
+
+	ok = MsInstallVLan(VLAN_ADAPTER_NAME_TAG, VLAN_CONNECTION_NAME, arg[0]);
+
+	FreeKakushi(k);
+
+	FreeWinUi();
+
+#ifdef	VISTA_HAM
+	if (ok == false)
+	{
+		_exit(1);
+	}
+	else
+	{
+		_exit(0);
+	}
+#endif
+#endif
+}
+
+void upgradevlan(UINT num, char **arg)
+{
+#ifdef	OS_WIN32
+	bool ok;
+	KAKUSHI *k = NULL;
+	if (num < 1)
+	{
+		Print("NO NAME.\n");
+		return;
+	}
+
+	InitWinUi(L"VPN", _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+	if (MsIsNt())
+	{
+		k = InitKakushi();
+	}
+
+	ok = MsUpgradeVLan(VLAN_ADAPTER_NAME_TAG, VLAN_CONNECTION_NAME, arg[0]);
+
+	FreeKakushi(k);
+
+	FreeWinUi();
+
+#ifdef	VISTA_HAM
+	if (ok == false)
+	{
+		_exit(1);
+	}
+	else
+	{
+		_exit(0);
+	}
+#endif
+#endif
+}
+
+void uninstvlan(UINT num, char **arg)
+{
+#ifdef	OS_WIN32
+	bool ok;
+	if (num < 1)
+	{
+		Print("NO NAME.\n");
+		return;
+	}
+
+	ok = MsUninstallVLan(arg[0]);
+
+#ifdef	VISTA_HAM
+	if (ok == false)
+	{
+		_exit(1);
+	}
+	else
+	{
+		_exit(0);
+	}
+#endif
+#endif
+}
+
+void sm_test(UINT num, char **arg)
+{
+#ifdef	OS_WIN32
+	SMExec();
+#endif
+}
+
+void cm_test(UINT num, char **arg)
+{
+#ifdef	OS_WIN32
+	CMExec();
+#endif
+}
+
+TEST_LIST test_list[] =
+{
+	{"cc", client_test},
+	{"ss", server_test},
+	{"instvlan", instvlan},
+	{"uninstvlan", uninstvlan},
+	{"upgradevlan", upgradevlan},
+	{"enablevlan", enablevlan},
+	{"disablevlan", disablevlan},
+	{"cm", cm_test},
+	{"sm", sm_test},
+	{"test", test},
+};
+
+// テスト関数
+void TestMain(char *cmd)
+{
+	char tmp[MAX_SIZE];
+	bool first = true;
+	bool exit_now = false;
+
+	Print("SoftEther UT-VPN Hamster Tester\n\n"
+		"Copyright (C) 2004-2010 SoftEther Corporation.\nCopyright (C) 2004-2010 University of Tsukuba, Japan.\n"
+		"Copyright (C) 2003-2010 Daiyuu Nobori.\nAll Rights Reserved.\n\n");
+
+#ifdef	OS_WIN32
+	MsSetEnableMinidump(false);
+#endif	// OS_WIN32
+
+	while (true)
+	{
+		Print("TEST>");
+		if (first && StrLen(cmd) != 0 && g_memcheck == false)
+		{
+			first = false;
+			StrCpy(tmp, sizeof(tmp), cmd);
+			exit_now = true;
+			Print("%s\n", cmd);
+		}
+		else
+		{
+			GetLine(tmp, sizeof(tmp));
+		}
+		Trim(tmp);
+		if (StrLen(tmp) != 0)
+		{
+			UINT i, num;
+			bool b = false;
+			TOKEN_LIST *token = ParseCmdLine(tmp);
+			char *cmd = token->Token[0];
+			if (!StrCmpi(cmd, "exit") || !StrCmpi(cmd, "quit") || !StrCmpi(cmd, "q"))
+			{
+				FreeToken(token);
+				break;
+			}
+			if (StartWith(tmp, "utvpncmd"))
+			{
+				wchar_t *s = CopyStrToUni(tmp);
+				CommandMain(s);
+				Free(s);
+			}
+			else
+			{
+				num = sizeof(test_list) / sizeof(TEST_LIST);
+				for (i = 0;i < num;i++)
+				{
+					if (!StrCmpi(test_list[i].command_str, cmd))
+					{
+						char **arg = Malloc(sizeof(char *) * (token->NumTokens - 1));
+						UINT j;
+						for (j = 0;j < token->NumTokens - 1;j++)
+						{
+							arg[j] = CopyStr(token->Token[j + 1]);
+						}
+						test_list[i].proc(token->NumTokens - 1, arg);
+						for (j = 0;j < token->NumTokens - 1;j++)
+						{
+							Free(arg[j]);
+						}
+						Free(arg);
+						b = true;
+						Print("\n");
+						break;
+					}
+				}
+				if (b == false)
+				{
+					Print("Invalid Command: %s\n\n", cmd);
+				}
+			}
+			FreeToken(token);
+
+			if (exit_now)
+			{
+				break;
+			}
+		}
+	}
+	Print("Exiting...\n\n");
+}
+
+#ifdef	WIN32
+// winmain 関数
+int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, char *CmdLine, int CmdShow)
+{
+	main(0, NULL);
+}
+#endif
+
+// main 関数
+int main(int argc, char *argv[])
+{
+	bool memchk = false;
+	UINT i;
+	char cmd[MAX_SIZE];
+	char *s;
+
+	printf("Starting Test Program...\n");
+
+	cmd[0] = 0;
+	if (argc >= 2)
+	{
+		for (i = 1;i < (UINT)argc;i++)
+		{
+			s = argv[i];
+			if (s[0] == '/')
+			{
+				if (!StrCmpi(s, "/memcheck"))
+				{
+					memchk = true;
+				}
+			}
+			else
+			{
+				StrCpy(cmd, sizeof(cmd), &s[0]);
+			}
+		}
+	}
+
+	InitMayaqua(memchk, true, argc, argv);
+	EnableProbe(true);
+	InitCedar();
+	SetHamMode();
+	TestMain(cmdline);
+	FreeCedar();
+	FreeMayaqua();
+
+	return 0;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Ham/Ham.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Ham/Ham.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Ham/Ham.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,85 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Ham.h
+// Ham.c のヘッダファイル
+
+
+// 関数プロトタイプ
+int main(int argc, char *argv[]);
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Cfg.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Cfg.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Cfg.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2280 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Cfg.c
+// 設定情報操作モジュール
+
+#define	CFG_C
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// 設定ファイルのバックアップの作成
+void BackupCfg(FOLDER *f, char *original)
+{
+	wchar_t *original_w = CopyStrToUni(original);
+
+	BackupCfgW(f, original_w);
+
+	Free(original_w);
+}
+void BackupCfgW(FOLDER *f, wchar_t *original)
+{
+	wchar_t dirname[MAX_PATH];
+	wchar_t filename[MAX_PATH];
+	wchar_t fullpath[MAX_PATH];
+	SYSTEMTIME st;
+	// 引数チェック
+	if (f == NULL || filename == NULL)
+	{
+		return;
+	}
+
+	// ディレクトリ名を決定
+	UniFormat(dirname, sizeof(dirname), L"@backup.%s", original[0] == L'@' ? original + 1 : original);
+
+	// ファイル名を決定
+	LocalTime(&st);
+	UniFormat(filename, sizeof(filename), L"%04u%02u%02u%02u_%s",
+		st.wYear, st.wMonth, st.wDay, st.wHour, original[0] == L'@' ? original + 1 : original);
+
+	// このファイル名が存在するかどうかチェックする
+	if (IsFileExistsW(filename))
+	{
+		return;
+	}
+
+	// ディレクトリ作成
+	MakeDirW(dirname);
+
+	// ファイル保存
+	UniFormat(fullpath, sizeof(fullpath), L"%s/%s", dirname, filename);
+	CfgSaveW(f, fullpath);
+}
+
+// 設定ファイル R/W を閉じる
+void FreeCfgRw(CFG_RW *rw)
+{
+	// 引数チェック
+	if (rw == NULL)
+	{
+		return;
+	}
+
+	if (rw->Io != NULL)
+	{
+		FileClose(rw->Io);
+	}
+
+	DeleteLock(rw->lock);
+	Free(rw->FileNameW);
+	Free(rw->FileName);
+	Free(rw);
+}
+
+// 設定ファイルの書き込み
+UINT SaveCfgRw(CFG_RW *rw, FOLDER *f)
+{
+	UINT ret = 0;
+	// 引数チェック
+	if (rw == NULL || f == NULL)
+	{
+		return 0;
+	}
+
+	Lock(rw->lock);
+	{
+		if (rw->Io != NULL)
+		{
+			FileClose(rw->Io);
+			rw->Io = NULL;
+		}
+
+		if (CfgSaveExW2(rw, f, rw->FileNameW, &ret))
+		{
+			if (rw->DontBackup == false)
+			{
+				BackupCfgW(f, rw->FileNameW);
+			}
+		}
+		else
+		{
+			ret = 0;
+		}
+
+		rw->Io = FileOpenW(rw->FileNameW, false);
+	}
+	Unlock(rw->lock);
+
+	return ret;
+}
+
+// 設定ファイル R/W の作成
+CFG_RW *NewCfgRw(FOLDER **root, char *cfg_name)
+{
+	return NewCfgRwEx(root, cfg_name, false);
+}
+CFG_RW *NewCfgRwW(FOLDER **root, wchar_t *cfg_name)
+{
+	return NewCfgRwExW(root, cfg_name, false);
+}
+CFG_RW *NewCfgRwEx(FOLDER **root, char *cfg_name, bool dont_backup)
+{
+	wchar_t *cfg_name_w = CopyStrToUni(cfg_name);
+	CFG_RW *ret = NewCfgRwExW(root, cfg_name_w, dont_backup);
+
+	Free(cfg_name_w);
+
+	return ret;
+}
+CFG_RW *NewCfgRwExW(FOLDER **root, wchar_t *cfg_name, bool dont_backup)
+{
+	CFG_RW *rw;
+	FOLDER *f;
+	// 引数チェック
+	if (cfg_name == NULL || root == NULL)
+	{
+		return NULL;
+	}
+
+	f = CfgReadW(cfg_name);
+	if (f == NULL)
+	{
+		rw = ZeroMalloc(sizeof(CFG_RW));
+		rw->lock = NewLock();
+		rw->FileNameW = CopyUniStr(cfg_name);
+		rw->FileName = CopyUniToStr(cfg_name);
+		rw->Io = FileCreateW(cfg_name);
+		*root = NULL;
+		rw->DontBackup = dont_backup;
+
+		return rw;
+	}
+
+	rw = ZeroMalloc(sizeof(CFG_RW));
+	rw->FileNameW = CopyUniStr(cfg_name);
+	rw->FileName = CopyUniToStr(cfg_name);
+	rw->Io = FileOpenW(cfg_name, false);
+	rw->lock = NewLock();
+
+	*root = f;
+
+	rw->DontBackup = dont_backup;
+
+	return rw;
+}
+
+// ファイルをコピーする
+bool FileCopy(char *src, char *dst)
+{
+	BUF *b;
+	bool ret = false;
+	// 引数チェック
+	if (src == NULL || dst == NULL)
+	{
+		return false;
+	}
+
+	b = ReadDump(src);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	SeekBuf(b, 0, 0);
+
+	ret = DumpBuf(b, dst);
+
+	FreeBuf(b);
+
+	return ret;
+}
+bool FileCopyW(wchar_t *src, wchar_t *dst)
+{
+	BUF *b;
+	bool ret = false;
+	// 引数チェック
+	if (src == NULL || dst == NULL)
+	{
+		return false;
+	}
+
+	b = ReadDumpW(src);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	SeekBuf(b, 0, 0);
+
+	ret = DumpBufW(b, dst);
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// ファイルへ設定を保存する
+void CfgSave(FOLDER *f, char *name)
+{
+	CfgSaveEx(NULL, f, name);
+}
+void CfgSaveW(FOLDER *f, wchar_t *name)
+{
+	CfgSaveExW(NULL, f, name);
+}
+bool CfgSaveEx(CFG_RW *rw, FOLDER *f, char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = CfgSaveExW(rw, f, name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool CfgSaveExW(CFG_RW *rw, FOLDER *f, wchar_t *name)
+{
+	return CfgSaveExW2(rw, f, name, NULL);
+}
+bool CfgSaveExW2(CFG_RW *rw, FOLDER *f, wchar_t *name, UINT *written_size)
+{
+	wchar_t tmp[MAX_SIZE];
+	bool text = true;
+	UCHAR hash[SHA1_SIZE];
+	BUF *b;
+	IO *o;
+	bool ret = true;
+	UINT dummy_int = 0;
+	// 引数チェック
+	if (name == NULL || f == NULL)
+	{
+		return false;
+	}
+	if (written_size == NULL)
+	{
+		written_size = &dummy_int;
+	}
+
+	// 同じディレクトリにある SAVE_BINARY_FILE_NAME_SWITCH ファイルがあるかどうか確認
+	if (IsFileExistsW(SAVE_BINARY_FILE_NAME_SWITCH))
+	{
+		text = false;
+	}
+
+	// バッファに変換
+	b = CfgFolderToBuf(f, text);
+	if (b == NULL)
+	{
+		return false;
+	}
+	// 内容をハッシュする
+	Hash(hash, b->Buf, b->Size, true);
+
+	// 最後に書き込んだ内容と書き込む内容を比較する
+	if (rw != NULL)
+	{
+		if (Cmp(hash, rw->LashHash, SHA1_SIZE) == 0)
+		{
+			// 内容が変更されていない
+			ret = false;
+		}
+		else
+		{
+			Copy(rw->LashHash, hash, SHA1_SIZE);
+		}
+	}
+
+	if (ret || OS_IS_UNIX(GetOsInfo()->OsType))
+	{
+		// 一時的なファイル名の生成
+		UniFormat(tmp, sizeof(tmp), L"%s.log", name);
+		// 現在存在するファイルを一時ファイルにコピー
+		FileCopyW(name, tmp);
+
+		// 新しいファイルを保存
+		o = FileCreateW(name);
+		if (o != NULL)
+		{
+			if (FileWrite(o, b->Buf, b->Size) == false)
+			{
+				// ファイル保存失敗
+				FileClose(o);
+				FileDeleteW(name);
+				FileRenameW(tmp, name);
+
+				if (rw != NULL)
+				{
+					Zero(rw->LashHash, sizeof(rw->LashHash));
+				}
+			}
+			else
+			{
+				// ファイル保存成功
+				FileClose(o);
+				// 一時ファイルの削除
+				FileDeleteW(tmp);
+			}
+		}
+		else
+		{
+			// ファイル保存失敗
+			FileRenameW(tmp, name);
+
+			if (rw != NULL)
+			{
+				Zero(rw->LashHash, sizeof(rw->LashHash));
+			}
+		}
+	}
+
+	*written_size = b->Size;
+
+	// メモリ解放
+	FreeBuf(b);
+
+	return ret;
+}
+
+// ファイルから設定を読み込む
+FOLDER *CfgRead(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	FOLDER *ret = CfgReadW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+FOLDER *CfgReadW(wchar_t *name)
+{
+	wchar_t tmp[MAX_SIZE];
+	wchar_t newfile[MAX_SIZE];
+	BUF *b;
+	IO *o;
+	UINT size;
+	void *buf;
+	FOLDER *f;
+	bool delete_new = false;
+	bool binary_file = false;
+	bool invalid_file = false;
+	UCHAR header[8];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	// 新しいファイル名の生成
+	UniFormat(newfile, sizeof(newfile), L"%s.new", name);
+	// 一時的なファイル名の生成
+	UniFormat(tmp, sizeof(tmp), L"%s.log", name);
+
+	// 新しいファイルが存在していれば読み込む
+	o = FileOpenW(newfile, false);
+	if (o == NULL)
+	{
+		// 一時的なファイルを読む
+		o = FileOpenW(tmp, false);
+	}
+	else
+	{
+		delete_new = true;
+	}
+	if (o == NULL)
+	{
+		// 一時的なファイルが無い場合は本来のファイルを読む
+		o = FileOpenW(name, false);
+	}
+	else
+	{
+		// 一時的なファイルのサイズが 0 の場合も本来のファイルを読み込む
+		if (FileSize(o) == 0)
+		{
+			invalid_file = true;
+		}
+
+		if (invalid_file)
+		{
+			FileClose(o);
+			o = FileOpenW(name, false);
+		}
+	}
+	if (o == NULL)
+	{
+		// 読み込みに失敗した
+		return NULL;
+	}
+
+	// バッファに読み込む
+	size = FileSize(o);
+	buf = Malloc(size);
+	FileRead(o, buf, size);
+	b = NewBuf();
+	WriteBuf(b, buf, size);
+	SeekBuf(b, 0, 0);
+
+	// ファイルを閉じる
+	FileClose(o);
+
+	if (delete_new)
+	{
+		// 新しいファイルを削除する
+		FileDeleteW(newfile);
+	}
+
+	// バッファの先頭 8 文字が "SEVPN_DB" の場合はバイナリファイル
+	ReadBuf(b, header, sizeof(header));
+	if (Cmp(header, TAG_BINARY, 8) == 0)
+	{
+		UCHAR hash1[SHA1_SIZE], hash2[SHA1_SIZE];
+		binary_file = true;
+
+		// ハッシュチェック
+		ReadBuf(b, hash1, sizeof(hash1));
+
+		Hash(hash2, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
+
+		if (Cmp(hash1, hash2, SHA1_SIZE) != 0)
+		{
+			// 破損ファイル
+			invalid_file = true;
+			FreeBuf(b);
+			return NULL;
+		}
+	}
+
+	SeekBuf(b, 0, 0);
+
+	if (binary_file)
+	{
+		SeekBuf(b, 8 + SHA1_SIZE, 0);
+	}
+
+	// バッファからフォルダに変換
+	if (binary_file == false)
+	{
+		// テキストモード
+		f = CfgBufTextToFolder(b);
+	}
+	else
+	{
+		// バイナリモード
+		f = CfgBufBinToFolder(b);
+	}
+
+	// メモリ解放
+	Free(buf);
+	FreeBuf(b);
+
+	FileDeleteW(newfile);
+
+	return f;
+}
+
+// Cfg のテスト
+void CfgTest2(FOLDER *f, UINT n)
+{
+}
+
+void CfgTest()
+{
+#if	0
+	FOLDER *root;
+	BUF *b;
+	Debug("\nCFG Test Begin\n");
+
+	root = CfgCreateFolder(NULL, TAG_ROOT);
+	CfgTest2(root, 5);
+
+	b = CfgFolderToBufText(root);
+	//Print("%s\n", b->Buf);
+	SeekBuf(b, 0, 0);
+
+	CfgDeleteFolder(root);
+
+	DumpBuf(b, "test1.config");
+
+	root = CfgBufTextToFolder(b);
+
+	FreeBuf(b);
+
+	b = CfgFolderToBufText(root);
+//	Print("%s\n", b->Buf);
+	DumpBuf(b, "test2.config");
+	FreeBuf(b);
+
+	CfgSave(root, "test.txt");
+
+	CfgDeleteFolder(root);
+
+	Debug("\nCFG Test End\n");
+#endif
+}
+
+// 1 行読み込む
+char *CfgReadNextLine(BUF *b)
+{
+	char *tmp;
+	char *buf;
+	UINT len;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	// 次の改行までの文字数を調査
+	tmp = (char *)b->Buf + b->Current;
+	if ((b->Size - b->Current) == 0)
+	{
+		// 最後まで読んだ
+		return NULL;
+	}
+	len = 0;
+	while (true)
+	{
+		if (tmp[len] == 13 || tmp[len] == 10)
+		{
+			if (tmp[len] == 13)
+			{
+				if (len < (b->Size - b->Current))
+				{
+					len++;
+				}
+			}
+			break;
+		}
+		len++;
+		if (len >= (b->Size - b->Current))
+		{
+			break;
+		}
+	}
+
+	// len だけ読み込む
+	buf = ZeroMalloc(len + 1);
+	ReadBuf(b, buf, len);
+	SeekBuf(b, 1, 1);
+
+	if (StrLen(buf) >= 1)
+	{
+		if (buf[StrLen(buf) - 1] == 13)
+		{
+			buf[StrLen(buf) - 1] = 0;
+		}
+	}
+
+	return buf;
+}
+
+// テキストストリームを読み込む
+bool CfgReadNextTextBUF(BUF *b, FOLDER *current)
+{
+	char *buf;
+	TOKEN_LIST *token;
+	char *name;
+	char *string;
+	char *data;
+	bool ret;
+	FOLDER *f;
+
+	// 引数チェック
+	if (b == NULL || current == NULL)
+	{
+		return false;
+	}
+
+	ret = true;
+
+	// 1 行読み込む
+	buf = CfgReadNextLine(b);
+	if (buf == NULL)
+	{
+		return false;
+	}
+
+	// この行を解析
+	token = ParseToken(buf, "\t ");
+	if (token == NULL)
+	{
+		Free(buf);
+		return false;
+	}
+
+	if (token->NumTokens >= 1)
+	{
+		if (!StrCmpi(token->Token[0], TAG_DECLARE))
+		{
+			if (token->NumTokens >= 2)
+			{
+				// declare
+				name = CfgUnescape(token->Token[1]);
+
+				// フォルダの作成
+				f = CfgCreateFolder(current, name);
+
+				// 次のフォルダを読み込む
+				while (true)
+				{
+					if (CfgReadNextTextBUF(b, f) == false)
+					{
+						break;
+					}
+				}
+
+				Free(name);
+			}
+		}
+		if (!StrCmpi(token->Token[0], "}"))
+		{
+			// end
+			ret = false;
+		}
+		if (token->NumTokens >= 3)
+		{
+			name = CfgUnescape(token->Token[1]);
+			data = token->Token[2];
+
+			if (!StrCmpi(token->Token[0], TAG_STRING))
+			{
+				// string
+				wchar_t *uni;
+				UINT uni_size;
+				string = CfgUnescape(data);
+				uni_size = CalcUtf8ToUni(string, StrLen(string));
+				if (uni_size != 0)
+				{
+					uni = Malloc(uni_size);
+					Utf8ToUni(uni, uni_size, string, StrLen(string));
+					CfgAddUniStr(current, name, uni);
+					Free(uni);
+				}
+				Free(string);
+			}
+			if (!StrCmpi(token->Token[0], TAG_INT))
+			{
+				// uint
+				CfgAddInt(current, name, ToInt(data));
+			}
+			if (!StrCmpi(token->Token[0], TAG_INT64))
+			{
+				// uint64
+				CfgAddInt64(current, name, ToInt64(data));
+			}
+			if (!StrCmpi(token->Token[0], TAG_BOOL))
+			{
+				// bool
+				bool b = false;
+				if (!StrCmpi(data, TAG_TRUE))
+				{
+					b = true;
+				}
+				else if (ToInt(data) != 0)
+				{
+					b = true;
+				}
+				CfgAddBool(current, name, b);
+			}
+			if (!StrCmpi(token->Token[0], TAG_BYTE))
+			{
+				// byte
+				char *unescaped_b64 = CfgUnescape(data);
+				void *tmp = Malloc(StrLen(unescaped_b64) * 4 + 64);
+				int size = B64_Decode(tmp, unescaped_b64, StrLen(unescaped_b64));
+				CfgAddByte(current, name, tmp, size);
+				Free(tmp);
+				Free(unescaped_b64);
+			}
+
+			Free(name);
+		}
+	}
+
+	// トークンの解放
+	FreeToken(token);
+
+	Free(buf);
+
+	return ret;
+}
+
+// ストリームテキストをフォルダに変換
+FOLDER *CfgBufTextToFolder(BUF *b)
+{
+	FOLDER *f, *c;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	// root フォルダから再帰的に読み込む
+	c = CfgCreateFolder(NULL, "tmp");
+
+	while (true)
+	{
+		// テキストストリームを読み込む
+		if (CfgReadNextTextBUF(b, c) == false)
+		{
+			break;
+		}
+	}
+
+	// root フォルダの取得
+	f = CfgGetFolder(c, TAG_ROOT);
+	if (f == NULL)
+	{
+		// root フォルダが見つからない
+		CfgDeleteFolder(c);
+		return NULL;
+	}
+
+	// tmp フォルダから root への参照を削除
+	Delete(c->Folders, f);
+	f->Parent = NULL;
+
+	// tmp フォルダを削除
+	CfgDeleteFolder(c);
+
+	// root フォルダを返す
+	return f;
+}
+
+// 次のフォルダを読み込む
+void CfgReadNextFolderBin(BUF *b, FOLDER *parent)
+{
+	char name[MAX_SIZE];
+	FOLDER *f;
+	UINT n, i;
+	UINT size;
+	UCHAR *buf;
+	wchar_t *string;
+	// 引数チェック
+	if (b == NULL || parent == NULL)
+	{
+		return;
+	}
+
+	// フォルダ名
+	ReadBufStr(b, name, sizeof(name));
+	f = CfgCreateFolder(parent, name);
+
+	// サブフォルダ数
+	n = ReadBufInt(b);
+	for (i = 0;i < n;i++)
+	{
+		// サブフォルダ
+		CfgReadNextFolderBin(b, f);
+	}
+
+	// アイテム数
+	n = ReadBufInt(b);
+	for (i = 0;i < n;i++)
+	{
+		UINT type;
+
+		// 名前
+		ReadBufStr(b, name, sizeof(name));
+		// 種類
+		type = ReadBufInt(b);
+
+		switch (type)
+		{
+		case ITEM_TYPE_INT:
+			// int
+			CfgAddInt(f, name, ReadBufInt(b));
+			break;
+
+		case ITEM_TYPE_INT64:
+			// int64
+			CfgAddInt64(f, name, ReadBufInt64(b));
+			break;
+
+		case ITEM_TYPE_BYTE:
+			// data
+			size = ReadBufInt(b);
+			buf = ZeroMalloc(size);
+			ReadBuf(b, buf, size);
+			CfgAddByte(f, name, buf, size);
+			Free(buf);
+			break;
+
+		case ITEM_TYPE_STRING:
+			// string
+			size = ReadBufInt(b);
+			buf = ZeroMalloc(size + 1);
+			ReadBuf(b, buf, size);
+			string = ZeroMalloc(CalcUtf8ToUni(buf, StrLen(buf)) + 4);
+			Utf8ToUni(string, 0, buf, StrLen(buf));
+			CfgAddUniStr(f, name, string);
+			Free(string);
+			Free(buf);
+			break;
+
+		case ITEM_TYPE_BOOL:
+			// bool
+			CfgAddBool(f, name, ReadBufInt(b) == 0 ? false : true);
+			break;
+		}
+	}
+}
+
+// バイナリをフォルダに変換
+FOLDER *CfgBufBinToFolder(BUF *b)
+{
+	FOLDER *f, *c;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	// 一時フォルダを作成
+	c = CfgCreateFolder(NULL, "tmp");
+
+	// バイナリを読み込む
+	CfgReadNextFolderBin(b, c);
+
+	// root の取得
+	f = CfgGetFolder(c, TAG_ROOT);
+	if (f == NULL)
+	{
+		// 見つからない
+		CfgDeleteFolder(c);
+		return NULL;
+	}
+
+	Delete(c->Folders, f);
+	f->Parent = NULL;
+
+	CfgDeleteFolder(c);
+
+	return f;
+}
+
+// フォルダをバイナリに変換
+BUF *CfgFolderToBufBin(FOLDER *f)
+{
+	BUF *b;
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+
+	// ヘッダ
+	WriteBuf(b, TAG_BINARY, 8);
+
+	// ハッシュ領域
+	Zero(hash, sizeof(hash));
+	WriteBuf(b, hash, sizeof(hash));
+
+	// ルートフォルダを出力 (再帰)
+	CfgOutputFolderBin(b, f);
+
+	// ハッシュ
+	Hash(((UCHAR *)b->Buf) + 8, ((UCHAR *)b->Buf) + 8 + SHA1_SIZE, b->Size - 8 - SHA1_SIZE, true);
+
+	return b;
+}
+
+// フォルダをストリームテキストに変換
+BUF *CfgFolderToBufText(FOLDER *f)
+{
+	return CfgFolderToBufTextEx(f, false);
+}
+BUF *CfgFolderToBufTextEx(FOLDER *f, bool no_banner)
+{
+	BUF *b;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	// ストリーム作成
+	b = NewBuf();
+
+	// 著作権情報
+	if (no_banner == false)
+	{
+		WriteBuf(b, TAG_CPYRIGHT, StrLen(TAG_CPYRIGHT));
+	}
+
+	// ルートフォルダを出力 (再帰)
+	CfgOutputFolderText(b, f, 0);
+
+	return b;
+}
+
+// フォルダ内容を出力 (フォルダを列挙)
+bool CfgEnumFolderProc(FOLDER *f, void *param)
+{
+	CFG_ENUM_PARAM *p;
+	// 引数チェック
+	if (f == NULL || param == NULL)
+	{
+		return false;
+	}
+
+	p = (CFG_ENUM_PARAM *)param;
+	// フォルダ内容を出力 (再帰)
+	CfgOutputFolderText(p->b, f, p->depth);
+
+	return true;
+}
+
+// アイテム内容を出力 (列挙)
+bool CfgEnumItemProc(ITEM *t, void *param)
+{
+	CFG_ENUM_PARAM *p;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return false;
+	}
+
+	p = (CFG_ENUM_PARAM *)param;
+	CfgAddItemText(p->b, t, p->depth);
+
+	return true;
+}
+
+// フォルダ内容を出力 (再帰、バイナリ)
+void CfgOutputFolderBin(BUF *b, FOLDER *f)
+{
+	UINT i;
+	// 引数チェック
+	if (b == NULL || f == NULL)
+	{
+		return;
+	}
+
+	// フォルダ名
+	WriteBufStr(b, f->Name);
+
+	// サブフォルダ個数
+	WriteBufInt(b, LIST_NUM(f->Folders));
+
+	// サブフォルダ
+	for (i = 0;i < LIST_NUM(f->Folders);i++)
+	{
+		FOLDER *sub = LIST_DATA(f->Folders, i);
+		CfgOutputFolderBin(b, sub);
+
+		if ((i % 100) == 99)
+		{
+			YieldCpu();
+		}
+	}
+
+	// アイテム個数
+	WriteBufInt(b, LIST_NUM(f->Items));
+
+	// アイテム
+	for (i = 0;i < LIST_NUM(f->Items);i++)
+	{
+		char *utf8;
+		UINT utf8_size;
+		ITEM *t = LIST_DATA(f->Items, i);
+
+		// アイテム名
+		WriteBufStr(b, t->Name);
+
+		// 型
+		WriteBufInt(b, t->Type);
+
+		switch (t->Type)
+		{
+		case ITEM_TYPE_INT:
+			// 整数
+			WriteBufInt(b, *((UINT *)t->Buf));
+			break;
+
+		case ITEM_TYPE_INT64:
+			// 64bit 整数
+			WriteBufInt64(b, *((UINT64 *)t->Buf));
+			break;
+
+		case ITEM_TYPE_BYTE:
+			// データサイズ
+			WriteBufInt(b, t->size);
+			// データ
+			WriteBuf(b, t->Buf, t->size);
+			break;
+
+		case ITEM_TYPE_STRING:
+			// 文字列
+			utf8_size = CalcUniToUtf8((wchar_t *)t->Buf) + 1;
+			utf8 = ZeroMalloc(utf8_size);
+			UniToUtf8(utf8, utf8_size, (wchar_t *)t->Buf);
+			WriteBufInt(b, StrLen(utf8));
+			WriteBuf(b, utf8, StrLen(utf8));
+			Free(utf8);
+			break;
+
+		case ITEM_TYPE_BOOL:
+			// ブール型
+			if (*((bool *)t->Buf) == false)
+			{
+				WriteBufInt(b, 0);
+			}
+			else
+			{
+				WriteBufInt(b, 1);
+			}
+			break;
+		}
+	}
+}
+
+// フォルダ内容を出力 (再帰、テキスト)
+void CfgOutputFolderText(BUF *b, FOLDER *f, UINT depth)
+{
+	CFG_ENUM_PARAM p;
+	// 引数チェック
+	if (b == NULL || f == NULL)
+	{
+		return;
+	}
+
+	// フォルダの開始を出力
+	CfgAddDeclare(b, f->Name, depth);
+	depth++;
+
+	Zero(&p, sizeof(CFG_ENUM_PARAM));
+	p.depth = depth;
+	p.b = b;
+	p.f = f;
+
+	// アイテム一覧を列挙
+	CfgEnumItem(f, CfgEnumItemProc, &p);
+
+	if (LIST_NUM(f->Folders) != 0 && LIST_NUM(f->Items) != 0)
+	{
+		WriteBuf(b, "\r\n", 2);
+	}
+
+	// フォルダ一覧を列挙
+	CfgEnumFolder(f, CfgEnumFolderProc, &p);
+	// フォルダの終了を出力
+	depth--;
+	CfgAddEnd(b, depth);
+
+	//WriteBuf(b, "\r\n", 2);
+}
+
+// アイテム内容を出力
+void CfgAddItemText(BUF *b, ITEM *t, UINT depth)
+{
+	char *data;
+	char *sub = NULL;
+	UINT len;
+	UINT size;
+	char *utf8;
+	UINT utf8_size;
+	wchar_t *string;
+	// 引数チェック
+	if (b == NULL || t == NULL)
+	{
+		return;
+	}
+
+	// データ種類別に処理をする
+	data = NULL;
+	switch (t->Type)
+	{
+	case ITEM_TYPE_INT:
+		data = Malloc(32);
+		ToStr(data, *((UINT *)t->Buf));
+		break;
+
+	case ITEM_TYPE_INT64:
+		data = Malloc(64);
+		ToStr64(data, *((UINT64 *)t->Buf));
+		break;
+
+	case ITEM_TYPE_BYTE:
+		data = ZeroMalloc(t->size * 4 + 32);
+		len = B64_Encode(data, t->Buf, t->size);
+		data[len] = 0;
+		break;
+
+	case ITEM_TYPE_STRING:
+		string = t->Buf;
+		utf8_size = CalcUniToUtf8(string);
+		utf8_size++;
+		utf8 = ZeroMalloc(utf8_size);
+		utf8[0] = 0;
+		UniToUtf8(utf8, utf8_size, string);
+		size = utf8_size;
+		data = utf8;
+		break;
+
+	case ITEM_TYPE_BOOL:
+		size = 32;
+		data = Malloc(size);
+		if (*((bool *)t->Buf) == false)
+		{
+			StrCpy(data, size, TAG_FALSE);
+		}
+		else
+		{
+			StrCpy(data, size, TAG_TRUE);
+		}
+		break;
+	}
+	if (data == NULL)
+	{
+		return;
+	}
+
+	// データ行を出力
+	CfgAddData(b, t->Type, t->Name, data, sub, depth);
+
+	// メモリ解放
+	Free(data);
+	if (sub != NULL)
+	{
+		Free(sub);
+	}
+}
+
+// データ行を出力
+void CfgAddData(BUF *b, UINT type, char *name, char *data, char *sub, UINT depth)
+{
+	char *tmp;
+	char *name2;
+	char *data2;
+	char *sub2 = NULL;
+	UINT tmp_size;
+	// 引数チェック
+	if (b == NULL || type == 0 || name == NULL || data == NULL)
+	{
+		return;
+	}
+
+	name2 = CfgEscape(name);
+	data2 = CfgEscape(data);
+	if (sub != NULL)
+	{
+		sub2 = CfgEscape(sub);
+	}
+
+	tmp_size = StrLen(name2) + StrLen(data2) + 2 + 64 + 1;
+	tmp = Malloc(tmp_size);
+
+	if (sub2 != NULL)
+	{
+		StrCpy(tmp, tmp_size, CfgTypeToStr(type));
+		StrCat(tmp, tmp_size, " ");
+		StrCat(tmp, tmp_size, name2);
+		StrCat(tmp, tmp_size, " ");
+		StrCat(tmp, tmp_size, data2);
+		StrCat(tmp, tmp_size, " ");
+		StrCat(tmp, tmp_size, sub2);
+	}
+	else
+	{
+		StrCpy(tmp, tmp_size, CfgTypeToStr(type));
+		StrCat(tmp, tmp_size, " ");
+		StrCat(tmp, tmp_size, name2);
+		StrCat(tmp, tmp_size, " ");
+		StrCat(tmp, tmp_size, data2);
+	}
+
+	Free(name2);
+	Free(data2);
+	if (sub2 != NULL)
+	{
+		Free(sub2);
+	}
+	CfgAddLine(b, tmp, depth);
+	Free(tmp);
+}
+
+// データ種類文字列を整数値に変換
+UINT CfgStrToType(char *str)
+{
+	if (!StrCmpi(str, TAG_INT)) return ITEM_TYPE_INT;
+	if (!StrCmpi(str, TAG_INT64)) return ITEM_TYPE_INT64;
+	if (!StrCmpi(str, TAG_BYTE)) return ITEM_TYPE_BYTE;
+	if (!StrCmpi(str, TAG_STRING)) return ITEM_TYPE_STRING;
+	if (!StrCmpi(str, TAG_BOOL)) return ITEM_TYPE_BOOL;
+	return 0;
+}
+
+// データの種類を文字列に変換
+char *CfgTypeToStr(UINT type)
+{
+	switch (type)
+	{
+	case ITEM_TYPE_INT:
+		return TAG_INT;
+	case ITEM_TYPE_INT64:
+		return TAG_INT64;
+	case ITEM_TYPE_BYTE:
+		return TAG_BYTE;
+	case ITEM_TYPE_STRING:
+		return TAG_STRING;
+	case ITEM_TYPE_BOOL:
+		return TAG_BOOL;
+	}
+	return NULL;
+}
+
+// End 行を出力
+void CfgAddEnd(BUF *b, UINT depth)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	CfgAddLine(b, "}", depth);
+//	CfgAddLine(b, TAG_END, depth);
+}
+
+// Declare 行を出力
+void CfgAddDeclare(BUF *b, char *name, UINT depth)
+{
+	char *tmp;
+	char *name2;
+	UINT tmp_size;
+	// 引数チェック
+	if (b == NULL || name == NULL)
+	{
+		return;
+	}
+
+	name2 = CfgEscape(name);
+
+	tmp_size = StrLen(name2) + 2 + StrLen(TAG_DECLARE);
+	tmp = Malloc(tmp_size);
+
+	Format(tmp, 0, "%s %s", TAG_DECLARE, name2);
+	CfgAddLine(b, tmp, depth);
+	CfgAddLine(b, "{", depth);
+	Free(tmp);
+	Free(name2);
+}
+
+// 1 行を出力
+void CfgAddLine(BUF *b, char *str, UINT depth)
+{
+	UINT i;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < depth;i++)
+	{
+		WriteBuf(b, "\t", 1);
+	}
+	WriteBuf(b, str, StrLen(str));
+	WriteBuf(b, "\r\n", 2);
+}
+
+// フォルダをストリームに変換
+BUF *CfgFolderToBuf(FOLDER *f, bool textmode)
+{
+	return CfgFolderToBufEx(f, textmode, false);
+}
+BUF *CfgFolderToBufEx(FOLDER *f, bool textmode, bool no_banner)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	if (textmode)
+	{
+		return CfgFolderToBufTextEx(f, no_banner);
+	}
+	else
+	{
+		return CfgFolderToBufBin(f);;
+	}
+}
+
+// 文字列のエスケープ復元
+char *CfgUnescape(char *str)
+{
+	char *tmp;
+	char *ret;
+	char tmp2[16];
+	UINT len, wp, i;
+	UINT code;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = StrLen(str);
+	tmp = ZeroMalloc(len + 1);
+	wp = 0;
+	if (len == 1 && str[0] == '$')
+	{
+		// 空文字
+		tmp[0] = 0;
+	}
+	else
+	{
+		for (i = 0;i < len;i++)
+		{
+			if (str[i] != '$')
+			{
+				tmp[wp++] = str[i];
+			}
+			else
+			{
+				tmp2[0] = '0';
+				tmp2[1] = 'x';
+				tmp2[2] = str[i + 1];
+				tmp2[3] = str[i + 2];
+				i += 2;
+				tmp2[4] = 0;
+				code = ToInt(tmp2);
+				tmp[wp++] = (char)code;
+			}
+		}
+	}
+	ret = Malloc(StrLen(tmp) + 1);
+	StrCpy(ret, StrLen(tmp) + 1, tmp);
+	Free(tmp);
+	return ret;
+}
+
+// 文字列のエスケープ
+char *CfgEscape(char *str)
+{
+	char *tmp;
+	char *ret;
+	char tmp2[16];
+	UINT len;
+	UINT wp, i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = StrLen(str);
+	tmp = ZeroMalloc(len * 3 + 2);
+	if (len == 0)
+	{
+		// 空文字
+		StrCpy(tmp, (len * 3 + 2), "$");
+	}
+	else
+	{
+		// 空文字以外
+		wp = 0;
+		for (i = 0;i < len;i++)
+		{
+			if (CfgCheckCharForName(str[i]))
+			{
+				tmp[wp++] = str[i];
+			}
+			else
+			{
+				tmp[wp++] = '$';
+				Format(tmp2, sizeof(tmp2), "%02X", (UINT)str[i]);
+				tmp[wp++] = tmp2[0];
+				tmp[wp++] = tmp2[1];
+			}
+		}
+	}
+	ret = Malloc(StrLen(tmp) + 1);
+	StrCpy(ret, 0, tmp);
+	Free(tmp);
+	return ret;
+}
+
+// 名前に使用することができる文字かどうかチェック
+bool CfgCheckCharForName(char c)
+{
+	if (c >= 0 && c <= 31)
+	{
+		return false;
+	}
+	if (c == ' ' || c == '\t')
+	{
+		return false;
+	}
+	if (c == '$')
+	{
+		return false;
+	}
+	return true;
+}
+
+// string 型の値の取得
+bool CfgGetStr(FOLDER *f, char *name, char *str, UINT size)
+{
+	wchar_t *tmp;
+	UINT tmp_size;
+	// 引数チェック
+	if (f == NULL || name == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	str[0] = 0;
+
+	// unicode 文字列を一時的に取得する
+	tmp_size = size * 4 + 10; // 一応これくらいとっておく
+	tmp = Malloc(tmp_size);
+	if (CfgGetUniStr(f, name, tmp, tmp_size) == false)
+	{
+		// 失敗
+		Free(tmp);
+		return false;
+	}
+
+	// ANSI 文字列にコピー
+	UniToStr(str, size, tmp);
+	Free(tmp);
+
+	return true;
+}
+
+// unicode_string 型の値の取得
+bool CfgGetUniStr(FOLDER *f, char *name, wchar_t *str, UINT size)
+{
+	ITEM *t;
+	// 引数チェック
+	if (f == NULL || name == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	str[0] = 0;
+
+	t = CfgFindItem(f, name);
+	if (t == NULL)
+	{
+		return false;
+	}
+	if (t->Type != ITEM_TYPE_STRING)
+	{
+		return false;
+	}
+	UniStrCpy(str, size, t->Buf);
+	return true;
+}
+
+// フォルダの存在を確認
+bool CfgIsFolder(FOLDER *f, char *name)
+{
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	return (CfgGetFolder(f, name) == NULL) ? false : true;
+}
+
+// アイテムの存在を確認
+bool CfgIsItem(FOLDER *f, char *name)
+{
+	ITEM *t;
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return false;
+	}
+
+	t = CfgFindItem(f, name);
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// byte[] 型を BUF で取得
+BUF *CfgGetBuf(FOLDER *f, char *name)
+{
+	ITEM *t;
+	BUF *b;
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	t = CfgFindItem(f, name);
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+	WriteBuf(b, t->Buf, t->size);
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// byte[] 型の値の取得
+UINT CfgGetByte(FOLDER *f, char *name, void *buf, UINT size)
+{
+	ITEM *t;
+	// 引数チェック
+	if (f == NULL || name == NULL || buf == NULL)
+	{
+		return 0;
+	}
+
+	t = CfgFindItem(f, name);
+	if (t == NULL)
+	{
+		return 0;
+	}
+	if (t->Type != ITEM_TYPE_BYTE)
+	{
+		return 0;
+	}
+	if (t->size <= size)
+	{
+		Copy(buf, t->Buf, t->size);
+		return t->size;
+	}
+	else
+	{
+		Copy(buf, t->Buf, size);
+		return t->size;
+	}
+}
+
+// int64 型の値の取得
+UINT64 CfgGetInt64(FOLDER *f, char *name)
+{
+	ITEM *t;
+	UINT64 *ret;
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	t = CfgFindItem(f, name);
+	if (t == NULL)
+	{
+		return 0;
+	}
+	if (t->Type != ITEM_TYPE_INT64)
+	{
+		return 0;
+	}
+	if (t->size != sizeof(UINT64))
+	{
+		return 0;
+	}
+
+	ret = (UINT64 *)t->Buf;
+	return *ret;
+}
+
+// bool 型の値の取得
+bool CfgGetBool(FOLDER *f, char *name)
+{
+	ITEM *t;
+	bool *ret;
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	t = CfgFindItem(f, name);
+	if (t == NULL)
+	{
+		return 0;
+	}
+	if (t->Type != ITEM_TYPE_BOOL)
+	{
+		return 0;
+	}
+	if (t->size != sizeof(bool))
+	{
+		return 0;
+	}
+
+	ret = (bool *)t->Buf;
+	if (*ret == false)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+// int 型の値の取得
+UINT CfgGetInt(FOLDER *f, char *name)
+{
+	ITEM *t;
+	UINT *ret;
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	t = CfgFindItem(f, name);
+	if (t == NULL)
+	{
+		return 0;
+	}
+	if (t->Type != ITEM_TYPE_INT)
+	{
+		return 0;
+	}
+	if (t->size != sizeof(UINT))
+	{
+		return 0;
+	}
+
+	ret = (UINT *)t->Buf;
+	return *ret;
+}
+
+// アイテムの検索
+ITEM *CfgFindItem(FOLDER *parent, char *name)
+{
+	ITEM *t, tt;
+	// 引数チェック
+	if (parent == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	tt.Name = ZeroMalloc(StrLen(name) + 1);
+	StrCpy(tt.Name, 0, name);
+	t = Search(parent->Items, &tt);
+	Free(tt.Name);
+
+	return t;
+}
+
+// フォルダの取得
+FOLDER *CfgGetFolder(FOLDER *parent, char *name)
+{
+	return CfgFindFolder(parent, name);
+}
+
+// フォルダの検索
+FOLDER *CfgFindFolder(FOLDER *parent, char *name)
+{
+	FOLDER *f, ff;
+	// 引数チェック
+	if (parent == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	ff.Name = ZeroMalloc(StrLen(name) + 1);
+	StrCpy(ff.Name, 0, name);
+	f = Search(parent->Folders, &ff);
+	Free(ff.Name);
+
+	return f;
+}
+
+// string 型の追加
+ITEM *CfgAddStr(FOLDER *f, char *name, char *str)
+{
+	wchar_t *tmp;
+	UINT tmp_size;
+	ITEM *t;
+	// 引数チェック
+	if (f == NULL || name == NULL || str == NULL)
+	{
+		return NULL;
+	}
+
+	// Unicode 文字列に変換
+	tmp_size = CalcStrToUni(str);
+	if (tmp_size == 0)
+	{
+		return NULL;
+	}
+	tmp = Malloc(tmp_size);
+	StrToUni(tmp, tmp_size, str);
+	t = CfgAddUniStr(f, name, tmp);
+	Free(tmp);
+
+	return t;
+}
+
+// unicode_string 型の追加
+ITEM *CfgAddUniStr(FOLDER *f, char *name, wchar_t *str)
+{
+	// 引数チェック
+	if (f == NULL || name == NULL || str == NULL)
+	{
+		return NULL;
+	}
+
+	return CfgCreateItem(f, name, ITEM_TYPE_STRING, str, UniStrSize(str));
+}
+
+// バイナリの追加
+ITEM *CfgAddBuf(FOLDER *f, char *name, BUF *b)
+{
+	// 引数チェック
+	if (f == NULL || name == NULL || b == NULL)
+	{
+		return NULL;
+	}
+	return CfgAddByte(f, name, b->Buf, b->Size);
+}
+
+// バイト型の追加
+ITEM *CfgAddByte(FOLDER *f, char *name, void *buf, UINT size)
+{
+	// 引数チェック
+	if (f == NULL || name == NULL || buf == NULL)
+	{
+		return NULL;
+	}
+	return CfgCreateItem(f, name, ITEM_TYPE_BYTE, buf, size);
+}
+
+// 64bit 整数型の追加
+ITEM *CfgAddInt64(FOLDER *f, char *name, UINT64 i)
+{
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return NULL;
+	}
+	return CfgCreateItem(f, name, ITEM_TYPE_INT64, &i, sizeof(UINT64));
+}
+
+// IP アドレス型の取得
+bool CfgGetIp(FOLDER *f, char *name, struct IP *ip)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (f == NULL || name == NULL || ip == NULL)
+	{
+		return false;
+	}
+
+	Zero(ip, sizeof(IP));
+
+	if (CfgGetStr(f, name, tmp, sizeof(tmp)) == false)
+	{
+		return false;
+	}
+
+	if (StrToIP(ip, tmp) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+UINT CfgGetIp32(FOLDER *f, char *name)
+{
+	IP p;
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return 0;
+	}
+
+	if (CfgGetIp(f, name, &p) == false)
+	{
+		return 0;
+	}
+
+	return IPToUINT(&p);
+}
+bool CfgGetIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
+{
+	IP ip;
+	// 引数チェック
+	Zero(addr, sizeof(IPV6_ADDR));
+	if (f == NULL || name == NULL || addr == NULL)
+	{
+		return false;
+	}
+
+	if (CfgGetIp(f, name, &ip) == false)
+	{
+		return false;
+	}
+
+	if (IsIP6(&ip) == false)
+	{
+		return false;
+	}
+
+	if (IPToIPv6Addr(addr, &ip) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// IP アドレス型の追加
+ITEM *CfgAddIp(FOLDER *f, char *name, struct IP *ip)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (f == NULL || name == NULL || ip == NULL)
+	{
+		return NULL;
+	}
+
+	IPToStr(tmp, sizeof(tmp), ip);
+
+	return CfgAddStr(f, name, tmp);
+}
+ITEM *CfgAddIp32(FOLDER *f, char *name, UINT ip)
+{
+	IP p;
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	UINTToIP(&p, ip);
+
+	return CfgAddIp(f, name, &p);
+}
+ITEM *CfgAddIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr)
+{
+	IP ip;
+	// 引数チェック
+	if (f == NULL || name == NULL || addr == NULL)
+	{
+		return NULL;
+	}
+
+	IPv6AddrToIP(&ip, addr);
+
+	return CfgAddIp(f, name, &ip);
+}
+
+// 整数型の追加
+ITEM *CfgAddInt(FOLDER *f, char *name, UINT i)
+{
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return NULL;
+	}
+	return CfgCreateItem(f, name, ITEM_TYPE_INT, &i, sizeof(UINT));
+}
+
+// bool 型の追加
+ITEM *CfgAddBool(FOLDER *f, char *name, bool b)
+{
+	bool v;
+	// 引数チェック
+	if (f == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	v = b ? 1 : 0;
+	return CfgCreateItem(f, name, ITEM_TYPE_BOOL, &b, sizeof(bool));
+}
+
+// アイテム名の比較関数
+int CmpItemName(void *p1, void *p2)
+{
+	ITEM *f1, *f2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	f1 = *(ITEM **)p1;
+	f2 = *(ITEM **)p2;
+	if (f1 == NULL || f2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(f1->Name, f2->Name);
+}
+
+// フォルダ名の比較関数
+int CmpFolderName(void *p1, void *p2)
+{
+	FOLDER *f1, *f2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	f1 = *(FOLDER **)p1;
+	f2 = *(FOLDER **)p2;
+	if (f1 == NULL || f2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(f1->Name, f2->Name);
+}
+
+// アイテムの列挙
+void CfgEnumItem(FOLDER *f, ENUM_ITEM proc, void *param)
+{
+	UINT i;
+	// 引数チェック
+	if (f == NULL || proc == NULL)
+	{
+		return;
+	}
+	
+	for (i = 0;i < LIST_NUM(f->Items);i++)
+	{
+		ITEM *tt = LIST_DATA(f->Items, i);
+		if (proc(tt, param) == false)
+		{
+			break;
+		}
+	}
+}
+
+// フォルダを列挙してトークンリストに格納
+TOKEN_LIST *CfgEnumFolderToTokenList(FOLDER *f)
+{
+	TOKEN_LIST *t, *ret;
+	UINT i;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(f->Folders);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		FOLDER *ff = LIST_DATA(f->Folders, i);
+		t->Token[i] = CopyStr(ff->Name);
+	}
+
+	ret = UniqueToken(t);
+	FreeToken(t);
+
+	return ret;
+}
+
+// アイテムを列挙してトークンリストに格納
+TOKEN_LIST *CfgEnumItemToTokenList(FOLDER *f)
+{
+	TOKEN_LIST *t, *ret;
+	UINT i;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return NULL;
+	}
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(f->Items);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		FOLDER *ff = LIST_DATA(f->Items, i);
+		t->Token[i] = CopyStr(ff->Name);
+	}
+
+	ret = UniqueToken(t);
+	FreeToken(t);
+
+	return ret;
+}
+
+// フォルダの列挙
+void CfgEnumFolder(FOLDER *f, ENUM_FOLDER proc, void *param)
+{
+	UINT i;
+	// 引数チェック
+	if (f == NULL || proc == NULL)
+	{
+		return;
+	}
+	
+	for (i = 0;i < LIST_NUM(f->Folders);i++)
+	{
+		FOLDER *ff = LIST_DATA(f->Folders, i);
+		if (proc(ff, param) == false)
+		{
+			break;
+		}
+
+		if ((i % 100) == 99)
+		{
+			YieldCpu();
+		}
+	}
+}
+
+// アイテムの作成
+ITEM *CfgCreateItem(FOLDER *parent, char *name, UINT type, void *buf, UINT size)
+{
+	UINT name_size;
+	ITEM *t;
+#ifdef	CHECK_CFG_NAME_EXISTS
+	ITEM tt;
+#endif	// CHECK_CFG_NAME_EXISTS
+	// 引数チェック
+	if (parent == NULL || name == NULL || type == 0 || buf == NULL)
+	{
+		return NULL;
+	}
+
+	name_size = StrLen(name) + 1;
+
+#ifdef	CHECK_CFG_NAME_EXISTS
+
+	// すでに同名のアイテムが無いかどうか確認
+	tt.Name = ZeroMalloc(name_size);
+	StrCpy(tt.Name, 0, name);
+	t = Search(parent->Items, &tt);
+	Free(tt.Name);
+	if (t != NULL)
+	{
+		// 重複している
+		return NULL;
+	}
+
+#endif	// CHECK_CFG_NAME_EXISTS
+
+	t = ZeroMalloc(sizeof(ITEM));
+	t->Buf = Malloc(size);
+	Copy(t->Buf, buf, size);
+	t->Name = ZeroMalloc(name_size);
+	StrCpy(t->Name, 0, name);
+	t->Type = type;
+	t->size = size;
+	t->Parent = parent;
+	
+	// 親のリストに追加
+	Insert(parent->Items, t);
+
+	return t;
+}
+
+// アイテムの削除
+void CfgDeleteItem(ITEM *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// 親のリストから削除
+	Delete(t->Parent->Items, t);
+
+	// メモリ解放
+	Free(t->Buf);
+	Free(t->Name);
+	Free(t);
+}
+
+
+// フォルダの削除
+void CfgDeleteFolder(FOLDER *f)
+{
+	FOLDER **ff;
+	ITEM **tt;
+	UINT num, i;
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	// サブフォルダをすべて削除
+	num = LIST_NUM(f->Folders);
+	ff = Malloc(sizeof(FOLDER *) * num);
+	Copy(ff, f->Folders->p, sizeof(FOLDER *) * num);
+	for (i = 0;i < num;i++)
+	{
+		CfgDeleteFolder(ff[i]);
+	}
+	Free(ff);
+
+	// アイテムをすべて削除
+	num = LIST_NUM(f->Items);
+	tt = Malloc(sizeof(ITEM *) * num);
+	Copy(tt, f->Items->p, sizeof(ITEM *) * num);
+	for (i = 0;i < num;i++)
+	{
+		CfgDeleteItem(tt[i]);
+	}
+	Free(tt);
+
+	// メモリ解放
+	Free(f->Name);
+	// 親のリストから削除
+	if (f->Parent != NULL)
+	{
+		Delete(f->Parent->Folders, f);
+	}
+	// リストの解放
+	ReleaseList(f->Folders);
+	ReleaseList(f->Items);
+
+	// 本体のメモリの解放
+	Free(f);
+}
+
+// ルートの作成
+FOLDER *CfgCreateRoot()
+{
+	return CfgCreateFolder(NULL, TAG_ROOT);
+}
+
+// フォルダの作成
+FOLDER *CfgCreateFolder(FOLDER *parent, char *name)
+{
+	UINT size;
+	FOLDER *f;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	size = StrLen(name) + 1;
+
+#ifdef	CHECK_CFG_NAME_EXISTS
+
+	// 親のリストの名前を検査
+	if (parent != NULL)
+	{
+		FOLDER ff;
+		ff.Name = ZeroMalloc(size);
+		StrCpy(ff.Name, 0, name);
+		f = Search(parent->Folders, &ff);
+		Free(ff.Name);
+		if (f != NULL)
+		{
+			// 既に同じ名前のフォルダが存在する
+			return NULL;
+		}
+	}
+
+#endif	// CHECK_CFG_NAME_EXISTS
+
+	f = ZeroMalloc(sizeof(FOLDER));
+	f->Items = NewListFast(CmpItemName);
+	f->Folders = NewListFast(CmpFolderName);
+	f->Name = ZeroMalloc(size);
+	StrCpy(f->Name, 0, name);
+	f->Parent = parent;
+
+	// 親のリストに追加
+	if (f->Parent != NULL)
+	{
+		Insert(f->Parent->Folders, f);
+	}
+	return f;
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Cfg.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Cfg.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Cfg.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,239 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Cfg.h
+// Cfg.c のヘッダ
+
+#ifndef	CFG_H
+#define	CFG_H
+
+// マクロ
+//#define	CHECK_CFG_NAME_EXISTS			// 既存の名前との重複チェックを行う
+
+#define	SAVE_BINARY_FILE_NAME_SWITCH	L"@save_binary"
+
+// 定数
+#define	TAG_DECLARE			"declare"
+#define	TAG_STRING			"string"
+#define	TAG_INT				"uint"
+#define	TAG_INT64			"uint64"
+#define	TAG_BOOL			"bool"
+#define	TAG_BYTE			"byte"
+#define	TAG_TRUE			"true"
+#define	TAG_FALSE			"false"
+#define	TAG_END				"end"
+#define	TAG_ROOT			"root"
+
+#define	TAG_CPYRIGHT		"\xef\xbb\xbf# SoftEther UT-VPN Software Configuration File\r\n# \r\n# You can edit this file when the program is not working.\r\n# \r\n"
+#define	TAG_BINARY			"SEVPN_DB"
+
+// データ型
+#define	ITEM_TYPE_INT		1		// int
+#define	ITEM_TYPE_INT64		2		// int64
+#define	ITEM_TYPE_BYTE		3		// byte
+#define	ITEM_TYPE_STRING	4		// string
+#define	ITEM_TYPE_BOOL		5		// bool
+
+// フォルダ
+struct FOLDER
+{
+	char *Name;				// フォルダ名
+	LIST *Items;			// アイテムのリスト
+	LIST *Folders;			// サブフォルダ
+	struct FOLDER *Parent;	// 親フォルダ
+};
+
+// アイテム
+struct ITEM
+{
+	char *Name;				// アイテム名
+	UINT Type;				// データ型
+	void *Buf;				// データ
+	UINT size;				// データサイズ
+	FOLDER *Parent;			// 親フォルダ
+};
+
+// 設定ファイルリーダライタ
+struct CFG_RW
+{
+	LOCK *lock;				// ロック
+	char *FileName;			// ファイル名 (ANSI)
+	wchar_t *FileNameW;		// ファイル名 (Unicode)
+	IO *Io;					// IO
+	UCHAR LashHash[SHA1_SIZE];	// 最後に書き込んだハッシュ値
+	bool DontBackup;		// バックアップを使用しない
+};
+
+typedef bool (*ENUM_FOLDER)(FOLDER *f, void *param);
+typedef bool (*ENUM_ITEM)(ITEM *t, void *param);
+
+// 列挙用のパラメータ
+struct CFG_ENUM_PARAM
+{
+	BUF *b;
+	FOLDER *f;
+	UINT depth;
+};
+
+int CmpItemName(void *p1, void *p2);
+int CmpFolderName(void *p1, void *p2);
+ITEM *CfgCreateItem(FOLDER *parent, char *name, UINT type, void *buf, UINT size);
+void CfgDeleteFolder(FOLDER *f);
+FOLDER *CfgCreateFolder(FOLDER *parent, char *name);
+void CfgEnumFolder(FOLDER *f, ENUM_FOLDER proc, void *param);
+TOKEN_LIST *CfgEnumFolderToTokenList(FOLDER *f);
+TOKEN_LIST *CfgEnumItemToTokenList(FOLDER *f);
+void CfgEnumItem(FOLDER *f, ENUM_ITEM proc, void *param);
+FOLDER *CfgFindFolder(FOLDER *parent, char *name);
+ITEM *CfgFindItem(FOLDER *parent, char *name);
+ITEM *CfgAddInt(FOLDER *f, char *name, UINT i);
+ITEM *CfgAddBool(FOLDER *f, char *name, bool b);
+ITEM *CfgAddInt64(FOLDER *f, char *name, UINT64 i);
+ITEM *CfgAddByte(FOLDER *f, char *name, void *buf, UINT size);
+ITEM *CfgAddBuf(FOLDER *f, char *name, BUF *b);
+ITEM *CfgAddStr(FOLDER *f, char *name, char *str);
+ITEM *CfgAddUniStr(FOLDER *f, char *name, wchar_t *str);
+FOLDER *CfgGetFolder(FOLDER *parent, char *name);
+UINT CfgGetInt(FOLDER *f, char *name);
+bool CfgGetBool(FOLDER *f, char *name);
+UINT64 CfgGetInt64(FOLDER *f, char *name);
+UINT CfgGetByte(FOLDER *f, char *name, void *buf, UINT size);
+BUF *CfgGetBuf(FOLDER *f, char *name);
+bool CfgGetStr(FOLDER *f, char *name, char *str, UINT size);
+bool CfgGetUniStr(FOLDER *f, char *name, wchar_t *str, UINT size);
+bool CfgIsItem(FOLDER *f, char *name);
+bool CfgIsFolder(FOLDER *f, char *name);
+void CfgTest();
+void CfgTest2(FOLDER *f, UINT n);
+char *CfgEscape(char *name);
+bool CfgCheckCharForName(char c);
+char *CfgUnescape(char *str);
+BUF *CfgFolderToBuf(FOLDER *f, bool textmode);
+BUF *CfgFolderToBufEx(FOLDER *f, bool textmode, bool no_banner);
+BUF *CfgFolderToBufText(FOLDER *f);
+BUF *CfgFolderToBufTextEx(FOLDER *f, bool no_banner);
+BUF *CfgFolderToBufBin(FOLDER *f);
+void CfgOutputFolderText(BUF *b, FOLDER *f, UINT depth);
+void CfgOutputFolderBin(BUF *b, FOLDER *f);
+void CfgAddLine(BUF *b, char *str, UINT depth);
+void CfgAddDeclare(BUF *b, char *name, UINT depth);
+void CfgAddEnd(BUF *b, UINT depth);
+void CfgAddData(BUF *b, UINT type, char *name, char *data, char *sub, UINT depth);
+UINT CfgStrToType(char *str);
+char *CfgTypeToStr(UINT type);
+void CfgAddItemText(BUF *b, ITEM *t, UINT depth);
+bool CfgEnumFolderProc(FOLDER *f, void *param);
+bool CfgEnumItemProc(ITEM *t, void *param);
+FOLDER *CfgBufTextToFolder(BUF *b);
+FOLDER *CfgBufBinToFolder(BUF *b);
+void CfgReadNextFolderBin(BUF *b, FOLDER *parent);
+char *CfgReadNextLine(BUF *b);
+bool CfgReadNextTextBuf(BUF *b, FOLDER *current);
+void CfgSave(FOLDER *f, char *name);
+void CfgSaveW(FOLDER *f, wchar_t *name);
+bool CfgSaveEx(CFG_RW *rw, FOLDER *f, char *name);
+bool CfgSaveExW(CFG_RW *rw, FOLDER *f, wchar_t *name);
+bool CfgSaveExW2(CFG_RW *rw, FOLDER *f, wchar_t *name, UINT *written_size);
+FOLDER *CfgRead(char *name);
+FOLDER *CfgReadW(wchar_t *name);
+FOLDER *CfgCreateRoot();
+void CfgTest();
+void CfgTest2(FOLDER *f, UINT n);
+CFG_RW *NewCfgRw(FOLDER **root, char *cfg_name);
+CFG_RW *NewCfgRwW(FOLDER **root, wchar_t *cfg_name);
+CFG_RW *NewCfgRwEx(FOLDER **root, char *cfg_name, bool dont_backup);
+CFG_RW *NewCfgRwExW(FOLDER **root, wchar_t *cfg_name, bool dont_backup);
+UINT SaveCfgRw(CFG_RW *rw, FOLDER *f);
+void FreeCfgRw(CFG_RW *rw);
+ITEM *CfgAddIp32(FOLDER *f, char *name, UINT ip);
+UINT CfgGetIp32(FOLDER *f, char *name);
+bool CfgGetIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr);
+ITEM *CfgAddIp6Addr(FOLDER *f, char *name, IPV6_ADDR *addr);
+bool FileCopy(char *src, char *dst);
+bool FileCopyW(wchar_t *src, wchar_t *dst);
+void BackupCfg(FOLDER *f, char *original);
+void BackupCfgW(FOLDER *f, wchar_t *original);
+
+#if	(!defined(CFG_C)) || (!defined(OS_UNIX))
+bool CfgGetIp(FOLDER *f, char *name, struct IP *ip);
+ITEM *CfgAddIp(FOLDER *f, char *name, struct IP *ip);
+#endif
+
+#endif	// CFG_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Encrypt.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Encrypt.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Encrypt.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,3545 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Encrypt.c
+// 暗号化および電子証明書ルーチン
+
+#define	ENCRYPT_C
+
+#define	__WINCRYPT_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/engine.h>
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include <openssl/pkcs7.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rc4.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <Mayaqua/Mayaqua.h>
+
+LOCK *openssl_lock = NULL;
+
+LOCK **ssl_lock_obj = NULL;
+UINT ssl_lock_num;
+static bool openssl_inited = false;
+
+// コールバック関数用
+typedef struct CB_PARAM
+{
+	char *password;
+} CB_PARAM;
+
+// 証明書が特定のディレクトリの CRL によって無効化されているかどうか確認する
+bool IsXRevoked(X *x)
+{
+	char dirname[MAX_PATH];
+	UINT i;
+	bool ret = false;
+	DIRLIST *t;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return false;
+	}
+
+	GetExeDir(dirname, sizeof(dirname));
+
+	// CRL ファイルの検索
+	t = EnumDir(dirname);
+
+	for (i = 0;i < t->NumFiles;i++)
+	{
+		char *name = t->File[i]->FileName;
+		if (t->File[i]->Folder == false)
+		{
+			if (EndWith(name, ".crl"))
+			{
+				char filename[MAX_PATH];
+				X_CRL *r;
+
+				ConbinePath(filename, sizeof(filename), dirname, name);
+
+				r = FileToXCrl(filename);
+
+				if (r != NULL)
+				{
+					if (IsXRevokedByXCrl(x, r))
+					{
+						ret = true;
+					}
+
+					FreeXCrl(r);
+				}
+			}
+		}
+	}
+
+	FreeDir(t);
+
+	return ret;
+}
+
+// 証明書が CRL によって無効化されているかどうか確認する
+bool IsXRevokedByXCrl(X *x, X_CRL *r)
+{
+#ifdef	OS_WIN32
+	X509_REVOKED tmp;
+	X509_CRL_INFO *info;
+	int index;
+	// 引数チェック
+	if (x == NULL || r == NULL)
+	{
+		return false;
+	}
+
+	Zero(&tmp, sizeof(tmp));
+	tmp.serialNumber = X509_get_serialNumber(x->x509);
+
+	info = r->Crl->crl;
+
+	if (sk_X509_REVOKED_is_sorted(info->revoked) == false)
+	{
+		sk_X509_REVOKED_sort(info->revoked);
+	}
+
+	index = sk_X509_REVOKED_find(info->revoked, &tmp);
+
+	if (index < 0)
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+#else	// OS_WIN32
+	return false;
+#endif	// OS_WIN32
+}
+
+// CRL の解放
+void FreeXCrl(X_CRL *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	X509_CRL_free(r->Crl);
+
+	Free(r);
+}
+
+// ファイルを CRL に変換
+X_CRL *FileToXCrl(char *filename)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	X_CRL *ret = FileToXCrlW(filename_w);
+
+	Free(filename_w);
+
+	return ret;
+}
+X_CRL *FileToXCrlW(wchar_t *filename)
+{
+	BUF *b;
+	X_CRL *r;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	b = ReadDumpW(filename);
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	r = BufToXCrl(b);
+
+	FreeBuf(b);
+
+	return r;
+}
+
+// バッファを CRL に変換
+X_CRL *BufToXCrl(BUF *b)
+{
+	X_CRL *r;
+	X509_CRL *x509crl;
+	BIO *bio;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	bio = BufToBio(b);
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	x509crl	= NULL;
+
+	if (d2i_X509_CRL_bio(bio, &x509crl) == NULL || x509crl == NULL)
+	{
+		FreeBio(bio);
+		return NULL;
+	}
+
+	r = ZeroMalloc(sizeof(X_CRL));
+	r->Crl = x509crl;
+
+	FreeBio(bio);
+
+	return r;
+}
+
+// バッファを公開鍵に変換
+K *RsaBinToPublic(void *data, UINT size)
+{
+	RSA *rsa;
+	K *k;
+	BIO *bio;
+	// 引数チェック
+	if (data == NULL || size < 4)
+	{
+		return NULL;
+	}
+
+	rsa = RSA_new();
+
+	if (rsa->e != NULL)
+	{
+		BN_free(rsa->e);
+	}
+
+	rsa->e = BN_new();
+	BN_set_word(rsa->e, RSA_F4);
+
+	if (rsa->n != NULL)
+	{
+		BN_free(rsa->n);
+	}
+
+	rsa->n = BinToBigNum(data, size);
+
+	bio = NewBio();
+	Lock(openssl_lock);
+	{
+		i2d_RSA_PUBKEY_bio(bio, rsa);
+	}
+	Unlock(openssl_lock);
+	BIO_seek(bio, 0);
+	k = BioToK(bio, false, false, NULL);
+	FreeBio(bio);
+
+	RSA_free(rsa);
+
+	return k;
+}
+
+// 公開鍵をバッファに変換
+BUF *RsaPublicToBuf(K *k)
+{
+	BUF *b;
+	// 引数チェック
+	if (k == NULL || k->pkey == NULL || k->pkey->pkey.rsa == NULL
+		|| k->pkey->pkey.rsa->n == NULL)
+	{
+		return NULL;
+	}
+
+	b = BigNumToBuf(k->pkey->pkey.rsa->n);
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	return b;
+}
+
+// 公開鍵をバイナリに変換
+void RsaPublicToBin(K *k, void *data)
+{
+	BUF *b;
+	// 引数チェック
+	if (k == NULL || k->pkey == NULL || k->pkey->pkey.rsa == NULL
+		|| k->pkey->pkey.rsa->n == NULL || data == NULL)
+	{
+		return;
+	}
+
+	b = BigNumToBuf(k->pkey->pkey.rsa->n);
+	if (b == NULL)
+	{
+		return;
+	}
+
+	Copy(data, b->Buf, b->Size);
+
+	FreeBuf(b);
+}
+
+// 公開鍵サイズの取得
+UINT RsaPublicSize(K *k)
+{
+	BUF *b;
+	UINT ret;
+	// 引数チェック
+	if (k == NULL || k->pkey == NULL || k->pkey->pkey.rsa == NULL
+		|| k->pkey->pkey.rsa->n == NULL)
+	{
+		return 0;
+	}
+
+	b = BigNumToBuf(k->pkey->pkey.rsa->n);
+	if (b == NULL)
+	{
+		return 0;
+	}
+
+	ret = b->Size;
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// ポインタを 32 ビットにハッシュする
+UINT HashPtrToUINT(void *p)
+{
+	UCHAR hash_data[MD5_SIZE];
+	UINT ret;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return 0;
+	}
+
+	Hash(hash_data, &p, sizeof(p), false);
+
+	Copy(&ret, hash_data, sizeof(ret));
+
+	return ret;
+}
+
+// NAME のコピー
+NAME *CopyName(NAME *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return NULL;
+	}
+
+	return NewName(n->CommonName, n->Organization, n->Unit,
+		n->Country, n->State, n->Local);
+}
+
+// バイナリを BIGNUM に変換
+BIGNUM *BinToBigNum(void *data, UINT size)
+{
+	BIGNUM *bn;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return NULL;
+	}
+
+	bn = BN_new();
+	BN_bin2bn(data, size, bn);
+
+	return bn;
+}
+
+// バッファを BIGNUM に変換
+BIGNUM *BufToBigNum(BUF *b)
+{
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	return BinToBigNum(b->Buf, b->Size);
+}
+
+// BIGNUM をバッファに変換
+BUF *BigNumToBuf(BIGNUM *bn)
+{
+	UINT size;
+	UCHAR *tmp;
+	BUF *b;
+	// 引数チェック
+	if (bn == NULL)
+	{
+		return NULL;
+	}
+
+	size = BN_num_bytes(bn);
+	tmp = ZeroMalloc(size);
+	BN_bn2bin(bn, tmp);
+
+	b = NewBuf();
+	WriteBuf(b, tmp, size);
+	Free(tmp);
+
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// OpenSSL のロックの初期化
+void OpenSSL_InitLock()
+{
+	UINT i;
+
+	// ロックオブジェクトの初期化
+	ssl_lock_num = CRYPTO_num_locks();
+	ssl_lock_obj = Malloc(sizeof(LOCK *) * ssl_lock_num);
+	for (i = 0;i < ssl_lock_num;i++)
+	{
+		ssl_lock_obj[i] = NewLock();
+	}
+
+	// ロック関数の設定
+	CRYPTO_set_locking_callback(OpenSSL_Lock);
+	CRYPTO_set_id_callback(OpenSSL_Id);
+}
+
+// OpenSSL のロックの解放
+void OpenSSL_FreeLock()
+{
+	UINT i;
+
+	for (i = 0;i < ssl_lock_num;i++)
+	{
+		DeleteLock(ssl_lock_obj[i]);
+	}
+	Free(ssl_lock_obj);
+	ssl_lock_obj = NULL;
+
+	CRYPTO_set_locking_callback(NULL);
+	CRYPTO_set_id_callback(NULL);
+}
+
+// OpenSSL のロック関数
+void OpenSSL_Lock(int mode, int n, const char *file, int line)
+{
+	LOCK *lock = ssl_lock_obj[n];
+
+	if (mode & CRYPTO_LOCK)
+	{
+		// ロック
+		Lock(lock);
+	}
+	else
+	{
+		// ロック解除
+		Unlock(lock);
+	}
+}
+
+// スレッド ID の返却
+unsigned long OpenSSL_Id(void)
+{
+	return (unsigned long)ThreadId();
+}
+
+// 証明書の表示名を取得
+void GetPrintNameFromX(wchar_t *str, UINT size, X *x)
+{
+	// 引数チェック
+	if (x == NULL || str == NULL)
+	{
+		return;
+	}
+
+	GetPrintNameFromName(str, size, x->subject_name);
+}
+void GetPrintNameFromXA(char *str, UINT size, X *x)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL || x == NULL)
+	{
+		return;
+	}
+
+	GetPrintNameFromX(tmp, sizeof(tmp), x);
+
+	UniToStr(str, size, tmp);
+}
+void GetAllNameFromXEx(wchar_t *str, UINT size, X *x)
+{
+	// 引数チェック
+	if (x == NULL || str == NULL)
+	{
+		return;
+	}
+
+	GetAllNameFromNameEx(str, size, x->subject_name);
+}
+void GetAllNameFromXExA(char *str, UINT size, X *x)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL || x == NULL)
+	{
+		return;
+	}
+
+	GetAllNameFromXEx(tmp, sizeof(tmp), x);
+
+	UniToStr(str, size, tmp);
+}
+
+// NAME から表示名を取得
+void GetPrintNameFromName(wchar_t *str, UINT size, NAME *name)
+{
+	// 引数チェック
+	if (str == NULL || name == NULL)
+	{
+		return;
+	}
+
+	if (name->CommonName != NULL)
+	{
+		UniStrCpy(str, size, name->CommonName);
+	}
+	else if (name->Organization != NULL)
+	{
+		UniStrCpy(str, size, name->Organization);
+	}
+	else if (name->Unit != NULL)
+	{
+		UniStrCpy(str, size, name->Unit);
+	}
+	else if (name->State != NULL)
+	{
+		UniStrCpy(str, size, name->State);
+	}
+	else if (name->Local != NULL)
+	{
+		UniStrCpy(str, size, name->Local);
+	}
+	else if (name->Country != NULL)
+	{
+		UniStrCpy(str, size, name->Country);
+	}
+	else
+	{
+		UniStrCpy(str, size, L"untitled");
+	}
+}
+
+// 証明書からすべての名前文字列を取得
+void GetAllNameFromX(wchar_t *str, UINT size, X *x)
+{
+	UCHAR md5[MD5_SIZE], sha1[SHA1_SIZE];
+	char tmp1[MD5_SIZE * 3 + 8], tmp2[SHA1_SIZE * 3 + 8];
+	wchar_t tmp3[sizeof(tmp1) + sizeof(tmp2) + 64];
+	// 引数チェック
+	if (str == NULL || x == NULL)
+	{
+		return;
+	}
+
+	GetAllNameFromName(str, size, x->subject_name);
+
+	if (x->serial != NULL && x->serial->size >= 1)
+	{
+		char tmp[128];
+		wchar_t tmp2[128];
+
+		BinToStr(tmp, sizeof(tmp), x->serial->data, x->serial->size);
+		UniFormat(tmp2, sizeof(tmp2), L", SERIAL=\"%S\"", tmp);
+
+		UniStrCat(str, size, tmp2);
+	}
+
+	// ダイジェスト値
+	GetXDigest(x, md5, false);
+	GetXDigest(x, sha1, true);
+
+	BinToStr(tmp1, sizeof(tmp1), md5, MD5_SIZE);
+	BinToStr(tmp2, sizeof(tmp2), sha1, SHA1_SIZE);
+
+	UniFormat(tmp3, sizeof(tmp3), L" (Digest: MD5=\"%S\", SHA1=\"%S\")", tmp1, tmp2);
+	UniStrCat(str, size, tmp3);
+}
+void GetAllNameFromA(char *str, UINT size, X *x)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL || x == NULL)
+	{
+		return;
+	}
+
+	GetAllNameFromX(tmp, sizeof(tmp), x);
+	UniToStr(str, size, tmp);
+}
+
+// NAME からすべての名前文字列を取得
+void GetAllNameFromName(wchar_t *str, UINT size, NAME *name)
+{
+	// 引数チェック
+	if (str == NULL || name == NULL)
+	{
+		return;
+	}
+
+	UniStrCpy(str, size, L"");
+	if (name->CommonName != NULL)
+	{
+		UniFormat(str, size, L"%sCN=%s, ", str, name->CommonName);
+	}
+	if (name->Organization != NULL)
+	{
+		UniFormat(str, size, L"%sO=%s, ", str, name->Organization);
+	}
+	if (name->Unit != NULL)
+	{
+		UniFormat(str, size, L"%sOU=%s, ", str, name->Unit);
+	}
+	if (name->State != NULL)
+	{
+		UniFormat(str, size, L"%sS=%s, ", str, name->State);
+	}
+	if (name->Local != NULL)
+	{
+		UniFormat(str, size, L"%sL=%s, ", str, name->Local);
+	}
+	if (name->Country != NULL)
+	{
+		UniFormat(str, size, L"%sC=%s, ", str, name->Country);
+	}
+
+	if (UniStrLen(str) >= 3)
+	{
+		UINT len = UniStrLen(str);
+		if (str[len - 2] == L',' &&
+			str[len - 1] == L' ')
+		{
+			str[len - 2] = 0;
+		}
+	}
+}
+void GetAllNameFromNameEx(wchar_t *str, UINT size, NAME *name)
+{
+	// 引数チェック
+	if (str == NULL || name == NULL)
+	{
+		return;
+	}
+
+	UniStrCpy(str, size, L"");
+	if (name->CommonName != NULL)
+	{
+		UniFormat(str, size, L"%s%s, ", str, name->CommonName);
+	}
+	if (name->Organization != NULL)
+	{
+		UniFormat(str, size, L"%s%s, ", str, name->Organization);
+	}
+	if (name->Unit != NULL)
+	{
+		UniFormat(str, size, L"%s%s, ", str, name->Unit);
+	}
+	if (name->State != NULL)
+	{
+		UniFormat(str, size, L"%s%s, ", str, name->State);
+	}
+	if (name->Local != NULL)
+	{
+		UniFormat(str, size, L"%s%s, ", str, name->Local);
+	}
+	if (name->Country != NULL)
+	{
+		UniFormat(str, size, L"%s%s, ", str, name->Country);
+	}
+
+	if (UniStrLen(str) >= 3)
+	{
+		UINT len = UniStrLen(str);
+		if (str[len - 2] == L',' &&
+			str[len - 1] == L' ')
+		{
+			str[len - 2] = 0;
+		}
+	}
+}
+
+// 鍵のクローン
+K *CloneK(K *k)
+{
+	BUF *b;
+	K *ret;
+	// 引数チェック
+	if (k == NULL)
+	{
+		return NULL;
+	}
+
+	b = KToBuf(k, false, NULL);
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	ret = BufToK(b, k->private_key, false, NULL);
+	FreeBuf(b);
+
+	return ret;
+}
+
+// 証明書のクローン
+X *CloneX(X *x)
+{
+	BUF *b;
+	X *ret;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return NULL;
+	}
+
+	b = XToBuf(x, false);
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	ret = BufToX(b, false);
+	FreeBuf(b);
+
+	return ret;
+}
+
+// P12 を生成する
+P12 *NewP12(X *x, K *k, char *password)
+{
+	PKCS12 *pkcs12;
+	P12 *p12;
+	// 引数チェック
+	if (x == NULL || k == NULL)
+	{
+		return false;
+	}
+	if (password && StrLen(password) == 0)
+	{
+		password = NULL;
+	}
+
+	Lock(openssl_lock);
+	{
+		pkcs12 = PKCS12_create(password, NULL, k->pkey, x->x509, NULL, 0, 0, 0, 0, 0);
+		if (pkcs12 == NULL)
+		{
+			Unlock(openssl_lock);
+			return NULL;
+		}
+	}
+	Unlock(openssl_lock);
+
+	p12 = PKCS12ToP12(pkcs12);
+
+	return p12;
+}
+
+// P12 が暗号化されているかどうかチェックする
+bool IsEncryptedP12(P12 *p12)
+{
+	X *x;
+	K *k;
+	// 引数チェック
+	if (p12 == NULL)
+	{
+		return false;
+	}
+
+	if (ParseP12(p12, &x, &k, NULL) == true)
+	{
+		FreeX(x);
+		FreeK(k);
+		return false;
+	}
+
+	return true;
+}
+
+// P12 から X と K を取り出す
+bool ParseP12(P12 *p12, X **x, K **k, char *password)
+{
+	EVP_PKEY *pkey;
+	X509 *x509;
+	// 引数チェック
+	if (p12 == NULL || x == NULL || k == NULL)
+	{
+		return false;
+	}
+	if (password && StrLen(password) == 0)
+	{
+		password = NULL;
+	}
+	if (password == NULL)
+	{
+		password = "";
+	}
+
+	// パスワード確認
+	Lock(openssl_lock);
+	{
+		if (PKCS12_verify_mac(p12->pkcs12, password, -1) == false &&
+			PKCS12_verify_mac(p12->pkcs12, NULL, -1) == false)
+		{
+			Unlock(openssl_lock);
+			return false;
+		}
+	}
+	Unlock(openssl_lock);
+
+	// 抽出
+	Lock(openssl_lock);
+	{
+		if (PKCS12_parse(p12->pkcs12, password, &pkey, &x509, NULL) == false)
+		{
+			if (PKCS12_parse(p12->pkcs12, NULL, &pkey, &x509, NULL) == false)
+			{
+				Unlock(openssl_lock);
+				return false;
+			}
+		}
+	}
+	Unlock(openssl_lock);
+
+	// 変換
+	*x = X509ToX(x509);
+
+	if (*x == NULL)
+	{
+		FreePKey(pkey);
+		return false;
+	}
+
+	*k = ZeroMalloc(sizeof(K));
+	(*k)->private_key = true;
+	(*k)->pkey = pkey;
+
+	return true;
+}
+
+// P12 をファイルに書き出す
+bool P12ToFile(P12 *p12, char *filename)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	bool ret = P12ToFileW(p12, filename_w);
+
+	return ret;
+}
+bool P12ToFileW(P12 *p12, wchar_t *filename)
+{
+	BUF *b;
+	// 引数チェック
+	if (p12 == NULL || filename == NULL)
+	{
+		return false;
+	}
+
+	b = P12ToBuf(p12);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	if (DumpBufW(b, filename) == false)
+	{
+		FreeBuf(b);
+		return false;
+	}
+
+	FreeBuf(b);
+
+	return true;
+}
+
+// ファイルから P12 を読み込む
+P12 *FileToP12(char *filename)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	P12 *ret = FileToP12W(filename_w);
+
+	Free(filename_w);
+
+	return ret;
+}
+P12 *FileToP12W(wchar_t *filename)
+{
+	BUF *b;
+	P12 *p12;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	b = ReadDumpW(filename);
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	p12 = BufToP12(b);
+	FreeBuf(b);
+
+	return p12;
+}
+
+// P12 の解放
+void FreeP12(P12 *p12)
+{
+	// 引数チェック
+	if (p12 == NULL)
+	{
+		return;
+	}
+
+	FreePKCS12(p12->pkcs12);
+	Free(p12);
+}
+
+// PKCS12 の解放
+void FreePKCS12(PKCS12 *pkcs12)
+{
+	// 引数チェック
+	if (pkcs12 == NULL)
+	{
+		return;
+	}
+
+	PKCS12_free(pkcs12);
+}
+
+// P12 を BUF に変換する
+BUF *P12ToBuf(P12 *p12)
+{
+	BIO *bio;
+	BUF *buf;
+	// 引数チェック
+	if (p12 == NULL)
+	{
+		return NULL;
+	}
+
+	bio = P12ToBio(p12);
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	buf = BioToBuf(bio);
+	FreeBio(bio);
+
+	SeekBuf(buf, 0, 0);
+
+	return buf;
+}
+
+// P12 を BIO に変換する
+BIO *P12ToBio(P12 *p12)
+{
+	BIO *bio;
+	// 引数チェック
+	if (p12 == NULL)
+	{
+		return NULL;
+	}
+
+	bio = NewBio();
+	Lock(openssl_lock);
+	{
+		i2d_PKCS12_bio(bio, p12->pkcs12);
+	}
+	Unlock(openssl_lock);
+
+	return bio;
+}
+
+// BUF から P12 を読み込む
+P12 *BufToP12(BUF *b)
+{
+	P12 *p12;
+	BIO *bio;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	bio = BufToBio(b);
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	p12 = BioToP12(bio);
+	FreeBio(bio);
+
+	return p12;
+}
+
+// BIO から P12 を読み込む
+P12 *BioToP12(BIO *bio)
+{
+	PKCS12 *pkcs12;
+	// 引数チェック
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	// 変換
+	Lock(openssl_lock);
+	{
+		pkcs12 = d2i_PKCS12_bio(bio, NULL);
+	}
+	Unlock(openssl_lock);
+	if (pkcs12 == NULL)
+	{
+		// 失敗
+		return NULL;
+	}
+
+	return PKCS12ToP12(pkcs12);
+}
+
+// PKCS12 から P12 を生成する
+P12 *PKCS12ToP12(PKCS12 *pkcs12)
+{
+	P12 *p12;
+	// 引数チェック
+	if (pkcs12 == NULL)
+	{
+		return NULL;
+	}
+
+	p12 = ZeroMalloc(sizeof(P12));
+	p12->pkcs12 = pkcs12;
+
+	return p12;
+}
+
+// バイナリを文字列に変換する
+char *ByteToStr(BYTE *src, UINT src_size)
+{
+	UINT size;
+	char *dst;
+	UINT i;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return NULL;
+	}
+
+	size = MAX(src_size * 3, 1);
+	dst = Malloc(size);
+	dst[size - 1] = 0;
+	for (i = 0;i < src_size;i++)
+	{
+		char tmp[3];
+		Format(tmp, sizeof(tmp), "%02x", src[i]);
+		dst[i * 3 + 0] = tmp[0];
+		dst[i * 3 + 1] = tmp[1];
+		dst[i * 3 + 2] = ((i == (src_size - 1) ? 0 : ' '));
+	}
+
+	return dst;
+}
+
+// X_SERIAL の解放
+void FreeXSerial(X_SERIAL *serial)
+{
+	// 引数チェック
+	if (serial == NULL)
+	{
+		return;
+	}
+
+	Free(serial->data);
+	Free(serial);
+}
+
+// X_SERIAL の比較
+bool CompareXSerial(X_SERIAL *s1, X_SERIAL *s2)
+{
+	// 引数チェック
+	if (s1 == NULL || s2 == NULL)
+	{
+		return false;
+	}
+
+	if (s1->size != s2->size)
+	{
+		return false;
+	}
+
+	if (Cmp(s1->data, s2->data, s1->size) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// X_SERIAL のコピー
+X_SERIAL *CloneXSerial(X_SERIAL *src)
+{
+	X_SERIAL *s;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return NULL;
+	}
+
+	s = ZeroMalloc(sizeof(X_SERIAL));
+	s->data = ZeroMalloc(src->size);
+	Copy(s->data, src->data, src->size);
+	s->size = src->size;
+
+	return s;
+}
+
+// X_SERIAL の初期化
+X_SERIAL *NewXSerial(void *data, UINT size)
+{
+	X_SERIAL *serial;
+	UCHAR *buf = (UCHAR *)data;
+	UINT i;
+	// 引数チェック
+	if (data == NULL || size == 0)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < size;i++)
+	{
+		if (buf[i] != 0)
+		{
+			break;
+		}
+	}
+	if (i == size)
+	{
+		i = size - 1;
+	}
+	buf += i;
+
+	serial = Malloc(sizeof(X_SERIAL));
+	serial->size = size - i;
+	serial->data = ZeroMalloc(size + 16);
+	Copy(serial->data, buf, size - i);
+
+	return serial;
+}
+
+// 2038 年 1 月 1 日までの日数を取得する
+UINT GetDaysUntil2038()
+{
+	UINT64 now = SystemTime64();
+	UINT64 target;
+	SYSTEMTIME st;
+
+	Zero(&st, sizeof(st));
+	st.wYear = 2038;
+	st.wMonth = 1;
+	st.wDay = 1;
+
+	target = SystemToUINT64(&st);
+
+	if (now >= target)
+	{
+		return 0;
+	}
+	else
+	{
+		return (UINT)((target - now) / (UINT64)(1000 * 60 * 60 * 24));
+	}
+}
+
+// X509 証明書を発行する
+X *NewX(K *pub, K *priv, X *ca, NAME *name, UINT days, X_SERIAL *serial)
+{
+	X509 *x509;
+	X *x;
+	// 引数チェック
+	if (pub == NULL || priv == NULL || name == NULL || ca == NULL)
+	{
+		return NULL;
+	}
+
+	x509 = NewX509(pub, priv, ca, name, days, serial);
+	if (x509 == NULL)
+	{
+		return NULL;
+	}
+
+	x = X509ToX(x509);
+
+	if (x == NULL)
+	{
+		return NULL;
+	}
+
+	return x;
+}
+
+// ルート証明書を作成する
+X *NewRootX(K *pub, K *priv, NAME *name, UINT days, X_SERIAL *serial)
+{
+	X509 *x509;
+	X *x, *x2;
+	// 引数チェック
+	if (pub == NULL || priv == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	x509 = NewRootX509(pub, priv, name, days, serial);
+	if (x509 == NULL)
+	{
+		return NULL;
+	}
+
+	x = X509ToX(x509);
+	if (x == NULL)
+	{
+		return NULL;
+	}
+
+	x2 = CloneX(x);
+	FreeX(x);
+
+	return x2;
+}
+
+// X509 証明書を発行する
+X509 *NewX509(K *pub, K *priv, X *ca, NAME *name, UINT days, X_SERIAL *serial)
+{
+	X509 *x509;
+	UINT64 notBefore, notAfter;
+	ASN1_TIME *t1, *t2;
+	X509_NAME *subject_name, *issuer_name;
+	// 引数チェック
+	if (pub == NULL || name == NULL || ca == NULL)
+	{
+		return NULL;
+	}
+	if (pub->private_key != false)
+	{
+		return NULL;
+	}
+	if (priv->private_key == false)
+	{
+		return NULL;
+	}
+
+	notBefore = SystemTime64();
+	notAfter = notBefore + (UINT64)days * (UINT64)3600 * (UINT64)24 * (UINT64)1000;
+
+
+	// X509 の作成
+	x509 = X509_new();
+	if (x509 == NULL)
+	{
+		return NULL;
+	}
+
+	// 有効期限の設定
+	t1 = X509_get_notBefore(x509);
+	t2 = X509_get_notAfter(x509);
+	if (!UINT64ToAsn1Time(t1, notBefore))
+	{
+		FreeX509(x509);
+		return NULL;
+	}
+	if (!UINT64ToAsn1Time(t2, notAfter))
+	{
+		FreeX509(x509);
+		return NULL;
+	}
+
+	// 名前の設定
+	subject_name = NameToX509Name(name);
+	if (subject_name == NULL)
+	{
+		FreeX509(x509);
+		return NULL;
+	}
+	issuer_name = X509_get_subject_name(ca->x509);
+	if (issuer_name == NULL)
+	{
+		FreeX509Name(subject_name);
+		FreeX509(x509);
+		return NULL;
+	}
+
+	X509_set_issuer_name(x509, issuer_name);
+	X509_set_subject_name(x509, subject_name);
+
+	FreeX509Name(subject_name);
+
+	// シリアル番号の設定
+	if (serial == NULL)
+	{
+		char zero = 0;
+		ASN1_INTEGER *s = x509->cert_info->serialNumber;
+		OPENSSL_free(s->data);
+		s->data = OPENSSL_malloc(sizeof(char));
+		Copy(s->data, &zero, sizeof(char));
+		s->length = sizeof(char);
+	}
+	else
+	{
+		ASN1_INTEGER *s = x509->cert_info->serialNumber;
+		OPENSSL_free(s->data);
+		s->data = OPENSSL_malloc(serial->size);
+		Copy(s->data, serial->data, serial->size);
+		s->length = serial->size;
+	}
+
+	Lock(openssl_lock);
+	{
+		// 公開鍵の設定
+		X509_set_pubkey(x509, pub->pkey);
+
+		// 署名
+		X509_sign(x509, priv->pkey, EVP_sha1());
+	}
+	Unlock(openssl_lock);
+
+	return x509;
+}
+
+// ルート X509 証明書を作成する
+X509 *NewRootX509(K *pub, K *priv, NAME *name, UINT days, X_SERIAL *serial)
+{
+	X509 *x509;
+	UINT64 notBefore, notAfter;
+	ASN1_TIME *t1, *t2;
+	X509_NAME *subject_name, *issuer_name;
+	// 引数チェック
+	if (pub == NULL || name == NULL || priv == NULL)
+	{
+		return NULL;
+	}
+	if (days == 0)
+	{
+		days = 365;
+	}
+	if (priv->private_key == false)
+	{
+		return NULL;
+	}
+	if (pub->private_key != false)
+	{
+		return NULL;
+	}
+
+	notBefore = SystemTime64();
+	notAfter = notBefore + (UINT64)days * (UINT64)3600 * (UINT64)24 * (UINT64)1000;
+
+	// X509 の作成
+	x509 = X509_new();
+	if (x509 == NULL)
+	{
+		return NULL;
+	}
+
+	// 有効期限の設定
+	t1 = X509_get_notBefore(x509);
+	t2 = X509_get_notAfter(x509);
+	if (!UINT64ToAsn1Time(t1, notBefore))
+	{
+		FreeX509(x509);
+		return NULL;
+	}
+	if (!UINT64ToAsn1Time(t2, notAfter))
+	{
+		FreeX509(x509);
+		return NULL;
+	}
+
+	// 名前の設定
+	subject_name = NameToX509Name(name);
+	if (subject_name == NULL)
+	{
+		FreeX509(x509);
+		return NULL;
+	}
+	issuer_name = NameToX509Name(name);
+	if (issuer_name == NULL)
+	{
+		FreeX509Name(subject_name);
+		FreeX509(x509);
+		return NULL;
+	}
+
+	X509_set_issuer_name(x509, issuer_name);
+	X509_set_subject_name(x509, subject_name);
+
+	FreeX509Name(subject_name);
+	FreeX509Name(issuer_name);
+
+	// シリアル番号の設定
+	if (serial == NULL)
+	{
+		char zero = 0;
+		ASN1_INTEGER *s = x509->cert_info->serialNumber;
+		OPENSSL_free(s->data);
+		s->data = OPENSSL_malloc(sizeof(char));
+		Copy(s->data, &zero, sizeof(char));
+		s->length = sizeof(char);
+	}
+	else
+	{
+		ASN1_INTEGER *s = x509->cert_info->serialNumber;
+		OPENSSL_free(s->data);
+		s->data = OPENSSL_malloc(serial->size);
+		Copy(s->data, serial->data, serial->size);
+		s->length = serial->size;
+	}
+
+	Lock(openssl_lock);
+	{
+		// 公開鍵の設定
+		X509_set_pubkey(x509, pub->pkey);
+
+		// 署名
+		X509_sign(x509, priv->pkey, EVP_sha1());
+	}
+	Unlock(openssl_lock);
+
+	return x509;
+}
+
+// NAME を X509_NAME に変換
+void *NameToX509Name(NAME *nm)
+{
+	X509_NAME *xn;
+	// 引数チェック
+	if (nm == NULL)
+	{
+		return NULL;
+	}
+
+	xn = X509_NAME_new();
+	if (xn == NULL)
+	{
+		return NULL;
+	}
+
+	// エントリの追加
+	AddX509Name(xn, NID_commonName, nm->CommonName);
+	AddX509Name(xn, NID_organizationName, nm->Organization);
+	AddX509Name(xn, NID_organizationalUnitName, nm->Unit);
+	AddX509Name(xn, NID_countryName, nm->Country);
+	AddX509Name(xn, NID_stateOrProvinceName, nm->State);
+	AddX509Name(xn, NID_localityName, nm->Local);
+
+	return xn;
+}
+
+// X509_NAME にエントリを追加する
+bool AddX509Name(void *xn, int nid, wchar_t *str)
+{
+	X509_NAME *x509_name;
+	UINT utf8_size;
+	BYTE *utf8;
+	// 引数チェック
+	if (xn == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	// UTF-8 に変換
+	utf8_size = CalcUniToUtf8(str);
+	if (utf8_size == 0)
+	{
+		return false;
+	}
+	utf8 = ZeroMalloc(utf8_size + 1);
+	UniToUtf8(utf8, utf8_size, str);
+	utf8[utf8_size] = 0;
+
+	// 追加
+	x509_name = (X509_NAME *)xn;
+	Lock(openssl_lock);
+	{
+		X509_NAME_add_entry_by_NID(x509_name, nid, MBSTRING_ASC, utf8, utf8_size, -1, 0);
+	}
+	Unlock(openssl_lock);
+	Free(utf8);
+
+	return true;
+}
+
+// X509_NAME を解放
+void FreeX509Name(void *xn)
+{
+	X509_NAME *x509_name;
+	// 引数チェック
+	if (xn == NULL)
+	{
+		return;
+	}
+
+	x509_name = (X509_NAME *)xn;
+	X509_NAME_free(x509_name);
+}
+
+// NAME の作成
+NAME *NewName(wchar_t *common_name, wchar_t *organization, wchar_t *unit,
+			  wchar_t *country, wchar_t *state, wchar_t *local)
+{
+	NAME *nm = ZeroMalloc(sizeof(NAME));
+
+	if (UniIsEmptyStr(common_name) == false)
+	{
+		nm->CommonName = CopyUniStr(common_name);
+	}
+
+	if (UniIsEmptyStr(organization) == false)
+	{
+		nm->Organization = CopyUniStr(organization);
+	}
+
+	if (UniIsEmptyStr(unit) == false)
+	{
+		nm->Unit = CopyUniStr(unit);
+	}
+
+	if (UniIsEmptyStr(country) == false)
+	{
+		nm->Country = CopyUniStr(country);
+	}
+
+	if (UniIsEmptyStr(state) == false)
+	{
+		nm->State = CopyUniStr(state);
+	}
+
+	if (UniIsEmptyStr(local) == false)
+	{
+		nm->Local = CopyUniStr(local);
+	}
+
+	return nm;
+}
+
+// 証明書の有効期限を現在時刻で確認する
+bool CheckXDateNow(X *x)
+{
+	// 引数チェック
+	if (x == NULL)
+	{
+		return false;
+	}
+
+	return CheckXDate(x, SystemTime64());
+}
+
+// 証明書の有効期限を確認する
+bool CheckXDate(X *x, UINT64 current_system_time)
+{
+	// 引数チェック
+	if (x == NULL)
+	{
+		return false;
+	}
+
+	if (x->notBefore >= current_system_time || x->notAfter <= current_system_time)
+	{
+		return false;
+	}
+	return true;
+}
+
+// 証明書の有効期限情報を読み込む
+void LoadXDates(X *x)
+{
+	// 引数チェック
+	if (x == NULL)
+	{
+		return;
+	}
+
+	x->notBefore = Asn1TimeToUINT64(x->x509->cert_info->validity->notBefore);
+	x->notAfter = Asn1TimeToUINT64(x->x509->cert_info->validity->notAfter);
+}
+
+// 64bit システム時刻を ASN1 時刻に変換する
+bool UINT64ToAsn1Time(void *asn1_time, UINT64 t)
+{
+	SYSTEMTIME st;
+	// 引数チェック
+	if (asn1_time == NULL)
+	{
+		return false;
+	}
+
+	UINT64ToSystem(&st, t);
+	return SystemToAsn1Time(asn1_time, &st);
+}
+
+// システム時刻を ASN1 時刻に変換する
+bool SystemToAsn1Time(void *asn1_time, SYSTEMTIME *s)
+{
+	char tmp[20];
+	ASN1_TIME *t;
+	// 引数チェック
+	if (asn1_time == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	if (SystemToStr(tmp, sizeof(tmp), s) == false)
+	{
+		return false;
+	}
+	t = (ASN1_TIME *)asn1_time;
+	if (t->data == NULL || t->length < sizeof(tmp))
+	{
+		t->data = OPENSSL_malloc(sizeof(tmp));
+	}
+	StrCpy((char *)t->data, t->length, tmp);
+	t->length = StrLen(tmp);
+	t->type = V_ASN1_UTCTIME;
+
+	return true;
+}
+
+// システム時刻を文字列に変換する
+bool SystemToStr(char *str, UINT size, SYSTEMTIME *s)
+{
+	// 引数チェック
+	if (str == NULL || s == NULL)
+	{
+		return false;
+	}
+
+	Format(str, size, "%02u%02u%02u%02u%02u%02uZ",
+		s->wYear % 100, s->wMonth, s->wDay,
+		s->wHour, s->wMinute, s->wSecond);
+
+	return true;
+}
+
+// ASN1 時刻を UINT64 時刻に変換する
+UINT64 Asn1TimeToUINT64(void *asn1_time)
+{
+	SYSTEMTIME st;
+	// 引数チェック
+	if (asn1_time == NULL)
+	{
+		return 0;
+	}
+
+	if (Asn1TimeToSystem(&st, asn1_time) == false)
+	{
+		return 0;
+	}
+	return SystemToUINT64(&st);
+}
+
+// ASN1 時刻をシステム時刻に変換する
+bool Asn1TimeToSystem(SYSTEMTIME *s, void *asn1_time)
+{
+	ASN1_TIME *t;
+	// 引数チェック
+	if (s == NULL || asn1_time == NULL)
+	{
+		return false;
+	}
+
+	t = (ASN1_TIME *)asn1_time;
+	if (StrToSystem(s, (char *)t->data) == false)
+	{
+		return false;
+	}
+
+	if (t->type == V_ASN1_GENERALIZEDTIME)
+	{
+		LocalToSystem(s, s);
+	}
+
+	return true;
+}
+
+// 文字列をシステム時刻に変換する
+bool StrToSystem(SYSTEMTIME *s, char *str)
+{
+	// 引数チェック
+	if (s == NULL || str == NULL)
+	{
+		return false;
+	}
+	if (StrLen(str) != 13)
+	{
+		return false;
+	}
+	if (str[12] != 'Z')
+	{
+		return false;
+	}
+
+	// 変換
+	{
+		char year[3] = {str[0], str[1], 0},
+			month[3] = {str[2], str[3], 0},
+			day[3] = {str[4], str[5], 0},
+			hour[3] = {str[6], str[7], 0},
+			minute[3] = {str[8], str[9], 0},
+			second[3] = {str[10], str[11], 0};
+		Zero(s, sizeof(SYSTEMTIME));
+		s->wYear = ToInt(year);
+		if (s->wYear >= 60)
+		{
+			s->wYear += 1900;
+		}
+		else
+		{
+			s->wYear += 2000;
+		}
+		s->wMonth = ToInt(month);
+		s->wDay = ToInt(day);
+		s->wHour = ToInt(hour);
+		s->wMinute = ToInt(minute);
+		s->wSecond = ToInt(second);
+		NormalizeSystem(s);
+	}
+
+	return true;
+}
+
+// RSA 署名の検査
+bool RsaVerify(void *data, UINT data_size, void *sign, K *k)
+{
+	return RsaVerifyEx(data, data_size, sign, k, 0);
+}
+bool RsaVerifyEx(void *data, UINT data_size, void *sign, K *k, UINT bits)
+{
+	UCHAR hash_data[SIGN_HASH_SIZE];
+	UCHAR decrypt_data[SIGN_HASH_SIZE];
+	// 引数チェック
+	if (data == NULL || sign == NULL || k == NULL || k->private_key != false)
+	{
+		return false;
+	}
+	if (bits == 0)
+	{
+		bits = 1024;
+	}
+
+	// データをハッシュ
+	if (HashForSign(hash_data, sizeof(hash_data), data, data_size) == false)
+	{
+		return false;
+	}
+
+	// 署名を解読
+	if (RSA_public_decrypt(bits / 8, sign, decrypt_data, k->pkey->pkey.rsa, RSA_PKCS1_PADDING) <= 0)
+	{
+		return false;
+	}
+
+	// 比較
+	if (Cmp(decrypt_data, hash_data, sizeof(SIGN_HASH_SIZE)) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// RSA 署名
+bool RsaSign(void *dst, void *src, UINT size, K *k)
+{
+	return RsaSignEx(dst, src, size, k, 0);
+}
+bool RsaSignEx(void *dst, void *src, UINT size, K *k, UINT bits)
+{
+	UCHAR hash[SIGN_HASH_SIZE];
+	// 引数チェック
+	if (dst == NULL || src == NULL || k == NULL || k->pkey->type != EVP_PKEY_RSA)
+	{
+		return false;
+	}
+	if (bits == 0)
+	{
+		bits = 1024;
+	}
+
+	Zero(dst, bits / 8);
+
+	// ハッシュ
+	if (HashForSign(hash, sizeof(hash), src, size) == false)
+	{
+		return false;
+	}
+
+	// 署名
+	if (RSA_private_encrypt(sizeof(hash), hash, dst, k->pkey->pkey.rsa, RSA_PKCS1_PADDING) <= 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// SHA-1 による署名データの生成
+bool HashForSign(void *dst, UINT dst_size, void *src, UINT src_size)
+{
+	UCHAR *buf = (UCHAR *)dst;
+	UCHAR sign_data[] =
+	{
+		0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E,
+		0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14,
+	};
+	// 引数チェック
+	if (dst == NULL || src == NULL || src_size == 0 || MIN_SIGN_HASH_SIZE > dst_size)
+	{
+		return false;
+	}
+
+	// ヘッダ部分
+	Copy(buf, sign_data, sizeof(sign_data));
+
+	// ハッシュ
+	HashSha1(HASHED_DATA(buf), src, src_size);
+
+	return true;
+}
+
+// RSA 公開鍵による復号化
+bool RsaPublicDecrypt(void *dst, void *src, UINT size, K *k)
+{
+	void *tmp;
+	int ret;
+	// 引数チェック
+	if (src == NULL || size == 0 || k == NULL)
+	{
+		return false;
+	}
+
+	tmp = ZeroMalloc(size);
+	Lock(openssl_lock);
+	{
+		ret = RSA_public_decrypt(size, src, tmp, k->pkey->pkey.rsa, RSA_NO_PADDING);
+	}
+	Unlock(openssl_lock);
+	if (ret <= 0)
+	{
+/*		Debug("RSA Error: 0x%x\n",
+			ERR_get_error());
+*/		Free(tmp);
+		return false;
+	}
+
+	Copy(dst, tmp, size);
+	Free(tmp);
+
+	return true;
+}
+
+// RSA 秘密鍵による暗号化
+bool RsaPrivateEncrypt(void *dst, void *src, UINT size, K *k)
+{
+	void *tmp;
+	int ret;
+	// 引数チェック
+	if (src == NULL || size == 0 || k == NULL)
+	{
+		return false;
+	}
+
+	tmp = ZeroMalloc(size);
+	Lock(openssl_lock);
+	{
+		ret = RSA_private_encrypt(size, src, tmp, k->pkey->pkey.rsa, RSA_NO_PADDING);
+	}
+	Unlock(openssl_lock);
+	if (ret <= 0)
+	{
+/*		Debug("RSA Error: %u\n",
+			ERR_GET_REASON(ERR_get_error()));
+*/		Free(tmp);
+		return false;
+	}
+
+	Copy(dst, tmp, size);
+	Free(tmp);
+
+	return true;
+}
+
+// RSA 秘密鍵による復号化
+bool RsaPrivateDecrypt(void *dst, void *src, UINT size, K *k)
+{
+	void *tmp;
+	int ret;
+	// 引数チェック
+	if (src == NULL || size == 0 || k == NULL)
+	{
+		return false;
+	}
+
+	tmp = ZeroMalloc(size);
+	Lock(openssl_lock);
+	{
+		ret = RSA_private_decrypt(size, src, tmp, k->pkey->pkey.rsa, RSA_NO_PADDING);
+	}
+	Unlock(openssl_lock);
+	if (ret <= 0)
+	{
+		return false;
+	}
+
+	Copy(dst, tmp, size);
+	Free(tmp);
+
+	return true;
+}
+
+// RSA 公開鍵による暗号化
+bool RsaPublicEncrypt(void *dst, void *src, UINT size, K *k)
+{
+	void *tmp;
+	int ret;
+	// 引数チェック
+	if (src == NULL || size == 0 || k == NULL)
+	{
+		return false;
+	}
+
+	tmp = ZeroMalloc(size);
+	Lock(openssl_lock);
+	{
+		ret = RSA_public_encrypt(size, src, tmp, k->pkey->pkey.rsa, RSA_NO_PADDING);
+	}
+	Unlock(openssl_lock);
+	if (ret <= 0)
+	{
+		return false;
+	}
+
+	Copy(dst, tmp, size);
+	Free(tmp);
+
+	return true;
+}
+
+// RSA 動作環境チェック
+bool RsaCheckEx()
+{
+	UINT num = 20;
+	UINT i;
+
+	for (i = 0;i < num;i++)
+	{
+		if (RsaCheck())
+		{
+			return true;
+		}
+
+		SleepThread(100);
+	}
+
+	return false;
+}
+bool RsaCheck()
+{
+	RSA *rsa;
+	K *priv_key, *pub_key;
+	BIO *bio;
+	char errbuf[MAX_SIZE];
+	UINT size = 0;
+	UINT bit = 32;
+	// 引数チェック
+
+	// 鍵生成
+	Lock(openssl_lock);
+	{
+		rsa = RSA_generate_key(bit, RSA_F4, NULL, NULL);
+	}
+	Unlock(openssl_lock);
+	if (rsa == NULL)
+	{
+		Debug("RSA_generate_key: err=%s\n", ERR_error_string(ERR_get_error(), errbuf));
+		return false;
+	}
+
+	// 秘密鍵
+	bio = NewBio();
+	Lock(openssl_lock);
+	{
+		i2d_RSAPrivateKey_bio(bio, rsa);
+	}
+	Unlock(openssl_lock);
+	BIO_seek(bio, 0);
+	priv_key = BioToK(bio, true, false, NULL);
+	FreeBio(bio);
+
+	// 公開鍵
+	bio = NewBio();
+	Lock(openssl_lock);
+	{
+		i2d_RSA_PUBKEY_bio(bio, rsa);
+	}
+	Unlock(openssl_lock);
+	BIO_seek(bio, 0);
+	pub_key = BioToK(bio, false, false, NULL);
+	FreeBio(bio);
+
+	RSA_free(rsa);
+
+	size = RsaPublicSize(pub_key);
+
+	if (size != ((bit + 7) / 8))
+	{
+		FreeK(priv_key);
+		FreeK(pub_key);
+
+		return false;
+	}
+
+	FreeK(priv_key);
+	FreeK(pub_key);
+
+	return true;
+}
+
+// RSA 鍵の生成
+bool RsaGen(K **priv, K **pub, UINT bit)
+{
+	RSA *rsa;
+	K *priv_key, *pub_key;
+	BIO *bio;
+	char errbuf[MAX_SIZE];
+	UINT size = 0;
+	// 引数チェック
+	if (priv == NULL || pub == NULL)
+	{
+		return false;
+	}
+	if (bit == 0)
+	{
+		bit = 1024;
+	}
+
+	// 鍵生成
+	Lock(openssl_lock);
+	{
+		rsa = RSA_generate_key(bit, RSA_F4, NULL, NULL);
+	}
+	Unlock(openssl_lock);
+	if (rsa == NULL)
+	{
+		Debug("RSA_generate_key: err=%s\n", ERR_error_string(ERR_get_error(), errbuf));
+		return false;
+	}
+
+	// 秘密鍵
+	bio = NewBio();
+	Lock(openssl_lock);
+	{
+		i2d_RSAPrivateKey_bio(bio, rsa);
+	}
+	Unlock(openssl_lock);
+	BIO_seek(bio, 0);
+	priv_key = BioToK(bio, true, false, NULL);
+	FreeBio(bio);
+
+	// 公開鍵
+	bio = NewBio();
+	Lock(openssl_lock);
+	{
+		i2d_RSA_PUBKEY_bio(bio, rsa);
+	}
+	Unlock(openssl_lock);
+	BIO_seek(bio, 0);
+	pub_key = BioToK(bio, false, false, NULL);
+	FreeBio(bio);
+
+	*priv = priv_key;
+	*pub = pub_key;
+
+	RSA_free(rsa);
+
+	size = RsaPublicSize(*pub);
+
+	if (size != ((bit + 7) / 8))
+	{
+		FreeK(*priv);
+		FreeK(*pub);
+
+		return RsaGen(priv, pub, bit);
+	}
+
+	return true;
+}
+
+// 証明書 X が証明書 x_issuer の発行者によって署名されているかどうか確認する
+bool CheckX(X *x, X *x_issuer)
+{
+	K *k;
+	bool ret;
+	// 引数チェック
+	if (x == NULL || x_issuer == NULL)
+	{
+		return false;
+	}
+
+	k = GetKFromX(x_issuer);
+	if (k == NULL)
+	{
+		return false;
+	}
+
+	ret = CheckSignature(x, k);
+	FreeK(k);
+
+	return ret;
+}
+
+// 証明書 X の署名を公開鍵 K で確認する
+bool CheckSignature(X *x, K *k)
+{
+	// 引数チェック
+	if (x == NULL || k == NULL)
+	{
+		return false;
+	}
+
+	Lock(openssl_lock);
+	{
+		if (X509_verify(x->x509, k->pkey) == 0)
+		{
+			Unlock(openssl_lock);
+			return false;
+		}
+	}
+	Unlock(openssl_lock);
+	return true;
+}
+
+// 証明書から公開鍵を取得する
+K *GetKFromX(X *x)
+{
+	EVP_PKEY *pkey;
+	K *k;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return NULL;
+	}
+
+	Lock(openssl_lock);
+	{
+		pkey = X509_get_pubkey(x->x509);
+	}
+	Unlock(openssl_lock);
+	if (pkey == NULL)
+	{
+		return NULL;
+	}
+
+	k = ZeroMalloc(sizeof(K));
+	k->pkey = pkey;
+
+	return k;
+}
+
+// 名前の比較
+bool CompareName(NAME *n1, NAME *n2)
+{
+	// 引数チェック
+	if (n1 == NULL || n2 == NULL)
+	{
+		return false;
+	}
+
+	// 名前比較
+	if (UniStrCmpi(n1->CommonName, n2->CommonName) == 0 &&
+		UniStrCmpi(n1->Organization, n2->Organization) == 0 &&
+		UniStrCmpi(n1->Unit, n2->Unit) == 0 &&
+		UniStrCmpi(n1->Country, n2->Country) == 0 &&
+		UniStrCmpi(n1->State, n2->State) == 0 &&
+		UniStrCmpi(n1->Local, n2->Local) == 0)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// X の名前の解放
+void FreeXNames(X *x)
+{
+	// 引数チェック
+	if (x == NULL)
+	{
+		return;
+	}
+
+	FreeName(x->issuer_name);
+	x->issuer_name = NULL;
+
+	FreeName(x->subject_name);
+	x->subject_name = NULL;
+}
+
+// 名前の解放
+void FreeName(NAME *n)
+{
+	// 引数チェック
+	if (n == NULL)
+	{
+		return;
+	}
+
+	// 文字列を解放
+	Free(n->CommonName);
+	Free(n->Organization);
+	Free(n->Unit);
+	Free(n->Country);
+	Free(n->State);
+	Free(n->Local);
+
+	// オブジェクトを解放
+	Free(n);
+
+	return;
+}
+
+// 証明書の名前を取得する
+void LoadXNames(X *x)
+{
+	X509 *x509;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return;
+	}
+
+	x509 = x->x509;
+	x->issuer_name = X509NameToName(X509_get_issuer_name(x509));
+	x->subject_name = X509NameToName(X509_get_subject_name(x509));
+}
+
+// X509_NAME 構造体を NAME 構造体に変換
+NAME *X509NameToName(void *xn)
+{
+	NAME *n;
+	// 引数チェック
+	if (xn == NULL)
+	{
+		return NULL;
+	}
+
+	n = ZeroMalloc(sizeof(NAME));
+
+	// 文字列を順番に取得する
+	n->CommonName = GetUniStrFromX509Name(xn, NID_commonName);
+	n->Organization = GetUniStrFromX509Name(xn, NID_organizationName);
+	n->Unit = GetUniStrFromX509Name(xn, NID_organizationalUnitName);
+	n->Country = GetUniStrFromX509Name(xn, NID_countryName);
+	n->State = GetUniStrFromX509Name(xn, NID_stateOrProvinceName);
+	n->Local = GetUniStrFromX509Name(xn, NID_localityName);
+
+	return n;
+}
+
+// X509_NAME 構造体の中から Unicode 文字列を読み込む
+wchar_t *GetUniStrFromX509Name(void *xn, int nid)
+{
+	UCHAR txt[1024];
+	bool b = false;
+	UINT i, size;
+	int index;
+	bool unicode = false;
+	bool is_utf_8 = false;
+	ASN1_OBJECT *obj;
+	ASN1_STRING *data;
+	// 引数チェック
+	if (xn == NULL || nid == 0)
+	{
+		return NULL;
+	}
+
+	Zero(txt, sizeof(txt));
+	if (X509_NAME_get_text_by_NID(xn, nid, (char *)txt, sizeof(txt) - 2) <= 0)
+	{
+		return NULL;
+	}
+
+	obj = OBJ_nid2obj(nid);
+	if (obj == NULL)
+	{
+		return NULL;
+	}
+	index = X509_NAME_get_index_by_OBJ(xn, obj, -1);
+	if (index < 0)
+	{
+		return NULL;
+	}
+	data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(xn, index));
+	if (data == NULL)
+	{
+		return NULL;
+	}
+	if (data->type == V_ASN1_BMPSTRING)
+	{
+		unicode = true;
+	}
+	if (data->type == V_ASN1_UTF8STRING || data->type == V_ASN1_T61STRING)
+	{
+		is_utf_8 = true;
+	}
+
+	size = UniStrLen((wchar_t *)txt) * 4 + 8;
+	for (i = 0;i < size;i++)
+	{
+		if (txt[i] >= 0x80)
+		{
+			unicode = true;
+			break;
+		}
+	}
+
+	if (is_utf_8)
+	{
+		wchar_t *ret;
+		UINT ret_size;
+
+		ret_size = CalcUtf8ToUni(txt, StrLen(txt));
+		ret = ZeroMalloc(ret_size + 8);
+		Utf8ToUni(ret, ret_size, txt, StrLen(txt));
+
+		return ret;
+	}
+	else if (unicode == false)
+	{
+		wchar_t tmp[1024];
+		StrToUni(tmp, sizeof(tmp), (char *)txt);
+		return CopyUniStr(tmp);
+	}
+	else
+	{
+		EndianUnicode((wchar_t *)txt);
+		return CopyUniStr((wchar_t *)txt);
+	}
+}
+
+// 証明書 x1 と x2 が等しいかどうかチェックする
+bool CompareX(X *x1, X *x2)
+{
+	// 引数チェック
+	if (x1 == NULL || x2 == NULL)
+	{
+		return false;
+	}
+
+	Lock(openssl_lock);
+	if (X509_cmp(x1->x509, x2->x509) == 0)
+	{
+		Unlock(openssl_lock);
+		return true;
+	}
+	else
+	{
+		Unlock(openssl_lock);
+		return false;
+	}
+}
+
+// K が X の秘密鍵かどうかチェックする
+bool CheckXandK(X *x, K *k)
+{
+	// 引数チェック
+	if (x == NULL || k == NULL)
+	{
+		return false;
+	}
+
+	Lock(openssl_lock);
+	if (X509_check_private_key(x->x509, k->pkey) != 0)
+	{
+		Unlock(openssl_lock);
+		return true;
+	}
+	else
+	{
+		Unlock(openssl_lock);
+		return false;
+	}
+}
+
+// ファイルから X を読み込む
+X *FileToX(char *filename)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	X *ret = FileToXW(filename_w);
+
+	Free(filename_w);
+
+	return ret;
+}
+X *FileToXW(wchar_t *filename)
+{
+	bool text;
+	BUF *b;
+	X *x;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	b = ReadDumpW(filename);
+	text = IsBase64(b);
+
+	x = BufToX(b, text);
+	FreeBuf(b);
+
+	return x;
+}
+
+// X をファイルに書き出す
+bool XToFile(X *x, char *filename, bool text)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	bool ret = XToFileW(x, filename_w, text);
+
+	Free(filename_w);
+
+	return ret;
+}
+bool XToFileW(X *x, wchar_t *filename, bool text)
+{
+	BUF *b;
+	bool ret;
+	// 引数チェック
+	if (x == NULL || filename == NULL)
+	{
+		return false;
+	}
+
+	b = XToBuf(x, text);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	ret = DumpBufW(b, filename);
+	FreeBuf(b);
+
+	return ret;
+}
+
+// ファイルから K を読み込む
+K *FileToK(char *filename, bool private_key, char *password)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	K *ret;
+
+	ret = FileToKW(filename_w, private_key, password);
+
+	Free(filename_w);
+
+	return ret;
+}
+K *FileToKW(wchar_t *filename, bool private_key, char *password)
+{
+	bool text;
+	BUF *b;
+	K *k;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	b = ReadDumpW(filename);
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	text = IsBase64(b);
+	if (text == false)
+	{
+		k = BufToK(b, private_key, false, NULL);
+	}
+	else
+	{
+		k = BufToK(b, private_key, true, NULL);
+		if (k == NULL)
+		{
+			k = BufToK(b, private_key, true, password);
+		}
+	}
+
+	FreeBuf(b);
+
+	return k;
+}
+
+// K をファイルに保存する
+bool KToFile(K *k, char *filename, bool text, char *password)
+{
+	wchar_t *filename_w = CopyStrToUni(filename);
+	bool ret = KToFileW(k, filename_w, text, password);
+
+	Free(filename_w);
+
+	return ret;
+}
+bool KToFileW(K *k, wchar_t *filename, bool text, char *password)
+{
+	BUF *b;
+	bool ret;
+	// 引数チェック
+	if (k == NULL || filename == NULL)
+	{
+		return false;
+	}
+
+	b = KToBuf(k, text, password);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	ret = DumpBufW(b, filename);
+	FreeBuf(b);
+
+	return ret;
+}
+
+// K を BUF に変換する
+BUF *KToBuf(K *k, bool text, char *password)
+{
+	BUF *buf;
+	BIO *bio;
+	// 引数チェック
+	if (k == NULL)
+	{
+		return NULL;
+	}
+
+	bio = KToBio(k, text, password);
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	buf = BioToBuf(bio);
+	FreeBio(bio);
+
+	SeekBuf(buf, 0, 0);
+
+	return buf;
+}
+
+// K を BIO に変換する
+BIO *KToBio(K *k, bool text, char *password)
+{
+	BIO *bio;
+	// 引数チェック
+	if (k == NULL)
+	{
+		return NULL;
+	}
+
+	bio = NewBio();
+
+	if (k->private_key)
+	{
+		// 秘密鍵
+		if (text == false)
+		{
+			// バイナリ形式
+			Lock(openssl_lock);
+			{
+				i2d_PrivateKey_bio(bio, k->pkey);
+			}
+			Unlock(openssl_lock);
+		}
+		else
+		{
+			// テキスト形式
+			if (password == 0 || StrLen(password) == 0)
+			{
+				// 暗号化無し
+				Lock(openssl_lock);
+				{
+					PEM_write_bio_PrivateKey(bio, k->pkey, NULL, NULL, 0, NULL, NULL);
+				}
+				Unlock(openssl_lock);
+			}
+			else
+			{
+				// 暗号化する
+				CB_PARAM cb;
+				cb.password = password;
+				Lock(openssl_lock);
+				{
+					PEM_write_bio_PrivateKey(bio, k->pkey, EVP_des_ede3_cbc(),
+						NULL, 0, (pem_password_cb *)PKeyPasswordCallbackFunction, &cb);
+				}
+				Unlock(openssl_lock);
+			}
+		}
+	}
+	else
+	{
+		// 公開鍵
+		if (text == false)
+		{
+			// バイナリ形式
+			Lock(openssl_lock);
+			{
+				i2d_PUBKEY_bio(bio, k->pkey);
+			}
+			Unlock(openssl_lock);
+		}
+		else
+		{
+			// テキスト形式
+			Lock(openssl_lock);
+			{
+				PEM_write_bio_PUBKEY(bio, k->pkey);
+			}
+			Unlock(openssl_lock);
+		}
+	}
+
+	return bio;
+}
+
+// BUF が Base64 エンコードされているかどうか調べる
+bool IsBase64(BUF *b)
+{
+	UINT i;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < b->Size;i++)
+	{
+		char c = ((char *)b->Buf)[i];
+		bool b = false;
+		if ('a' <= c && c <= 'z')
+		{
+			b = true;
+		}
+		else if ('A' <= c && c <= 'Z')
+		{
+			b = true;
+		}
+		else if ('0' <= c && c <= '9')
+		{
+			b = true;
+		}
+		else if (c == ':' || c == '.' || c == ';' || c == ',')
+		{
+			b = true;
+		}
+		else if (c == '!' || c == '&' || c == '#' || c == '(' || c == ')')
+		{
+			b = true;
+		}
+		else if (c == '-' || c == ' ')
+		{
+			b = true;
+		}
+		else if (c == 13 || c == 10 || c == EOF)
+		{
+			b = true;
+		}
+		else if (c == '\t' || c == '=' || c == '+' || c == '/')
+		{
+			b = true;
+		}
+		if (b == false)
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+// BUF に含まれている K が暗号化されているかどうか調べる
+bool IsEncryptedK(BUF *b, bool private_key)
+{
+	K *k;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return false;
+	}
+	if (IsBase64(b) == false)
+	{
+		return false;
+	}
+
+	k = BufToK(b, private_key, true, NULL);
+	if (k != NULL)
+	{
+		FreeK(k);
+		return false;
+	}
+
+	return true;
+}
+
+// BUF を K に変換
+K *BufToK(BUF *b, bool private_key, bool text, char *password)
+{
+	BIO *bio;
+	K *k;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	bio = BufToBio(b);
+	k = BioToK(bio, private_key, text, password);
+	FreeBio(bio);
+
+	return k;
+}
+
+// K を解放
+void FreeK(K *k)
+{
+	// 引数チェック
+	if (k == NULL)
+	{
+		return;
+	}
+
+	FreePKey(k->pkey);
+	Free(k);
+}
+
+// 秘密鍵を解放
+void FreePKey(EVP_PKEY *pkey)
+{
+	// 引数チェック
+	if (pkey == NULL)
+	{
+		return;
+	}
+
+	EVP_PKEY_free(pkey);
+}
+
+// BIO を K に変換する
+K *BioToK(BIO *bio, bool private_key, bool text, char *password)
+{
+	EVP_PKEY *pkey;
+	K *k;
+	// 引数チェック
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	if (password != NULL && StrLen(password) == 0)
+	{
+		password = NULL;
+	}
+
+	if (private_key == false)
+	{
+		// 公開鍵
+		if (text == false)
+		{
+			// バイナリ形式
+			pkey = d2i_PUBKEY_bio(bio, NULL);
+			if (pkey == NULL)
+			{
+				return NULL;
+			}
+		}
+		else
+		{
+			// テキスト形式
+			CB_PARAM cb;
+			cb.password = password;
+			Lock(openssl_lock);
+			{
+				pkey = PEM_read_bio_PUBKEY(bio, NULL, (pem_password_cb *)PKeyPasswordCallbackFunction, &cb);
+			}
+			Unlock(openssl_lock);
+			if (pkey == NULL)
+			{
+				return NULL;
+			}
+		}
+	}
+	else
+	{
+		if (text == false)
+		{
+			// バイナリ形式
+			Lock(openssl_lock);
+			{
+				pkey = d2i_PrivateKey_bio(bio, NULL);
+			}
+			Unlock(openssl_lock);
+			if (pkey == NULL)
+			{
+				return NULL;
+			}
+		}
+		else
+		{
+			// テキスト形式
+			CB_PARAM cb;
+			cb.password = password;
+			Lock(openssl_lock);
+			{
+				pkey = PEM_read_bio_PrivateKey(bio, NULL, (pem_password_cb *)PKeyPasswordCallbackFunction, &cb);
+			}
+			Unlock(openssl_lock);
+			if (pkey == NULL)
+			{
+				return NULL;
+			}
+		}
+	}
+
+	k = ZeroMalloc(sizeof(K));
+	k->pkey = pkey;
+	k->private_key = private_key;
+
+	return k;
+}
+
+// パスワードコールバック関数
+int PKeyPasswordCallbackFunction(char *buf, int bufsize, int verify, void *param)
+{
+	CB_PARAM *cb;
+	// 引数チェック
+	if (buf == NULL || param == NULL || bufsize == 0)
+	{
+		return 0;
+	}
+
+	cb = (CB_PARAM *)param;
+	if (cb->password == NULL)
+	{
+		return 0;
+	}
+
+	return StrCpy(buf, bufsize, cb->password);
+}
+
+// X を BUF に変換する
+BUF *XToBuf(X *x, bool text)
+{
+	BIO *bio;
+	BUF *b;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return NULL;
+	}
+
+	bio = XToBio(x, text);
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	b = BioToBuf(bio);
+	FreeBio(bio);
+
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// X を BIO に変換する
+BIO *XToBio(X *x, bool text)
+{
+	BIO *bio;
+	// 引数チェック
+	if (x == NULL)
+	{
+		return NULL;
+	}
+
+	bio = NewBio();
+
+	Lock(openssl_lock);
+	{
+		if (text == false)
+		{
+			// バイナリ形式
+			i2d_X509_bio(bio, x->x509);
+		}
+		else
+		{
+			// テキスト形式
+			PEM_write_bio_X509(bio, x->x509);
+		}
+	}
+	Unlock(openssl_lock);
+
+	return bio;
+}
+
+// X の解放
+void FreeX(X *x)
+{
+	// 引数チェック
+	if (x == NULL)
+	{
+		return;
+	}
+
+	// 名前解放
+	FreeXNames(x);
+
+
+	// シリアル解放
+	FreeXSerial(x->serial);
+
+	if (x->do_not_free == false)
+	{
+		FreeX509(x->x509);
+	}
+	Free(x);
+}
+
+// X509 の解放
+void FreeX509(X509 *x509)
+{
+	// 引数チェック
+	if (x509 == NULL)
+	{
+		return;
+	}
+
+	Lock(openssl_lock);
+	{
+		X509_free(x509);
+	}
+	Unlock(openssl_lock);
+}
+
+// BUF を X に変換する
+X *BufToX(BUF *b, bool text)
+{
+	X *x;
+	BIO *bio;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	bio = BufToBio(b);
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	x = BioToX(bio, text);
+
+	FreeBio(bio);
+
+	return x;
+}
+
+// X のダイジェストを取得する
+void GetXDigest(X *x, UCHAR *buf, bool sha1)
+{
+	// 引数チェック
+	if (x == NULL)
+	{
+		return;
+	}
+
+	if (sha1 == false)
+	{
+		UINT size = MD5_SIZE;
+		X509_digest(x->x509, EVP_md5(), buf, (unsigned int *)&size);
+	}
+	else
+	{
+		UINT size = SHA1_SIZE;
+		X509_digest(x->x509, EVP_sha1(), buf, (unsigned int *)&size);
+	}
+}
+
+// BIO を X に変換する
+X *BioToX(BIO *bio, bool text)
+{
+	X *x;
+	X509 *x509;
+	// 引数チェック
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	Lock(openssl_lock);
+	{
+		// x509 の読み込み
+		if (text == false)
+		{
+			// バイナリモード
+			x509 = d2i_X509_bio(bio, NULL);
+		}
+		else
+		{
+			// テキストモード
+			x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+		}
+	}
+	Unlock(openssl_lock);
+
+	if (x509 == NULL)
+	{
+		return NULL;
+	}
+
+	x = X509ToX(x509);
+
+	if (x == NULL)
+	{
+		return NULL;
+	}
+
+	return x;
+}
+
+// X509 を X に変換する
+X *X509ToX(X509 *x509)
+{
+	X *x;
+	K *k;
+	BUF *b;
+	UINT size;
+	UINT type;
+	// 引数チェック
+	if (x509 == NULL)
+	{
+		return NULL;
+	}
+
+	x = ZeroMalloc(sizeof(X));
+	x->x509 = x509;
+
+	// 名前
+	LoadXNames(x);
+
+	// 有効期限
+	LoadXDates(x);
+
+	// ルート証明書かどうかチェックする
+	if (CompareName(x->issuer_name, x->subject_name))
+	{
+		K *pubkey = GetKFromX(x);
+		if (pubkey != NULL)
+		{
+			if (CheckXandK(x, pubkey))
+			{
+				x->root_cert = true;
+			}
+			FreeK(pubkey);
+		}
+	}
+
+	// シリアル番号の取得
+	x->serial = NewXSerial(x509->cert_info->serialNumber->data,
+		x509->cert_info->serialNumber->length);
+	if (x->serial == NULL)
+	{
+		char zero = 0;
+		x->serial = NewXSerial(&zero, sizeof(char));
+	}
+
+	k = GetKFromX(x);
+	if (k == NULL)
+	{
+		FreeX(x);
+		return NULL;
+	}
+
+	b = KToBuf(k, false, NULL);
+
+	size = b->Size;
+	type = k->pkey->type;
+
+	FreeBuf(b);
+
+	FreeK(k);
+
+	if (type == EVP_PKEY_RSA)
+	{
+		x->is_compatible_bit = true;
+
+		switch (size)
+		{
+		case 162:
+			x->bits = 1024;
+			break;
+
+		case 226:
+			x->bits = 1536;
+			break;
+
+		case 294:
+			x->bits = 2048;
+			break;
+
+		case 442:
+			x->bits = 3072;
+			break;
+
+		case 550:
+			x->bits = 4096;
+			break;
+
+		default:
+			x->is_compatible_bit = false;
+			break;
+		}
+	}
+
+	return x;
+}
+
+// BIO を作成する
+BIO *NewBio()
+{
+	return BIO_new(BIO_s_mem());
+}
+
+// BIO を解放する
+void FreeBio(BIO *bio)
+{
+	// 引数チェック
+	if (bio == NULL)
+	{
+		return;
+	}
+
+	BIO_free(bio);
+}
+
+// BIO を BUF に変換する
+BUF *BioToBuf(BIO *bio)
+{
+	BUF *b;
+	UINT size;
+	void *tmp;
+	// 引数チェック
+	if (bio == NULL)
+	{
+		return NULL;
+	}
+
+	BIO_seek(bio, 0);
+	size = bio->num_write;
+	tmp = Malloc(size);
+	BIO_read(bio, tmp, size);
+
+	b = NewBuf();
+	WriteBuf(b, tmp, size);
+	Free(tmp);
+
+	return b;
+}
+
+// BUF を BIO に変換する
+BIO *BufToBio(BUF *b)
+{
+	BIO *bio;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	Lock(openssl_lock);
+	{
+		bio = BIO_new(BIO_s_mem());
+		if (bio == NULL)
+		{
+			Unlock(openssl_lock);
+			return NULL;
+		}
+		BIO_write(bio, b->Buf, b->Size);
+		BIO_seek(bio, 0);
+	}
+	Unlock(openssl_lock);
+
+	return bio;
+}
+
+// 128bit 乱数生成
+void Rand128(void *buf)
+{
+	Rand(buf, 16);
+}
+
+// 64bit 乱数生成
+UINT64 Rand64()
+{
+	UINT64 i;
+	Rand(&i, sizeof(i));
+	return i;
+}
+
+// 32bit 乱数生成
+UINT Rand32()
+{
+	UINT i;
+	Rand(&i, sizeof(i));
+	return i;
+}
+
+// 16bit 乱数生成
+USHORT Rand16()
+{
+	USHORT i;
+	Rand(&i, sizeof(i));
+	return i;
+}
+
+// 8bit 乱数生成
+UCHAR Rand8()
+{
+	UCHAR i;
+	Rand(&i, sizeof(i));
+	return i;
+}
+
+// 1bit 乱数生成
+bool Rand1()
+{
+	return (Rand32() % 2) == 0 ? false : true;
+}
+
+// 乱数生成
+void Rand(void *buf, UINT size)
+{
+	// 引数チェック
+	if (buf == NULL || size == 0)
+	{
+		return;
+	}
+	RAND_bytes(buf, size);
+}
+
+// OpenSSL が確保しているスレッド固有情報を削除する
+void FreeOpenSSLThreadState()
+{
+	ERR_remove_state(0);
+}
+
+// 暗号化ライブラリの解放
+void FreeCryptLibrary()
+{
+	openssl_inited = false;
+
+	DeleteLock(openssl_lock);
+	openssl_lock = NULL;
+//	RAND_Free_For_SoftEther();
+	OpenSSL_FreeLock();
+}
+
+// 暗号化ライブラリの初期化
+void InitCryptLibrary()
+{
+	char tmp[16];
+//	RAND_Init_For_SoftEther()
+	openssl_lock = NewLock();
+	SSL_library_init();
+	//OpenSSL_add_all_algorithms();
+	OpenSSL_add_all_ciphers();
+	SSLeay_add_all_digests();
+	ERR_load_crypto_strings();
+	SSL_load_error_strings();
+
+#ifdef	OS_UNIX
+	{
+		char *name1 = "/dev/random";
+		char *name2 = "/dev/urandom";
+		IO *o;
+		o = FileOpen(name1, false);
+		if (o == NULL)
+		{
+			o = FileOpen(name2, false);
+			if (o == NULL)
+			{
+				UINT64 now = SystemTime64();
+				BUF *b;
+				UINT i;
+				b = NewBuf();
+				for (i = 0;i < 4096;i++)
+				{
+					UCHAR c = rand() % 256;
+					WriteBuf(b, &c, 1);
+				}
+				WriteBuf(b, &now, sizeof(now));
+				RAND_seed(b->Buf, b->Size);
+				FreeBuf(b);
+			}
+			else
+			{
+				FileClose(o);
+			}
+		}
+		else
+		{
+			FileClose(o);
+		}
+	}
+#endif	// OS_UNIX
+
+	RAND_poll();
+
+#ifdef	OS_WIN32
+//	RAND_screen();
+#endif
+	Rand(tmp, sizeof(tmp));
+	OpenSSL_InitLock();
+
+	openssl_inited = true;
+}
+
+// 内部ハッシュ関数
+void InternalHash(void *dst, void *src, UINT size, bool sha1)
+{
+	// 引数チェック
+	if (dst == NULL || (src == NULL && size != 0))
+	{
+		return;
+	}
+
+	if (sha1 == false)
+	{
+		// MD5 ハッシュ
+		MD5(src, size, dst);
+	}
+	else
+	{
+		// SHA ハッシュ
+		SHA(src, size, dst);
+	}
+}
+
+// SHA-1 専用ハッシュ関数
+void HashSha1(void *dst, void *src, UINT size)
+{
+	SHA1(src, size, dst);
+}
+
+// ハッシュ関数
+void Hash(void *dst, void *src, UINT size, bool sha1)
+{
+	InternalHash(dst, src, size, sha1);
+}
+
+// 新しい CRYPT オブジェクトの作成
+CRYPT *NewCrypt(void *key, UINT size)
+{
+	CRYPT *c = ZeroMalloc(sizeof(CRYPT));
+
+	SetKey(c, key, size);
+
+	return c;
+}
+
+// CRYPT オブジェクトの解放
+void FreeCrypt(CRYPT *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	// メモリ解放
+	Free(c);
+}
+
+// 暗号化と解読
+void InternalEncrypt(CRYPT *c, void *dst, void *src, UINT size)
+{
+	UINT x, y, sx, sy;
+	UINT *state;
+	UCHAR *endsrc;
+	UCHAR *s = (UCHAR *)src;
+	UCHAR *d = (UCHAR *)dst;
+	// 引数チェック
+	if (c == NULL || dst == NULL || src == NULL || size == 0)
+	{
+		return;
+	}
+
+	state = (UINT *)c->state;
+	x = c->x;
+	y = c->y;
+
+	for (endsrc = s + size;s != endsrc;s++, d++)
+	{
+		x = (x + 1) & 0xff;
+		sx = state[x];
+		y = (sx + y) & 0xff;
+		state[x] = sy = state[y];
+		state[y] = sx;
+		*d = *s ^ state[(sx + sy) & 0xff];
+	}
+	c->x = x;
+	c->y = y;
+}
+void Encrypt(CRYPT *c, void *dst, void *src, UINT size)
+{
+	InternalEncrypt(c, dst, src, size);
+}
+
+// 鍵の更新
+void SetKey(CRYPT *c, void *key, UINT size)
+{
+	UINT i, t, u, ki, si;
+	UINT *state;
+	UCHAR *k = (UCHAR *)key;
+	// 引数チェック
+	if (c == NULL || key == NULL)
+	{
+		return;
+	}
+
+	// 鍵のセット
+	state = (UINT *)c->state;
+	c->x = c->y = 0;
+	for (i = 0;i < 256;i++)
+	{
+		state[i] = i;
+	}
+	ki = si = 0;
+
+	for (i = 0;i < 256;i++)
+	{
+		t = state[i];
+		si = (si + k[ki] + t) & 0xff;
+		u = state[si];
+		state[si] = t;
+		state[i] = u;
+		if (++ki >= size)
+		{
+			ki = 0;
+		}
+	}
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Encrypt.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Encrypt.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Encrypt.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,320 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Encrypt.h
+// Encrypt.c のヘッダ
+
+#ifndef	ENCRYPT_H
+#define	ENCRYPT_H
+
+// OpenSSL の関数
+void RAND_Init_For_SoftEther();
+void RAND_Free_For_SoftEther();
+
+
+
+// 定数
+#define	MIN_SIGN_HASH_SIZE		(15 + SHA1_SIZE)
+#define	SIGN_HASH_SIZE			(MIN_SIGN_HASH_SIZE)
+
+// マクロ
+#define	HASHED_DATA(p)			(((UCHAR *)p) + 15)
+
+
+
+// 暗号化コンテキスト
+struct CRYPT
+{
+	int x, y;
+	int state[256];
+};
+
+// 証明書内の名前
+struct NAME
+{
+	wchar_t *CommonName;		// CN
+	wchar_t *Organization;		// O
+	wchar_t *Unit;				// OU
+	wchar_t *Country;			// C
+	wchar_t *State;				// ST
+	wchar_t *Local;				// L
+};
+
+// シリアル番号
+struct X_SERIAL
+{
+	UINT size;
+	UCHAR *data;
+};
+
+// 証明書
+struct X
+{
+	X509 *x509;
+	NAME *issuer_name;
+	NAME *subject_name;
+	bool root_cert;
+	UINT64 notBefore;
+	UINT64 notAfter;
+	X_SERIAL *serial;
+	bool do_not_free;
+	bool is_compatible_bit;
+	UINT bits;
+};
+
+// 鍵
+struct K
+{
+	EVP_PKEY *pkey;
+	bool private_key;
+};
+
+// PKCS#12
+struct P12
+{
+	PKCS12 *pkcs12;
+};
+
+// CEL
+struct X_CRL
+{
+	X509_CRL *Crl;
+};
+
+// 定数
+#define	MD5_SIZE	16
+#define	SHA1_SIZE	20
+
+// OpenSSL のロック
+extern LOCK **ssl_lock_obj;
+
+// 関数プロトタイプ
+CRYPT *NewCrypt(void *key, UINT size);
+void FreeCrypt(CRYPT *c);
+void SetKey(CRYPT *c, void *key, UINT size);
+void Encrypt(CRYPT *c, void *dst, void *src, UINT size);
+void InternalEncrypt(CRYPT *c, void *dst, void *src, UINT size);
+void Hash(void *dst, void *src, UINT size, bool sha1);
+void HashSha1(void *dst, void *src, UINT size);
+void InternalHash(void *dst, void *src, UINT size, bool sha1);
+void InitCryptLibrary();
+void Rand(void *buf, UINT size);
+void Rand128(void *buf);
+UINT64 Rand64();
+UINT Rand32();
+USHORT Rand16();
+UCHAR Rand8();
+bool Rand1();
+UINT HashPtrToUINT(void *p);
+
+void CertTest();
+BIO *BufToBio(BUF *b);
+BUF *BioToBuf(BIO *bio);
+BIO *NewBio();
+void FreeBio(BIO *bio);
+X *BioToX(BIO *bio, bool text);
+X *BufToX(BUF *b, bool text);
+void FreeX509(X509 *x509);
+void FreeX(X *x);
+BIO *XToBio(X *x, bool text);
+BUF *XToBuf(X *x, bool text);
+K *BioToK(BIO *bio, bool private_key, bool text, char *password);
+int PKeyPasswordCallbackFunction(char *buf, int bufsize, int verify, void *param);
+void FreePKey(EVP_PKEY *pkey);
+void FreeK(K *k);
+K *BufToK(BUF *b, bool private_key, bool text, char *password);
+bool IsEncryptedK(BUF *b, bool private_key);
+bool IsBase64(BUF *b);
+BIO *KToBio(K *k, bool text, char *password);
+BUF *KToBuf(K *k, bool text, char *password);
+X *FileToX(char *filename);
+X *FileToXW(wchar_t *filename);
+bool XToFile(X *x, char *filename, bool text);
+bool XToFileW(X *x, wchar_t *filename, bool text);
+K *FileToK(char *filename, bool private_key, char *password);
+K *FileToKW(wchar_t *filename, bool private_key, char *password);
+bool KToFile(K *k, char *filename, bool text, char *password);
+bool KToFileW(K *k, wchar_t *filename, bool text, char *password);
+bool CheckXandK(X *x, K *k);
+bool CompareX(X *x1, X *x2);
+NAME *X509NameToName(void *xn);
+wchar_t *GetUniStrFromX509Name(void *xn, int nid);
+void LoadXNames(X *x);
+void FreeXNames(X *x);
+void FreeName(NAME *n);
+bool CompareName(NAME *n1, NAME *n2);
+K *GetKFromX(X *x);
+bool CheckSignature(X *x, K *k);
+X *X509ToX(X509 *x509);
+bool CheckX(X *x, X *x_issuer);
+bool Asn1TimeToSystem(SYSTEMTIME *s, void *asn1_time);
+bool StrToSystem(SYSTEMTIME *s, char *str);
+UINT64 Asn1TimeToUINT64(void *asn1_time);
+bool SystemToAsn1Time(void *asn1_time, SYSTEMTIME *s);
+bool UINT64ToAsn1Time(void *asn1_time, UINT64 t);
+bool SystemToStr(char *str, UINT size, SYSTEMTIME *s);
+void LoadXDates(X *x);
+bool CheckXDate(X *x, UINT64 current_system_time);
+bool CheckXDateNow(X *x);
+NAME *NewName(wchar_t *common_name, wchar_t *organization, wchar_t *unit,
+			  wchar_t *country, wchar_t *state, wchar_t *local);
+void *NameToX509Name(NAME *nm);
+void FreeX509Name(void *xn);
+bool AddX509Name(void *xn, int nid, wchar_t *str);
+X509 *NewRootX509(K *pub, K *priv, NAME *name, UINT days, X_SERIAL *serial);
+X *NewRootX(K *pub, K *priv, NAME *name, UINT days, X_SERIAL *serial);
+X509 *NewX509(K *pub, K *priv, X *ca, NAME *name, UINT days, X_SERIAL *serial);
+X *NewX(K *pub, K *priv, X *ca, NAME *name, UINT days, X_SERIAL *serial);
+UINT GetDaysUntil2038();
+X_SERIAL *NewXSerial(void *data, UINT size);
+void FreeXSerial(X_SERIAL *serial);
+char *ByteToStr(BYTE *src, UINT src_size);
+P12 *BioToP12(BIO *bio);
+P12 *PKCS12ToP12(PKCS12 *pkcs12);
+P12 *BufToP12(BUF *b);
+BIO *P12ToBio(P12 *p12);
+BUF *P12ToBuf(P12 *p12);
+void FreePKCS12(PKCS12 *pkcs12);
+void FreeP12(P12 *p12);
+P12 *FileToP12(char *filename);
+P12 *FileToP12W(wchar_t *filename);
+bool P12ToFile(P12 *p12, char *filename);
+bool P12ToFileW(P12 *p12, wchar_t *filename);
+bool ParseP12(P12 *p12, X **x, K **k, char *password);
+bool IsEncryptedP12(P12 *p12);
+P12 *NewP12(X *x, K *k, char *password);
+X *CloneX(X *x);
+K *CloneK(K *k);
+void FreeCryptLibrary();
+void GetPrintNameFromX(wchar_t *str, UINT size, X *x);
+void GetPrintNameFromXA(char *str, UINT size, X *x);
+void GetPrintNameFromName(wchar_t *str, UINT size, NAME *name);
+void GetAllNameFromX(wchar_t *str, UINT size, X *x);
+void GetAllNameFromA(char *str, UINT size, X *x);
+void GetAllNameFromName(wchar_t *str, UINT size, NAME *name);
+void GetAllNameFromNameEx(wchar_t *str, UINT size, NAME *name);
+void GetAllNameFromXEx(wchar_t *str, UINT size, X *x);
+void GetAllNameFromXExA(char *str, UINT size, X *x);
+BUF *BigNumToBuf(BIGNUM *bn);
+BIGNUM *BinToBigNum(void *data, UINT size);
+BIGNUM *BufToBigNum(BUF *b);
+X_SERIAL *CloneXSerial(X_SERIAL *src);
+bool CompareXSerial(X_SERIAL *s1, X_SERIAL *s2);
+void GetXDigest(X *x, UCHAR *buf, bool sha1);
+NAME *CopyName(NAME *n);
+
+
+bool RsaGen(K **priv, K **pub, UINT bit);
+bool RsaCheck();
+bool RsaCheckEx();
+bool RsaPublicEncrypt(void *dst, void *src, UINT size, K *k);
+bool RsaPrivateDecrypt(void *dst, void *src, UINT size, K *k);
+bool RsaPrivateEncrypt(void *dst, void *src, UINT size, K *k);
+bool RsaPublicDecrypt(void *dst, void *src, UINT size, K *k);
+bool RsaSign(void *dst, void *src, UINT size, K *k);
+bool RsaSignEx(void *dst, void *src, UINT size, K *k, UINT bits);
+bool HashForSign(void *dst, UINT dst_size, void *src, UINT src_size);
+bool RsaVerify(void *data, UINT data_size, void *sign, K *k);
+bool RsaVerifyEx(void *data, UINT data_size, void *sign, K *k, UINT bits);
+UINT RsaPublicSize(K *k);
+void RsaPublicToBin(K *k, void *data);
+BUF *RsaPublicToBuf(K *k);
+K *RsaBinToPublic(void *data, UINT size);
+
+X_CRL *FileToXCrl(char *filename);
+X_CRL *FileToXCrlW(wchar_t *filename);
+X_CRL *BufToXCrl(BUF *b);
+void FreeXCrl(X_CRL *r);
+bool IsXRevokedByXCrl(X *x, X_CRL *r);
+bool IsXRevoked(X *x);
+
+
+
+void OpenSSL_InitLock();
+void OpenSSL_FreeLock();
+void OpenSSL_Lock(int mode, int n, const char *file, int line);
+unsigned long OpenSSL_Id(void);
+void FreeOpenSSLThreadState();
+
+#ifdef	ENCRYPT_C
+// 内部関数
+
+
+#endif	// ENCRYPT_C
+
+#endif	// ENCRYPT_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/FileIO.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/FileIO.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/FileIO.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2234 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// FileIO.c
+// ファイル入出力コード
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+static char exe_file_name[MAX_SIZE] = "/tmp/a.out";
+static wchar_t exe_file_name_w[MAX_SIZE] = L"/tmp/a.out";
+static LIST *hamcore = NULL;
+static IO *hamcore_io = NULL;
+
+
+// ファイルを保存する
+bool SaveFileW(wchar_t *name, void *data, UINT size)
+{
+	IO *io;
+	// 引数チェック
+	if (name == NULL || (data == NULL && size != 0))
+	{
+		return false;
+	}
+
+	io = FileCreateW(name);
+	if (io == NULL)
+	{
+		return false;
+	}
+
+	if (FileWrite(io, data, size) == false)
+	{
+		FileClose(io);
+		return false;
+	}
+
+	FileClose(io);
+
+	return true;
+}
+bool SaveFile(char *name, void *data, UINT size)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = SaveFileW(name_w, data, size);
+
+	Free(name_w);
+
+	return ret;
+}
+
+// ファイルが存在するかどうか確認する
+bool IsFile(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = IsFileW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool IsFileW(wchar_t *name)
+{
+	IO *io;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	io = FileOpenExW(name, false, false);
+	if (io == NULL)
+	{
+		return false;
+	}
+
+	FileClose(io);
+
+	return true;
+}
+
+// ファイルを置換してリネームする
+bool FileReplaceRename(char *old_name, char *new_name)
+{
+	wchar_t *old_name_w = CopyStrToUni(old_name);
+	wchar_t *new_name_w = CopyStrToUni(new_name);
+	bool ret = FileReplaceRenameW(old_name_w, new_name_w);
+
+	Free(old_name_w);
+	Free(new_name_w);
+
+	return ret;
+}
+bool FileReplaceRenameW(wchar_t *old_name, wchar_t *new_name)
+{
+	// 引数チェック
+	if (old_name == NULL || new_name == NULL)
+	{
+		return false;
+	}
+
+	if (FileCopyW(old_name, new_name) == false)
+	{
+		return false;
+	}
+
+	FileDeleteW(old_name);
+
+	return true;
+}
+
+// ファイル名を安全な名前にする
+void ConvertSafeFileName(char *dst, UINT size, char *src)
+{
+	UINT i;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	StrCpy(dst, size, src);
+	for (i = 0;i < StrLen(dst);i++)
+	{
+		if (IsSafeChar(dst[i]) == false)
+		{
+			dst[i] = '_';
+		}
+	}
+}
+void ConvertSafeFileNameW(wchar_t *dst, UINT size, wchar_t *src)
+{
+	UINT i;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	UniStrCpy(dst, size, src);
+	for (i = 0;i < UniStrLen(dst);i++)
+	{
+		if (UniIsSafeChar(dst[i]) == false)
+		{
+			dst[i] = L'_';
+		}
+	}
+}
+
+// ディスクの空き容量を取得する
+bool GetDiskFree(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
+{
+	bool ret;
+	// 引数チェック
+	if (path == NULL)
+	{
+		path = "./";
+	}
+
+#ifdef	OS_WIN32
+	ret = Win32GetDiskFree(path, free_size, used_size, total_size);
+#else	// OS_WIN32
+	ret = UnixGetDiskFree(path, free_size, used_size, total_size);
+#endif	// OS_WIN32
+
+	return ret;
+}
+bool GetDiskFreeW(wchar_t *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
+{
+	bool ret;
+	// 引数チェック
+	if (path == NULL)
+	{
+		path = L"./";
+	}
+
+#ifdef	OS_WIN32
+	ret = Win32GetDiskFreeW(path, free_size, used_size, total_size);
+#else	// OS_WIN32
+	ret = UnixGetDiskFreeW(path, free_size, used_size, total_size);
+#endif	// OS_WIN32
+
+	return ret;
+}
+
+// ディレクトリの列挙
+DIRLIST *EnumDirEx(char *dirname, COMPARE *compare)
+{
+	wchar_t *dirname_w = CopyStrToUni(dirname);
+	DIRLIST *ret = EnumDirExW(dirname_w, compare);
+
+	Free(dirname_w);
+
+	return ret;
+}
+DIRLIST *EnumDirExW(wchar_t *dirname, COMPARE *compare)
+{
+	DIRLIST *d = NULL;
+	// 引数チェック
+	if (dirname == NULL)
+	{
+		dirname = L"./";
+	}
+
+	if (compare == NULL)
+	{
+		compare = CompareDirListByName;
+	}
+
+#ifdef	OS_WIN32
+	d = Win32EnumDirExW(dirname, compare);
+#else	// OS_WIN32
+	d = UnixEnumDirExW(dirname, compare);
+#endif	// OS_WIN32
+
+	return d;
+}
+DIRLIST *EnumDir(char *dirname)
+{
+	return EnumDirEx(dirname, NULL);
+}
+DIRLIST *EnumDirW(wchar_t *dirname)
+{
+	return EnumDirExW(dirname, NULL);
+}
+
+// DIRLIST リストの比較
+int CompareDirListByName(void *p1, void *p2)
+{
+	DIRENT *d1, *d2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	d1 = *(DIRENT **)p1;
+	d2 = *(DIRENT **)p2;
+	if (d1 == NULL || d2 == NULL)
+	{
+		return 0;
+	}
+	return UniStrCmpi(d1->FileNameW, d2->FileNameW);
+}
+
+// ディレクトリ列挙の解放
+void FreeDir(DIRLIST *d)
+{
+	UINT i;
+	// 引数チェック
+	if (d == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < d->NumFiles;i++)
+	{
+		DIRENT *f = d->File[i];
+		Free(f->FileName);
+		Free(f->FileNameW);
+		Free(f);
+	}
+	Free(d->File);
+	Free(d);
+}
+
+
+// ファイル名を安全にする
+void UniSafeFileName(wchar_t *name)
+{
+	UINT i, len, dlen;
+	static wchar_t *danger_str = L"\\/:*?\"<>|";
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	dlen = UniStrLen(danger_str);
+	len = UniStrLen(name);
+
+	for (i = 0;i < len;i++)
+	{
+		wchar_t c = name[i];
+		UINT j;
+		for (j = 0;j < dlen;j++)
+		{
+			if (c == danger_str[j])
+			{
+				c = L'_';
+			}
+		}
+		name[i] = c;
+	}
+}
+void SafeFileNameW(wchar_t *name)
+{
+	UniSafeFileName(name);
+}
+
+// HamCore の読み込み
+BUF *ReadHamcoreW(wchar_t *filename)
+{
+	char *filename_a = CopyUniToStr(filename);
+	BUF *ret;
+
+	ret = ReadHamcore(filename_a);
+
+	Free(filename_a);
+
+	return ret;
+}
+BUF *ReadHamcore(char *name)
+{
+	wchar_t tmp[MAX_SIZE];
+	wchar_t exe_dir[MAX_SIZE];
+	BUF *b;
+	char filename[MAX_PATH];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	if (name[0] == '|')
+	{
+		name++;
+	}
+
+	if (name[0] == '/' || name[0] == '\\')
+	{
+		name++;
+	}
+
+	StrCpy(filename, sizeof(filename), name);
+
+	ReplaceStrEx(filename, sizeof(filename), filename, "/", "\\", true);
+
+	if (MayaquaIsMinimalMode())
+	{
+		return NULL;
+	}
+
+	// ローカルディスクの hamcore/ ディレクトリにファイルがあればそれを読み込む
+	GetExeDirW(exe_dir, sizeof(exe_dir));
+
+	UniFormat(tmp, sizeof(tmp), L"%s/%S/%S", exe_dir, HAMCORE_DIR_NAME, filename);
+
+	b = ReadDumpW(tmp);
+	if (b != NULL)
+	{
+		return b;
+	}
+
+	// 無い場合は HamCore ファイルシステムから探す
+	LockList(hamcore);
+	{
+		HC t, *c;
+		UINT i;
+
+		Zero(&t, sizeof(t));
+		t.FileName = filename;
+		c = Search(hamcore, &t);
+
+		if (c == NULL)
+		{
+			// ファイルが存在しない
+			b = NULL;
+		}
+		else
+		{
+			// ファイルが存在する
+			if (c->Buffer != NULL)
+			{
+				// 既に読み込まれている
+				b = NewBuf();
+				WriteBuf(b, c->Buffer, c->Size);
+				SeekBuf(b, 0, 0);
+				c->LastAccess = Tick64();
+			}
+			else
+			{
+				// 読み込まれていないのでファイルから読み込む
+				if (FileSeek(hamcore_io, 0, c->Offset) == false)
+				{
+					// シークに失敗した
+					b = NULL;
+				}
+				else
+				{
+					// 圧縮データを読み込む
+					void *data = Malloc(c->SizeCompressed);
+					if (FileRead(hamcore_io, data, c->SizeCompressed) == false)
+					{
+						// 読み込みに失敗した
+						Free(data);
+						b = NULL;
+					}
+					else
+					{
+						// 展開する
+						c->Buffer = ZeroMalloc(c->Size);
+						if (Uncompress(c->Buffer, c->Size, data, c->SizeCompressed) != c->Size)
+						{
+							// 展開に失敗した
+							Free(data);
+							Free(c->Buffer);
+							b = NULL;
+						}
+						else
+						{
+							// 成功した
+							Free(data);
+							b = NewBuf();
+							WriteBuf(b, c->Buffer, c->Size);
+							SeekBuf(b, 0, 0);
+							c->LastAccess = Tick64();
+						}
+					}
+				}
+			}
+		}
+
+		// 有効期限の切れたキャッシュを削除する
+		for (i = 0;i < LIST_NUM(hamcore);i++)
+		{
+			HC *c = LIST_DATA(hamcore, i);
+
+			if (c->Buffer != NULL)
+			{
+				if (((c->LastAccess + HAMCORE_CACHE_EXPIRES) <= Tick64()) ||
+					(StartWith(c->FileName, "Li")))
+				{
+					Free(c->Buffer);
+					c->Buffer = NULL;
+				}
+			}
+		}
+	}
+	UnlockList(hamcore);
+
+	return b;
+}
+
+// HamCore ファイルシステムの初期化
+void InitHamcore()
+{
+	wchar_t tmp[MAX_PATH];
+	wchar_t tmp2[MAX_PATH];
+	wchar_t exe_dir[MAX_PATH];
+	UINT i, num;
+	char header[HAMCORE_HEADER_SIZE];
+
+	hamcore = NewList(CompareHamcore);
+
+	if (MayaquaIsMinimalMode())
+	{
+		return;
+	}
+
+	GetExeDirW(exe_dir, sizeof(exe_dir));
+	UniFormat(tmp, sizeof(tmp), L"%s/%S", exe_dir, HAMCORE_FILE_NAME);
+
+	UniFormat(tmp2, sizeof(tmp2), L"%s/%S", exe_dir, HAMCORE_FILE_NAME_2);
+
+	// _hamcore.utvpn がある場合は hamcore.utvpn に上書きする
+	FileReplaceRenameW(tmp2, tmp);
+
+	// hamcore.utvpn ファイルがあれば読み込む
+	hamcore_io = FileOpenW(tmp, false);
+	if (hamcore_io == NULL)
+	{
+		// 無い場合は別の場所を探す
+#ifdef	OS_WIN32
+		UniFormat(tmp, sizeof(tmp), L"%S/%S", MsGetSystem32Dir(), HAMCORE_FILE_NAME);
+#else	// OS_WIN32
+		UniFormat(tmp, sizeof(tmp), L"/bin/%S", HAMCORE_FILE_NAME);
+#endif	// OS_WIN32
+
+		hamcore_io = FileOpenW(tmp, false);
+		if (hamcore_io == NULL)
+		{
+			return;
+		}
+	}
+
+	// ファイルヘッダを読み込む
+	Zero(header, sizeof(header));
+	FileRead(hamcore_io, header, HAMCORE_HEADER_SIZE);
+
+	if (Cmp(header, HAMCORE_HEADER_DATA, HAMCORE_HEADER_SIZE) != 0)
+	{
+		// ヘッダ不正
+		FileClose(hamcore_io);
+		hamcore_io = NULL;
+		return;
+	}
+
+	// ファイル個数
+	num = 0;
+	FileRead(hamcore_io, &num, sizeof(num));
+	num = Endian32(num);
+	for (i = 0;i < num;i++)
+	{
+		// ファイル名
+		char tmp[MAX_SIZE];
+		UINT str_size = 0;
+		HC *c;
+
+		FileRead(hamcore_io, &str_size, sizeof(str_size));
+		str_size = Endian32(str_size);
+		if (str_size >= 1)
+		{
+			str_size--;
+		}
+
+		Zero(tmp, sizeof(tmp));
+		FileRead(hamcore_io, tmp, str_size);
+
+		c = ZeroMalloc(sizeof(HC));
+		c->FileName = CopyStr(tmp);
+
+		FileRead(hamcore_io, &c->Size, sizeof(UINT));
+		c->Size = Endian32(c->Size);
+
+		FileRead(hamcore_io, &c->SizeCompressed, sizeof(UINT));
+		c->SizeCompressed = Endian32(c->SizeCompressed);
+
+		FileRead(hamcore_io, &c->Offset, sizeof(UINT));
+		c->Offset = Endian32(c->Offset);
+
+		Insert(hamcore, c);
+	}
+}
+
+// HamCore ファイルシステムの解放
+void FreeHamcore()
+{
+	UINT i;
+	for (i = 0;i < LIST_NUM(hamcore);i++)
+	{
+		HC *c = LIST_DATA(hamcore, i);
+		Free(c->FileName);
+		if (c->Buffer != NULL)
+		{
+			Free(c->Buffer);
+		}
+		Free(c);
+	}
+	ReleaseList(hamcore);
+
+	FileClose(hamcore_io);
+	hamcore_io = NULL;
+	hamcore = NULL;
+}
+
+// Hamcore のビルド
+void BuildHamcore()
+{
+	BUF *b;
+	char tmp[MAX_SIZE];
+	char exe_dir[MAX_SIZE];
+	char *s;
+	bool ok = true;
+	LIST *o;
+	UINT i;
+
+	GetExeDir(exe_dir, sizeof(exe_dir));
+	Format(tmp, sizeof(tmp), "%s/%s", exe_dir, HAMCORE_TEXT_NAME);
+
+	b = ReadDump(tmp);
+	if (b == NULL)
+	{
+		Print("Failed to open %s.\n", tmp);
+		return;
+	}
+
+	o = NewListFast(CompareHamcore);
+
+	while ((s = CfgReadNextLine(b)) != NULL)
+	{
+		char tmp[MAX_SIZE];
+		BUF *b;
+		Trim(s);
+
+		Format(tmp, sizeof(tmp), "%s/%s/%s", exe_dir, HAMCORE_DIR_NAME, s);
+
+		b = ReadDump(tmp);
+		if (b == NULL)
+		{
+			Print("Failed to open %s.\n", s);
+			ok = false;
+		}
+		else
+		{
+			HC *c = ZeroMalloc(sizeof(HC));
+			UINT tmp_size;
+			void *tmp;
+			c->FileName = CopyStr(s);
+			c->Size = b->Size;
+			tmp_size = CalcCompress(c->Size);
+			tmp = Malloc(tmp_size);
+			c->SizeCompressed = Compress(tmp, tmp_size, b->Buf, b->Size);
+			c->Buffer = tmp;
+			Insert(o, c);
+			Print("%s: %u -> %u\n", s, c->Size, c->SizeCompressed);
+			FreeBuf(b);
+		}
+
+		Free(s);
+	}
+
+	if (ok)
+	{
+		// 各ファイルのバッファのオフセットを計算する
+		UINT i, z;
+		char tmp[MAX_SIZE];
+		BUF *b;
+		z = 0;
+		z += HAMCORE_HEADER_SIZE;
+		// ファイルの個数
+		z += sizeof(UINT);
+		// まずファイルテーブル
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			HC *c = LIST_DATA(o, i);
+			// ファイル名
+			z += StrLen(c->FileName) + sizeof(UINT);
+			// ファイルサイズ
+			z += sizeof(UINT);
+			z += sizeof(UINT);
+			// オフセットデータ
+			z += sizeof(UINT);
+		}
+		// ファイル本体
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			HC *c = LIST_DATA(o, i);
+			// バッファ本体
+			c->Offset = z;
+			printf("%s: offset: %u\n", c->FileName, c->Offset);
+			z += c->SizeCompressed;
+		}
+		// 書き込み
+		b = NewBuf();
+		// ヘッダ
+		WriteBuf(b, HAMCORE_HEADER_DATA, HAMCORE_HEADER_SIZE);
+		WriteBufInt(b, LIST_NUM(o));
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			HC *c = LIST_DATA(o, i);
+			// ファイル名
+			WriteBufStr(b, c->FileName);
+			// ファイルサイズ
+			WriteBufInt(b, c->Size);
+			WriteBufInt(b, c->SizeCompressed);
+			// オフセット
+			WriteBufInt(b, c->Offset);
+		}
+		// 本体
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			HC *c = LIST_DATA(o, i);
+			WriteBuf(b, c->Buffer, c->SizeCompressed);
+		}
+		// 書き込み
+		Format(tmp, sizeof(tmp), "%s/%s", exe_dir, HAMCORE_FILE_NAME "__");
+		Print("Writing %s...\n", tmp);
+		FileDelete(tmp);
+		DumpBuf(b, tmp);
+		FreeBuf(b);
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		HC *c = LIST_DATA(o, i);
+		Free(c->Buffer);
+		Free(c->FileName);
+		Free(c);
+	}
+
+	ReleaseList(o);
+
+	FreeBuf(b);
+}
+
+// HC の比較
+int CompareHamcore(void *p1, void *p2)
+{
+	HC *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(HC **)p1;
+	c2 = *(HC **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(c1->FileName, c2->FileName);
+}
+
+// EXE ファイルがあるディレクトリ名の取得
+void GetExeDir(char *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	GetDirNameFromFilePath(name, size, exe_file_name);
+}
+void GetExeDirW(wchar_t *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	GetDirNameFromFilePathW(name, size, exe_file_name_w);
+}
+
+// EXE ファイル名の取得
+void GetExeName(char *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	StrCpy(name, size, exe_file_name);
+}
+void GetExeNameW(wchar_t *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	UniStrCpy(name, size, exe_file_name_w);
+}
+
+// EXE ファイル名の取得初期化
+void InitGetExeName(char *arg)
+{
+	wchar_t *arg_w = NULL;
+	// 引数チェック
+	if (arg == NULL)
+	{
+		arg = "./a.out";
+	}
+
+	arg_w = CopyUtfToUni(arg);
+
+#ifdef	OS_WIN32
+	Win32GetExeNameW(exe_file_name_w, sizeof(exe_file_name_w));
+#else	// OS_WIN32
+	UnixGetExeNameW(exe_file_name_w, sizeof(exe_file_name_w), arg_w);
+#endif	// OS_WIN32
+
+	UniToStr(exe_file_name, sizeof(exe_file_name), exe_file_name_w);
+
+	Free(arg_w);
+}
+
+// Unix における実行可能バイナリファイルのフルパスの取得
+void UnixGetExeNameW(wchar_t *name, UINT size, wchar_t *arg)
+{
+	UNI_TOKEN_LIST *t;
+	char *path_str;
+	wchar_t *path_str_w;
+	bool ok = false;
+	// 引数チェック
+	if (name == NULL || arg == NULL)
+	{
+		return;
+	}
+
+	path_str = GetCurrentPathEnvStr();
+	path_str_w = CopyUtfToUni(path_str);
+
+	t = ParseSplitedPathW(path_str_w);
+
+	if (t != NULL)
+	{
+		UINT i;
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			wchar_t *s = t->Token[i];
+			wchar_t tmp[MAX_SIZE];
+
+			ConbinePathW(tmp, sizeof(tmp), s, arg);
+
+			if (IsFileExistsInnerW(tmp))
+			{
+#ifdef	OS_UNIX
+				if (UnixCheckExecAccessW(tmp) == false)
+				{
+					continue;
+				}
+#endif	// OS_UNIX
+				ok = true;
+				UniStrCpy(name, size, tmp);
+				break;
+			}
+		}
+
+		UniFreeToken(t);
+	}
+
+	Free(path_str);
+	Free(path_str_w);
+
+	if (ok == false)
+	{
+		// パスの検索に失敗した場合
+#ifdef	OS_UNIX
+		UnixGetCurrentDirW(name, size);
+#else	// OS_UNIX
+		Win32GetCurrentDirW(name, size);
+#endif	// OS_UNIX
+		ConbinePathW(name, size, name, arg);
+	}
+}
+
+// 安全なファイル名を生成する
+void MakeSafeFileName(char *dst, UINT size, char *src)
+{
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	StrCpy(tmp, sizeof(tmp), src);
+	ReplaceStrEx(tmp, sizeof(tmp), tmp, "..", "__", false);
+	ReplaceStrEx(tmp, sizeof(tmp), tmp, "/", "_", false);
+	ReplaceStrEx(tmp, sizeof(tmp), tmp, "\\", "_", false);
+	ReplaceStrEx(tmp, sizeof(tmp), tmp, "@", "_", false);
+	ReplaceStrEx(tmp, sizeof(tmp), tmp, "|", "_", false);
+
+	StrCpy(dst, size, tmp);
+}
+void MakeSafeFileNameW(wchar_t *dst, UINT size, wchar_t *src)
+{
+	wchar_t tmp[MAX_PATH];
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	UniStrCpy(tmp, sizeof(tmp), src);
+	UniReplaceStrEx(tmp, sizeof(tmp), tmp, L"..", L"__", false);
+	UniReplaceStrEx(tmp, sizeof(tmp), tmp, L"/", L"_", false);
+	UniReplaceStrEx(tmp, sizeof(tmp), tmp, L"\\", L"_", false);
+	UniReplaceStrEx(tmp, sizeof(tmp), tmp, L"@", L"_", false);
+	UniReplaceStrEx(tmp, sizeof(tmp), tmp, L"|", L"_", false);
+
+	UniStrCpy(dst, size, tmp);
+}
+
+// ファイルパスからファイル名を取得する
+void GetFileNameFromFilePathW(wchar_t *dst, UINT size, wchar_t *filepath)
+{
+	wchar_t tmp[MAX_SIZE];
+	UINT i, len, wp;
+	// 引数チェック
+	if (dst == NULL || filepath == NULL)
+	{
+		return;
+	}
+
+	len = MIN(UniStrLen(filepath), (MAX_SIZE - 2));
+	wp = 0;
+
+	for (i = 0;i < (len + 1);i++)
+	{
+		wchar_t c = filepath[i];
+
+		switch (c)
+		{
+		case L'\\':
+		case L'/':
+		case 0:
+			tmp[wp] = 0;
+			wp = 0;
+			break;
+
+		default:
+			tmp[wp] = c;
+			wp++;
+			break;
+		}
+	}
+
+	UniStrCpy(dst, size, tmp);
+}
+void GetFileNameFromFilePath(char *dst, UINT size, char *filepath)
+{
+	char tmp[MAX_SIZE];
+	UINT i, len, wp;
+	// 引数チェック
+	if (dst == NULL || filepath == NULL)
+	{
+		return;
+	}
+
+	len = MIN(StrLen(filepath), (MAX_SIZE - 2));
+	wp = 0;
+
+	for (i = 0;i < (len + 1);i++)
+	{
+		char c = filepath[i];
+
+		switch (c)
+		{
+		case '\\':
+		case '/':
+		case 0:
+			tmp[wp] = 0;
+			wp = 0;
+			break;
+
+		default:
+			tmp[wp] = c;
+			wp++;
+			break;
+		}
+	}
+
+	StrCpy(dst, size, tmp);
+}
+void GetDirNameFromFilePathW(wchar_t *dst, UINT size, wchar_t *filepath)
+{
+	wchar_t tmp[MAX_SIZE];
+	UINT wp;
+	UINT i;
+	UINT len;
+	// 引数チェック
+	if (dst == NULL || filepath == NULL)
+	{
+		return;
+	}
+
+	UniStrCpy(tmp, sizeof(tmp), filepath);
+	if (UniEndWith(tmp, L"\\") || UniEndWith(tmp, L"/"))
+	{
+		tmp[UniStrLen(tmp) - 1] = 0;
+	}
+
+	len = UniStrLen(tmp);
+
+	UniStrCpy(dst, size, L"");
+
+	wp = 0;
+
+	for (i = 0;i < len;i++)
+	{
+		wchar_t c = tmp[i];
+		if (c == L'/' || c == L'\\')
+		{
+			tmp[wp++] = 0;
+			wp = 0;
+			UniStrCat(dst, size, tmp);
+			tmp[wp++] = c;
+		}
+		else
+		{
+			tmp[wp++] = c;
+		}
+	}
+
+	if (UniStrLen(dst) == 0)
+	{
+		UniStrCpy(dst, size, L"/");
+	}
+
+	NormalizePathW(dst, size, dst);
+}
+
+// ファイルパスからディレクトリ名を取得する
+void GetDirNameFromFilePath(char *dst, UINT size, char *filepath)
+{
+	char tmp[MAX_SIZE];
+	UINT wp;
+	UINT i;
+	UINT len;
+	// 引数チェック
+	if (dst == NULL || filepath == NULL)
+	{
+		return;
+	}
+
+	StrCpy(tmp, sizeof(tmp), filepath);
+	if (EndWith(tmp, "\\") || EndWith(tmp, "/"))
+	{
+		tmp[StrLen(tmp) - 1] = 0;
+	}
+
+	len = StrLen(tmp);
+
+	StrCpy(dst, size, "");
+
+	wp = 0;
+
+	for (i = 0;i < len;i++)
+	{
+		char c = tmp[i];
+		if (c == '/' || c == '\\')
+		{
+			tmp[wp++] = 0;
+			wp = 0;
+			StrCat(dst, size, tmp);
+			tmp[wp++] = c;
+		}
+		else
+		{
+			tmp[wp++] = c;
+		}
+	}
+
+	if (StrLen(dst) == 0)
+	{
+		StrCpy(dst, size, "/");
+	}
+
+	NormalizePath(dst, size, dst);
+}
+
+// 2 つのパスを結合する
+void ConbinePath(char *dst, UINT size, char *dirname, char *filename)
+{
+	wchar_t dst_w[MAX_PATH];
+	wchar_t *dirname_w = CopyStrToUni(dirname);
+	wchar_t *filename_w = CopyStrToUni(filename);
+
+	ConbinePathW(dst_w, sizeof(dst_w), dirname_w, filename_w);
+
+	Free(dirname_w);
+	Free(filename_w);
+
+	UniToStr(dst, size, dst_w);
+}
+void ConbinePathW(wchar_t *dst, UINT size, wchar_t *dirname, wchar_t *filename)
+{
+	bool is_full_path;
+	wchar_t tmp[MAX_SIZE];
+	wchar_t filename_ident[MAX_SIZE];
+	// 引数チェック
+	if (dst == NULL || dirname == NULL || filename == NULL)
+	{
+		return;
+	}
+
+	NormalizePathW(filename_ident, sizeof(filename_ident), filename);
+
+	is_full_path = false;
+
+	if (UniStartWith(filename_ident, L"\\") || UniStartWith(filename_ident, L"/"))
+	{
+		is_full_path = true;
+	}
+
+	filename = &filename_ident[0];
+
+#ifdef	OS_WIN32
+	if (UniStrLen(filename) >= 2)
+	{
+		if ((L'a' <= filename[0] && filename[0] <= L'z') || (L'A' <= filename[0] && filename[0] <= L'Z'))
+		{
+			if (filename[1] == L':')
+			{
+				is_full_path = true;
+			}
+		}
+	}
+#endif	// OS_WIN32
+
+	if (is_full_path == false)
+	{
+		UniStrCpy(tmp, sizeof(tmp), dirname);
+		if (UniEndWith(tmp, L"/") == false && UniEndWith(tmp, L"\\") == false)
+		{
+			UniStrCat(tmp, sizeof(tmp), L"/");
+		}
+		UniStrCat(tmp, sizeof(tmp), filename);
+	}
+	else
+	{
+		UniStrCpy(tmp, sizeof(tmp), filename);
+	}
+
+	NormalizePathW(dst, size, tmp);
+}
+void CombinePath(char *dst, UINT size, char *dirname, char *filename)
+{
+	ConbinePath(dst, size, dirname, filename);
+}
+void CombinePathW(wchar_t *dst, UINT size, wchar_t *dirname, wchar_t *filename)
+{
+	ConbinePathW(dst, size, dirname, filename);
+}
+
+// ファイルが存在するかどうか確認する
+bool IsFileExists(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = IsFileExistsW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool IsFileExistsW(wchar_t *name)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	InnerFilePathW(tmp, sizeof(tmp), name);
+
+	return IsFileExistsInnerW(tmp);
+}
+bool IsFileExistsInner(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = IsFileExistsInnerW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool IsFileExistsInnerW(wchar_t *name)
+{
+	IO *o;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	o = FileOpenInnerW(name, false, false);
+	if (o == NULL)
+	{
+		return false;
+	}
+
+	FileClose(o);
+
+	return true;
+}
+
+// 現在の環境変数 PATH の内容を取得
+char *GetCurrentPathEnvStr()
+{
+	char tmp[1024];
+	char *tag_name;
+
+#ifdef	OS_WIN32
+	tag_name = "Path";
+#else	// OS_WIN32
+	tag_name = "PATH";
+#endif	// OS_WIN32
+
+	if (GetEnv(tag_name, tmp, sizeof(tmp)) == false)
+	{
+#ifdef	OS_WIN32
+		Win32GetCurrentDir(tmp, sizeof(tmp));
+#else	// OS_WIN32
+		UnixGetCurrentDir(tmp, sizeof(tmp));
+#endif	// OS_WIN32
+	}
+
+	return CopyStr(tmp);
+}
+
+// コロン文字列で区切られた複数のパスを取得する
+UNI_TOKEN_LIST *ParseSplitedPathW(wchar_t *path)
+{
+	UNI_TOKEN_LIST *ret;
+	wchar_t *tmp = UniCopyStr(path);
+	wchar_t *split_str;
+	UINT i;
+
+	UniTrim(tmp);
+	UniTrimCrlf(tmp);
+	UniTrim(tmp);
+	UniTrimCrlf(tmp);
+
+#ifdef	OS_WIN32
+	split_str = L";";
+#else	// OS_WIN32
+	split_str = L":";
+#endif	// OS_WIN32
+
+	ret = UniParseToken(tmp, split_str);
+
+	if (ret != NULL)
+	{
+		for (i = 0;i < ret->NumTokens;i++)
+		{
+			UniTrim(ret->Token[i]);
+			UniTrimCrlf(ret->Token[i]);
+			UniTrim(ret->Token[i]);
+			UniTrimCrlf(ret->Token[i]);
+		}
+	}
+
+	Free(tmp);
+
+	return ret;
+}
+TOKEN_LIST *ParseSplitedPath(char *path)
+{
+	TOKEN_LIST *ret;
+	char *tmp = CopyStr(path);
+	char *split_str;
+	UINT i;
+
+	Trim(tmp);
+	TrimCrlf(tmp);
+	Trim(tmp);
+	TrimCrlf(tmp);
+
+#ifdef	OS_WIN32
+	split_str = ";";
+#else	// OS_WIN32
+	split_str = ":";
+#endif	// OS_WIN32
+
+	ret = ParseToken(tmp, split_str);
+
+	if (ret != NULL)
+	{
+		for (i = 0;i < ret->NumTokens;i++)
+		{
+			Trim(ret->Token[i]);
+			TrimCrlf(ret->Token[i]);
+			Trim(ret->Token[i]);
+			TrimCrlf(ret->Token[i]);
+		}
+	}
+
+	Free(tmp);
+
+	return ret;
+}
+
+// 現在のディレクトリを取得する
+void GetCurrentDirW(wchar_t *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+	Win32GetCurrentDirW(name, size);
+#else	// OS_WIN32
+	UnixGetCurrentDirW(name, size);
+#endif	// OS_WIN32
+}
+void GetCurrentDir(char *name, UINT size)
+{
+	wchar_t name_w[MAX_PATH];
+
+	GetCurrentDirW(name_w, sizeof(name_w));
+
+	UniToStr(name, size, name_w);
+}
+
+// ファイルパスを正規化する
+void NormalizePathW(wchar_t *dst, UINT size, wchar_t *src)
+{
+	wchar_t tmp[MAX_SIZE];
+	UNI_TOKEN_LIST *t;
+	bool first_double_slash = false;
+	bool first_single_slash = false;
+	wchar_t win32_drive_char = 0;
+	bool is_full_path = false;
+	UINT i;
+	SK *sk;
+	// 引数チェック
+	if (dst == NULL || src == 0)
+	{
+		return;
+	}
+
+	// パスを変換する (Win32, UNIX 変換)
+	UniStrCpy(tmp, sizeof(tmp), src);
+	ConvertPathW(tmp);
+	UniTrim(tmp);
+
+	// 先頭が "./" や "../" で始まっている場合はカレントディレクトリに置換する
+	if (UniStartWith(tmp, L"./") || UniStartWith(tmp, L".\\") ||
+		UniStartWith(tmp, L"../") || UniStartWith(tmp, L"..\\") ||
+		UniStrCmpi(tmp, L".") == 0 || UniStrCmpi(tmp, L"..") == 0)
+	{
+		wchar_t cd[MAX_SIZE];
+		Zero(cd, sizeof(cd));
+
+#ifdef	OS_WIN32
+		Win32GetCurrentDirW(cd, sizeof(cd));
+#else	// OS_WIN32
+		UnixGetCurrentDirW(cd, sizeof(cd));
+#endif	// OS_WIN32
+
+		if (UniStartWith(tmp, L".."))
+		{
+			UniStrCat(cd, sizeof(cd), L"/../");
+			UniStrCat(cd, sizeof(cd), tmp + 2);
+		}
+		else
+		{
+			UniStrCat(cd, sizeof(cd), L"/");
+			UniStrCat(cd, sizeof(cd), tmp);
+		}
+
+		UniStrCpy(tmp, sizeof(tmp), cd);
+	}
+
+	// 先頭が "~/" で始まっている場合はホームディレクトリに置換する
+	if (UniStartWith(tmp, L"~/") || UniStartWith(tmp, L"~\\"))
+	{
+		wchar_t tmp2[MAX_SIZE];
+		GetHomeDirW(tmp2, sizeof(tmp2));
+		UniStrCat(tmp2, sizeof(tmp2), L"/");
+		UniStrCat(tmp2, sizeof(tmp2), tmp + 2);
+		UniStrCpy(tmp, sizeof(tmp), tmp2);
+	}
+
+	if (UniStartWith(tmp, L"//") || UniStartWith(tmp, L"\\\\"))
+	{
+		// 最初が "//" または "\\" で始まる
+		first_double_slash = true;
+		is_full_path = true;
+	}
+	else if (UniStartWith(tmp, L"/") || UniStartWith(tmp, L"\\"))
+	{
+		// 最初が "\" で始まる
+		first_single_slash = true;
+		is_full_path = true;
+	}
+
+	if (UniStrLen(tmp) >= 2)
+	{
+		if (tmp[1] == L':')
+		{
+			if (OS_IS_WINDOWS(GetOsInfo()->OsType))
+			{
+				// Win32 のドライブ文字列表記
+				wchar_t tmp2[MAX_SIZE];
+				is_full_path = true;
+				win32_drive_char = tmp[0];
+				UniStrCpy(tmp2, sizeof(tmp2), tmp + 2);
+				UniStrCpy(tmp, sizeof(tmp), tmp2);
+			}
+		}
+	}
+
+	if (UniStrLen(tmp) == 1 && (tmp[0] == L'/' || tmp[0] == L'\\'))
+	{
+		tmp[0] = 0;
+	}
+
+	// トークン分割
+	t = UniParseToken(tmp, L"/\\");
+
+	sk = NewSk();
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		wchar_t *s = t->Token[i];
+
+		if (UniStrCmpi(s, L".") == 0)
+		{
+			continue;
+		}
+		else if (UniStrCmpi(s, L"..") == 0)
+		{
+			if (sk->num_item >= 1 && (first_double_slash == false || sk->num_item >= 2))
+			{
+				Pop(sk);
+			}
+		}
+		else
+		{
+			Push(sk, s);
+		}
+	}
+
+	// トークン結合
+	UniStrCpy(tmp, sizeof(tmp), L"");
+
+	if (first_double_slash)
+	{
+		UniStrCat(tmp, sizeof(tmp), L"//");
+	}
+	else if (first_single_slash)
+	{
+		UniStrCat(tmp, sizeof(tmp), L"/");
+	}
+
+	if (win32_drive_char != 0)
+	{
+		wchar_t d[2];
+		d[0] = win32_drive_char;
+		d[1] = 0;
+		UniStrCat(tmp, sizeof(tmp), d);
+		UniStrCat(tmp, sizeof(tmp), L":/");
+	}
+
+	for (i = 0;i < sk->num_item;i++)
+	{
+		UniStrCat(tmp, sizeof(tmp), (wchar_t *)sk->p[i]);
+		if (i != (sk->num_item - 1))
+		{
+			UniStrCat(tmp, sizeof(tmp), L"/");
+		}
+	}
+
+	ReleaseSk(sk);
+
+	UniFreeToken(t);
+
+	ConvertPathW(tmp);
+
+	UniStrCpy(dst, size, tmp);
+}
+void NormalizePath(char *dst, UINT size, char *src)
+{
+	wchar_t dst_w[MAX_SIZE];
+	wchar_t *src_w = CopyStrToUni(src);
+
+	NormalizePathW(dst_w, sizeof(dst_w), src_w);
+
+	Free(src_w);
+
+	UniToStr(dst, size, dst_w);
+}
+
+// ファイルを閉じて削除する
+void FileCloseAndDelete(IO *o)
+{
+	wchar_t *name;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	name = CopyUniStr(o->NameW);
+	FileClose(o);
+
+	FileDeleteW(name);
+
+	Free(name);
+}
+
+// ファイル名の変更
+bool FileRename(char *old_name, char *new_name)
+{
+	wchar_t *old_name_w = CopyStrToUni(old_name);
+	wchar_t *new_name_w = CopyStrToUni(new_name);
+	bool ret = FileRenameW(old_name_w, new_name_w);
+
+	Free(old_name_w);
+	Free(new_name_w);
+
+	return ret;
+}
+bool FileRenameW(wchar_t *old_name, wchar_t *new_name)
+{
+	wchar_t tmp1[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	// 引数チェック
+	if (old_name == NULL || new_name == NULL)
+	{
+		return false;
+	}
+
+	InnerFilePathW(tmp1, sizeof(tmp1), old_name);
+	InnerFilePathW(tmp2, sizeof(tmp2), new_name);
+
+	return FileRenameInnerW(tmp1, tmp2);
+}
+bool FileRenameInner(char *old_name, char *new_name)
+{
+	wchar_t *old_name_w = CopyStrToUni(old_name);
+	wchar_t *new_name_w = CopyStrToUni(new_name);
+	bool ret = FileRenameInnerW(old_name_w, new_name_w);
+
+	Free(old_name_w);
+	Free(new_name_w);
+
+	return ret;
+}
+bool FileRenameInnerW(wchar_t *old_name, wchar_t *new_name)
+{
+	// 引数チェック
+	if (old_name == NULL || new_name == NULL)
+	{
+		return false;
+	}
+
+	return OSFileRenameW(old_name, new_name);
+}
+
+// パスの変換
+void ConvertPath(char *path)
+{
+	UINT i, len;
+#ifdef	PATH_BACKSLASH
+	char new_char = '\\';
+#else
+	char new_char = '/';
+#endif
+
+	len = StrLen(path);
+	for (i = 0;i < len;i++)
+	{
+		if (path[i] == '\\' || path[i] == '/')
+		{
+			path[i] = new_char;
+		}
+	}
+}
+void ConvertPathW(wchar_t *path)
+{
+	UINT i, len;
+#ifdef	PATH_BACKSLASH
+	wchar_t new_char = L'\\';
+#else
+	wchar_t new_char = L'/';
+#endif
+
+	len = UniStrLen(path);
+	for (i = 0;i < len;i++)
+	{
+		if (path[i] == L'\\' || path[i] == L'/')
+		{
+			path[i] = new_char;
+		}
+	}
+}
+
+// ディレクトリの削除
+bool DeleteDir(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = DeleteDirW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool DeleteDirW(wchar_t *name)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	InnerFilePathW(tmp, sizeof(tmp), name);
+
+	return DeleteDirInnerW(tmp);
+}
+bool DeleteDirInner(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = DeleteDirInnerW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool DeleteDirInnerW(wchar_t *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	return OSDeleteDirW(name);
+}
+
+// 内部ファイルパスの生成
+void InnerFilePathW(wchar_t *dst, UINT size, wchar_t *src)
+{
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	if (src[0] != L'@')
+	{
+		NormalizePathW(dst, size, src);
+	}
+	else
+	{
+		wchar_t dir[MAX_SIZE];
+		GetExeDirW(dir, sizeof(dir));
+		ConbinePathW(dst, size, dir, &src[1]);
+	}
+}
+void InnerFilePath(char *dst, UINT size, char *src)
+{
+	wchar_t dst_w[MAX_PATH];
+	wchar_t *src_w = CopyStrToUni(src);
+
+	InnerFilePathW(dst_w, sizeof(dst_w), src_w);
+
+	Free(src_w);
+
+	UniToStr(dst, size, dst_w);
+}
+
+// ディレクトリの再帰作成
+void MakeDirEx(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+
+	MakeDirExW(name_w);
+
+	Free(name_w);
+}
+void MakeDirExW(wchar_t *name)
+{
+	LIST *o;
+	wchar_t tmp[MAX_PATH];
+	wchar_t tmp2[MAX_PATH];
+	UINT i;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	o = NewListFast(NULL);
+
+	UniStrCpy(tmp, sizeof(tmp), name);
+	while (true)
+	{
+		wchar_t *s = CopyUniStr(tmp);
+
+		Add(o, s);
+
+		GetDirNameFromFilePathW(tmp2, sizeof(tmp2), tmp);
+
+		if (UniStrCmpi(tmp2, tmp) == 0)
+		{
+			break;
+		}
+
+		UniStrCpy(tmp, sizeof(tmp), tmp2);
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		UINT j = LIST_NUM(o) - i - 1;
+		wchar_t *s = LIST_DATA(o, j);
+
+		if (UniStrCmpi(s, L"\\") != 0 && UniStrCmpi(s, L"/") != 0)
+		{
+			MakeDirW(s);
+		}
+	}
+
+	UniFreeStrList(o);
+}
+
+// ディレクトリの作成
+bool MakeDir(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = MakeDirW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool MakeDirW(wchar_t *name)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	InnerFilePathW(tmp, sizeof(tmp), name);
+
+	return MakeDirInnerW(tmp);
+}
+bool MakeDirInner(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = MakeDirInnerW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool MakeDirInnerW(wchar_t *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	return OSMakeDirW(name);
+}
+
+// ファイルの削除
+bool FileDelete(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = FileDeleteW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool FileDeleteW(wchar_t *name)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	InnerFilePathW(tmp, sizeof(tmp), name);
+
+	return FileDeleteInnerW(tmp);
+}
+bool FileDeleteInner(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	bool ret = FileDeleteInnerW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+bool FileDeleteInnerW(wchar_t *name)
+{
+	wchar_t name2[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	UniStrCpy(name2, sizeof(name2), name);
+	ConvertPathW(name2);
+
+	return OSFileDeleteW(name2);
+}
+
+// ファイルをシークする
+bool FileSeek(IO *o, UINT mode, int offset)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return false;
+	}
+
+	if (o->HamMode == false)
+	{
+		return OSFileSeek(o->pData, mode, offset);
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// ファイル名を指定してファイルサイズを取得する
+UINT FileSizeEx(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	UINT ret = FileSizeExW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+UINT FileSizeExW(wchar_t *name)
+{
+	IO *io;
+	UINT size;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return 0;
+	}
+
+	io = FileOpenW(name, false);
+	if (io == NULL)
+	{
+		return 0;
+	}
+
+	size = FileSize(io);
+
+	FileClose(io);
+
+	return size;
+}
+
+// ファイルサイズを取得する
+UINT64 FileSize64(IO *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return 0;
+	}
+
+	if (o->HamMode == false)
+	{
+		return OSFileSize(o->pData);
+	}
+	else
+	{
+		return (UINT64)o->HamBuf->Size;
+	}
+}
+UINT FileSize(IO *o)
+{
+	UINT64 size = (UINT)(FileSize64(o));
+
+	if (size >= 4294967296ULL)
+	{
+		size = 4294967295ULL;
+	}
+
+	return (UINT)size;
+}
+
+// ファイルから読み込む
+bool FileRead(IO *o, void *buf, UINT size)
+{
+	// 引数チェック
+	if (o == NULL || buf == NULL)
+	{
+		return false;
+	}
+
+	// KS
+	KS_INC(KS_IO_READ_COUNT);
+	KS_ADD(KS_IO_TOTAL_READ_SIZE, size);
+
+	if (size == 0)
+	{
+		return true;
+	}
+
+	if (o->HamMode == false)
+	{
+		return OSFileRead(o->pData, buf, size);
+	}
+	else
+	{
+		return ReadBuf(o->HamBuf, buf, size) == size ? true : false;
+	}
+}
+
+// ファイルに書き込む
+bool FileWrite(IO *o, void *buf, UINT size)
+{
+	// 引数チェック
+	if (o == NULL || buf == NULL)
+	{
+		return false;
+	}
+	if (o->WriteMode == false)
+	{
+		return false;
+	}
+
+	// KS
+	KS_INC(KS_IO_WRITE_COUNT);
+	KS_ADD(KS_IO_TOTAL_WRITE_SIZE, size);
+
+	if (size == 0)
+	{
+		return true;
+	}
+
+	return OSFileWrite(o->pData, buf, size);
+}
+
+// ファイルをフラッシュする
+void FileFlush(IO *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	if (o->HamMode)
+	{
+		return;
+	}
+
+	OSFileFlush(o->pData);
+}
+
+// ファイルを閉じる
+void FileClose(IO *o)
+{
+	FileCloseEx(o, false);
+}
+void FileCloseEx(IO *o, bool no_flush)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	if (o->HamMode == false)
+	{
+		OSFileClose(o->pData, no_flush);
+	}
+	else
+	{
+		FreeBuf(o->HamBuf);
+	}
+	Free(o);
+
+	// KS
+	KS_INC(KS_IO_CLOSE_COUNT);
+}
+
+// ファイルを作成する
+IO *FileCreateInner(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	IO *ret = FileCreateInnerW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+IO *FileCreateInnerW(wchar_t *name)
+{
+	IO *o;
+	void *p;
+	wchar_t name2[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	UniStrCpy(name2, sizeof(name2), name);
+	ConvertPathW(name2);
+
+	p = OSFileCreateW(name2);
+	if (p == NULL)
+	{
+		return NULL;
+	}
+
+	o = ZeroMalloc(sizeof(IO));
+	o->pData = p;
+	UniStrCpy(o->NameW, sizeof(o->NameW), name2);
+	UniToStr(o->Name, sizeof(o->Name), o->NameW);
+	o->WriteMode = true;
+
+	// KS
+	KS_INC(KS_IO_CREATE_COUNT);
+
+	return o;
+}
+IO *FileCreate(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	IO *ret = FileCreateW(name_w);
+
+	Free(name_w);
+
+	return ret;
+}
+IO *FileCreateW(wchar_t *name)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	InnerFilePathW(tmp, sizeof(tmp), name);
+
+	return FileCreateInnerW(tmp);
+}
+
+// ファイルにすべてのデータを書き込む
+bool FileWriteAll(char *name, void *data, UINT size)
+{
+	IO *io;
+	// 引数チェック
+	if (name == NULL || (data == NULL && size != 0))
+	{
+		return false;
+	}
+
+	io = FileCreate(name);
+
+	if (io == NULL)
+	{
+		return false;
+	}
+
+	FileWrite(io, data, size);
+
+	FileClose(io);
+
+	return true;
+}
+bool FileWriteAllW(wchar_t *name, void *data, UINT size)
+{
+	IO *io;
+	// 引数チェック
+	if (name == NULL || (data == NULL && size != 0))
+	{
+		return false;
+	}
+
+	io = FileCreateW(name);
+
+	if (io == NULL)
+	{
+		return false;
+	}
+
+	FileWrite(io, data, size);
+
+	FileClose(io);
+
+	return true;
+}
+
+// ファイルを開く
+IO *FileOpenInner(char *name, bool write_mode, bool read_lock)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	IO *ret = FileOpenInnerW(name_w, write_mode, read_lock);
+
+	Free(name_w);
+
+	return ret;
+}
+IO *FileOpenInnerW(wchar_t *name, bool write_mode, bool read_lock)
+{
+	IO *o;
+	void *p;
+	wchar_t name2[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	UniStrCpy(name2, sizeof(name2), name);
+	ConvertPathW(name2);
+
+	p = OSFileOpenW(name2, write_mode, read_lock);
+	if (p == NULL)
+	{
+		return NULL;
+	}
+
+	o = ZeroMalloc(sizeof(IO));
+	o->pData = p;
+	UniStrCpy(o->NameW, sizeof(o->NameW), name2);
+	UniToStr(o->Name, sizeof(o->Name), o->NameW);
+	o->WriteMode = write_mode;
+
+	// KS
+	KS_INC(KS_IO_OPEN_COUNT);
+
+	return o;
+}
+IO *FileOpen(char *name, bool write_mode)
+{
+	return FileOpenEx(name, write_mode, true);
+}
+IO *FileOpenW(wchar_t *name, bool write_mode)
+{
+	return FileOpenExW(name, write_mode, true);
+}
+IO *FileOpenEx(char *name, bool write_mode, bool read_lock)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+	IO *ret = FileOpenExW(name_w, write_mode, read_lock);
+
+	Free(name_w);
+
+	return ret;
+}
+IO *FileOpenExW(wchar_t *name, bool write_mode, bool read_lock)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	InnerFilePathW(tmp, sizeof(tmp), name);
+
+	if (name[0] == L'|')
+	{
+		IO *o = ZeroMalloc(sizeof(IO));
+		name++;
+		UniStrCpy(o->NameW, sizeof(o->NameW), name);
+		UniToStr(o->Name, sizeof(o->Name), o->NameW);
+		o->HamMode = true;
+		o->HamBuf = ReadHamcoreW(name);
+		if (o->HamBuf == NULL)
+		{
+			Free(o);
+			return NULL;
+		}
+		return o;
+	}
+	else
+	{
+		return FileOpenInnerW(tmp, write_mode, read_lock);
+	}
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/FileIO.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/FileIO.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/FileIO.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,235 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// FileIO.h
+// FileIO.c のヘッダ
+
+#ifndef	FILEIO_H
+#define	FILEIO_H
+
+// 定数
+#define	HAMCORE_DIR_NAME			"hamcore"
+#define	HAMCORE_FILE_NAME			"hamcore.utvpn"
+#define	HAMCORE_FILE_NAME_2			"_hamcore.utvpn"
+#define	HAMCORE_TEXT_NAME			"hamcore.txt"
+#define	HAMCORE_HEADER_DATA			"HamCore"
+#define	HAMCORE_HEADER_SIZE			7
+#define	HAMCORE_CACHE_EXPIRES		(5 * 60 * 1000)
+
+// IO 構造体
+struct IO
+{
+	char Name[MAX_SIZE];
+	wchar_t NameW[MAX_SIZE];
+	void *pData;
+	bool WriteMode;
+	bool HamMode;
+	BUF *HamBuf;
+};
+
+// HC 構造体
+typedef struct HC
+{
+	char *FileName;				// ファイル名
+	UINT Size;					// ファイルサイズ
+	UINT SizeCompressed;		// 圧縮されたファイルサイズ
+	UINT Offset;				// オフセット
+	void *Buffer;				// バッファ
+	UINT64 LastAccess;			// 最後にアクセスした日時
+} HC;
+
+// DIRENT 構造体
+struct DIRENT
+{
+	bool Folder;				// フォルダ
+	char *FileName;				// ファイル名 (ANSI)
+	wchar_t *FileNameW;			// ファイル名 (Unicode)
+	UINT64 FileSize;			// ファイルサイズ
+	UINT64 CreateDate;			// 作成日時
+	UINT64 UpdateDate;			// 更新日時
+};
+
+// DIRLIST 構造体
+struct DIRLIST
+{
+	UINT NumFiles;				// ファイル数
+	struct DIRENT **File;			// ファイル配列
+};
+
+bool DeleteDirInner(char *name);
+bool DeleteDirInnerW(wchar_t *name);
+bool DeleteDir(char *name);
+bool DeleteDirW(wchar_t *name);
+bool MakeDirInner(char *name);
+bool MakeDirInnerW(wchar_t *name);
+bool MakeDir(char *name);
+bool MakeDirW(wchar_t *name);
+void MakeDirEx(char *name);
+void MakeDirExW(wchar_t *name);
+bool FileDeleteInner(char *name);
+bool FileDeleteInnerW(wchar_t *name);
+bool FileDelete(char *name);
+bool FileDeleteW(wchar_t *name);
+bool FileSeek(IO *o, UINT mode, int offset);
+UINT FileSize(IO *o);
+UINT64 FileSize64(IO *o);
+UINT FileSizeEx(char *name);
+UINT FileSizeExW(wchar_t *name);
+UINT FileRead(IO *o, void *buf, UINT size);
+UINT FileWrite(IO *o, void *buf, UINT size);
+void FileFlush(IO *o);
+void FileClose(IO *o);
+void FileCloseEx(IO *o, bool no_flush);
+void FileCloseAndDelete(IO *o);
+IO *FileCreateInner(char *name);
+IO *FileCreateInnerW(wchar_t *name);
+IO *FileCreate(char *name);
+IO *FileCreateW(wchar_t *name);
+bool FileWriteAll(char *name, void *data, UINT size);
+bool FileWriteAllW(wchar_t *name, void *data, UINT size);
+IO *FileOpenInner(char *name, bool write_mode, bool read_lock);
+IO *FileOpenInnerW(wchar_t *name, bool write_mode, bool read_lock);
+IO *FileOpen(char *name, bool write_mode);
+IO *FileOpenW(wchar_t *name, bool write_mode);
+IO *FileOpenEx(char *name, bool write_mode, bool read_lock);
+IO *FileOpenExW(wchar_t *name, bool write_mode, bool read_lock);
+void ConvertPath(char *path);
+void ConvertPathW(wchar_t *path);
+bool FileRenameInner(char *old_name, char *new_name);
+bool FileRenameInnerW(wchar_t *old_name, wchar_t *new_name);
+bool FileRename(char *old_name, char *new_name);
+bool FileRenameW(wchar_t *old_name, wchar_t *new_name);
+void NormalizePath(char *dst, UINT size, char *src);
+void NormalizePathW(wchar_t *dst, UINT size, wchar_t *src);
+TOKEN_LIST *ParseSplitedPath(char *path);
+UNI_TOKEN_LIST *ParseSplitedPathW(wchar_t *path);
+char *GetCurrentPathEnvStr();
+bool IsFileExistsInner(char *name);
+bool IsFileExistsInnerW(wchar_t *name);
+bool IsFileExists(char *name);
+bool IsFileExistsW(wchar_t *name);
+void InnerFilePath(char *dst, UINT size, char *src);
+void InnerFilePathW(wchar_t *dst, UINT size, wchar_t *src);
+void ConbinePath(char *dst, UINT size, char *dirname, char *filename);
+void ConbinePathW(wchar_t *dst, UINT size, wchar_t *dirname, wchar_t *filename);
+void CombinePath(char *dst, UINT size, char *dirname, char *filename);
+void CombinePathW(wchar_t *dst, UINT size, wchar_t *dirname, wchar_t *filename);
+void GetDirNameFromFilePath(char *dst, UINT size, char *filepath);
+void GetDirNameFromFilePathW(wchar_t *dst, UINT size, wchar_t *filepath);
+void GetFileNameFromFilePath(char *dst, UINT size, char *filepath);
+void GetFileNameFromFilePathW(wchar_t *dst, UINT size, wchar_t *filepath);
+void MakeSafeFileName(char *dst, UINT size, char *src);
+void MakeSafeFileNameW(wchar_t *dst, UINT size, wchar_t *src);
+void InitGetExeName(char *arg);
+void UnixGetExeNameW(wchar_t *name, UINT size, wchar_t *arg);
+void GetExeName(char *name, UINT size);
+void GetExeNameW(wchar_t *name, UINT size);
+void GetExeDir(char *name, UINT size);
+void GetExeDirW(wchar_t *name, UINT size);
+void BuildHamcore();
+int CompareHamcore(void *p1, void *p2);
+void InitHamcore();
+void FreeHamcore();
+BUF *ReadHamcore(char *name);
+BUF *ReadHamcoreW(wchar_t *filename);
+void SafeFileName(char *name);
+void SafeFileNameW(wchar_t *name);
+void UniSafeFileName(wchar_t *name);
+DIRLIST *EnumDir(char *dirname);
+DIRLIST *EnumDirW(wchar_t *dirname);
+DIRLIST *EnumDirEx(char *dirname, COMPARE *compare);
+DIRLIST *EnumDirExW(wchar_t *dirname, COMPARE *compare);
+void FreeDir(DIRLIST *d);
+int CompareDirListByName(void *p1, void *p2);
+bool GetDiskFree(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size);
+bool GetDiskFreeW(wchar_t *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size);
+void ConvertSafeFileName(char *dst, UINT size, char *src);
+void ConvertSafeFileNameW(wchar_t *dst, UINT size, wchar_t *src);
+bool FileReplaceRename(char *old_name, char *new_name);
+bool FileReplaceRenameW(wchar_t *old_name, wchar_t *new_name);
+bool IsFile(char *name);
+bool IsFileW(wchar_t *name);
+void GetCurrentDirW(wchar_t *name, UINT size);
+void GetCurrentDir(char *name, UINT size);
+bool SaveFileW(wchar_t *name, void *data, UINT size);
+bool SaveFile(char *name, void *data, UINT size);
+
+
+#endif	// FILEIO_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Internat.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Internat.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Internat.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,3396 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Internat.c
+// 国際化のための文字列変換ライブラリ
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+extern LOCK *token_lock;
+static char charset[MAX_SIZE] = "EUCJP";
+static LOCK *iconv_lock = NULL;
+void *iconv_cache_wide_to_str = 0;
+void *iconv_cache_str_to_wide = 0;
+
+// 文字列が含まれているかどうかチェック
+bool UniInStr(wchar_t *str, wchar_t *keyword)
+{
+	return UniInStrEx(str, keyword, false);
+}
+bool UniInStrEx(wchar_t *str, wchar_t *keyword, bool case_sensitive)
+{
+	// 引数チェック
+	if (UniIsEmptyStr(str) || UniIsEmptyStr(keyword))
+	{
+		return false;
+	}
+
+	if (UniSearchStrEx(str, keyword, 0, case_sensitive) == INFINITE)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// バイナリデータに変換
+BUF *UniStrToBin(wchar_t *str)
+{
+	char *str_a = CopyUniToStr(str);
+	BUF *ret;
+
+	ret = StrToBin(str_a);
+
+	Free(str_a);
+
+	return ret;
+}
+
+// 指定した文字の列を生成する
+wchar_t *UniMakeCharArray(wchar_t c, UINT count)
+{
+	UINT i;
+	wchar_t *ret = Malloc(sizeof(wchar_t) * (count + 1));
+
+	for (i = 0;i < count;i++)
+	{
+		ret[i] = c;
+	}
+
+	ret[count] = 0;
+
+	return ret;
+}
+
+// 安全な文字かどうかチェック
+bool UniIsSafeChar(wchar_t c)
+{
+	UINT i, len;
+	wchar_t *check_str =
+		L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+		L"abcdefghijklmnopqrstuvwxyz"
+		L"0123456789"
+		L" ()-_#%&.";
+
+	len = UniStrLen(check_str);
+	for (i = 0;i < len;i++)
+	{
+		if (c == check_str[i])
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+// トークンリストを文字列リストに変換する
+LIST *UniTokenListToList(UNI_TOKEN_LIST *t)
+{
+	UINT i;
+	LIST *o;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(NULL);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		Insert(o, UniCopyStr(t->Token[i]));
+	}
+
+	return o;
+}
+
+// 文字列リストをトークンリストに変換する
+UNI_TOKEN_LIST *UniListToTokenList(LIST *o)
+{
+	UINT i;
+	UNI_TOKEN_LIST *t;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	t = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(wchar_t *) * t->NumTokens);
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		t->Token[i] = UniCopyStr(LIST_DATA(o, i));
+	}
+
+	return t;
+}
+
+// 文字列リストを解放する
+void UniFreeStrList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t *s = LIST_DATA(o, i);
+		Free(s);
+	}
+
+	ReleaseList(o);
+}
+
+// 文字列リストを文字列に変換する
+BUF *UniStrListToStr(LIST *o)
+{
+	BUF *b;
+	UINT i;
+	wchar_t c;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+	b = NewBuf();
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t *s = LIST_DATA(o, i);
+		WriteBuf(b, s, UniStrSize(s));
+	}
+
+	c = 0;
+	WriteBuf(b, &c, sizeof(c));
+
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// 文字列 (NULL区切り) をリストに変換する
+LIST *UniStrToStrList(wchar_t *str, UINT size)
+{
+	LIST *o;
+	wchar_t *tmp;
+	UINT tmp_size;
+	UINT i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(NULL);
+
+	i = 0;
+	while (true)
+	{
+		if (i >= size)
+		{
+			break;
+		}
+		if (*str == 0)
+		{
+			break;
+		}
+
+		tmp_size = UniStrSize(str);
+		tmp = ZeroMalloc(tmp_size);
+		UniStrCpy(tmp, tmp_size, str);
+		Add(o, tmp);
+		str += UniStrLen(str) + 1;
+		i++;
+	}
+
+	return o;
+}
+
+// 改行コードを正規化する
+wchar_t *UniNormalizeCrlf(wchar_t *str)
+{
+	wchar_t *ret;
+	UINT ret_size, i, len, wp;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = UniStrLen(str);
+	ret_size = sizeof(wchar_t) * (len + 32) * 2;
+	ret = Malloc(ret_size);
+
+	wp = 0;
+
+	for (i = 0;i < len;i++)
+	{
+		wchar_t c = str[i];
+
+		switch (c)
+		{
+		case L'\r':
+			if (str[i + 1] == L'\n')
+			{
+				i++;
+			}
+			ret[wp++] = L'\r';
+			ret[wp++] = L'\n';
+			break;
+
+		case L'\n':
+			ret[wp++] = L'\r';
+			ret[wp++] = L'\n';
+			break;
+
+		default:
+			ret[wp++] = c;
+			break;
+		}
+	}
+
+	ret[wp++] = 0;
+
+	return ret;
+}
+
+// str が key で終了するかどうかチェック
+bool UniEndWith(wchar_t *str, wchar_t *key)
+{
+	UINT str_len;
+	UINT key_len;
+	// 引数チェック
+	if (str == NULL || key == NULL)
+	{
+		return false;
+	}
+
+	// 比較
+	str_len = UniStrLen(str);
+	key_len = UniStrLen(key);
+	if (str_len < key_len)
+	{
+		return false;
+	}
+
+	if (UniStrCmpi(str + (str_len - key_len), key) == 0)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// str が key で始まるかどうかチェック
+bool UniStartWith(wchar_t *str, wchar_t *key)
+{
+	UINT str_len;
+	UINT key_len;
+	wchar_t *tmp;
+	bool ret;
+	// 引数チェック
+	if (str == NULL || key == NULL)
+	{
+		return false;
+	}
+
+	// 比較
+	str_len = UniStrLen(str);
+	key_len = UniStrLen(key);
+	if (str_len < key_len)
+	{
+		return false;
+	}
+	if (str_len == 0 || key_len == 0)
+	{
+		return false;
+	}
+	tmp = CopyUniStr(str);
+	tmp[key_len] = 0;
+
+	if (UniStrCmpi(tmp, key) == 0)
+	{
+		ret = true;
+	}
+	else
+	{
+		ret = false;
+	}
+
+	Free(tmp);
+
+	return ret;
+}
+
+// 整数をカンマ区切り文字列に変換する
+void UniToStr3(wchar_t *str, UINT size, UINT64 value)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	ToStr3(tmp, sizeof(tmp), value);
+
+	StrToUni(str, size, tmp);
+}
+
+// 文字列のフォーマット (内部関数)
+wchar_t *InternalFormatArgs(wchar_t *fmt, va_list args, bool ansi_mode)
+{
+	UINT i, len;
+	wchar_t *tmp;
+	UINT tmp_size;
+	LIST *o;
+	UINT mode = 0;
+	UINT wp;
+	UINT total_size;
+	wchar_t *ret;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return NULL;
+	}
+
+	len = UniStrLen(fmt);
+	tmp_size = UniStrSize(fmt);
+	tmp = Malloc(tmp_size);
+
+	o = NewListFast(NULL);
+
+	mode = 0;
+
+	wp = 0;
+
+	for (i = 0;i < len;i++)
+	{
+		wchar_t c = fmt[i];
+
+		if (mode == 0)
+		{
+			// 通常の文字モード
+			switch (c)
+			{
+			case L'%':
+				// 書式指定の開始
+				if (fmt[i + 1] == L'%')
+				{
+					// 次の文字も % の場合は % を一文字出力するだけ
+					i++;
+					tmp[wp++] = c;
+				}
+				else
+				{
+					// 次の文字が % でない場合は状態遷移を行う
+					mode = 1;
+					tmp[wp++] = 0;
+					wp = 0;
+					Add(o, CopyUniStr(tmp));
+					tmp[wp++] = c;
+				}
+				break;
+			default:
+				// 通常の文字
+				tmp[wp++] = c;
+				break;
+			}
+		}
+		else
+		{
+			char *tag;
+			char dst[MAX_SIZE];
+			wchar_t *target_str;
+			wchar_t *padding_str;
+			bool left_padding;
+			UINT target_str_len;
+			UINT total_len;
+			wchar_t *output_str;
+			UINT padding;
+			// 書式指定モード
+			switch (c)
+			{
+			case L'c':
+			case L'C':
+			case L'd':
+			case L'i':
+			case L'o':
+			case L'u':
+			case L'x':
+			case L'X':
+				// int 型
+				tmp[wp++] = c;
+				tmp[wp++] = 0;
+				tag = CopyUniToStr(tmp);
+
+				#ifdef	OS_WIN32
+					ReplaceStrEx(tag, 0, tag, "ll", "I64", false);
+				#else	// OS_WIN32
+					ReplaceStrEx(tag, 0, tag, "I64", "ll", false);
+				#endif	// OS_WIN32
+
+				if ((UniStrLen(tmp) >= 5 && tmp[UniStrLen(tmp) - 4] == L'I' &&
+					tmp[UniStrLen(tmp) - 3] == L'6' &&
+					tmp[UniStrLen(tmp) - 2] == L'4') ||
+					(
+					UniStrLen(tmp) >= 4 && tmp[UniStrLen(tmp) - 3] == L'l' &&
+					tmp[UniStrLen(tmp) - 2] == L'l'))
+				{
+					#ifdef	OS_WIN32
+						_snprintf(dst, sizeof(dst), tag, va_arg(args, UINT64));
+					#else	// OS_WIN32
+						snprintf(dst, sizeof(dst), tag, va_arg(args, UINT64));
+					#endif	// OS_WIN32
+				}
+				else
+				{
+					#ifdef	OS_WIN32
+						_snprintf(dst, sizeof(dst), tag, va_arg(args, int));
+					#else	// OS_WIN32
+						snprintf(dst, sizeof(dst), tag, va_arg(args, int));
+					#endif	// OS_WIN32
+				}
+
+				Free(tag);
+				Add(o, CopyStrToUni(dst));
+
+				wp = 0;
+				mode = 0;
+				break;
+			case L'e':
+			case L'E':
+			case L'f':
+			case L'g':
+			case L'G':
+				// double 型
+				tmp[wp++] = c;
+				tmp[wp++] = 0;
+				tag = CopyUniToStr(tmp);
+
+				#ifdef	OS_WIN32
+					_snprintf(dst, sizeof(dst), tag, va_arg(args, double));
+				#else	// OS_WIN32
+					snprintf(dst, sizeof(dst), tag, va_arg(args, double));
+				#endif	// OS_WIN32
+
+				Free(tag);
+				Add(o, CopyStrToUni(dst));
+
+				wp = 0;
+				mode = 0;
+				break;
+			case L'n':
+			case L'p':
+				// ポインタ型
+				tmp[wp++] = c;
+				tmp[wp++] = 0;
+				tag = ZeroMalloc(UniStrSize(tmp) + 32);
+				UniToStr(tag, 0, tmp);
+
+				#ifdef	OS_WIN32
+					_snprintf(dst, sizeof(dst), tag, va_arg(args, void *));
+				#else	// OS_WIN32
+					snprintf(dst, sizeof(dst), tag, va_arg(args, void *));
+				#endif	// OS_WIN32
+
+				Free(tag);
+				Add(o, CopyStrToUni(dst));
+
+				wp = 0;
+				mode = 0;
+				break;
+			case L's':
+			case L'S':
+				// 文字列型
+				tmp[wp++] = c;
+				tmp[wp++] = 0;
+
+				if (ansi_mode == false)
+				{
+					if (c == L'S')
+					{
+						c = L's';
+					}
+					else
+					{
+						c = L'S';
+					}
+				}
+
+				if (c == L's')
+				{
+					target_str = CopyStrToUni(va_arg(args, char *));
+				}
+				else
+				{
+					target_str = CopyUniStr(va_arg(args, wchar_t *));
+				}
+
+				if (target_str == NULL)
+				{
+					target_str = CopyUniStr(L"(null)");
+				}
+
+				padding = 0;
+				left_padding = false;
+				if (tmp[1] == L'-')
+				{
+					// 左詰め
+					if (UniStrLen(tmp) >= 3)
+					{
+						padding = UniToInt(&tmp[2]);
+					}
+					left_padding = true;
+				}
+				else
+				{
+					// 右詰め
+					if (UniStrLen(tmp) >= 2)
+					{
+						padding = UniToInt(&tmp[1]);
+					}
+				}
+
+				target_str_len = UniStrWidth(target_str);
+
+				if (padding > target_str_len)
+				{
+					UINT len = padding - target_str_len;
+					UINT i;
+					padding_str = ZeroMalloc(sizeof(wchar_t) * (len + 1));
+					for (i = 0;i < len;i++)
+					{
+						padding_str[i] = L' ';
+					}
+				}
+				else
+				{
+					padding_str = ZeroMalloc(sizeof(wchar_t));
+				}
+
+				total_len = sizeof(wchar_t) * (UniStrLen(padding_str) + UniStrLen(target_str) + 1);
+				output_str = ZeroMalloc(total_len);
+				output_str[0] = 0;
+
+				if (left_padding == false)
+				{
+					UniStrCat(output_str, total_len, padding_str);
+				}
+				UniStrCat(output_str, total_len, target_str);
+				if (left_padding)
+				{
+					UniStrCat(output_str, total_len, padding_str);
+				}
+
+				Add(o, output_str);
+
+				Free(target_str);
+				Free(padding_str);
+
+				wp = 0;
+				mode = 0;
+				break;
+			default:
+				// 通常の文字列
+				tmp[wp++] = c;
+				break;
+			}
+		}
+	}
+	tmp[wp++] = 0;
+	wp = 0;
+
+	if (UniStrLen(tmp) >= 1)
+	{
+		Add(o, CopyUniStr(tmp));
+	}
+
+	total_size = sizeof(wchar_t);
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t *s = LIST_DATA(o, i);
+		total_size += UniStrLen(s) * sizeof(wchar_t);
+	}
+
+	ret = ZeroMalloc(total_size);
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t *s = LIST_DATA(o, i);
+		UniStrCat(ret, total_size, s);
+		Free(s);
+	}
+
+	ReleaseList(o);
+
+	Free(tmp);
+
+	return ret;
+}
+
+// 文字列の横幅サイズを取得する
+UINT UniStrWidth(wchar_t *str)
+{
+	UINT i, len, ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	ret = 0;
+	len = UniStrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		if (str[i] <= 255)
+		{
+			ret++;
+		}
+		else
+		{
+			ret += 2;
+		}
+	}
+	return ret;
+}
+
+// Unicode 文字列をダンプ表示する
+void DumpUniStr(wchar_t *str)
+{
+	UINT i, len;
+	char *s;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	s = CopyUniToStr(str);
+
+	Print("DumpUniStr: %s\n  ", s);
+
+	len = UniStrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		Print("0x%04X ", str[i]);
+	}
+	Print("\n");
+
+	Free(s);
+}
+
+// 文字列をダンプ表示する
+void DumpStr(char *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	Print("DumpStr: %s\n  ", str);
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		Print("0x%02X ", str[i]);
+	}
+	Print("\n");
+}
+
+// 1 文字 2 バイトの文字列を 1 文字 4 場合の wchar_t に変換する
+wchar_t *Utf16ToWide(USHORT *str)
+{
+	wchar_t *ret;
+	UINT len, i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = 0;
+	while (true)
+	{
+		if (str[len] == 0)
+		{
+			break;
+		}
+		len++;
+	}
+
+	ret = Malloc((len + 1) * sizeof(wchar_t));
+	for (i = 0;i < len + 1;i++)
+	{
+		ret[i] = (wchar_t)str[i];
+	}
+
+	return ret;
+}
+
+// 1 文字 4 バイトの wchar_t 文字列を 1 文字 2 バイトに変換する
+USHORT *WideToUtf16(wchar_t *str)
+{
+	USHORT *ret;
+	UINT len;
+	UINT ret_size;
+	UINT i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = UniStrLen(str);
+
+	ret_size = (len + 1) * 2;
+	ret = Malloc(ret_size);
+
+	for (i = 0;i < len + 1;i++)
+	{
+		ret[i] = (USHORT)str[i];
+	}
+
+	return ret;
+}
+
+// 国際ライブラリの初期化
+void InitInternational()
+{
+#ifdef	OS_UNIX
+	void *d;
+
+	if (iconv_lock != NULL)
+	{
+		return;
+	}
+
+	GetCurrentCharSet(charset, sizeof(charset));
+	d = IconvWideToStrInternal();
+	if (d == (void *)-1)
+	{
+#ifdef	UNIX_MACOS
+		StrCpy(charset, sizeof(charset), "utf8");
+#else	// UNIX_MACOS
+		StrCpy(charset, sizeof(charset), "EUCJP");
+#endif	// UNIX_MACOS
+		d = IconvWideToStrInternal();
+		if (d == (void *)-1)
+		{
+			StrCpy(charset, sizeof(charset), "US");
+		}
+		else
+		{
+			IconvFreeInternal(d);
+		}
+	}
+	else
+	{
+		IconvFreeInternal(d);
+	}
+
+	iconv_lock = NewLockMain();
+
+	iconv_cache_wide_to_str = IconvWideToStrInternal();
+	iconv_cache_str_to_wide = IconvStrToWideInternal();
+#endif	// OS_UNIX
+}
+
+// 国際ライブラリの解放
+void FreeInternational()
+{
+#ifdef	OS_UNIX
+#endif	// OS_UNIX
+}
+
+#ifdef	OS_UNIX
+
+// 文字列を Unicode に変換した場合のサイズを計算する
+UINT UnixCalcStrToUni(char *str)
+{
+	wchar_t *tmp;
+	UINT len, tmp_size;
+	UINT ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	len = StrLen(str);
+	tmp_size = len * 5 + 10;
+	tmp = ZeroMalloc(tmp_size);
+	UnixStrToUni(tmp, tmp_size, str);
+	ret = UniStrLen(tmp);
+	Free(tmp);
+
+	return (ret + 1) * sizeof(wchar_t);
+}
+
+// 文字列を Unicode に変換する
+UINT UnixStrToUni(wchar_t *s, UINT size, char *str)
+{
+	void *d;
+	char *inbuf;
+	size_t insize;
+	char *outbuf;
+	char *outbuf_orig;
+	size_t outsize;
+	wchar_t *tmp;
+	// 引数チェック
+	if (s == NULL || str == NULL)
+	{
+		return 0;
+	}
+
+	d = IconvStrToWide();
+	if (d == (void *)-1)
+	{
+		UniStrCpy(s, size, L"");
+		return 0;
+	}
+
+	inbuf = (char *)str;
+	insize = StrLen(str) + 1;
+	outsize = insize * 5 + 10;
+	outbuf_orig = outbuf = ZeroMalloc(outsize);
+
+	if (iconv((iconv_t)d, (char **)&inbuf, (size_t *)&insize, (char **)&outbuf, (size_t *)&outsize) == (size_t)(-1))
+	{
+		Free(outbuf_orig);
+		UniStrCpy(s, size, L"");
+		IconvFree(d);
+		return 0;
+	}
+
+	tmp = Utf16ToWide((USHORT *)outbuf_orig);
+	Free(outbuf_orig);
+
+	UniStrCpy(s, size, tmp);
+	IconvFree(d);
+
+	Free(tmp);
+
+	return UniStrLen(s);
+}
+
+// Unicode を文字列にした場合のサイズを計算する
+UINT UnixCalcUniToStr(wchar_t *s)
+{
+	char *tmp;
+	UINT tmp_size;
+	UINT ret;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	tmp_size = UniStrLen(s) * 5 + 10;
+	tmp = ZeroMalloc(tmp_size);
+	UnixUniToStr(tmp, tmp_size, s);
+
+	ret = StrSize(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// Unicode を文字列に変換する
+UINT UnixUniToStr(char *str, UINT size, wchar_t *s)
+{
+	USHORT *tmp;
+	char *inbuf;
+	size_t insize;
+	char *outbuf;
+	char *outbuf_orig;
+	size_t outsize;
+	void *d;
+	// 引数チェック
+	if (str == NULL || s == NULL)
+	{
+		return 0;
+	}
+
+	// まず wchar_t 文字列を 2 バイトの並びに変換する
+	tmp = WideToUtf16(s);
+	inbuf = (char *)tmp;
+	insize = (UniStrLen(s) + 1) * 2;
+	outsize = insize * 5 + 10;
+	outbuf_orig = outbuf = ZeroMalloc(outsize);
+
+	d = IconvWideToStr();
+	if (d == (void *)-1)
+	{
+		StrCpy(str, size, "");
+		Free(outbuf);
+		Free(tmp);
+		return 0;
+	}
+
+	if (iconv((iconv_t)d, (char **)&inbuf, (size_t *)&insize, (char **)&outbuf, (size_t *)&outsize) == (size_t)(-1))
+	{
+		Free(outbuf_orig);
+		IconvFree(d);
+		StrCpy(str, size, "");
+		Free(tmp);
+		return 0;
+	}
+
+	StrCpy(str, size, outbuf_orig);
+
+	Free(outbuf_orig);
+	IconvFree(d);
+	Free(tmp);
+
+	return StrLen(str);
+}
+
+// whcar_t を char に変換する
+void *IconvWideToStrInternal()
+{
+	return (void *)iconv_open(charset, IsBigEndian() ? "UTF-16BE" : "UTF-16LE");
+}
+
+// char を wchar_t に変換する
+void *IconvStrToWideInternal()
+{
+	return (void *)iconv_open(IsBigEndian() ? "UTF-16BE" : "UTF-16LE", charset);
+}
+
+// ハンドルを閉じる
+int IconvFreeInternal(void *d)
+{
+	iconv_close((iconv_t)d);
+	return 0;
+}
+
+void *IconvWideToStr()
+{
+	if (iconv_cache_wide_to_str == (void *)-1)
+	{
+		return (void *)-1;
+	}
+
+	Lock(iconv_lock);
+
+	return iconv_cache_wide_to_str;
+}
+
+void *IconvStrToWide()
+{
+	if (iconv_cache_str_to_wide == (void *)-1)
+	{
+		return (void *)-1;
+	}
+
+	Lock(iconv_lock);
+
+	return iconv_cache_str_to_wide;
+}
+
+int IconvFree(void *d)
+{
+	Unlock(iconv_lock);
+
+	return 0;
+}
+
+// 現在使用されている文字セットを環境変数から取得する
+void GetCurrentCharSet(char *name, UINT size)
+{
+	char tmp[MAX_SIZE];
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	if (GetEnv("LANG", tmp, sizeof(tmp)) == false)
+	{
+		if (GetEnv("LOCATION", tmp, sizeof(tmp)) == false)
+		{
+			StrCpy(tmp, sizeof(tmp), "ja_JP.eucJP");
+		}
+	}
+
+	Trim(tmp);
+
+	t = ParseToken(tmp, ".");
+	if (t->NumTokens >= 2)
+	{
+		StrCpy(name, size, t->Token[1]);
+	}
+	else
+	{
+		if (t->NumTokens == 1)
+		{
+			StrCpy(name, size, t->Token[0]);
+		}
+		else
+		{
+			StrCpy(name, size, "eucJP");
+		}
+	}
+	FreeToken(t);
+
+	StrUpper(name);
+}
+
+#endif	// OS_UNIX
+
+// 指定された文字列が空白かどうかチェック
+bool UniIsEmptyStr(wchar_t *str)
+{
+	return IsEmptyUniStr(str);
+}
+bool IsEmptyUniStr(wchar_t *str)
+{
+	bool ret;
+	wchar_t *s;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return true;
+	}
+
+	s = UniCopyStr(str);
+
+	UniTrim(s);
+	if (UniStrLen(s) == 0)
+	{
+		ret = true;
+	}
+	else
+	{
+		ret = false;
+	}
+
+	Free(s);
+
+	return ret;
+}
+
+// 指定された文字列が数字かどうかチェック
+bool UniIsNum(wchar_t *str)
+{
+	char tmp[MAX_SIZE];
+
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	return IsNum(tmp);
+}
+
+
+// 中身が無い Unicode トークンリスト
+UNI_TOKEN_LIST *UniNullToken()
+{
+	UNI_TOKEN_LIST *ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+	ret->Token = ZeroMalloc(0);
+
+	return ret;
+}
+
+// 中身が無い Unicode トークンリスト (別名)
+UNI_TOKEN_LIST *NullUniToken()
+{
+	return UniNullToken();
+}
+
+// トークンリストを Unicode トークンリストに変換する
+UNI_TOKEN_LIST *TokenListToUniTokenList(TOKEN_LIST *src)
+{
+	UNI_TOKEN_LIST *ret;
+	UINT i;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+	ret->NumTokens = src->NumTokens;
+	ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
+
+	for (i = 0;i < ret->NumTokens;i++)
+	{
+		ret->Token[i] = CopyStrToUni(src->Token[i]);
+	}
+
+	return ret;
+}
+
+// Unicode トークンリストをトークンリストに変換する
+TOKEN_LIST *UniTokenListToTokenList(UNI_TOKEN_LIST *src)
+{
+	TOKEN_LIST *ret;
+	UINT i;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->NumTokens = src->NumTokens;
+	ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+
+	for (i = 0;i < ret->NumTokens;i++)
+	{
+		ret->Token[i] = CopyUniToStr(src->Token[i]);
+	}
+
+	return ret;
+}
+
+// Unicode 文字列コピー
+wchar_t *UniCopyStr(wchar_t *str)
+{
+	return CopyUniStr(str);
+}
+
+// トークンリストのコピー
+UNI_TOKEN_LIST *UniCopyToken(UNI_TOKEN_LIST *src)
+{
+	UNI_TOKEN_LIST *ret;
+	UINT i;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->NumTokens = src->NumTokens;
+	ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
+	for (i = 0;i < ret->NumTokens;i++)
+	{
+		ret->Token[i] = CopyUniStr(src->Token[i]);
+	}
+
+	return ret;
+}
+
+// コマンドライン文字列をパースする
+UNI_TOKEN_LIST *UniParseCmdLine(wchar_t *str)
+{
+	UNI_TOKEN_LIST *t;
+	LIST *o;
+	UINT i, len, wp, mode;
+	wchar_t c;
+	wchar_t *tmp;
+	bool ignore_space = false;
+	// 引数チェック
+	if (str == NULL)
+	{
+		// トークン無し
+		return UniNullToken();
+	}
+
+	o = NewListFast(NULL);
+	tmp = Malloc(UniStrSize(str) + 32);
+
+	wp = 0;
+	mode = 0;
+
+	len = UniStrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		c = str[i];
+
+		switch (mode)
+		{
+		case 0:
+			// 次のトークンを発見するモード
+			if (c == L' ' || c == L'\t')
+			{
+				// 次の文字へ進める
+			}
+			else
+			{
+				// トークンの開始
+				if (c == L'\"')
+				{
+					if (str[i + 1] == L'\"')
+					{
+						// 2 重の " は 1 個の " 文字として見なす
+						tmp[wp++] = L'\"';
+						i++;
+					}
+					else
+					{
+						// 1 個の " はスペース無視フラグを有効にする
+						ignore_space = true;
+					}
+				}
+				else
+				{
+					tmp[wp++] = c;
+				}
+
+				mode = 1;
+			}
+			break;
+
+		case 1:
+			if (ignore_space == false && (c == L' ' || c == L'\t'))
+			{
+				// トークンの終了
+				tmp[wp++] = 0;
+				wp = 0;
+
+				Insert(o, UniCopyStr(tmp));
+				mode = 0;
+			}
+			else
+			{
+				if (c == L'\"')
+				{
+					if (str[i + 1] == L'\"')
+					{
+						// 2 重の " は 1 個の " 文字として見なす
+						tmp[wp++] = L'\"';
+						i++;
+					}
+					else
+					{
+						if (ignore_space == false)
+						{
+							// 1 個の " はスペース無視フラグを有効にする
+							ignore_space = true;
+						}
+						else
+						{
+							// スペース無視フラグを無効にする
+							ignore_space = false;
+						}
+					}
+				}
+				else
+				{
+					tmp[wp++] = c;
+				}
+			}
+			break;
+		}
+	}
+
+	if (wp != 0)
+	{
+		tmp[wp++] = 0;
+		Insert(o, UniCopyStr(tmp));
+	}
+
+	Free(tmp);
+
+	t = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(wchar_t *) * t->NumTokens);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+
+	return t;
+}
+
+// Unicode 文字列を 64bit 整数に変換する
+UINT64 UniToInt64(wchar_t *str)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	return ToInt64(tmp);
+}
+
+// 64bit 整数を Unicode 文字列に変換する
+void UniToStr64(wchar_t *str, UINT64 value)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	ToStr64(tmp, value);
+
+	StrToUni(str, 0, tmp);
+}
+
+// ANSI を UTF に変換する
+UINT StrToUtf(char *utfstr, UINT size, char *str)
+{
+	char *tmp;
+	// 引数チェック
+	if (utfstr == NULL || str == NULL)
+	{
+		StrCpy(utfstr, size, "");
+		return 0;
+	}
+
+	tmp = CopyStrToUtf(str);
+
+	StrCpy(utfstr, size, tmp);
+
+	Free(tmp);
+
+	return StrLen(utfstr);
+}
+
+// UTF を ANSI に変換する
+UINT UtfToStr(char *str, UINT size, char *utfstr)
+{
+	char *tmp;
+	// 引数チェック
+	if (str == NULL || utfstr == NULL)
+	{
+		StrCpy(str, size, "");
+		return 0;
+	}
+
+	tmp = CopyUtfToStr(utfstr);
+
+	StrCpy(str, size, tmp);
+
+	Free(tmp);
+
+	return StrLen(str);
+}
+
+// Unicode を UTF に変換する
+UINT UniToUtf(char *utfstr, UINT size, wchar_t *unistr)
+{
+	char *tmp;
+	// 引数チェック
+	if (utfstr == NULL || unistr == NULL)
+	{
+		StrCpy(utfstr, size, "");
+		return 0;
+	}
+
+	tmp = CopyUniToStr(unistr);
+
+	StrCpy(utfstr, size, tmp);
+
+	Free(tmp);
+
+	return StrLen(utfstr);
+}
+
+// UTF を Unicode に変換する
+UINT UtfToUni(wchar_t *unistr, UINT size, char *utfstr)
+{
+	wchar_t *tmp;
+	// 引数チェック
+	if (unistr == NULL || utfstr == NULL)
+	{
+		UniStrCpy(unistr, size, L"");
+		return 0;
+	}
+
+	tmp = CopyUtfToUni(utfstr);
+
+	UniStrCpy(unistr, size, tmp);
+
+	Free(tmp);
+
+	return UniStrLen(unistr);
+}
+
+// UTF8 文字列を Unicode 文字列にコピーする
+wchar_t *CopyUtfToUni(char *utfstr)
+{
+	UINT size;
+	wchar_t *ret;
+	UINT utfstr_len;
+	// 引数チェック
+	if (utfstr == NULL)
+	{
+		return NULL;
+	}
+
+	utfstr_len = StrLen(utfstr);
+
+	size = CalcUtf8ToUni((BYTE *)utfstr, utfstr_len);
+	ret = ZeroMalloc(size + sizeof(wchar_t));
+	Utf8ToUni(ret, size, (BYTE *)utfstr, utfstr_len);
+
+	return ret;
+}
+
+// UTF8 文字列を ANSI 文字列にコピーする
+char *CopyUtfToStr(char *utfstr)
+{
+	wchar_t *uni;
+	char *ret;
+	// 引数チェック
+	if (utfstr == NULL)
+	{
+		return NULL;
+	}
+
+	uni = CopyUtfToUni(utfstr);
+	if (uni == NULL)
+	{
+		return CopyStr("");
+	}
+
+	ret = CopyUniToStr(uni);
+
+	Free(uni);
+
+	return ret;
+}
+
+// Unicode 文字列を ANSI 文字列にコピーする
+char *CopyUniToStr(wchar_t *unistr)
+{
+	char *str;
+	UINT str_size;
+	// 引数チェック
+	if (unistr == NULL)
+	{
+		return NULL;
+	}
+
+	str_size = CalcUniToStr(unistr);
+	if (str_size == 0)
+	{
+		return CopyStr("");
+	}
+	str = Malloc(str_size);
+	UniToStr(str, str_size, unistr);
+
+	return str;
+}
+
+// ANSI 文字列を Unicode 文字列にコピーする
+wchar_t *CopyStrToUni(char *str)
+{
+	wchar_t *uni;
+	UINT uni_size;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	uni_size = CalcStrToUni(str);
+	if (uni_size == 0)
+	{
+		return CopyUniStr(L"");
+	}
+	uni = Malloc(uni_size);
+	StrToUni(uni, uni_size, str);
+
+	return uni;
+}
+
+// Unicode 文字列を UTF8 文字列にコピーする
+char *CopyUniToUtf(wchar_t *unistr)
+{
+	UINT size;
+	char *ret;
+	// 引数チェック
+	if (unistr == NULL)
+	{
+		return NULL;
+	}
+
+	size = CalcUniToUtf8(unistr);
+	ret = ZeroMalloc(size + sizeof(char));
+
+	UniToUtf8((char *)ret, size, unistr);
+
+	return ret;
+}
+
+// ANSI 文字列を UTF8 文字列にコピーする
+char *CopyStrToUtf(char *str)
+{
+	wchar_t *unistr;
+	char *ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	unistr = CopyStrToUni(str);
+	if (unistr == NULL)
+	{
+		return CopyStr("");
+	}
+
+	ret = CopyUniToUtf(unistr);
+
+	Free(unistr);
+
+	return ret;
+}
+
+// Unicode 文字列をコピーする
+wchar_t *CopyUniStr(wchar_t *str)
+{
+	UINT len;
+	wchar_t *dst;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = UniStrLen(str);
+	dst = Malloc((len + 1) * sizeof(wchar_t));
+	UniStrCpy(dst, 0, str);
+
+	return dst;
+}
+
+// 安全な文字列かどうかチェック
+bool IsSafeUniStr(wchar_t *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	len = UniStrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		if (IsSafeUniChar(str[i]) == false)
+		{
+			return false;
+		}
+	}
+	if (str[0] == L' ')
+	{
+		return false;
+	}
+	if (len != 0)
+	{
+		if (str[len - 1] == L' ')
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+// 安全な文字かどうかチェック
+bool IsSafeUniChar(wchar_t c)
+{
+	UINT i, len;
+	wchar_t *check_str =
+		L"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+		L"abcdefghijklmnopqrstuvwxyz"
+		L"0123456789"
+		L" ()-_#%&.";
+
+	len = UniStrLen(check_str);
+	for (i = 0;i < len;i++)
+	{
+		if (c == check_str[i])
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+// UTF-8 文字列を ANSI 文字列に変換する
+UINT Utf8ToStr(char *str, UINT str_size, BYTE *u, UINT size)
+{
+	UINT ret, uni_size;
+	wchar_t *tmp;
+	// 引数チェック
+	if (u == NULL || str == NULL)
+	{
+		return 0;
+	}
+
+	// Unicode に変換する
+	uni_size = CalcUtf8ToUni(u, size);
+	if (uni_size == 0)
+	{
+		if (str_size >= 1)
+		{
+			StrCpy(str, 0, "");
+			return 0;
+		}
+	}
+	tmp = Malloc(uni_size);
+	Utf8ToUni(tmp, uni_size, u, size);
+
+	// ANSI に変換する
+	ret = UniToStr(str, str_size, tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// UTF-8 文字列を ANSI 文字列に変換した場合に必要なサイズを取得する
+UINT CalcUtf8ToStr(BYTE *u, UINT size)
+{
+	UINT ret, uni_size;
+	wchar_t *tmp;
+	// 引数チェック
+	if (u == NULL)
+	{
+		return 0;
+	}
+
+	// Unicode に変換する
+	uni_size = CalcUtf8ToUni(u, size);
+	if (uni_size == 0)
+	{
+		return 0;
+	}
+	tmp = Malloc(uni_size);
+	Utf8ToUni(tmp, uni_size, u, size);
+
+	// ANSI に変換する
+	ret = CalcUniToStr(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// ANSI 文字列を UTF-8 文字列に変換する
+UINT StrToUtf8(BYTE *u, UINT size, char *str)
+{
+	UINT ret, uni_size;
+	wchar_t *tmp;
+	// 引数チェック
+	if (u == NULL || str == NULL)
+	{
+		return 0;
+	}
+
+	// Unicode に変換する
+	uni_size = CalcStrToUni(str);
+	if (uni_size == 0)
+	{
+		return 0;
+	}
+	tmp = Malloc(uni_size);
+	StrToUni(tmp, uni_size, str);
+
+	// UTF-8 に変換する
+	ret = UniToUtf8(u, size, tmp);
+
+	Free(tmp);
+
+	return ret;
+}
+
+// ANSI 文字列を UTF-8 文字列に変換するために必要なサイズを取得する
+UINT CalcStrToUtf8(char *str)
+{
+	UINT ret;
+	UINT uni_size;
+	wchar_t *tmp;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	// Unicode に変換する
+	uni_size = CalcStrToUni(str);
+	if (uni_size == 0)
+	{
+		return 0;
+	}
+	tmp = Malloc(uni_size);
+	StrToUni(tmp, uni_size, str);
+
+	// UTF-8 に変換した場合のサイズを取得する
+	ret = CalcUniToUtf8(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// Unicode 文字列を ANSI 文字列に変換する
+UINT UniToStr(char *str, UINT size, wchar_t *s)
+{
+#ifdef	OS_WIN32
+	UINT ret;
+	char *tmp;
+	UINT new_size;
+	// 引数チェック
+	if (s == NULL || str == NULL)
+	{
+		return 0;
+	}
+
+	new_size = CalcUniToStr(s);
+	if (new_size == 0)
+	{
+		if (size >= 1)
+		{
+			StrCpy(str, 0, "");
+		}
+		return 0;
+	}
+	tmp = Malloc(new_size);
+	tmp[0] = 0;
+	wcstombs(tmp, s, new_size);
+	tmp[new_size - 1] = 0;
+	ret = StrCpy(str, size, tmp);
+	Free(tmp);
+
+	return ret;
+#else	// OS_WIN32
+	return UnixUniToStr(str, size, s);
+#endif	// OS_WIN32
+}
+
+// Unicode 文字列を ANSI 文字列に変換するための必要なバイト数を取得する
+UINT CalcUniToStr(wchar_t *s)
+{
+#ifdef	OS_WIN32
+	UINT ret;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	ret = (UINT)wcstombs(NULL, s, UniStrLen(s));
+	if (ret == (UINT)-1)
+	{
+		return 0;
+	}
+
+	return ret + 1;
+#else	// OS_WIN32
+	return UnixCalcUniToStr(s);
+#endif	// OS_WIN32
+}
+
+// ANSI 文字列を Unicode 文字列に変換する
+UINT StrToUni(wchar_t *s, UINT size, char *str)
+{
+#ifdef	OS_WIN32
+	UINT ret;
+	wchar_t *tmp;
+	UINT new_size;
+	// 引数チェック
+	if (s == NULL || str == NULL)
+	{
+		return 0;
+	}
+
+	new_size = CalcStrToUni(str);
+	if (new_size == 0)
+	{
+		if (size >= 2)
+		{
+			UniStrCpy(s, 0, L"");
+		}
+		return 0;
+	}
+	tmp = Malloc(new_size);
+	tmp[0] = 0;
+	mbstowcs(tmp, str, StrLen(str));
+	tmp[(new_size - 1) / sizeof(wchar_t)] = 0;
+	ret = UniStrCpy(s, size, tmp);
+	Free(tmp);
+
+	return ret;
+#else	// OS_WIN32
+	return UnixStrToUni(s, size, str);
+#endif	// OS_WIN32
+}
+
+// ANSI 文字列を Unicode 文字列に変換するための必要なバイト数を取得する
+UINT CalcStrToUni(char *str)
+{
+#ifdef	OS_WIN32
+	UINT ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	ret = (UINT)mbstowcs(NULL, str, StrLen(str));
+	if (ret == (UINT)-1)
+	{
+		return 0;
+	}
+
+	return (ret + 1) * sizeof(wchar_t);
+#else	// OS_WIN32
+	return UnixCalcStrToUni(str);
+#endif	// OS_WIN32
+}
+
+// UTF-8 文字列を Unicode 文字列に変換する
+UINT Utf8ToUni(wchar_t *s, UINT size, BYTE *u, UINT u_size)
+{
+	UINT i, wp, num;
+	// 引数チェック
+	if (s == NULL || u == NULL)
+	{
+		return 0;
+	}
+	if (size == 0)
+	{
+		size = 0x3fffffff;
+	}
+	if (u_size == 0)
+	{
+		u_size = StrLen((char *)u);
+	}
+
+	i = 0;
+	wp = 0;
+	num = 0;
+	while (true)
+	{
+		UINT type;
+		wchar_t c;
+		BYTE c1, c2;
+
+		type = GetUtf8Type(u, u_size, i);
+		if (type == 0)
+		{
+			break;
+		}
+		switch (type)
+		{
+		case 1:
+			c1 = 0;
+			c2 = u[i];
+			break;
+		case 2:
+			c1 = (((u[i] & 0x1c) >> 2) & 0x07);
+			c2 = (((u[i] & 0x03) << 6) & 0xc0) | (u[i + 1] & 0x3f);
+			break;
+		case 3:
+			c1 = ((((u[i] & 0x0f) << 4) & 0xf0)) | (((u[i + 1] & 0x3c) >> 2) & 0x0f);
+			c2 = (((u[i + 1] & 0x03) << 6) & 0xc0) | (u[i + 2] & 0x3f);
+			break;
+		}
+		i += type;
+
+		c = 0;
+
+		if (IsBigEndian())
+		{
+			if (sizeof(wchar_t) == 2)
+			{
+				((BYTE *)&c)[0] = c1;
+				((BYTE *)&c)[1] = c2;
+			}
+			else
+			{
+				((BYTE *)&c)[2] = c1;
+				((BYTE *)&c)[3] = c2;
+			}
+		}
+		else
+		{
+			((BYTE *)&c)[0] = c2;
+			((BYTE *)&c)[1] = c1;
+		}
+
+		if (wp < ((size / sizeof(wchar_t)) - 1))
+		{
+			s[wp++] = c;
+			num++;
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	if (wp < (size / sizeof(wchar_t)))
+	{
+		s[wp++] = 0;
+	}
+
+	return num;
+}
+
+// UTF-8 を Unicode に変換した場合のバッファサイズを取得する
+UINT CalcUtf8ToUni(BYTE *u, UINT u_size)
+{
+	// 引数チェック
+	if (u == NULL)
+	{
+		return 0;
+	}
+	if (u_size == 0)
+	{
+		u_size = StrLen((char *)u);
+	}
+
+	return (Utf8Len(u, u_size) + 1) * sizeof(wchar_t);
+}
+
+// UTF-8 文字列の文字数を取得する
+UINT Utf8Len(BYTE *u, UINT size)
+{
+	UINT i, num;
+	// 引数チェック
+	if (u == NULL)
+	{
+		return 0;
+	}
+	if (size == 0)
+	{
+		size = StrLen((char *)u);
+	}
+
+	i = num = 0;
+	while (true)
+	{
+		UINT type;
+
+		type = GetUtf8Type(u, size, i);
+		if (type == 0)
+		{
+			break;
+		}
+		i += type;
+		num++;
+	}
+
+	return num;
+}
+
+// Unicode 文字列を UTF-8 文字列に変換する
+UINT UniToUtf8(BYTE *u, UINT size, wchar_t *s)
+{
+	UINT i, len, type, wp;
+	// 引数チェック
+	if (u == NULL || s == NULL)
+	{
+		return 0;
+	}
+	if (size == 0)
+	{
+		size = 0x3fffffff;
+	}
+
+	len = UniStrLen(s);
+	wp = 0;
+	for (i = 0;i < len;i++)
+	{
+		BYTE c1, c2;
+		wchar_t c = s[i];
+
+		if (IsBigEndian())
+		{
+			if (sizeof(wchar_t) == 2)
+			{
+				c1 = ((BYTE *)&c)[0];
+				c2 = ((BYTE *)&c)[1];
+			}
+			else
+			{
+				c1 = ((BYTE *)&c)[2];
+				c2 = ((BYTE *)&c)[3];
+			}
+		}
+		else
+		{
+			c1 = ((BYTE *)&c)[1];
+			c2 = ((BYTE *)&c)[0];
+		}
+
+		type = GetUniType(s[i]);
+		switch (type)
+		{
+		case 1:
+			if (wp < size)
+			{
+				u[wp++] = c2;
+			}
+			break;
+		case 2:
+			if (wp < size)
+			{
+				u[wp++] = 0xc0 | (((((c1 & 0x07) << 2) & 0x1c)) | (((c2 & 0xc0) >> 6) & 0x03));
+			}
+			if (wp < size)
+			{
+				u[wp++] = 0x80 | (c2 & 0x3f);
+			}
+			break;
+		case 3:
+			if (wp < size)
+			{
+				u[wp++] = 0xe0 | (((c1 & 0xf0) >> 4) & 0x0f);
+			}
+			if (wp < size)
+			{
+				u[wp++] = 0x80 | (((c1 & 0x0f) << 2) & 0x3c) | (((c2 & 0xc0) >> 6) & 0x03);
+			}
+			if (wp < size)
+			{
+				u[wp++] = 0x80 | (c2 & 0x3f);
+			}
+			break;
+		}
+	}
+	if (wp < size)
+	{
+		u[wp] = 0;
+	}
+	return wp;
+}
+
+// Unicode 文字列を UTF-8 文字列に変換した場合の文字列長を計算する
+UINT CalcUniToUtf8(wchar_t *s)
+{
+	UINT i, len, size;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	size = 0;
+	len = UniStrLen(s);
+	for (i = 0;i < len;i++)
+	{
+		size += GetUniType(s[i]);
+	}
+
+	return size;
+}
+
+// s で始まる UTF-8 文字列の offset 番地の最初の 1 文字が何バイトで構成されているかを取得
+UINT GetUtf8Type(BYTE *s, UINT size, UINT offset)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+	if ((offset + 1) > size)
+	{
+		return 0;
+	}
+	if ((s[offset] & 0x80) == 0)
+	{
+		// 1 バイト
+		return 1;
+	}
+	if ((s[offset] & 0x20) == 0)
+	{
+		// 2 バイト
+		if ((offset + 2) > size)
+		{
+			return 0;
+		}
+		return 2;
+	}
+	// 3 バイト
+	if ((offset + 3) > size)
+	{
+		return 0;
+	}
+	return 3;
+}
+
+// 文字 c を UTF-8 に変換した場合の種類 (バイト数)
+UINT GetUniType(wchar_t c)
+{
+	BYTE c1, c2;
+
+	if (IsBigEndian())
+	{
+		if (sizeof(wchar_t) == 2)
+		{
+			c1 = ((BYTE *)&c)[0];
+			c2 = ((BYTE *)&c)[1];
+		}
+		else
+		{
+			c1 = ((BYTE *)&c)[2];
+			c2 = ((BYTE *)&c)[3];
+		}
+	}
+	else
+	{
+		c1 = ((BYTE *)&c)[1];
+		c2 = ((BYTE *)&c)[0];
+	}
+
+	if (c1 == 0)
+	{
+		if (c2 <= 0x7f)
+		{
+			// 1 バイト
+			return 1;
+		}
+		else
+		{
+			// 2 バイト
+			return 2;
+		}
+	}
+	if ((c1 & 0xf8) == 0)
+	{
+		// 2 バイト
+		return 2;
+	}
+	// 3 バイト
+	return 3;
+}
+
+// 文字列の置換 (大文字小文字を区別しない)
+UINT UniReplaceStri(wchar_t *dst, UINT size, wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword)
+{
+	return UniReplaceStrEx(dst, size, string, old_keyword, new_keyword, false);
+}
+
+// 文字列の置換 (大文字小文字を区別する)
+UINT UniReplaceStr(wchar_t *dst, UINT size, wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword)
+{
+	return UniReplaceStrEx(dst, size, string, old_keyword, new_keyword, true);
+}
+
+// 文字列の置換
+UINT UniReplaceStrEx(wchar_t *dst, UINT size, wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword, bool case_sensitive)
+{
+	UINT i, j, num, len_string, len_old, len_new, len_ret, wp;
+	wchar_t *ret;
+	// 引数チェック
+	if (string == NULL || old_keyword == NULL || new_keyword == NULL)
+	{
+		return 0;
+	}
+
+	// 文字列長の取得
+	len_string = UniStrLen(string);
+	len_old = UniStrLen(old_keyword);
+	len_new = UniStrLen(new_keyword);
+
+	// 最終文字列長の取得
+	len_ret = UniCalcReplaceStrEx(string, old_keyword, new_keyword, case_sensitive);
+	// メモリ確保
+	ret = Malloc((len_ret + 1) * sizeof(wchar_t));
+	ret[len_ret] = 0;
+
+	// 検索と置換
+	i = j = num = wp = 0;
+	while (true)
+	{
+		i = UniSearchStrEx(string, old_keyword, i, case_sensitive);
+		if (i == INFINITE)
+		{
+			Copy(&ret[wp], &string[j], (len_string - j) * sizeof(wchar_t));
+			wp += len_string - j;
+			break;
+		}
+		num++;
+		Copy(&ret[wp], &string[j], (i - j) * sizeof(wchar_t));
+		wp += i - j;
+		Copy(&ret[wp], new_keyword, len_new * sizeof(wchar_t));
+		wp += len_new;
+		i += len_old;
+		j = i;
+	}
+
+	// 検索結果のコピー
+	UniStrCpy(dst, size, ret);
+
+	// メモリ解放
+	Free(ret);
+
+	return num;
+}
+
+// 文字列の置換後の文字列長を計算する
+UINT UniCalcReplaceStrEx(wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword, bool case_sensitive)
+{
+	UINT i, num;
+	UINT len_string, len_old, len_new;
+	// 引数チェック
+	if (string == NULL || old_keyword == NULL || new_keyword == NULL)
+	{
+		return 0;
+	}
+
+	// 文字列長の取得
+	len_string = UniStrLen(string);
+	len_old = UniStrLen(old_keyword);
+	len_new = UniStrLen(new_keyword);
+
+	if (len_old == len_new)
+	{
+		return len_string;
+	}
+
+	// 検索処理
+	num = 0;
+	i = 0;
+	while (true)
+	{
+		i = UniSearchStrEx(string, old_keyword, i, case_sensitive);
+		if (i == INFINITE)
+		{
+			break;
+		}
+		i += len_old;
+		num++;
+	}
+
+	// 計算
+	return len_string + len_new * num - len_old * num;
+}
+
+// 文字列の検索 (大文字 / 小文字を区別する)
+UINT UniSearchStr(wchar_t *string, wchar_t *keyword, UINT start)
+{
+	return UniSearchStrEx(string, keyword, start, true);
+}
+
+// 文字列の検索 (大文字 / 小文字を区別しない)
+UINT UniSearchStri(wchar_t *string, wchar_t *keyword, UINT start)
+{
+	return UniSearchStrEx(string, keyword, start, false);
+}
+
+// 文字列 string から文字列 keyword を検索して最初に見つかった文字の場所を返す
+// (1文字目に見つかったら 0, 見つからなかったら INFINITE)
+UINT UniSearchStrEx(wchar_t *string, wchar_t *keyword, UINT start, bool case_sensitive)
+{
+	UINT len_string, len_keyword;
+	UINT i;
+	wchar_t *cmp_string, *cmp_keyword;
+	bool found;
+	// 引数チェック
+	if (string == NULL || keyword == NULL)
+	{
+		return INFINITE;
+	}
+
+	// string の長さを取得
+	len_string = UniStrLen(string);
+	if (len_string <= start)
+	{
+		// start の値が不正
+		return INFINITE;
+	}
+
+	// keyword の長さを取得
+	len_keyword = UniStrLen(keyword);
+	if (len_keyword == 0)
+	{
+		// キーワードが無い
+		return INFINITE;
+	}
+
+	if (len_string < len_keyword)
+	{
+		return INFINITE;
+	}
+
+	if (len_string == len_keyword)
+	{
+		if (case_sensitive)
+		{
+			if (UniStrCmp(string, keyword) == 0)
+			{
+				return 0;
+			}
+			else
+			{
+				return INFINITE;
+			}
+		}
+		else
+		{
+			if (UniStrCmpi(string, keyword) == 0)
+			{
+				return 0;
+			}
+			else
+			{
+				return INFINITE;
+			}
+		}
+	}
+
+	if (case_sensitive)
+	{
+		cmp_string = string;
+		cmp_keyword = keyword;
+	}
+	else
+	{
+		cmp_string = Malloc((len_string + 1) * sizeof(wchar_t));
+		UniStrCpy(cmp_string, (len_string + 1) * sizeof(wchar_t), string);
+		cmp_keyword = Malloc((len_keyword + 1) * sizeof(wchar_t));
+		UniStrCpy(cmp_keyword, (len_keyword + 1) * sizeof(wchar_t), keyword);
+		UniStrUpper(cmp_string);
+		UniStrUpper(cmp_keyword);
+	}
+
+	// 検索
+	found = false;
+	for (i = start;i < (len_string - len_keyword + 1);i++)
+	{
+		// 比較する
+		if (!wcsncmp(&cmp_string[i], cmp_keyword, len_keyword))
+		{
+			// 発見した
+			found = true;
+			break;
+		}
+	}
+
+	if (case_sensitive == false)
+	{
+		// メモリ解放
+		Free(cmp_keyword);
+		Free(cmp_string);
+	}
+
+	if (found == false)
+	{
+		return INFINITE;
+	}
+	return i;
+}
+
+// トークンリストの解放
+void UniFreeToken(UNI_TOKEN_LIST *tokens)
+{
+	UINT i;
+	if (tokens == NULL)
+	{
+		return;
+	}
+	for (i = 0;i < tokens->NumTokens;i++)
+	{
+		Free(tokens->Token[i]);
+	}
+	Free(tokens->Token);
+	Free(tokens);
+}
+
+// UNIX 版トークンのパース
+UNI_TOKEN_LIST *UnixUniParseToken(wchar_t *src, wchar_t *separator)
+{
+	UNI_TOKEN_LIST *ret;
+	TOKEN_LIST *t;
+	char *src_s;
+	char *sep_s;
+
+	// 引数チェック
+	if (src == NULL || separator == NULL)
+	{
+		ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+		ret->Token = ZeroMalloc(0);
+		return ret;
+	}
+
+	src_s = CopyUniToStr(src);
+	sep_s = CopyUniToStr(separator);
+
+	t = ParseToken(src_s, sep_s);
+
+	ret = TokenListToUniTokenList(t);
+	FreeToken(t);
+
+	Free(src_s);
+	Free(sep_s);
+
+	return ret;
+}
+
+// トークンのパース
+UNI_TOKEN_LIST *UniParseToken(wchar_t *src, wchar_t *separator)
+{
+#ifdef	OS_WIN32
+	UNI_TOKEN_LIST *ret;
+	wchar_t *tmp;
+	wchar_t *str1, *str2;
+	UINT len, num;
+
+#ifdef	OS_UNIX
+	wchar_t *state = NULL;
+#endif	// OS_UNIX
+
+	// 引数チェック
+	if (src == NULL)
+	{
+		ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+		ret->Token = ZeroMalloc(0);
+		return ret;
+	}
+	if (separator == NULL)
+	{
+		separator = L" .\t\r\n";
+	}
+	len = UniStrLen(src);
+	str1 = Malloc((len + 1) * sizeof(wchar_t));
+	str2 = Malloc((len + 1) * sizeof(wchar_t));
+	UniStrCpy(str1, 0, src);
+	UniStrCpy(str2, 0, src);
+
+	Lock(token_lock);
+	{
+		tmp = wcstok(str1, separator
+#ifdef	OS_UNIX
+			, &state
+#endif	// OS_UNIX
+			);
+		num = 0;
+		while (tmp != NULL)
+		{
+			num++;
+			tmp = wcstok(NULL, separator
+#ifdef	OS_UNIX
+				, &state
+#endif	// OS_UNIX
+				);
+		}
+		ret = Malloc(sizeof(UNI_TOKEN_LIST));
+		ret->NumTokens = num;
+		ret->Token = (wchar_t **)Malloc(sizeof(wchar_t *) * num);
+		num = 0;
+		tmp = wcstok(str2, separator
+#ifdef	OS_UNIX
+			, &state
+#endif	// OS_UNIX
+			);
+		while (tmp != NULL)
+		{
+			ret->Token[num] = (wchar_t *)Malloc((UniStrLen(tmp) + 1) * sizeof(wchar_t));
+			UniStrCpy(ret->Token[num], 0, tmp);
+			num++;
+			tmp = wcstok(NULL, separator
+#ifdef	OS_UNIX
+				, &state
+#endif	// OS_UNIX
+				);
+		}
+	}
+	Unlock(token_lock);
+
+	Free(str1);
+	Free(str2);
+	return ret;
+#else	// OS_WIN32
+	return UnixUniParseToken(src, separator);
+#endif	// OS_WIN32
+}
+
+// 1 行を標準入力から取得
+bool UniGetLine(wchar_t *str, UINT size)
+{
+#ifdef	OS_WIN32
+	return UniGetLineWin32(str, size);
+#else	// OS_WIN32
+	return UniGetLineUnix(str, size);
+#endif	// OS_WIN32
+}
+void AnsiGetLineUnix(char *str, UINT size)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		char tmp[MAX_SIZE];
+		fgets(tmp, sizeof(tmp) - 1, stdin);
+		return;
+	}
+	if (size <= 1)
+	{
+		return;
+	}
+
+	// 標準入力からデータを読み込み
+	fgets(str, (int)(size - 1), stdin);
+
+	TrimCrlf(str);
+}
+bool UniGetLineUnix(wchar_t *str, UINT size)
+{
+	char *str_a;
+	UINT str_a_size = size;
+	if (str == NULL || size < sizeof(wchar_t))
+	{
+		return false;
+	}
+	if (str_a_size >= 0x7fffffff)
+	{
+		str_a_size = MAX_SIZE;
+	}
+	str_a_size *= 2;
+
+	str_a = ZeroMalloc(str_a_size);
+
+	AnsiGetLineUnix(str_a, str_a_size);
+
+	StrToUni(str, size, str_a);
+
+	Free(str_a);
+
+	return true;
+}
+bool UniGetLineWin32(wchar_t *str, UINT size)
+{
+	bool ret = false;
+
+#ifdef	OS_WIN32
+	ret = Win32InputW(str, size);
+#endif	// OS_WIN32
+
+	return ret;
+}
+
+// 末尾の \r \n を削除
+void UniTrimCrlf(wchar_t *str)
+{
+	UINT len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	len = UniStrLen(str);
+	if (len == 0)
+	{
+		return;
+	}
+
+	if (str[len - 1] == L'\n')
+	{
+		if (len >= 2 && str[len - 2] == L'\r')
+		{
+			str[len - 2] = 0;
+		}
+		str[len - 1] = 0;
+	}
+	else if(str[len - 1] == L'\r')
+	{
+		str[len - 1] = 0;
+	}
+}
+
+// 文字列の左右の空白を削除
+void UniTrim(wchar_t *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	UniTrimLeft(str);
+	UniTrimRight(str);
+}
+
+// 文字列の右側の空白を削除
+void UniTrimRight(wchar_t *str)
+{
+	wchar_t *buf, *tmp;
+	UINT len, i, wp, wp2;
+	bool flag;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	len = UniStrLen(str);
+	if (len == 0)
+	{
+		return;
+	}
+	if (str[len - 1] != L' ' && str[len - 1] != L'\t')
+	{
+		return;
+	}
+
+	buf = Malloc((len + 1) * sizeof(wchar_t));
+	tmp = Malloc((len + 1) * sizeof(wchar_t));
+	flag = false;
+	wp = wp2 = 0;
+	for (i = 0;i < len;i++)
+	{
+		if (str[i] != L' ' && str[i] != L'\t')
+		{
+			Copy(&buf[wp], tmp, wp2 * sizeof(wchar_t));
+			wp += wp2;
+			wp2 = 0;
+			buf[wp++] = str[i];
+		}
+		else
+		{
+			tmp[wp2++] = str[i];
+		}
+	}
+	buf[wp] = 0;
+	UniStrCpy(str, 0, buf);
+	Free(buf);
+	Free(tmp);
+}
+
+// 文字列の左側の空白を削除
+void UniTrimLeft(wchar_t *str)
+{
+	wchar_t *buf;
+	UINT len, i, wp;
+	bool flag;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	len = UniStrLen(str);
+	if (len == 0)
+	{
+		return;
+	}
+	if (str[0] != L' ' && str[0] != L'\t')
+	{
+		return;
+	}
+
+	buf = Malloc((len + 1) * sizeof(wchar_t));
+	flag = false;
+	wp = 0;
+	for (i = 0;i < len;i++)
+	{
+		if (str[i] != L' ' && str[i] != L'\t')
+		{
+			flag = true;
+		}
+		if (flag)
+		{
+			buf[wp++] = str[i];
+		}
+	}
+	buf[wp] = 0;
+	UniStrCpy(str, 0, buf);
+	Free(buf);
+}
+
+// 整数を 16 進文字列に変換 (8桁固定)
+void UniToStrx8(wchar_t *str, UINT i)
+{
+	UniFormat(str, 0, L"0x%08x", i);
+}
+
+// 整数を 16 進文字列に変換
+void UniToStrx(wchar_t *str, UINT i)
+{
+	UniFormat(str, 0, L"0x%02x", i);
+}
+
+// 符号付整数を文字列に変換
+void UniToStri(wchar_t *str, int i)
+{
+	UniFormat(str, 0, L"%i", i);
+}
+
+// 整数を文字列に変換
+void UniToStru(wchar_t *str, UINT i)
+{
+	UniFormat(str, 0, L"%u", i);
+}
+
+// 文字列を符号付整数に変換
+int UniToInti(wchar_t *str)
+{
+	char tmp[128];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	return ToInt(tmp);
+}
+
+// 文字列を整数に変換
+UINT UniToInt(wchar_t *str)
+{
+	char tmp[128];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	UniToStr(tmp, sizeof(tmp), str);
+
+	return ToInti(tmp);
+}
+
+// 64bit 用フォーマット文字列置換
+wchar_t *UniReplaceFormatStringFor64(wchar_t *fmt)
+{
+	wchar_t *tmp;
+	wchar_t *ret;
+	UINT tmp_size;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return NULL;
+	}
+
+	tmp_size = UniStrSize(fmt) * 2;
+	tmp = ZeroMalloc(tmp_size);
+
+#ifdef	OS_WIN32
+	UniReplaceStrEx(tmp, tmp_size, fmt, L"%ll", L"%I64", false);
+#else	// OS_WIN32
+	UniReplaceStrEx(tmp, tmp_size, fmt, L"%I64", L"%ll", false);
+
+	if (1)
+	{
+		UINT i, len;
+		bool f = false;
+		len = UniStrLen(tmp);
+		for (i = 0;i < len;i++)
+		{
+			if (tmp[i] == L'%')
+			{
+				f = true;
+			}
+
+			if (f)
+			{
+				switch (tmp[i])
+				{
+				case L'c':
+				case L'C':
+				case L'd':
+				case L'i':
+				case L'o':
+				case L'u':
+				case L'x':
+				case L'X':
+				case L'e':
+				case L'E':
+				case L'f':
+				case L'g':
+				case L'G':
+				case L'n':
+				case L'p':
+				case L's':
+				case L'S':
+					if (tmp[i] == L's')
+					{
+						tmp[i] = L'S';
+					}
+					else if (tmp[i] == L'S')
+					{
+						tmp[i] = L's';
+					}
+					f = false;
+					break;
+				}
+			}
+		}
+	}
+
+#endif	// OS_WIN32
+
+	ret = CopyUniStr(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// 文字列を画面に表示する
+void UniPrintStr(wchar_t *string)
+{
+	// 引数チェック
+	if (string == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_UNIX
+	if (true)
+	{
+		char *str = CopyUniToStr(string);
+
+		if (str != NULL)
+		{
+			fputs(str, stdout);
+		}
+		else
+		{
+			fputs("", stdout);
+		}
+
+		Free(str);
+	}
+#else	// OS_UNIX
+	Win32PrintW(string);
+#endif	// OS_UNIX
+}
+
+// 文字列を引数付きで表示する
+void UniPrintArgs(wchar_t *fmt, va_list args)
+{
+	wchar_t *str;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+
+	str = InternalFormatArgs(fmt, args, false);
+
+	UniPrintStr(str);
+
+	Free(str);
+}
+
+// 文字列を表示する
+void UniPrint(wchar_t *fmt, ...)
+{
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	UniPrintArgs(fmt, args);
+	va_end(args);
+}
+
+// デバッグ文字列を引数付きで表示する
+void UniDebugArgs(wchar_t *fmt, va_list args)
+{
+	if (g_debug == false)
+	{
+		return;
+	}
+
+	UniPrintArgs(fmt, args);
+}
+
+// デバッグ文字列を表示する
+void UniDebug(wchar_t *fmt, ...)
+{
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	UniDebugArgs(fmt, args);
+	va_end(args);
+}
+
+// 文字列をフォーマットする (引数リスト)
+void UniFormatArgs(wchar_t *buf, UINT size, wchar_t *fmt, va_list args)
+{
+	wchar_t *ret;
+	// 引数チェック
+	if (buf == NULL || fmt == NULL)
+	{
+		return;
+	}
+	if (size == 1)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_FORMAT_COUNT);
+
+	ret = InternalFormatArgs(fmt, args, false);
+
+	UniStrCpy(buf, size, ret);
+
+	Free(ret);
+}
+
+// 文字列をフォーマットして結果をコピーする
+wchar_t *CopyUniFormat(wchar_t *fmt, ...)
+{
+	wchar_t *ret, *str;
+	UINT size;
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return NULL;
+	}
+
+	size = MAX(UniStrSize(fmt) * 10, MAX_SIZE * 10);
+	str = Malloc(size);
+
+	va_start(args, fmt);
+	UniFormatArgs(str, size, fmt, args);
+
+	ret = UniCopyStr(str);
+	Free(str);
+	va_end(args);
+
+	return ret;
+}
+
+// 文字列をフォーマットする
+void UniFormat(wchar_t *buf, UINT size, wchar_t *fmt, ...)
+{
+	va_list args;
+	// 引数チェック
+	if (buf == NULL || fmt == NULL)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	UniFormatArgs(buf, size, fmt, args);
+	va_end(args);
+}
+
+// 柔軟な文字列比較
+int UniSoftStrCmp(wchar_t *str1, wchar_t *str2)
+{
+	UINT ret;
+	wchar_t *tmp1, *tmp2;
+	// 引数チェック
+	if (str1 == NULL && str2 == NULL)
+	{
+		return 0;
+	}
+	if (str1 == NULL)
+	{
+		return 1;
+	}
+	if (str2 == NULL)
+	{
+		return -1;
+	}
+
+	tmp1 = CopyUniStr(str1);
+	tmp2 = CopyUniStr(str2);
+
+	UniTrim(tmp1);
+	UniTrim(tmp2);
+
+	ret = UniStrCmpi(tmp1, tmp2);
+
+	Free(tmp1);
+	Free(tmp2);
+
+	return ret;
+}
+
+// 文字列を大文字・小文字を区別せずに比較する
+int UniStrCmpi(wchar_t *str1, wchar_t *str2)
+{
+	UINT i;
+	// 引数チェック
+	if (str1 == NULL && str2 == NULL)
+	{
+		return 0;
+	}
+	if (str1 == NULL)
+	{
+		return 1;
+	}
+	if (str2 == NULL)
+	{
+		return -1;
+	}
+
+	// 文字列比較
+	i = 0;
+	while (true)
+	{
+		wchar_t c1, c2;
+		c1 = UniToUpper(str1[i]);
+		c2 = UniToUpper(str2[i]);
+		if (c1 > c2)
+		{
+			return 1;
+		}
+		else if (c1 < c2)
+		{
+			return -1;
+		}
+		if (str1[i] == 0 || str2[i] == 0)
+		{
+			return 0;
+		}
+		i++;
+	}
+}
+
+// 文字列を比較する
+int UniStrCmp(wchar_t *str1, wchar_t *str2)
+{
+	// 引数チェック
+	if (str1 == NULL && str2 == NULL)
+	{
+		return 0;
+	}
+	if (str1 == NULL)
+	{
+		return 1;
+	}
+	if (str2 == NULL)
+	{
+		return -1;
+	}
+
+	return wcscmp(str1, str2);
+}
+
+// 文字列を小文字にする
+void UniStrLower(wchar_t *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	len = UniStrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		str[i] = UniToLower(str[i]);
+	}
+}
+
+// 文字列を大文字にする
+void UniStrUpper(wchar_t *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	len = UniStrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		str[i] = UniToUpper(str[i]);
+	}
+}
+
+// 文字を小文字にする
+wchar_t UniToLower(wchar_t c)
+{
+	if (c >= L'A' && c <= L'Z')
+	{
+		c += L'a' - L'A';
+	}
+
+	return c;
+}
+
+// 文字を大文字にする
+wchar_t UniToUpper(wchar_t c)
+{
+	if (c >= L'a' && c <= L'z')
+	{
+		c -= L'a' - L'A';
+	}
+
+	return c;
+}
+
+// 文字列結合
+UINT UniStrCat(wchar_t *dst, UINT size, wchar_t *src)
+{
+	UINT len1, len2, len_test;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return 0;
+	}
+	if (size != 0 && size < sizeof(wchar_t))
+	{
+		return 0;
+	}
+	if (size == sizeof(wchar_t))
+	{
+		wcscpy(dst, L"");
+		return 0;
+	}
+	if (size == 0)
+	{
+		// 長さ無視
+		size = 0x3fffffff;
+	}
+
+	len1 = UniStrLen(dst);
+	len2 = UniStrLen(src);
+	len_test = len1 + len2 + 1;
+	if (len_test > (size / sizeof(wchar_t)))
+	{
+		if (len2 <= (len_test - (size / sizeof(wchar_t))))
+		{
+			return 0;
+		}
+		len2 -= len_test - (size / sizeof(wchar_t));
+	}
+	Copy(&dst[len1], src, len2 * sizeof(wchar_t));
+	dst[len1 + len2] = 0;
+
+	return len1 + len2;
+}
+UINT UniStrCatLeft(wchar_t *dst, UINT size, wchar_t *src)
+{
+	wchar_t *s;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return 0;
+	}
+
+	s = UniCopyStr(dst);
+	UniStrCpy(dst, size, s);
+	UniStrCat(dst, size, src);
+	Free(s);
+
+	return UniStrLen(dst);
+}
+
+// 文字列コピー
+UINT UniStrCpy(wchar_t *dst, UINT size, wchar_t *src)
+{
+	UINT len;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		if (src == NULL && dst != NULL)
+		{
+			if (size >= sizeof(wchar_t))
+			{
+				dst[0] = L'\0';
+			}
+		}
+		return 0;
+	}
+	if (dst == src)
+	{
+		return UniStrLen(src);
+	}
+	if (size != 0 && size < sizeof(wchar_t))
+	{
+		return 0;
+	}
+	if (size == sizeof(wchar_t))
+	{
+		wcscpy(dst, L"");
+		return 0;
+	}
+	if (size == 0)
+	{
+		// 長さ無視
+		size = 0x3fffffff;
+	}
+
+	// 長さをチェック
+	len = UniStrLen(src);
+	if (len <= (size / sizeof(wchar_t) - 1))
+	{
+		Copy(dst, src, (len + 1) * sizeof(wchar_t));
+	}
+	else
+	{
+		len = size / 2 - 1;
+		Copy(dst, src, len * sizeof(wchar_t));
+		dst[len] = 0;
+	}
+
+	return len;
+}
+
+// 文字が指定されたバッファサイズ以内かどうかチェック
+bool UniCheckStrSize(wchar_t *str, UINT size)
+{
+	// 引数チェック
+	if (str == NULL || size <= 1)
+	{
+		return false;
+	}
+
+	return UniCheckStrLen(str, size / sizeof(wchar_t) - 1);
+}
+
+// 文字数が指定された長さ以内かどうかチェック
+bool UniCheckStrLen(wchar_t *str, UINT len)
+{
+	UINT count = 0;
+	UINT i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;;i++)
+	{
+		if (str[i] == 0)
+		{
+			return true;
+		}
+		count++;
+		if (count > len)
+		{
+			return false;
+		}
+	}
+}
+
+// 文字列の格納に必要なバッファサイズの取得
+UINT UniStrSize(wchar_t *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	return (UniStrLen(str) + 1) * sizeof(wchar_t);
+}
+
+// 文字列の長さの取得
+UINT UniStrLen(wchar_t *str)
+{
+	UINT i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	i = 0;
+	while (true)
+	{
+		if (str[i] == 0)
+		{
+			break;
+		}
+		i++;
+	}
+
+	return i;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Internat.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Internat.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Internat.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,217 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Internat.h
+// Internat.c のヘッダ
+
+#ifndef	INTERNAT_H
+#define	INTERNAT_H
+
+// 文字列トークン
+struct UNI_TOKEN_LIST
+{
+	UINT NumTokens;
+	wchar_t **Token;
+};
+
+UINT UniStrLen(wchar_t *str);
+UINT UniStrSize(wchar_t *str);
+UINT UniStrCpy(wchar_t *dst, UINT size, wchar_t *src);
+bool UniCheckStrSize(wchar_t *str, UINT size);
+bool UniCheckStrLen(wchar_t *str, UINT len);
+UINT UniStrCat(wchar_t *dst, UINT size, wchar_t *src);
+UINT UniStrCatLeft(wchar_t *dst, UINT size, wchar_t *src);
+wchar_t UniToLower(wchar_t c);
+wchar_t UniToUpper(wchar_t c);
+void UniStrLower(wchar_t *str);
+void UniStrUpper(wchar_t *str);
+int UniStrCmp(wchar_t *str1, wchar_t *str2);
+int UniStrCmpi(wchar_t *str1, wchar_t *str2);
+int UniSoftStrCmp(wchar_t *str1, wchar_t *str2);
+void UniFormat(wchar_t *buf, UINT size, wchar_t *fmt, ...);
+wchar_t *CopyUniFormat(wchar_t *fmt, ...);
+void UniFormatArgs(wchar_t *buf, UINT size, wchar_t *fmt, va_list args);
+void UniDebugArgs(wchar_t *fmt, va_list args);
+void UniDebug(wchar_t *fmt, ...);
+void UniPrint(wchar_t *fmt, ...);
+void UniPrintArgs(wchar_t *fmt, va_list args);
+void UniPrintStr(wchar_t *string);
+void UniToStrx8(wchar_t *str, UINT i);
+void UniToStrx(wchar_t *str, UINT i);
+void UniToStri(wchar_t *str, int i);
+void UniToStru(wchar_t *str, UINT i);
+int UniToInti(wchar_t *str);
+UINT UniToInt(wchar_t *str);
+void UniTrim(wchar_t *str);
+void UniTrimLeft(wchar_t *str);
+void UniTrimRight(wchar_t *str);
+void UniTrimCrlf(wchar_t *str);
+bool UniGetLine(wchar_t *str, UINT size);
+bool UniGetLineWin32(wchar_t *str, UINT size);
+bool UniGetLineUnix(wchar_t *str, UINT size);
+void UniFreeToken(UNI_TOKEN_LIST *tokens);
+UNI_TOKEN_LIST *UniParseToken(wchar_t *src, wchar_t *separator);
+UINT UniSearchStrEx(wchar_t *string, wchar_t *keyword, UINT start, bool case_sensitive);
+UINT UniSearchStri(wchar_t *string, wchar_t *keyword, UINT start);
+UINT UniSearchStr(wchar_t *string, wchar_t *keyword, UINT start);
+UINT UniCalcReplaceStrEx(wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword, bool case_sensitive);
+UINT UniReplaceStrEx(wchar_t *dst, UINT size, wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword, bool case_sensitive);
+UINT UniReplaceStri(wchar_t *dst, UINT size, wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword);
+UINT UniReplaceStr(wchar_t *dst, UINT size, wchar_t *string, wchar_t *old_keyword, wchar_t *new_keyword);
+UINT GetUniType(wchar_t c);
+UINT GetUtf8Type(BYTE *s, UINT size, UINT offset);
+UINT CalcUniToUtf8(wchar_t *s);
+UINT UniToUtf8(BYTE *u, UINT size, wchar_t *s);
+UINT Utf8Len(BYTE *u, UINT size);
+UINT CalcUtf8ToUni(BYTE *u, UINT u_size);
+UINT Utf8ToUni(wchar_t *s, UINT size, BYTE *u, UINT u_size);
+UINT CalcStrToUni(char *str);
+UINT StrToUni(wchar_t *s, UINT size, char *str);
+UINT CalcUniToStr(wchar_t *s);
+UINT UniToStr(char *str, UINT size, wchar_t *s);
+UINT CalcStrToUtf8(char *str);
+UINT StrToUtf8(BYTE *u, UINT size, char *str);
+UINT CalcUtf8ToStr(BYTE *u, UINT size);
+UINT Utf8ToStr(char *str, UINT str_size, BYTE *u, UINT size);
+bool IsSafeUniStr(wchar_t *str);
+bool IsSafeUniChar(wchar_t c);
+wchar_t *CopyUniStr(wchar_t *str);
+wchar_t *CopyStrToUni(char *str);
+UINT StrToUtf(char *utfstr, UINT size, char *str);
+UINT UtfToStr(char *str, UINT size, char *utfstr);
+UINT UniToUtf(char *utfstr, UINT size, wchar_t *unistr);
+UINT UtfToUni(wchar_t *unistr, UINT size, char *utfstr);
+char *CopyUniToUtf(wchar_t *unistr);
+char *CopyStrToUtf(char *str);
+char *CopyUniToStr(wchar_t *unistr);
+wchar_t *CopyUtfToUni(char *utfstr);
+char *CopyUtfToStr(char *utfstr);
+wchar_t *UniReplaceFormatStringFor64(wchar_t *fmt);
+void UniToStr64(wchar_t *str, UINT64 value);
+UINT64 UniToInt64(wchar_t *str);
+UNI_TOKEN_LIST *UniParseCmdLine(wchar_t *str);
+UNI_TOKEN_LIST *UniCopyToken(UNI_TOKEN_LIST *src);
+wchar_t *UniCopyStr(wchar_t *str);
+TOKEN_LIST *UniTokenListToTokenList(UNI_TOKEN_LIST *src);
+UNI_TOKEN_LIST *TokenListToUniTokenList(TOKEN_LIST *src);
+UNI_TOKEN_LIST *UniNullToken();
+UNI_TOKEN_LIST *NullUniToken();
+bool UniIsNum(wchar_t *str);
+bool IsEmptyUniStr(wchar_t *str);
+bool UniIsEmptyStr(wchar_t *str);
+void InitInternational();
+void FreeInternational();
+USHORT *WideToUtf16(wchar_t *str);
+wchar_t *Utf16ToWide(USHORT *str);
+void DumpUniStr(wchar_t *str);
+void DumpStr(char *str);
+wchar_t *InternalFormatArgs(wchar_t *fmt, va_list args, bool ansi_mode);
+UINT UniStrWidth(wchar_t *str);
+UNI_TOKEN_LIST *UnixUniParseToken(wchar_t *src, wchar_t *separator);
+void UniToStr3(wchar_t *str, UINT size, UINT64 value);
+bool UniEndWith(wchar_t *str, wchar_t *key);
+bool UniStartWith(wchar_t *str, wchar_t *key);
+wchar_t *UniNormalizeCrlf(wchar_t *str);
+LIST *UniStrToStrList(wchar_t *str, UINT size);
+BUF *UniStrListToStr(LIST *o);
+void UniFreeStrList(LIST *o);
+UNI_TOKEN_LIST *UniListToTokenList(LIST *o);
+LIST *UniTokenListToList(UNI_TOKEN_LIST *t);
+bool UniIsSafeChar(wchar_t c);
+wchar_t *UniMakeCharArray(wchar_t c, UINT count);
+BUF *UniStrToBin(wchar_t *str);
+bool UniInStr(wchar_t *str, wchar_t *keyword);
+bool UniInStrEx(wchar_t *str, wchar_t *keyword, bool case_sensitive);
+
+#ifdef	OS_UNIX
+void GetCurrentCharSet(char *name, UINT size);
+UINT UnixCalcStrToUni(char *str);
+UINT UnixStrToUni(wchar_t *s, UINT size, char *str);
+UINT UnixCalcUniToStr(wchar_t *s);
+UINT UnixUniToStr(char *str, UINT size, wchar_t *s);
+void *IconvWideToStr();
+void *IconvStrToWide();
+int IconvFree(void *d);
+void *IconvWideToStrInternal();
+void *IconvStrToWideInternal();
+int IconvFreeInternal(void *d);
+#endif	// OS_UNIX
+
+#endif	// INTERNAT_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Kernel.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Kernel.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Kernel.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1903 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Kernel.c
+// システムサービス処理ルーチン
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+#ifndef TM_YEAR_MAX
+#define TM_YEAR_MAX         2106
+#endif
+#ifndef TM_MON_MAX
+#define TM_MON_MAX          1
+#endif
+#ifndef TM_MDAY_MAX
+#define TM_MDAY_MAX         7
+#endif
+#ifndef TM_HOUR_MAX
+#define TM_HOUR_MAX         6
+#endif
+#ifndef TM_MIN_MAX
+#define TM_MIN_MAX          28
+#endif
+#ifndef TM_SEC_MAX
+#define TM_SEC_MAX          14
+#endif
+
+/* free mktime function
+   Copyright 1988, 1989 by David MacKenzie <djm@ai.mit.edu>
+   and Michael Haertel <mike@ai.mit.edu>
+   Unlimited distribution permitted provided this copyright notice is
+   retained and any functional modifications are prominently identified.  */
+#define ADJUST_TM(tm_member, tm_carry, modulus) \
+	if ((tm_member) < 0){ \
+		tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
+		tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
+	} else if ((tm_member) >= (modulus)) { \
+		tm_carry += (tm_member) / (modulus); \
+		tm_member = (tm_member) % (modulus); \
+	}
+#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
+#define leapday(m, y) ((m) == 1 && leap (y))
+#define monthlen(m, y) (ydays[(m)+1] - ydays[m] + leapday (m, y))
+static int ydays[] =
+{
+	0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
+};
+
+
+static wchar_t *default_locale_str =
+L"- - $ : : $ Sun Mon Tue Wed Thu Fri Sat : : : $ (None)";
+
+static LOCALE current_locale;
+LOCK *tick_manual_lock = NULL;
+UINT g_zero = 0;
+
+// リアルタイムシステムタイマの取得
+UINT TickRealtime()
+{
+#if	defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES)
+	return Tick() + 1;
+#else
+	return TickRealtimeManual() + 1;
+#endif
+}
+
+#ifndef	OS_WIN32
+
+static UINT64 last_manual_tick = 0;
+static UINT64 manual_tick_add_value = 0;
+
+// clock_gettime が無いシステム向け (MacOS X など)
+UINT TickRealtimeManual()
+{
+	UINT64 ret;
+	Lock(tick_manual_lock);
+	{
+		ret = TickGetRealtimeTickValue64();
+
+		if (last_manual_tick != 0 && (last_manual_tick > ret))
+		{
+			manual_tick_add_value += (last_manual_tick - ret);
+		}
+
+		last_manual_tick = ret;
+	}
+	Unlock(tick_manual_lock);
+
+	return (UINT)(ret + manual_tick_add_value);
+}
+
+// 現在時刻から適当な値を返す
+UINT64 TickGetRealtimeTickValue64()
+{
+	struct timeval tv;
+	struct timezone tz;
+	UINT64 ret;
+
+	memset(&tv, 0, sizeof(tv));
+	memset(&tz, 0, sizeof(tz));
+
+	gettimeofday(&tv, &tz);
+
+	ret = (UINT64)tv.tv_sec * 1000ULL + (UINT64)tv.tv_usec / 1000ULL;
+
+	return ret;
+}
+
+#endif	// OS_WIN32
+
+// ホームディレクトリを取得
+void GetHomeDirW(wchar_t *path, UINT size)
+{
+	// 引数チェック
+	if (path == NULL)
+	{
+		return;
+	}
+
+	if (GetEnvW(L"HOME", path, size) == false)
+	{
+		wchar_t drive[MAX_SIZE];
+		wchar_t hpath[MAX_SIZE];
+		if (GetEnvW(L"HOMEDRIVE", drive, sizeof(drive)) &&
+			GetEnvW(L"HOMEPATH", hpath, sizeof(hpath)))
+		{
+			UniFormat(path, sizeof(path), L"%s%s", drive, hpath);
+		}
+		else
+		{
+#ifdef	OS_WIN32
+			Win32GetCurrentDirW(path, size);
+#else	// OS_WIN32
+			UnixGetCurrentDirW(path, size);
+#endif	// OS_WIN32
+		}
+	}
+}
+void GetHomeDir(char *path, UINT size)
+{
+	// 引数チェック
+	if (path == NULL)
+	{
+		return;
+	}
+
+	if (GetEnv("HOME", path, size) == false)
+	{
+		char drive[MAX_SIZE];
+		char hpath[MAX_SIZE];
+		if (GetEnv("HOMEDRIVE", drive, sizeof(drive)) &&
+			GetEnv("HOMEPATH", hpath, sizeof(hpath)))
+		{
+			Format(path, sizeof(path), "%s%s", drive, hpath);
+		}
+		else
+		{
+#ifdef	OS_WIN32
+			Win32GetCurrentDir(path, size);
+#else	// OS_WIN32
+			UnixGetCurrentDir(path, size);
+#endif	// OS_WIN32
+		}
+	}
+}
+
+// 環境変数文字列を取得
+bool GetEnv(char *name, char *data, UINT size)
+{
+	char *ret;
+	// 引数チェック
+	if (name == NULL || data == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(data, size, "");
+
+	ret = getenv(name);
+	if (ret == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(data, size, ret);
+
+	return true;
+}
+bool GetEnvW(wchar_t *name, wchar_t *data, UINT size)
+{
+#ifdef	OS_WIN32
+	return GetEnvW_ForWin32(name, data, size);
+#else	// OS_WIN32
+	return GetEnvW_ForUnix(name, data, size);
+#endif	// OS_WIN32
+}
+
+#ifdef	OS_WIN32
+bool GetEnvW_ForWin32(wchar_t *name, wchar_t *data, UINT size)
+{
+	wchar_t *ret;
+	// 引数チェック
+	if (name == NULL || data == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		bool ret;
+		char *name_a = CopyUniToStr(name);
+		char data_a[MAX_SIZE];
+
+		ret = GetEnv(name_a, data_a, sizeof(data_a));
+
+		if (ret)
+		{
+			StrToUni(data, size, data_a);
+		}
+
+		Free(name_a);
+
+		return ret;
+	}
+
+	UniStrCpy(data, size, L"");
+
+	ret = _wgetenv(name);
+	if (ret == NULL)
+	{
+		return false;
+	}
+
+	UniStrCpy(data, size, ret);
+
+	return true;
+}
+
+#endif	// OS_WIN32
+
+#ifdef	OS_UNIX
+
+bool GetEnvW_ForUnix(wchar_t *name, wchar_t *data, UINT size)
+{
+	char *name_a;
+	bool ret;
+	char data_a[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL || data == NULL)
+	{
+		return false;
+	}
+
+	name_a = CopyUniToUtf(name);
+
+	ret = GetEnv(name_a, data_a, sizeof(data_a));
+
+	if (ret)
+	{
+		UtfToUni(data, size, data_a);
+	}
+
+	Free(name_a);
+
+	return ret;
+}
+
+#endif	// OS_UNIX
+
+// メモリ情報取得
+void GetMemInfo(MEMINFO *info)
+{
+	OSGetMemInfo(info);
+}
+
+// シングルインスタンスの開始
+INSTANCE *NewSingleInstance(char *instance_name)
+{
+	return NewSingleInstanceEx(instance_name, false);
+}
+INSTANCE *NewSingleInstanceEx(char *instance_name, bool user_local)
+{
+	char name[MAX_SIZE];
+	INSTANCE *ret;
+	void *data;
+
+	if (instance_name != NULL)
+	{
+		if (user_local == false)
+		{
+			HashInstanceName(name, sizeof(name), instance_name);
+		}
+		else
+		{
+			HashInstanceNameLocal(name, sizeof(name), instance_name);
+		}
+
+		data = OSNewSingleInstance(name);
+	}
+	else
+	{
+		data = OSNewSingleInstance(NULL);
+	}
+
+	if (data == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(INSTANCE));
+	if (instance_name != NULL)
+	{
+		ret->Name = CopyStr(instance_name);
+	}
+
+	ret->pData = data;
+
+	return ret;
+}
+
+// シングルインスタンスの解放
+void FreeSingleInstance(INSTANCE *inst)
+{
+	// 引数チェック
+	if (inst == NULL)
+	{
+		return;
+	}
+
+	OSFreeSingleInstance(inst->pData);
+
+	if (inst->Name != NULL)
+	{
+		Free(inst->Name);
+	}
+	Free(inst);
+}
+
+// インスタンス名をハッシュする
+void HashInstanceName(char *name, UINT size, char *instance_name)
+{
+	char tmp[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	char key[11];
+	// 引数チェック
+	if (name == NULL || instance_name == NULL)
+	{
+		return;
+	}
+
+	StrCpy(tmp, sizeof(tmp), instance_name);
+	Trim(tmp);
+	StrUpper(tmp);
+
+	Hash(hash, tmp, StrLen(tmp), SHA1_SIZE);
+	BinToStr(key, sizeof(key), hash, 5);
+	key[10] = 0;
+
+	Format(name, size, "VPN-%s", key);
+
+	if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))
+	{
+		if (GET_KETA(GetOsInfo()->OsType, 100) >= 2 ||
+			GetOsInfo()->OsType == OSTYPE_WINDOWS_NT_4_TERMINAL_SERVER)
+		{
+			StrCpy(tmp, sizeof(tmp), name);
+			Format(name, size, "Global\\%s", tmp);
+		}
+	}
+}
+void HashInstanceNameLocal(char *name, UINT size, char *instance_name)
+{
+	char tmp[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	char key[11];
+	// 引数チェック
+	if (name == NULL || instance_name == NULL)
+	{
+		return;
+	}
+
+	StrCpy(tmp, sizeof(tmp), instance_name);
+	Trim(tmp);
+	StrUpper(tmp);
+
+	Hash(hash, tmp, StrLen(tmp), SHA1_SIZE);
+	BinToStr(key, sizeof(key), hash, 5);
+	key[10] = 0;
+
+	Format(name, size, "VPN-%s", key);
+
+	if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))
+	{
+		if (GET_KETA(GetOsInfo()->OsType, 100) >= 2 ||
+			GetOsInfo()->OsType == OSTYPE_WINDOWS_NT_4_TERMINAL_SERVER)
+		{
+			StrCpy(tmp, sizeof(tmp), name);
+			Format(name, size, "Local\\%s", tmp);
+		}
+	}
+}
+
+// プロセスの起動
+bool Run(char *filename, char *arg, bool hide, bool wait)
+{
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return false;
+	}
+
+	return OSRun(filename, arg, hide, wait);
+}
+bool RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)
+{
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return false;
+	}
+
+	return OSRunW(filename, arg, hide, wait);
+}
+
+// 日付・時刻関係の関数
+void GetDateTimeStr64Uni(wchar_t *str, UINT size, UINT64 sec64)
+{
+	char tmp[MAX_SIZE];
+	if (str == NULL)
+	{
+		return;
+	}
+
+	GetDateTimeStr64(tmp, sizeof(tmp), sec64);
+	StrToUni(str, size, tmp);
+}
+void GetDateTimeStr64(char *str, UINT size, UINT64 sec64)
+{
+	SYSTEMTIME st;
+	UINT64ToSystem(&st, sec64);
+	GetDateTimeStr(str, size, &st);
+}
+void GetDateTimeStrMilli64(char *str, UINT size, UINT64 sec64)
+{
+	SYSTEMTIME st;
+	UINT64ToSystem(&st, sec64);
+	GetDateTimeStrMilli(str, size, &st);
+}
+void GetDateStr64(char *str, UINT size, UINT64 sec64)
+{
+	SYSTEMTIME st;
+	if (sec64 == 0)
+	{
+		StrCpy(str, size, "(Unknown)");
+		return;
+	}
+	UINT64ToSystem(&st, sec64);
+	GetDateStr(str, size, &st);
+}
+void GetDateTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
+{
+	SYSTEMTIME st;
+	if (locale == NULL)
+	{
+		locale = &current_locale;
+	}
+	if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
+	{
+		UniStrCpy(str, size, locale->Unknown);
+		return;
+	}
+	UINT64ToSystem(&st, sec64);
+	GetDateTimeStrEx(str, size, &st, locale);
+}
+void GetTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
+{
+	SYSTEMTIME st;
+	if (locale == NULL)
+	{
+		locale = &current_locale;
+	}
+	if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
+	{
+		UniStrCpy(str, size, locale->Unknown);
+		return;
+	}
+	UINT64ToSystem(&st, sec64);
+	GetTimeStrEx(str, size, &st, locale);
+}
+void GetDateStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
+{
+	SYSTEMTIME st;
+	if (locale == NULL)
+	{
+		locale = &current_locale;
+	}
+	if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
+	{
+		UniStrCpy(str, size, locale->Unknown);
+		return;
+	}
+	UINT64ToSystem(&st, sec64);
+	GetDateStrEx(str, size, &st, locale);
+}
+void GetTimeStrMilli64(char *str, UINT size, UINT64 sec64)
+{
+	SYSTEMTIME st;
+	if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
+	{
+		StrCpy(str, size, "(Unknown)");
+		return;
+	}
+	UINT64ToSystem(&st, sec64);
+	GetTimeStrMilli(str, size, &st);
+}
+void GetTimeStr64(char *str, UINT size, UINT64 sec64)
+{
+	SYSTEMTIME st;
+	if (sec64 == 0 || SystemToLocal64(sec64) == 0 || LocalToSystem64(sec64) == 0)
+	{
+		StrCpy(str, size, "(Unknown)");
+		return;
+	}
+	UINT64ToSystem(&st, sec64);
+	GetTimeStr(str, size, &st);
+}
+
+// 現在の POSIX 実装で使用しても安全な時刻に変換する
+UINT64 SafeTime64(UINT64 sec64)
+{
+	return MAKESURE(sec64, 0, 2115947647000ULL);
+}
+
+// スレッドプール
+static SK *thread_pool = NULL;
+static COUNTER *thread_count = NULL;
+
+// スレッドプールの初期化
+void InitThreading()
+{
+	thread_pool = NewSk();
+	thread_count = NewCounter();
+}
+
+// スレッドプールの解放
+void FreeThreading()
+{
+	while (true)
+	{
+		if (Count(thread_count) == 0)
+		{
+			break;
+		}
+
+		SleepThread(25);
+	}
+
+	while (true)
+	{
+		THREAD_POOL_DATA *pd;
+		THREAD *t = Pop(thread_pool);
+
+		if (t == NULL)
+		{
+			break;
+		}
+
+		pd = (THREAD_POOL_DATA *)t->param;
+
+		pd->ThreadProc = NULL;
+		Set(pd->Event);
+
+		WaitThreadInternal(t);
+
+		pd = (THREAD_POOL_DATA *)t->param;
+		ReleaseEvent(pd->Event);
+		ReleaseEvent(pd->InitFinishEvent);
+
+		ReleaseThreadInternal(t);
+
+		Free(pd);
+	}
+
+	ReleaseSk(thread_pool);
+
+	DeleteCounter(thread_count);
+	thread_count = NULL;
+}
+
+// スレッドプールプロシージャ
+void ThreadPoolProc(THREAD *t, void *param)
+{
+	THREAD_POOL_DATA *pd;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	pd = (THREAD_POOL_DATA *)param;
+
+	NoticeThreadInitInternal(t);
+
+	while (true)
+	{
+		THREAD *thread;
+		UINT i, num;
+		EVENT **ee;
+
+		// 次の仕事を待つ
+		Wait(pd->Event, INFINITE);
+
+		if (pd->ThreadProc == NULL)
+		{
+			// プールスレッドの動作停止
+			break;
+		}
+
+		thread = pd->Thread;
+		thread->ThreadId = ThreadId();
+
+		// 初期化完了
+		Set(pd->InitFinishEvent);
+
+		// スレッドプロシージャの実行
+		pd->ThreadProc(pd->Thread, thread->param);
+
+		thread->PoolHalting = true;
+
+		// 待機イベントリストを叩く
+		LockList(thread->PoolWaitList);
+		{
+			num = LIST_NUM(thread->PoolWaitList);
+			ee = ToArray(thread->PoolWaitList);
+
+			DeleteAll(thread->PoolWaitList);
+		}
+		UnlockList(thread->PoolWaitList);
+
+		for (i = 0;i < num;i++)
+		{
+			EVENT *e = ee[i];
+
+			Set(e);
+			ReleaseEvent(e);
+		}
+
+		Free(ee);
+
+		while (true)
+		{
+			if (Count(thread->ref->c) <= 1)
+			{
+				break;
+			}
+
+			Wait(thread->release_event, 256);
+		}
+
+		ReleaseThread(thread);
+
+#ifdef	OS_WIN32
+		// Win32 の場合: スレッドの優先順位を元に戻す
+		MsRestoreThreadPriority();
+#endif	// OS_WIN32
+
+		// スレッドプールに自分自身を登録する
+		LockSk(thread_pool);
+		{
+			Push(thread_pool, t);
+		}
+		UnlockSk(thread_pool);
+
+		Dec(thread_count);
+	}
+}
+
+// 何もしない
+UINT DoNothing()
+{
+	return g_zero;
+}
+
+// スレッド作成 (プール)
+THREAD *NewThread(THREAD_PROC *thread_proc, void *param)
+{
+	THREAD *host = NULL;
+	THREAD_POOL_DATA *pd = NULL;
+	THREAD *ret;
+	bool new_thread = false;
+	// 引数チェック
+	if (thread_proc == NULL)
+	{
+		return NULL;
+	}
+
+	if (IsTrackingEnabled() == false)
+	{
+		DoNothing();
+	}
+
+	Inc(thread_count);
+
+	LockSk(thread_pool);
+	{
+		// 現在プールに空いているスレッドがあるかどうか調べる
+		host = Pop(thread_pool);
+	}
+	UnlockSk(thread_pool);
+
+	if (host == NULL)
+	{
+		// 空いているスレッドが見つからなかったので新しいスレッドを作成する
+		pd = ZeroMalloc(sizeof(THREAD_POOL_DATA));
+		pd->Event = NewEvent();
+		pd->InitFinishEvent = NewEvent();
+		host = NewThreadInternal(ThreadPoolProc, pd);
+		WaitThreadInitInternal(host);
+
+		new_thread = true;
+	}
+	else
+	{
+		pd = (THREAD_POOL_DATA *)host->param;
+	}
+
+	// プールスレッドの作成
+	ret = ZeroMalloc(sizeof(THREAD));
+	ret->ref = NewRef();
+	ret->thread_proc = thread_proc;
+	ret->param = param;
+	ret->pData = NULL;
+	ret->init_finished_event = NewEvent();
+	ret->PoolThread = true;
+	ret->PoolWaitList = NewList(NULL);
+	ret->PoolHostThread = host;
+	ret->release_event = NewEvent();
+
+	// 実行
+	pd->ThreadProc = thread_proc;
+	pd->Thread = ret;
+	AddRef(ret->ref);
+
+	Set(pd->Event);
+
+	Wait(pd->InitFinishEvent, INFINITE);
+
+	return ret;
+}
+
+// スレッドのクリーンアップ (プール)
+void CleanupThread(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	ReleaseEvent(t->init_finished_event);
+	ReleaseEvent(t->release_event);
+	ReleaseList(t->PoolWaitList);
+
+	Free(t);
+}
+
+// スレッド解放 (プール)
+void ReleaseThread(THREAD *t)
+{
+	UINT ret;
+	EVENT *e;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	e = t->release_event;
+	if (e != NULL)
+	{
+		AddRef(e->ref);
+	}
+
+	ret = Release(t->ref);
+	Set(e);
+
+	ReleaseEvent(e);
+
+	if (ret == 0)
+	{
+		CleanupThread(t);
+	}
+}
+
+// スレッドの初期化完了を通知 (プール)
+void NoticeThreadInit(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// 通知
+	Set(t->init_finished_event);
+}
+
+// スレッドの初期化完了を待機 (プール)
+void WaitThreadInit(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_WAITFORTHREAD_COUNT);
+
+	// 待機
+	Wait(t->init_finished_event, INFINITE);
+}
+
+// スレッドの終了を待機 (プール)
+bool WaitThread(THREAD *t, UINT timeout)
+{
+	bool ret = false;
+	EVENT *e = NULL;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	LockList(t->PoolWaitList);
+	{
+		if (t->PoolHalting)
+		{
+			// 既に停止済み
+			ret = true;
+		}
+		else
+		{
+			// 終了時通知イベントをリストに登録する
+			e = NewEvent();
+			AddRef(e->ref);
+			Insert(t->PoolWaitList, e);
+		}
+	}
+	UnlockList(t->PoolWaitList);
+
+	if (e != NULL)
+	{
+		// イベント待機
+		ret = Wait(e, timeout);
+
+		LockList(t->PoolWaitList);
+		{
+			if (Delete(t->PoolWaitList, e))
+			{
+				ReleaseEvent(e);
+			}
+		}
+		UnlockList(t->PoolWaitList);
+
+		ReleaseEvent(e);
+	}
+
+	return ret;
+}
+
+// スレッド ID の取得
+UINT ThreadId()
+{
+	return OSThreadId();
+}
+
+// スレッドの作成
+THREAD *NewThreadInternal(THREAD_PROC *thread_proc, void *param)
+{
+	THREAD *t;
+	UINT retry = 0;
+	// 引数チェック
+	if (thread_proc == NULL)
+	{
+		return NULL;
+	}
+
+	// スレッドオブジェクト初期化
+	t = ZeroMalloc(sizeof(THREAD));
+	t->init_finished_event = NewEvent();
+
+	t->param = param;
+	t->ref = NewRef();
+	t->thread_proc = thread_proc;
+
+	// OS がスレッドを初期化するまで待機
+	while (true)
+	{
+		if ((retry++) > 60)
+		{
+			printf("\n\n*** error: new thread create failed.\n\n");
+			AbortExit();
+		}
+		if (OSInitThread(t))
+		{
+			break;
+		}
+		SleepThread(500);
+	}
+
+	// KS
+	KS_INC(KS_NEWTHREAD_COUNT);
+
+	return t;
+}
+
+// スレッドの解放
+void ReleaseThreadInternal(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	if (Release(t->ref) == 0)
+	{
+		CleanupThreadInternal(t);
+	}
+}
+
+// スレッドのクリーンアップ
+void CleanupThreadInternal(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// スレッドの解放
+	OSFreeThread(t);
+
+	// イベント解放
+	ReleaseEvent(t->init_finished_event);
+	// メモリ解放
+	Free(t);
+
+	// KS
+	KS_INC(KS_FREETHREAD_COUNT);
+}
+
+// スレッドの終了を待機する
+bool WaitThreadInternal(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	return OSWaitThread(t);
+}
+
+// スレッドの初期化が完了したことを通知する
+void NoticeThreadInitInternal(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// 通知
+	Set(t->init_finished_event);
+}
+
+// スレッドの初期化が完了するまで待機する
+void WaitThreadInitInternal(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_WAITFORTHREAD_COUNT);
+
+	// 待機
+	Wait(t->init_finished_event, INFINITE);
+}
+
+// 日時文字列をロケール情報を使用して取得
+void GetDateTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
+{
+	wchar_t tmp1[MAX_SIZE];
+	wchar_t tmp2[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL || st == NULL)
+	{
+		return;
+	}
+
+	GetDateStrEx(tmp1, sizeof(tmp1), st, locale);
+	GetTimeStrEx(tmp2, sizeof(tmp2), st, locale);
+	UniFormat(str, size, L"%s %s", tmp1, tmp2);
+}
+
+// 時刻文字列をロケール情報を使用して取得
+void GetTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
+{
+	wchar_t *tag = L"%02u%s%02u%s%02u%s";
+	// 引数チェック
+	if (str == NULL || st == NULL)
+	{
+		return;
+	}
+
+	if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)
+	{
+		tag = L"%2u%s%2u%s%2u%s";
+	}
+
+	locale = (locale != NULL ? locale : &current_locale);
+	UniFormat(str, size,
+		tag,
+		st->wHour, locale->HourStr,
+		st->wMinute, locale->MinuteStr,
+		st->wSecond, locale->SecondStr);
+}
+
+// 日付文字列をロケール情報を使用して取得
+void GetDateStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale)
+{
+	wchar_t *tag = L"%04u%s%02u%s%02u%s (%s)";
+	// 引数チェック
+	if (str == NULL || st == NULL)
+	{
+		return;
+	}
+
+	if (_GETLANG() == SE_LANG_JAPANESE || _GETLANG() == SE_LANG_CHINESE_ZH)
+	{
+		tag = L"%4u%s%2u%s%2u%s(%s)";
+	}
+
+	locale = (locale != NULL ? locale : &current_locale);
+	UniFormat(str, size,
+		tag,
+		st->wYear, locale->YearStr,
+		st->wMonth, locale->MonthStr,
+		st->wDay, locale->DayStr,
+		locale->DayOfWeek[st->wDayOfWeek]);
+}
+
+// 時刻文字列をミリ秒単位で取得 (例: 12:34:56.789)
+void GetTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
+{
+	// 引数チェック
+	if (st == NULL || str == NULL)
+	{
+		return;
+	}
+
+	Format(str, size, "%02u:%02u:%02u.%03u",
+		st->wHour, st->wMinute, st->wSecond, st->wMilliseconds);
+}
+
+// 時刻文字列を取得 (例: 12:34:56)
+void GetTimeStr(char *str, UINT size, SYSTEMTIME *st)
+{
+	// 引数チェック
+	if (str == NULL || st == NULL)
+	{
+		return;
+	}
+
+	Format(str, size, "%02u:%02u:%02u",
+		st->wHour, st->wMinute, st->wSecond);
+}
+
+// 日付文字列を取得 (例: 2004/07/23)
+void GetDateStr(char *str, UINT size, SYSTEMTIME *st)
+{
+	// 引数チェック
+	if (str == NULL || st == NULL)
+	{
+		return;
+	}
+
+	Format(str, size, "%04u-%02u-%02u",
+		st->wYear, st->wMonth, st->wDay);
+}
+
+// 日時文字列を取得 (例: 2004/07/23 12:34:56)
+void GetDateTimeStr(char *str, UINT size, SYSTEMTIME *st)
+{
+	// 引数チェック
+	if (str == NULL || st == NULL)
+	{
+		return;
+	}
+
+	Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u",
+		st->wYear, st->wMonth, st->wDay,
+		st->wHour, st->wMinute, st->wSecond);
+}
+
+// 日時文字列をミリ秒単位で取得 (例: 2004/07/23 12:34:56.789)
+void GetDateTimeStrMilli(char *str, UINT size, SYSTEMTIME *st)
+{
+	// 引数チェック
+	if (str == NULL || st == NULL)
+	{
+		return;
+	}
+
+	Format(str, size, "%04u-%02u-%02u %02u:%02u:%02u.%03u",
+		st->wYear, st->wMonth, st->wDay,
+		st->wHour, st->wMinute, st->wSecond,
+		st->wMilliseconds);
+}
+
+// 時間文字列の取得
+void GetSpanStr(char *str, UINT size, UINT64 sec64)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	StrCpy(tmp, sizeof(tmp), "");
+	if (sec64 >= (UINT64)(1000 * 3600 * 24))
+	{
+		Format(tmp, sizeof(tmp), "%u:", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)));
+	}
+
+	Format(tmp, sizeof(tmp), "%s%02u:%02u:%02u", tmp,
+		(UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
+		(UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),
+		(UINT)(sec64 % (UINT64)(1000 * 60)) / 1000);
+
+	Trim(tmp);
+	StrCpy(str, size, tmp);
+}
+
+// 時間文字列の取得 (ミリ秒単位)
+void GetSpanStrMilli(char *str, UINT size, UINT64 sec64)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	StrCpy(tmp, sizeof(tmp), "");
+	if (sec64 >= (UINT64)(1000 * 3600 * 24))
+	{
+		Format(tmp, sizeof(tmp), "%u:", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)));
+	}
+
+	Format(tmp, sizeof(tmp), "%s%02u:%02u:%02u.%03u", tmp,
+		(UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
+		(UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),
+		(UINT)(sec64 % (UINT64)(1000 * 60)) / 1000,
+		(UINT)(sec64 % (UINT64)(1000)));
+
+	Trim(tmp);
+	StrCpy(str, size, tmp);
+}
+
+// 時間文字列の取得 (拡張)
+void GetSpanStrEx(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale)
+{
+	wchar_t tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	locale = (locale != NULL ? locale : &current_locale);
+
+	UniStrCpy(tmp, sizeof(tmp), L"");
+	if (sec64 >= (UINT64)(1000 * 3600 * 24))
+	{
+		UniFormat(tmp, sizeof(tmp), L"%u%s ", (UINT)(sec64 / (UINT64)(1000 * 3600 * 24)),
+			locale->SpanDay);
+	}
+
+	UniFormat(tmp, sizeof(tmp), L"%s%u%s %02u%s %02u%s", tmp,
+		(UINT)(sec64 % (UINT64)(1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
+		locale->SpanHour,
+		(UINT)(sec64 % (UINT64)(1000 * 60 * 60)) / (1000 * 60),
+		locale->SpanMinute,
+		(UINT)(sec64 % (UINT64)(1000 * 60)) / 1000,
+		locale->SpanSecond);
+
+	UniTrim(tmp);
+	UniStrCpy(str, size, tmp);
+}
+
+// 現在のロケール情報を取得
+void GetCurrentLocale(LOCALE *locale)
+{
+	// 引数チェック
+	if (locale == NULL)
+	{
+		return;
+	}
+
+	Copy(locale, &current_locale, sizeof(LOCALE));
+}
+
+// ロケール情報を設定
+void SetLocale(wchar_t *str)
+{
+	wchar_t *set_locale_str;
+	LOCALE tmp;
+
+	if (str != NULL)
+	{
+		set_locale_str = str;
+	}
+	else
+	{
+		set_locale_str = default_locale_str;
+	}
+
+	if (LoadLocale(&tmp, set_locale_str) == false)
+	{
+		if (LoadLocale(&tmp, default_locale_str) == false)
+		{
+			return;
+		}
+	}
+
+	Copy(&current_locale, &tmp, sizeof(LOCALE));
+}
+
+#define	COPY_LOCALE_STR(dest, size, src)	UniStrCpy(dest, size, UniStrCmp(src, L"$") == 0 ? L"" : src)
+
+// ロケール情報の読み込み
+bool LoadLocale(LOCALE *locale, wchar_t *str)
+{
+	UNI_TOKEN_LIST *tokens;
+	UINT i;
+	// 引数チェック
+	if (locale == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	// トークンの解析
+	tokens = UniParseToken(str, L" ");
+	if (tokens->NumTokens != 18)
+	{
+		UniFreeToken(tokens);
+		return false;
+	}
+
+	// 構造体にセット
+	Zero(locale, sizeof(LOCALE));
+	COPY_LOCALE_STR(locale->YearStr, sizeof(locale->YearStr), tokens->Token[0]);
+	COPY_LOCALE_STR(locale->MonthStr, sizeof(locale->MonthStr), tokens->Token[1]);
+	COPY_LOCALE_STR(locale->DayStr, sizeof(locale->DayStr), tokens->Token[2]);
+	COPY_LOCALE_STR(locale->HourStr, sizeof(locale->HourStr), tokens->Token[3]);
+	COPY_LOCALE_STR(locale->MinuteStr, sizeof(locale->MinuteStr), tokens->Token[4]);
+	COPY_LOCALE_STR(locale->SecondStr, sizeof(locale->SecondStr), tokens->Token[5]);
+
+	for (i = 0;i < 7;i++)
+	{
+		COPY_LOCALE_STR(locale->DayOfWeek[i], sizeof(locale->DayOfWeek[i]),
+			tokens->Token[6 + i]);
+	}
+
+	COPY_LOCALE_STR(locale->SpanDay, sizeof(locale->SpanDay), tokens->Token[13]);
+	COPY_LOCALE_STR(locale->SpanHour, sizeof(locale->SpanHour), tokens->Token[14]);
+	COPY_LOCALE_STR(locale->SpanMinute, sizeof(locale->SpanMinute), tokens->Token[15]);
+	COPY_LOCALE_STR(locale->SpanSecond, sizeof(locale->SpanSecond), tokens->Token[16]);
+
+	COPY_LOCALE_STR(locale->Unknown, sizeof(locale->Unknown), tokens->Token[17]);
+
+	UniFreeToken(tokens);
+	return true;
+}
+
+// tm を SYSTEMTIME に変換
+void TmToSystem(SYSTEMTIME *st, struct tm *t)
+{
+	struct tm tmp;
+	// 引数チェック
+	if (st == NULL || t == NULL)
+	{
+		return;
+	}
+
+	Copy(&tmp, t, sizeof(struct tm));
+	NormalizeTm(&tmp);
+
+	Zero(st, sizeof(SYSTEMTIME));
+	st->wYear = MAKESURE(tmp.tm_year + 1900, 1970, 2037);
+	st->wMonth = MAKESURE(tmp.tm_mon + 1, 1, 12);
+	st->wDay = MAKESURE(tmp.tm_mday, 1, 31);
+	st->wDayOfWeek = MAKESURE(tmp.tm_wday, 0, 6);
+	st->wHour = MAKESURE(tmp.tm_hour, 0, 23);
+	st->wMinute = MAKESURE(tmp.tm_min, 0, 59);
+	st->wSecond = MAKESURE(tmp.tm_sec, 0, 59);
+	st->wMilliseconds = 0;
+}
+
+// SYSTEMTIME を tm に変換
+void SystemToTm(struct tm *t, SYSTEMTIME *st)
+{
+	// 引数チェック
+	if (t == NULL || st == NULL)
+	{
+		return;
+	}
+
+	Zero(t, sizeof(struct tm));
+	t->tm_year = MAKESURE(st->wYear, 1970, 2037) - 1900;
+	t->tm_mon = MAKESURE(st->wMonth, 1, 12) - 1;
+	t->tm_mday = MAKESURE(st->wDay, 1, 31);
+	t->tm_hour = MAKESURE(st->wHour, 0, 23);
+	t->tm_min = MAKESURE(st->wMinute, 0, 59);
+	t->tm_sec = MAKESURE(st->wSecond, 0, 59);
+
+	t->tm_isdst = -1;
+	NormalizeTm(t);
+}
+
+// time_t を SYSTEMTIME に変換
+void TimeToSystem(SYSTEMTIME *st, time_t t)
+{
+	struct tm tmp;
+	// 引数チェック
+	if (st == NULL)
+	{
+		return;
+	}
+
+	TimeToTm(&tmp, t);
+	TmToSystem(st, &tmp);
+}
+
+// SYSTEMTIME を time_t に変換
+time_t SystemToTime(SYSTEMTIME *st)
+{
+	struct tm t;
+	// 引数チェック
+	if (st == NULL)
+	{
+		return 0;
+	}
+
+	SystemToTm(&t, st);
+	return TmToTime(&t);
+}
+
+// tm を time_t に変換
+time_t TmToTime(struct tm *t)
+{
+	time_t tmp;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return 0;
+	}
+
+	tmp = c_mkgmtime(t);
+	if (tmp == (time_t)-1)
+	{
+		return 0;
+	}
+	return tmp;
+}
+
+// time_t を tm に変換
+void TimeToTm(struct tm *t, time_t time)
+{
+	struct tm *ret;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+#ifndef	OS_UNIX
+	ret = gmtime(&time);
+#else	// OS_UNIX
+	ret = malloc(sizeof(struct tm));
+	memset(ret, 0, sizeof(ret));
+	gmtime_r(&time, ret);
+#endif	// OS_UNIX
+
+	if (ret == NULL)
+	{
+		Zero(t, sizeof(struct tm));
+	}
+	else
+	{
+		Copy(t, ret, sizeof(struct tm));
+	}
+
+#ifdef	OS_UNIX
+	free(ret);
+#endif	// OS_UNIX
+}
+
+// tm を正規化
+void NormalizeTm(struct tm *t)
+{
+	struct tm *ret;
+	time_t tmp;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	tmp = c_mkgmtime(t);
+	if (tmp == (time_t)-1)
+	{
+		return;
+	}
+
+#ifndef	OS_UNIX
+	ret = gmtime(&tmp);
+#else	// OS_UNIX
+	ret = malloc(sizeof(struct tm));
+	memset(ret, 0, sizeof(ret));
+	gmtime_r(&tmp, ret);
+#endif	// OS_UNIX
+
+	if (ret == NULL)
+	{
+		Zero(t, sizeof(struct tm));
+	}
+	else
+	{
+		Copy(t, ret, sizeof(struct tm));
+	}
+
+#ifdef	OS_UNIX
+	free(ret);
+#endif	// OS_UNIX
+}
+
+// SYSTEMTIME を正規化
+void NormalizeSystem(SYSTEMTIME *st)
+{
+	UINT64 sec64;
+	// 引数チェック
+	if (st == NULL)
+	{
+		return;
+	}
+
+	sec64 = SystemToUINT64(st);
+	UINT64ToSystem(st, sec64);
+}
+
+// 64bit ローカル時刻をシステム時刻に変換
+UINT64 LocalToSystem64(UINT64 t)
+{
+	SYSTEMTIME st;
+	UINT64ToSystem(&st, t);
+	LocalToSystem(&st, &st);
+	return SystemToUINT64(&st);
+}
+
+// 64bit システム時刻をローカル時刻に変換
+UINT64 SystemToLocal64(UINT64 t)
+{
+	SYSTEMTIME st;
+	UINT64ToSystem(&st, t);
+	SystemToLocal(&st, &st);
+	return SystemToUINT64(&st);
+}
+
+// ローカル時刻をシステム時刻に変換
+void LocalToSystem(SYSTEMTIME *system, SYSTEMTIME *local)
+{
+	UINT64 sec64;
+	// 引数チェック
+	if (local == NULL || system == NULL)
+	{
+		return;
+	}
+
+	sec64 = (UINT64)((INT64)SystemToUINT64(local) - GetTimeDiffEx(local, true));
+	UINT64ToSystem(system, sec64);
+}
+
+// システム時刻をローカル時刻に変換
+void SystemToLocal(SYSTEMTIME *local, SYSTEMTIME *system)
+{
+	UINT64 sec64;
+	// 引数チェック
+	if (local == NULL || system == NULL)
+	{
+		return;
+	}
+
+	sec64 = (UINT64)((INT64)SystemToUINT64(system) + GetTimeDiffEx(system, false));
+	UINT64ToSystem(local, sec64);
+}
+
+// 指定時刻をベースにしてシステム時刻とローカル時刻との間の時差を取得
+INT64 GetTimeDiffEx(SYSTEMTIME *basetime, bool local_time)
+{
+	time_t tmp;
+	struct tm t1, t2;
+	SYSTEMTIME snow;
+	struct tm now;
+	SYSTEMTIME s1, s2;
+	INT64 ret;
+
+	Copy(&snow, basetime, sizeof(SYSTEMTIME));
+
+	SystemToTm(&now, &snow);
+	if (local_time == false)
+	{
+		tmp = c_mkgmtime(&now);
+	}
+	else
+	{
+		tmp = mktime(&now);
+	}
+
+	if (tmp == (time_t)-1)
+	{
+		return 0;
+	}
+
+	Copy(&t1, localtime(&tmp), sizeof(struct tm));
+	Copy(&t2, gmtime(&tmp), sizeof(struct tm));
+	TmToSystem(&s1, &t1);
+	TmToSystem(&s2, &t2);
+
+	ret = (INT)SystemToUINT64(&s1) - (INT)SystemToUINT64(&s2);
+
+	return ret;
+}
+
+// システム時刻とローカル時刻との間の時差を取得
+INT64 GetTimeDiff()
+{
+	time_t tmp;
+	struct tm t1, t2;
+	SYSTEMTIME snow;
+	struct tm now;
+	SYSTEMTIME s1, s2;
+	INT64 ret;
+
+	static INT64 cache = INFINITE;
+
+	if (cache != INFINITE)
+	{
+		// 1 度測定したらキャッシュデータを返す
+		return cache;
+	}
+
+	SystemTime(&snow);
+	SystemToTm(&now, &snow);
+	tmp = c_mkgmtime(&now);
+	if (tmp == (time_t)-1)
+	{
+		return 0;
+	}
+
+	Copy(&t1, localtime(&tmp), sizeof(struct tm));
+	Copy(&t2, gmtime(&tmp), sizeof(struct tm));
+	TmToSystem(&s1, &t1);
+	TmToSystem(&s2, &t2);
+
+	cache = ret = (INT)SystemToUINT64(&s1) - (INT)SystemToUINT64(&s2);
+
+	return ret;
+}
+
+// UINT64 を SYSTEMTIME に変換
+void UINT64ToSystem(SYSTEMTIME *st, UINT64 sec64)
+{
+	UINT64 tmp64;
+	UINT sec, millisec;
+	time_t time;
+	// 引数チェック
+	if (st == NULL)
+	{
+		return;
+	}
+
+	sec64 = SafeTime64(sec64 + 32400000ULL);
+	tmp64 = sec64 / (UINT64)1000;
+	millisec = (UINT)(sec64 - tmp64 * (UINT64)1000);
+	sec = (UINT)tmp64;
+	time = (time_t)sec;
+	TimeToSystem(st, time);
+	st->wMilliseconds = (WORD)millisec;
+}
+
+// SYSTEMTIME を UINT64 に変換
+UINT64 SystemToUINT64(SYSTEMTIME *st)
+{
+	UINT64 sec64;
+	time_t time;
+	// 引数チェック
+	if (st == NULL)
+	{
+		return 0;
+	}
+
+	time = SystemToTime(st);
+	sec64 = (UINT64)time * (UINT64)1000;
+	sec64 += st->wMilliseconds;
+
+	return sec64 - 32400000ULL;
+}
+
+// ローカル時刻を UINT64 で取得
+UINT64 LocalTime64()
+{
+	SYSTEMTIME s;
+	LocalTime(&s);
+	return SystemToUINT64(&s);
+}
+
+// システム時刻を UINT64 で取得
+UINT64 SystemTime64()
+{
+	SYSTEMTIME s;
+	SystemTime(&s);
+	return SystemToUINT64(&s);
+}
+
+// ローカル時刻の取得
+void LocalTime(SYSTEMTIME *st)
+{
+	SYSTEMTIME tmp;
+	// 引数チェック
+	if (st == NULL)
+	{
+		return;
+	}
+
+	SystemTime(&tmp);
+	SystemToLocal(st, &tmp);
+}
+
+// システム時刻の取得
+void SystemTime(SYSTEMTIME *st)
+{
+	// 引数チェック
+	if (st == NULL)
+	{
+		return;
+	}
+
+	OSGetSystemTime(st);
+
+	// KS
+	KS_INC(KS_GETTIME_COUNT);
+}
+
+/* free mktime function
+   Copyright 1988, 1989 by David MacKenzie <djm@ai.mit.edu>
+   and Michael Haertel <mike@ai.mit.edu>
+   Unlimited distribution permitted provided this copyright notice is
+   retained and any functional modifications are prominently identified.  */
+time_t c_mkgmtime(struct tm *tm)
+{
+	int years, months, days, hours, minutes, seconds;
+
+	years = tm->tm_year + 1900;   /* year - 1900 -> year */
+	months = tm->tm_mon;          /* 0..11 */
+	days = tm->tm_mday - 1;       /* 1..31 -> 0..30 */
+	hours = tm->tm_hour;          /* 0..23 */
+	minutes = tm->tm_min;         /* 0..59 */
+	seconds = tm->tm_sec;         /* 0..61 in ANSI C. */
+
+	ADJUST_TM(seconds, minutes, 60);
+	ADJUST_TM(minutes, hours, 60);
+	ADJUST_TM(hours, days, 24);
+	ADJUST_TM(months, years, 12);
+	if (days < 0)
+		do {
+			if (--months < 0) {
+				--years;
+				months = 11;
+			}
+			days += monthlen(months, years);
+		} while (days < 0);
+	else
+		while (days >= monthlen(months, years)) {
+			days -= monthlen(months, years);
+			if (++months >= 12) {
+				++years;
+				months = 0;
+			}
+		}
+
+		/* Restore adjusted values in tm structure */
+		tm->tm_year = years - 1900;
+		tm->tm_mon = months;
+		tm->tm_mday = days + 1;
+		tm->tm_hour = hours;
+		tm->tm_min = minutes;
+		tm->tm_sec = seconds;
+
+		/* Set `days' to the number of days into the year. */
+		days += ydays[months] + (months > 1 && leap (years));
+		tm->tm_yday = days;
+
+		/* Now calculate `days' to the number of days since Jan 1, 1970. */
+		days = (unsigned)days + 365 * (unsigned)(years - 1970) +
+			(unsigned)(nleap (years));
+		tm->tm_wday = ((unsigned)days + 4) % 7; /* Jan 1, 1970 was Thursday. */
+		tm->tm_isdst = 0;
+
+		if (years < 1970)
+			return (time_t)-1;
+
+#if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
+#if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
+		if (years > TM_YEAR_MAX ||
+			(years == TM_YEAR_MAX &&
+			(tm->tm_yday > ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
+			(TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) ||
+			(tm->tm_yday == ydays[TM_MON_MAX] + (TM_MDAY_MAX - 1) +
+			(TM_MON_MAX > 1 && leap (TM_YEAR_MAX)) &&
+			(hours > TM_HOUR_MAX ||
+			(hours == TM_HOUR_MAX &&
+			(minutes > TM_MIN_MAX ||
+			(minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
+			return (time_t)-1;
+#endif
+#endif
+
+		return (time_t)(86400L * (unsigned long)(unsigned)days +
+			3600L * (unsigned long)hours +
+			(unsigned long)(60 * minutes + seconds));
+}
+
+// システムタイマの取得
+UINT Tick()
+{
+	// KS
+	KS_INC(KS_GETTICK_COUNT);
+	return OSGetTick();
+}
+
+// スレッドのスリープ
+void SleepThread(UINT time)
+{
+	// KS
+	KS_INC(KS_SLEEPTHREAD_COUNT);
+
+	OSSleep(time);
+}
+
+// イールド
+void YieldCpu()
+{
+	OSYield();
+}
+
+// システム停止 (異常終了)
+void AbortExit()
+{
+#ifdef	OS_WIN32
+	_exit(1);
+#else	// OS_WIN32
+
+#ifdef	RLIMIT_CORE
+	UnixSetResourceLimit(RLIMIT_CORE, 0);
+#endif	// RLIMIT_CORE
+
+	abort();
+#endif	// OS_WIN32
+}
+
+
+void AbortExitEx(char *msg)
+{
+	FILE *f;
+	// 引数チェック
+	if (msg == NULL)
+	{
+		msg = "Unknown Error";
+	}
+
+	f = fopen("abort_error_log.txt", "w");
+	if (f != NULL)
+	{
+		fwrite(msg, 1, strlen(msg), f);
+		fclose(f);
+	}
+
+	fputs("Fatal Error: ", stdout);
+	fputs(msg, stdout);
+	fputs("\r\n", stdout);
+
+#ifdef	OS_WIN32
+	_exit(1);
+#else	// OS_WIN32
+
+#ifdef	RLIMIT_CORE
+	UnixSetResourceLimit(RLIMIT_CORE, 0);
+#endif	// RLIMIT_CORE
+
+	abort();
+#endif	// OS_WIN32
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Kernel.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Kernel.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Kernel.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,227 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+#ifndef	KERNEL_H
+#define	KERNEL_H
+
+// メモリ使用情報
+struct MEMINFO
+{
+	UINT64 TotalMemory;
+	UINT64 UsedMemory;
+	UINT64 FreeMemory;
+	UINT64 TotalPhys;
+	UINT64 UsedPhys;
+	UINT64 FreePhys;
+};
+
+// ロケール情報
+struct LOCALE
+{
+	wchar_t YearStr[16], MonthStr[16], DayStr[16];
+	wchar_t HourStr[16], MinuteStr[16], SecondStr[16];
+	wchar_t DayOfWeek[7][16];
+	wchar_t SpanDay[16], SpanHour[16], SpanMinute[16], SpanSecond[16];
+	wchar_t Unknown[32];
+};
+
+
+// スレッドプロシージャ
+typedef void (THREAD_PROC)(THREAD *thread, void *param);
+
+// スレッド
+struct THREAD
+{
+	REF *ref;
+	THREAD_PROC *thread_proc;
+	void *param;
+	void *pData;
+	EVENT *init_finished_event;
+	void *AppData1, *AppData2, *AppData3;
+	UINT AppInt1, AppInt2, AppInt3;
+	UINT ThreadId;
+	bool PoolThread;
+	THREAD *PoolHostThread;
+	LIST *PoolWaitList;						// スレッド停止待機リスト
+	volatile bool PoolHalting;				// スレッド停止中
+	EVENT *release_event;
+};
+
+// スレッドプールデータ
+struct THREAD_POOL_DATA
+{
+	EVENT *Event;						// 待機イベント
+	EVENT *InitFinishEvent;				// 初期化完了イベント
+	THREAD *Thread;						// 現在割り当てられているスレッド
+	THREAD_PROC *ThreadProc;			// 現在割り当てられているスレッドプロシージャ
+};
+
+// インスタンス
+struct INSTANCE
+{
+	char *Name;							// 名前
+	void *pData;						// データ
+};
+
+// 関数プロトタイプ
+void SleepThread(UINT time);
+THREAD *NewThreadInternal(THREAD_PROC *thread_proc, void *param);
+void ReleaseThreadInternal(THREAD *t);
+void CleanupThreadInternal(THREAD *t);
+void NoticeThreadInitInternal(THREAD *t);
+void WaitThreadInitInternal(THREAD *t);
+bool WaitThreadInternal(THREAD *t);
+THREAD *NewThread(THREAD_PROC *thread_proc, void *param);
+void ReleaseThread(THREAD *t);
+void CleanupThread(THREAD *t);
+void NoticeThreadInit(THREAD *t);
+void WaitThreadInit(THREAD *t);
+bool WaitThread(THREAD *t, UINT timeout);
+void InitThreading();
+void FreeThreading();
+void ThreadPoolProc(THREAD *t, void *param);
+
+time_t c_mkgmtime(struct tm *tm);
+void TmToSystem(SYSTEMTIME *st, struct tm *t);
+void SystemToTm(struct tm *t, SYSTEMTIME *st);
+void TimeToSystem(SYSTEMTIME *st, time_t t);
+time_t SystemToTime(SYSTEMTIME *st);
+time_t TmToTime(struct tm *t);
+void TimeToTm(struct tm *t, time_t time);
+void NormalizeTm(struct tm *t);
+void NormalizeSystem(SYSTEMTIME *st);
+void LocalToSystem(SYSTEMTIME *system, SYSTEMTIME *local);
+void SystemToLocal(SYSTEMTIME *local, SYSTEMTIME *system);
+INT64 GetTimeDiffEx(SYSTEMTIME *basetime, bool local_time);
+void UINT64ToSystem(SYSTEMTIME *st, UINT64 sec64);
+UINT64 SystemToUINT64(SYSTEMTIME *st);
+UINT64 LocalTime64();
+UINT64 SystemTime64();
+void LocalTime(SYSTEMTIME *st);
+void SystemTime(SYSTEMTIME *st);
+void SetLocale(wchar_t *str);
+bool LoadLocale(LOCALE *locale, wchar_t *str);
+void GetCurrentLocale(LOCALE *locale);
+void GetDateTimeStr(char *str, UINT size, SYSTEMTIME *st);
+void GetDateTimeStrMilli(char *str, UINT size, SYSTEMTIME *st);
+void GetDateStr(char *str, UINT size, SYSTEMTIME *st);
+void GetDateTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale);
+void GetTimeStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale);
+void GetDateStrEx(wchar_t *str, UINT size, SYSTEMTIME *st, LOCALE *locale);
+void GetTimeStrMilli(char *str, UINT size, SYSTEMTIME *st);
+void GetTimeStr(char *str, UINT size, SYSTEMTIME *st);
+UINT Tick();
+UINT TickRealtime();
+UINT TickRealtimeManual();
+UINT64 TickGetRealtimeTickValue64();
+UINT64 SystemToLocal64(UINT64 t);
+UINT64 LocalToSystem64(UINT64 t);
+UINT ThreadId();
+void GetDateTimeStr64(char *str, UINT size, UINT64 sec64);
+void GetDateTimeStr64Uni(wchar_t *str, UINT size, UINT64 sec64);
+void GetDateTimeStrMilli64(char *str, UINT size, UINT64 sec64);
+void GetDateStr64(char *str, UINT size, UINT64 sec64);
+void GetDateTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale);
+void GetTimeStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale);
+void GetDateStrEx64(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale);
+void GetTimeStrMilli64(char *str, UINT size, UINT64 sec64);
+void GetTimeStr64(char *str, UINT size, UINT64 sec64);
+UINT64 SafeTime64(UINT64 sec64);
+bool Run(char *filename, char *arg, bool hide, bool wait);
+bool RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait);
+void HashInstanceName(char *name, UINT size, char *instance_name);
+void HashInstanceNameLocal(char *name, UINT size, char *instance_name);
+INSTANCE *NewSingleInstance(char *instance_name);
+INSTANCE *NewSingleInstanceEx(char *instance_name, bool user_local);
+void FreeSingleInstance(INSTANCE *inst);
+void GetSpanStr(char *str, UINT size, UINT64 sec64);
+void GetSpanStrEx(wchar_t *str, UINT size, UINT64 sec64, LOCALE *locale);
+void GetSpanStrMilli(char *str, UINT size, UINT64 sec64);
+void GetMemInfo(MEMINFO *info);
+bool GetEnv(char *name, char *data, UINT size);
+bool GetEnvW(wchar_t *name, wchar_t *data, UINT size);
+bool GetEnvW_ForWin32(wchar_t *name, wchar_t *data, UINT size);
+bool GetEnvW_ForUnix(wchar_t *name, wchar_t *data, UINT size);
+void GetHomeDir(char *path, UINT size);
+void GetHomeDirW(wchar_t *path, UINT size);
+void AbortExit();
+void AbortExitEx(char *msg);
+void YieldCpu();
+UINT DoNothing();
+
+#endif	// KERNEL_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/MayaType.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/MayaType.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/MayaType.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,432 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// MayaType.h
+// Mayaqua Kernel 型宣言ヘッダファイル
+
+#ifndef	MAYATYPE_H
+#define	MAYATYPE_H
+
+// windows.h ヘッダが include されているかどうかをチェック
+#ifndef	WINDOWS_H
+#ifdef	_WINDOWS_
+#define	WINDOWS_H
+#endif	// _WINDOWS_
+#endif	// WINDOWS_H
+
+
+#if	!defined(ENCRYPT_C) && !defined(HAM_C)
+// OpenSSL が使用する構造体
+typedef struct x509_st X509;
+typedef struct evp_pkey_st EVP_PKEY;
+typedef struct bio_st BIO;
+typedef struct ssl_st SSL;
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct X509_req_st X509_REQ;
+typedef struct PKCS12 PKCS12;
+typedef struct bignum_st BIGNUM;
+typedef struct x509_crl_st X509_CRL;
+#endif	// ENCRYPT_C
+
+// 
+// 定数
+// 
+
+// 標準のバッファサイズ
+#define	STD_SIZE			512
+#define	MAX_SIZE			512
+#define	BUF_SIZE			512
+
+// 対応 Windows OS 一覧
+#define	SUPPORTED_WINDOWS_LIST		"Windows 98 / 98 SE / ME / NT 4.0 SP6a / 2000 SP4 / XP SP2, SP3 / Server 2003 SP2 / SBS 2003 SP2 / Storage Server 2003 SP2 / Vista SP1, SP2 / Server 2008 SP1, SP2 / Storage Server 2008 SP1, SP2 / Home Server / 7 / Server 2008 R2"
+
+// 無限
+#ifndef	WINDOWS_H
+#define	INFINITE			(0xFFFFFFFF)
+#endif
+
+
+#define	SRC_NAME			__FILE__	// ソースコードのファイル名
+#define	SRC_LINE			__LINE__	// ソースコード中の行番号
+
+// 最大パスサイズ
+#ifndef	WINDOWS_H
+#define	MAX_PATH			260
+#endif	// WINDOWS_H
+
+// シークの種類
+#ifndef	FILE_BEGIN
+#define	FILE_BEGIN	SEEK_SET
+#endif	// FILE_BEGIN
+#ifndef	FILE_END
+#define	FILE_END	SEEK_END
+#endif	// FILE_END
+#ifndef	FILE_CURRENT
+#define	FILE_CURRENT	SEEK_CUR
+#endif	// FILE_CURRENT
+
+#ifndef	INVALID_SOCKET
+#define	INVALID_SOCKET		(-1)
+#endif	// INVALID_SOCKET
+
+#ifndef	SOCKET_ERROR
+#define	SOCKET_ERROR		(-1)
+#endif	//SOCKET_ERROR
+
+// 比較関数
+typedef int (COMPARE)(void *p1, void *p2);
+
+// 
+// マクロ
+
+
+#ifdef	MAX
+#undef	MAX
+#endif	// MAX
+
+#ifdef	MIN
+#undef	MIN
+#endif	// MIN
+
+// a と b の最小値を求める
+#define	MIN(a, b)			((a) >= (b) ? (b) : (a))
+// a と b の最大値を求める
+#define	MAX(a, b)			((a) >= (b) ? (a) : (b))
+
+// int を bool にする
+#define	INT_TO_BOOL(i)		(((i) == 0) ? false : true)
+#define	MAKEBOOL(i)			INT_TO_BOOL(i)
+#define	BOOL_TO_INT(i)		(((i) == false) ? 0 : 1)
+
+// max_value よりも小さい a を返す
+#define	LESS(a, max_value)	((a) <= (max_value) ? (a) : (max_value))
+// min_value よりも大きい a を返す
+#define	MORE(a, min_value)	((a) >= (min_value) ? (a) : (min_value))
+// a が b と c の内部にある値かどうか調べる
+#define	INNER(a, b, c)		(((b) <= (c) && (a) >= (b) && (a) <= (c)) || ((b) >= (c) && (a) >= (c) && (a) <= (b)))
+// a が b と c の外部にある値かどうか調べる
+#define	OUTER(a, b, c)		(!INNER((a), (b), (c)))
+// a を b と c の間にある値となるように調整する
+#define	MAKESURE(a, b, c)		(((b) <= (c)) ? (MORE(LESS((a), (c)), (b))) : (MORE(LESS((a), (b)), (c))))
+
+// ポインタを UINT にする
+#define	POINTER_TO_KEY(p)		((sizeof(void *) == sizeof(UINT)) ? (UINT)(p) : HashPtrToUINT(p))
+// UINT とポインタを比較する
+#define	COMPARE_POINTER_AND_KEY(p, i)	(POINTER_TO_KEY(p) == (i))
+// ポインタを UINT64 にする
+#define	POINTER_TO_UINT64(p)	(((sizeof(void *) == sizeof(UINT64)) ? (UINT64)(p) : (UINT64)((UINT)(p))))
+// UINT64 をポインタにする
+#define	UINT64_TO_POINTER(i)	((sizeof(void *) == sizeof(UINT64)) ? (void *)(i) : (void *)((UINT)(i)))
+
+// 
+// 型宣言
+// 
+
+// BOOL 型
+#ifndef	WINDOWS_H
+typedef	unsigned int		BOOL;
+#define	TRUE				1
+#define	FALSE				0
+#endif	// WINDOWS_H
+
+// bool 型
+#ifndef	WIN32HTML_CPP
+typedef	unsigned int		bool;
+#define	true				1
+#define	false				0
+#endif	// WIN32HTML_CPP
+
+// 32bit 整数型
+#ifndef	WINDOWS_H
+typedef	unsigned int		UINT;
+typedef	unsigned int		UINT32;
+typedef	unsigned int		DWORD;
+typedef	signed int			INT;
+typedef	signed int			INT32;
+
+typedef	int					UINT_PTR;
+typedef	long				LONG_PTR;
+
+#endif
+
+// 16bit 整数型
+typedef	unsigned short		WORD;
+typedef	unsigned short		USHORT;
+typedef	signed short		SHORT;
+
+// 8bit 整数型
+typedef	unsigned char		BYTE;
+typedef	unsigned char		UCHAR;
+
+#ifndef	WIN32HTML_CPP
+typedef signed char			CHAR;
+#endif	// WIN32HTML_CPP
+
+
+// 64bit 整数型
+typedef	unsigned long long	UINT64;
+typedef signed long long	INT64;
+
+#ifdef	OS_UNIX
+// コンパイルエラーの回避
+#define	__cdecl
+#define	__declspec(x)
+// socket 型
+typedef	int SOCKET;
+#else	// OS_UNIX
+#ifndef	_WINSOCK2API_
+typedef UINT_PTR SOCKET;
+#endif	// _WINSOCK2API_
+#endif	// OS_UNIX
+
+// OS の種類
+#define	OSTYPE_WINDOWS_95						1100	// Windows 95
+#define	OSTYPE_WINDOWS_98						1200	// Windows 98
+#define	OSTYPE_WINDOWS_ME						1300	// Windows Me
+#define	OSTYPE_WINDOWS_UNKNOWN					1400	// Windows (不明)
+#define	OSTYPE_WINDOWS_NT_4_WORKSTATION			2100	// Windows NT 4.0 Workstation
+#define	OSTYPE_WINDOWS_NT_4_SERVER				2110	// Windows NT 4.0 Server
+#define	OSTYPE_WINDOWS_NT_4_SERVER_ENTERPRISE	2111	// Windows NT 4.0 Server, Enterprise Edition
+#define	OSTYPE_WINDOWS_NT_4_TERMINAL_SERVER		2112	// Windows NT 4.0 Terminal Server
+#define	OSTYPE_WINDOWS_NT_4_BACKOFFICE			2113	// BackOffice Server 4.5
+#define	OSTYPE_WINDOWS_NT_4_SMS					2114	// Small Business Server 4.5
+#define	OSTYPE_WINDOWS_2000_PROFESSIONAL		2200	// Windows 2000 Professional
+#define	OSTYPE_WINDOWS_2000_SERVER				2211	// Windows 2000 Server
+#define	OSTYPE_WINDOWS_2000_ADVANCED_SERVER		2212	// Windows 2000 Advanced Server
+#define	OSTYPE_WINDOWS_2000_DATACENTER_SERVER	2213	// Windows 2000 Datacenter Server
+#define	OSTYPE_WINDOWS_2000_BACKOFFICE			2214	// BackOffice Server 2000
+#define	OSTYPE_WINDOWS_2000_SBS					2215	// Small Business Server 2000
+#define	OSTYPE_WINDOWS_XP_HOME					2300	// Windows XP Home Edition
+#define	OSTYPE_WINDOWS_XP_PROFESSIONAL			2301	// Windows XP Professional
+#define	OSTYPE_WINDOWS_2003_WEB					2410	// Windows Server 2003 Web Edition
+#define	OSTYPE_WINDOWS_2003_STANDARD			2411	// Windows Server 2003 Standard Edition
+#define	OSTYPE_WINDOWS_2003_ENTERPRISE			2412	// Windows Server 2003 Enterprise Edition
+#define	OSTYPE_WINDOWS_2003_DATACENTER			2413	// Windows Server 2003 DataCenter Edition
+#define	OSTYPE_WINDOWS_2003_BACKOFFICE			2414	// BackOffice Server 2003
+#define	OSTYPE_WINDOWS_2003_SBS					2415	// Small Business Server 2003
+#define	OSTYPE_WINDOWS_LONGHORN_PROFESSIONAL	2500	// Windows Vista
+#define	OSTYPE_WINDOWS_LONGHORN_SERVER			2510	// Windows Server 2008
+#define	OSTYPE_WINDOWS_7						2600	// Windows 7
+#define	OSTYPE_WINDOWS_SERVER_2008_R2			2610	// Windows Server 2008 R2
+#define	OSTYPE_WINDOWS_8						2700	// Windows 8
+#define	OSTYPE_WINDOWS_SERVER_8					2710	// Windows Server 8
+#define	OSTYPE_UNIX_UNKNOWN						3000	// 不明な UNIX
+#define	OSTYPE_LINUX							3100	// Linux
+#define	OSTYPE_SOLARIS							3200	// Solaris
+#define	OSTYPE_CYGWIN							3300	// Cygwin
+#define	OSTYPE_BSD								3400	// BSD
+#define	OSTYPE_MACOS_X							3500	// MacOS X
+
+
+// OS 判別用マクロ
+#define	GET_KETA(t, i)			(((t) % (i * 10)) / i)
+#define	OS_IS_WINDOWS_9X(t)		(GET_KETA(t, 1000) == 1)
+#define	OS_IS_WINDOWS_NT(t)		(GET_KETA(t, 1000) == 2)
+#define	OS_IS_WINDOWS(t)		(OS_IS_WINDOWS_9X(t) || OS_IS_WINDOWS_NT(t))
+#define	OS_IS_SERVER(t)			(OS_IS_WINDOWS_NT(t) && GET_KETA(t, 10))
+#define	OS_IS_WORKSTATION(t)	((OS_IS_WINDOWS_NT(t) && (!(GET_KETA(t, 10)))) || OS_IS_WINDOWS_9X(t))
+#define	OS_IS_UNIX(t)			(GET_KETA(t, 1000) == 3)
+
+
+// OS 情報
+typedef struct OS_INFO
+{
+	UINT OsType;								// OS の種類
+	UINT OsServicePack;							// サービスパック番号
+	char *OsSystemName;							// OS システム名
+	char *OsProductName;						// OS 製品名
+	char *OsVendorName;							// OS ベンダ名
+	char *OsVersion;							// OS バージョン
+	char *KernelName;							// カーネル名
+	char *KernelVersion;						// カーネルバージョン
+} OS_INFO;
+
+// 時刻型
+#ifndef	WINDOWS_H
+typedef struct SYSTEMTIME
+{
+	WORD wYear;
+	WORD wMonth;
+	WORD wDayOfWeek;
+	WORD wDay;
+	WORD wHour;
+	WORD wMinute;
+	WORD wSecond;
+	WORD wMilliseconds;
+} SYSTEMTIME;
+#endif	// WINDOWS_H
+
+
+// Object.h
+typedef struct LOCK LOCK;
+typedef struct COUNTER COUNTER;
+typedef struct REF REF;
+typedef struct EVENT EVENT;
+typedef struct DEADCHECK DEADCHECK;
+
+// Tracking.h
+typedef struct CALLSTACK_DATA CALLSTACK_DATA;
+typedef struct TRACKING_OBJECT TRACKING_OBJECT;
+typedef struct MEMORY_STATUS MEMORY_STATUS;
+typedef struct TRACKING_LIST TRACKING_LIST;
+
+// FileIO.h
+typedef struct IO IO;
+
+// Memory.h
+typedef struct MEMTAG MEMTAG;
+typedef struct BUF BUF;
+typedef struct FIFO FIFO;
+typedef struct LIST LIST;
+typedef struct QUEUE QUEUE;
+typedef struct SK SK;
+typedef struct CANDIDATE CANDIDATE;
+typedef struct STRMAP_ENTRY STRMAP_ENTRY;
+
+// Str.h
+typedef struct TOKEN_LIST TOKEN_LIST;
+typedef struct INI_ENTRY INI_ENTRY;
+
+// Internat.h
+typedef struct UNI_TOKEN_LIST UNI_TOKEN_LIST;
+
+// Encrypt.h
+typedef struct CRYPT CRYPT;
+typedef struct NAME NAME;
+typedef struct X_SERIAL X_SERIAL;
+typedef struct X X;
+typedef struct K K;
+typedef struct P12 P12;
+typedef struct X_CRL X_CRL;
+
+// Secure.h
+typedef struct SECURE_DEVICE SECURE_DEVICE;
+typedef struct SEC_INFO SEC_INFO;
+typedef struct SECURE SECURE;
+typedef struct SEC_OBJ SEC_OBJ;
+
+// Kernel.h
+typedef struct MEMINFO MEMINFO;
+typedef struct LOCALE LOCALE;
+typedef struct THREAD THREAD;
+typedef struct THREAD_POOL_DATA THREAD_POOL_DATA;
+typedef struct INSTANCE INSTANCE;
+
+// Pack.h
+typedef struct VALUE VALUE;
+typedef struct ELEMENT ELEMENT;
+typedef struct PACK PACK;
+
+// Cfg.h
+typedef struct FOLDER FOLDER;
+typedef struct ITEM ITEM;
+typedef struct CFG_RW CFG_RW;
+typedef struct CFG_ENUM_PARAM CFG_ENUM_PARAM;
+
+// Table.h
+typedef struct TABLE TABLE;
+
+// Network.h
+typedef struct IP IP;
+typedef struct DNSCACHE DNSCACHE;
+typedef struct SOCK_EVENT SOCK_EVENT;
+typedef struct SOCK SOCK;
+typedef struct SOCKSET SOCKSET;
+typedef struct CANCEL CANCEL;
+typedef struct ROUTE_ENTRY ROUTE_ENTRY;
+typedef struct ROUTE_TABLE ROUTE_TABLE;
+//typedef struct SOCKLIST SOCKLIST;
+typedef struct IP_CLIENT IP_CLIENT;
+typedef struct ROUTE_CHANGE ROUTE_CHANGE;
+typedef struct ROUTE_CHANGE_DATA ROUTE_CHANGE_DATA;
+typedef struct GETIP_THREAD_PARAM GETIP_THREAD_PARAM;
+typedef struct WIN32_RELEASEADDRESS_THREAD_PARAM WIN32_RELEASEADDRESS_THREAD_PARAM;
+typedef struct IPV6_ADDR IPV6_ADDR;
+
+// Tick64.h
+typedef struct ADJUST_TIME ADJUST_TIME;
+typedef struct TICK64 TICK64;
+
+// FileIO.h
+typedef struct DIRENT DIRENT;
+typedef struct DIRLIST DIRLIST;
+
+
+
+
+#endif	// MAYATYPE_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Mayaqua.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Mayaqua.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Mayaqua.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1174 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Mayaqua.c
+// Mayaqua Kernel プログラム
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <locale.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// グローバル変数
+bool g_memcheck;								// メモリチェックの有効化
+bool g_debug;									// デバッグモード
+UINT64 kernel_status[NUM_KERNEL_STATUS];		// カーネル状態
+UINT64 kernel_status_max[NUM_KERNEL_STATUS];	// カーネル状態 (最大値)
+LOCK *kernel_status_lock[NUM_KERNEL_STATUS];	// カーネル状態ロック
+BOOL kernel_status_inited = false;				// カーネル状態初期化フラグ
+bool g_little_endian = true;
+char *cmdline = NULL;							// コマンドライン
+wchar_t *uni_cmdline = NULL;					// Unicode コマンドライン
+
+// スタティック変数
+static char *exename = NULL;						// EXE ファイル名 (ANSI)
+static wchar_t *exename_w = NULL;					// EXE ファイル名 (Unicode)
+static TOKEN_LIST *cmdline_token = NULL;			// コマンドライントークン
+static UNI_TOKEN_LIST *cmdline_uni_token = NULL;	// コマンドライントークン (Unicode)
+static OS_INFO *os_info = NULL;						// OS 情報
+static bool dot_net_mode = false;
+static bool minimal_mode = false;
+static UINT last_time_check = 0;
+static UINT first_time_check = 0;
+static bool is_nt = false;
+static bool is_ham_mode = false;
+static UINT init_mayaqua_counter = 0;
+static bool use_probe = false;
+static BUF *probe_buf = NULL;
+static LOCK *probe_lock = NULL;
+static UINT64 probe_start = 0;
+static UINT64 probe_last = 0;
+static bool probe_enabled = false;
+
+// チェックサムを計算する
+USHORT CalcChecksum16(void *buf, UINT size)
+{
+	int sum = 0;
+	USHORT *addr = (USHORT *)buf;
+	int len = (int)size;
+	USHORT *w = addr;
+	int nleft = len;
+	USHORT answer = 0;
+
+	while (nleft > 1)
+	{
+		sum += *w++;
+		nleft -= 2;
+	}
+
+	if (nleft == 1)
+	{
+		*(UCHAR *)(&answer) = *(UCHAR *)w;
+		sum += answer;
+	}
+
+	sum = (sum >> 16) + (sum & 0xffff);
+	sum += (sum >> 16);
+
+	answer = ~sum;
+
+	return answer;
+}
+
+// データ付き Probe の書き込み
+void WriteProbeData(char *filename, UINT line, char *str, void *data, UINT size)
+{
+	char tmp[MAX_SIZE];
+	USHORT cs;
+
+	if (IsProbeEnabled() == false)
+	{
+		return;
+	}
+
+	// データのチェックサムをとる
+	if (size != 0)
+	{
+		cs = CalcChecksum16(data, size);
+	}
+	else
+	{
+		cs = 0;
+	}
+
+	// 文字列の生成
+	snprintf(tmp, sizeof(tmp), "\"%s\" (Size=%5u, Crc=0x%04X)", str, size, cs);
+
+	WriteProbe(filename, line, tmp);
+}
+
+// Probe の書き込み
+void WriteProbe(char *filename, UINT line, char *str)
+{
+#ifdef	OS_WIN32
+	char *s;
+	char tmp[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	UINT64 now = 0;
+	UINT64 time;
+
+	if (IsProbeEnabled() == false)
+	{
+		return;
+	}
+
+	now = MsGetHiResCounter();
+
+	Lock(probe_lock);
+	{
+		UINT64 diff;
+		
+		time = MsGetHiResTimeSpanUSec(now - probe_start);
+
+		diff = time - probe_last;
+
+		if (time < probe_last)
+		{
+			diff = 0;
+		}
+
+		probe_last = time;
+
+		ToStr64(tmp, time);
+		MakeCharArray2(tmp2, ' ', (UINT)(MIN(12, (int)12 - (int)StrLen(tmp))));
+		WriteBuf(probe_buf, tmp2, StrLen(tmp2));
+		WriteBuf(probe_buf, tmp, StrLen(tmp));
+
+		s = " [+";
+		WriteBuf(probe_buf, s, StrLen(s));
+
+		ToStr64(tmp, diff);
+		MakeCharArray2(tmp2, ' ', (UINT)(MIN(12, (int)12 - (int)StrLen(tmp))));
+		WriteBuf(probe_buf, tmp2, StrLen(tmp2));
+		WriteBuf(probe_buf, tmp, StrLen(tmp));
+
+		s = "] - ";
+		WriteBuf(probe_buf, s, StrLen(s));
+
+		WriteBuf(probe_buf, filename, StrLen(filename));
+
+		s = "(";
+		WriteBuf(probe_buf, s, StrLen(s));
+
+		ToStr64(tmp, (UINT64)line);
+		WriteBuf(probe_buf, tmp, StrLen(tmp));
+
+		s = "): ";
+		WriteBuf(probe_buf, s, StrLen(s));
+
+		WriteBuf(probe_buf, str, StrLen(str));
+
+		s = "\r\n";
+		WriteBuf(probe_buf, s, StrLen(s));
+	}
+	Unlock(probe_lock);
+#endif	// OS_WIN32
+}
+
+// Probe の初期化
+void InitProbe()
+{
+	probe_buf = NewBuf();
+	probe_lock = NewLock();
+	probe_enabled = false;
+
+	probe_start = 0;
+
+#ifdef	OS_WIN32
+	probe_start = MsGetHiResCounter();
+#endif	// OS_WIN32
+}
+
+// Probe の解放
+void FreeProbe()
+{
+	if (probe_buf->Size >= 1)
+	{
+		SYSTEMTIME st;
+		char filename[MAX_SIZE];
+
+		// ファイルにすべて書き出す
+		MakeDirEx("@probe_log");
+
+		LocalTime(&st);
+
+		snprintf(filename, sizeof(filename), "@probe_log/%04u%02u%02u_%02u%02u%02u.log",
+			st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+
+		DumpBuf(probe_buf, filename);
+	}
+
+	FreeBuf(probe_buf);
+	DeleteLock(probe_lock);
+}
+
+// Probe を有効 / 無効にする
+void EnableProbe(bool enable)
+{
+	probe_enabled = enable;
+}
+
+// Probe が有効かどうか取得する
+bool IsProbeEnabled()
+{
+#ifndef	USE_PROBE
+	return false;
+#else	// USE_PROBE
+	return probe_enabled;
+#endif	// USE_PROBE
+}
+
+// Ham モードに設定する
+void SetHamMode()
+{
+	is_ham_mode = true;
+}
+
+// Ham モードかどうか取得する
+bool IsHamMode()
+{
+	return is_ham_mode;
+}
+
+// 前回の呼び出しから現在までにかかった時間を表示
+void TimeCheck()
+{
+#ifdef OS_WIN32
+	UINT now, ret, total;
+	now = Win32GetTick();
+	if (last_time_check == 0)
+	{
+		ret = 0;
+	}
+	else
+	{
+		ret = now - last_time_check;
+	}
+	last_time_check = now;
+
+	if (first_time_check == 0)
+	{
+		first_time_check = now;
+	}
+
+	total = now - first_time_check;
+
+	printf(" -- %3.3f / %3.3f\n", (double)ret / 1000.0f, (double)total / 1000.0f);
+#endif	// OS_WIN32
+}
+
+// IA64 かどうか
+bool IsIA64()
+{
+	if (Is64() == false)
+	{
+		return false;
+	}
+
+#ifndef	MAYAQUA_IA_64
+	return false;
+#else	// MAYAQUA_IA_64
+	return true;
+#endif	// MAYAQUA_IA_64
+}
+
+// x64 かどうか
+bool IsX64()
+{
+	if (Is64() == false)
+	{
+		return false;
+	}
+
+#ifndef	MAYAQUA_IA_64
+	return true;
+#else	// MAYAQUA_IA_64
+	return false;
+#endif	// MAYAQUA_IA_64
+}
+
+// 64bit かどうか
+bool Is64()
+{
+#ifdef	CPU_64
+	return true;
+#else	// CPU_64
+	return false;
+#endif	// CPU_64
+}
+
+// 32bit かどうか
+bool Is32()
+{
+	return Is64() ? false : true;
+}
+
+// .NET モード
+void MayaquaDotNetMode()
+{
+	dot_net_mode = true;
+}
+
+// .NET モードかどうか取得
+bool MayaquaIsDotNetMode()
+{
+	return dot_net_mode;
+}
+
+// エンディアンチェック
+void CheckEndian()
+{
+	unsigned short test;
+	UCHAR *buf;
+
+	test = 0x1234;
+	buf = (UCHAR *)&test;
+	if (buf[0] == 0x12)
+	{
+		g_little_endian = false;
+	}
+	else
+	{
+		g_little_endian = true;
+	}
+}
+
+// 最小モードにする
+void MayaquaMinimalMode()
+{
+	minimal_mode = true;
+}
+bool MayaquaIsMinimalMode()
+{
+	return minimal_mode;
+}
+
+// NT かどうか
+bool IsNt()
+{
+	return is_nt;
+}
+
+// Unicode をサポートしているかどうか
+bool IsUnicode()
+{
+#ifdef	OS_WIN32
+	// Windows
+	return IsNt();
+#else	// OS_WIN32
+	// UNIX
+	return true;
+#endif	// OS_WIN32
+}
+
+// Mayaqua ライブラリの初期化
+void InitMayaqua(bool memcheck, bool debug, int argc, char **argv)
+{
+	wchar_t tmp[MAX_PATH];
+
+	if ((init_mayaqua_counter++) > 0)
+	{
+		return;
+	}
+
+	g_memcheck = memcheck;
+	g_debug = debug;
+	cmdline = NULL;
+	if (dot_net_mode == false)
+	{
+		// .NET モードでこれを呼ぶとなぜか落ちる
+		setbuf(stdout, NULL);
+	}
+
+	// NT かどうか取得
+#ifdef	OS_WIN32
+	is_nt = Win32IsNt();
+#endif	// OS_WIN32
+
+	// エンディアンチェック
+	CheckEndian();
+
+#ifdef	OS_WIN32
+	_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
+#endif	// OS_WIN32
+
+	// CRT のロケール情報を日本語にする
+	setlocale(LC_ALL, "");
+
+	// OS の初期化
+	OSInit();
+
+	// 乱数の初期化
+	srand((UINT)SystemTime64());
+
+	tick_manual_lock = NewLock();
+
+	// FIFO システムの初期化
+	InitFifo();
+
+	// カーネルステータスの初期化
+	InitKernelStatus();
+
+	// トラッキングの初期化
+	InitTracking();
+
+	// スレッドプールの初期化
+	InitThreading();
+
+	// 文字列ライブラリの初期化
+	InitStringLibrary();
+
+	// ロケール情報の初期化
+	SetLocale(NULL);
+
+	// 暗号化ライブラリの初期化
+	InitCryptLibrary();
+
+	// リアルタイムクロックの初期化
+	InitTick64();
+
+	// ネットワーク通信モジュールの初期化
+	InitNetwork();
+
+	// EXE ファイル名の取得の初期化
+	InitGetExeName(argc >= 1 ? argv[0] : NULL);
+
+	// コマンドライン文字列の初期化
+	InitCommandLineStr(argc, argv);
+
+	// OS 情報の初期化
+	InitOsInfo();
+
+	// オペレーティングシステム固有の初期化
+#ifdef	OS_WIN32
+	MsInit();	// Microsoft Win32
+#endif	// OS_WIN32
+
+	// セキュリティトークンモジュールの初期化
+	InitSecure();
+
+	if (OSIsSupportedOs() == false)
+	{
+		// 強制終了
+		exit(0);
+	}
+
+	// RSA チェック
+	if (RsaCheckEx() == false)
+	{
+		// 強制終了
+		Alert("OpenSSL Library Init Failed. (too old?)\nPlease install the latest version of OpenSSL.\n\n", "RsaCheck()");
+		exit(0);
+	}
+
+	// HamCore ファイルシステムの初期化
+	InitHamcore();
+
+	// デフォルトで japanese.stb を読み込む
+	LoadTable(DEFAULT_TABLE_FILE_NAME);
+
+	if (exename == NULL)
+	{
+		// 実行可能ファイル名
+		exename = CopyStr("unknown");
+	}
+
+	// 自分自身の実行可能ファイル名が見つかるかどうか検査する
+	// (見つからない場合は変なパスで起動されているので終了する)
+	GetExeNameW(tmp, sizeof(tmp));
+	if (IsFileExistsW(tmp) == false)
+	{
+		wchar_t tmp2[MAX_SIZE];
+
+		UniFormat(tmp2, sizeof(tmp2),
+			L"Error: Executable binary file \"%s\" not found.\r\n\r\n"
+			L"Please execute program with full path.\r\n",
+			tmp);
+
+		AlertW(tmp2, NULL);
+		_exit(0);
+	}
+
+	CheckUnixTempDir();
+
+	// Probe の初期化
+	InitProbe();
+}
+
+// Mayaqua ライブラリの解放
+void FreeMayaqua()
+{
+	if ((--init_mayaqua_counter) > 0)
+	{
+		return;
+	}
+
+	// Probe の解放
+	FreeProbe();
+
+	// テーブルを削除
+	FreeTable();
+
+	// セキュリティトークンモジュールの解放
+	FreeSecure();
+
+	// オペレーティングシステム固有の解放
+#ifdef	OS_WIN32
+	MsFree();
+#endif	// OS_WIN32
+
+	// OS 情報の解放
+	FreeOsInfo();
+
+	// HamCore ファイルシステムの解放
+	FreeHamcore();
+
+	// コマンドライン文字列の解放
+	FreeCommandLineStr();
+
+	// コマンドライントークンの解放
+	FreeCommandLineTokens();
+
+	// ネットワーク通信モジュールの解放
+	FreeNetwork();
+
+	// リアルタイムクロックの解放
+	FreeTick64();
+
+	// 暗号化ライブラリの解放
+	FreeCryptLibrary();
+
+	// 文字列ライブラリの解放
+	FreeStringLibrary();
+
+	// スレッドプールの解放
+	FreeThreading();
+
+#ifndef	VPN_SPEED
+	// カーネル状態の表示
+	if (g_debug)
+	{
+		PrintKernelStatus();
+	}
+
+	// デバッグ情報の表示
+	if (g_memcheck)
+	{
+		PrintDebugInformation();
+	}
+#endif	// VPN_SPEED
+
+	// トラッキングの解放
+	FreeTracking();
+
+	// カーネルステータスの解放
+	FreeKernelStatus();
+
+	DeleteLock(tick_manual_lock);
+	tick_manual_lock = NULL;
+
+	// OS の解放
+	OSFree();
+}
+
+// UNIX で /tmp が使用できるかどうか確認する
+void CheckUnixTempDir()
+{
+	if (OS_IS_UNIX(GetOsInfo()->OsType))
+	{
+		char tmp[128], tmp2[64];
+		UINT64 now = SystemTime64();
+		IO *o;
+
+		MakeDir("/tmp");
+
+		Format(tmp2, sizeof(tmp2), "%I64u", now);
+
+		Format(tmp, sizeof(tmp), "/tmp/.%s", tmp2);
+
+		o = FileCreate(tmp);
+		if (o == NULL)
+		{
+			o = FileOpen(tmp, false);
+			if (o == NULL)
+			{
+				Print("Unable to use /tmp.\n\n");
+				exit(0);
+				return;
+			}
+		}
+
+		FileClose(o);
+
+		FileDelete(tmp);
+	}
+}
+
+// アラートの表示
+void Alert(char *msg, char *caption)
+{
+	OSAlert(msg, caption);
+}
+void AlertW(wchar_t *msg, wchar_t *caption)
+{
+	OSAlertW(msg, caption);
+}
+
+// OS 情報の表示
+void PrintOsInfo(OS_INFO *info)
+{
+	// 引数チェック
+	if (info == NULL)
+	{
+		return;
+	}
+
+	Print(
+		"OS Type          : %u\n"
+		"OS Service Pack  : %u\n"
+		"os_is_windows    : %s\n"
+		"os_is_windows_nt : %s\n"
+		"OS System Name   : %s\n"
+		"OS Product Name  : %s\n"
+		"OS Vendor Name   : %s\n"
+		"OS Version       : %s\n"
+		"Kernel Name      : %s\n"
+		"Kernel Version   : %s\n",
+		info->OsType,
+		info->OsServicePack,
+		OS_IS_WINDOWS(info->OsType) ? "true" : "false",
+		OS_IS_WINDOWS_NT(info->OsType) ? "true" : "false",
+		info->OsSystemName,
+		info->OsProductName,
+		info->OsVendorName,
+		info->OsVersion,
+		info->KernelName,
+		info->KernelVersion);
+
+#ifdef	OS_WIN32
+	{
+		char *exe, *dir;
+		exe = MsGetExeFileName();
+		dir = MsGetExeDirName();
+
+		Print(
+			"EXE File Path    : %s\n"
+			"EXE Dir Path     : %s\n"
+			"Process Id       : %u\n"
+			"Process Handle   : 0x%X\n",
+			exe, dir, MsGetCurrentProcessId(), MsGetCurrentProcess());
+	}
+#endif	// OS_WIN32
+}
+
+// OS 種類の取得
+UINT GetOsType()
+{
+	OS_INFO *i = GetOsInfo();
+
+	if (i == NULL)
+	{
+		return 0;
+	}
+
+	return i->OsType;
+}
+
+// OS 情報の取得
+OS_INFO *GetOsInfo()
+{
+	return os_info;
+}
+
+// OS 情報の初期化
+void InitOsInfo()
+{
+	if (os_info != NULL)
+	{
+		return;
+	}
+
+	os_info = ZeroMalloc(sizeof(OS_INFO));
+
+	OSGetOsInfo(os_info);
+}
+
+// OS 情報の解放
+void FreeOsInfo()
+{
+	if (os_info == NULL)
+	{
+		return;
+	}
+
+	Free(os_info->OsSystemName);
+	Free(os_info->OsProductName);
+	Free(os_info->OsVendorName);
+	Free(os_info->OsVersion);
+	Free(os_info->KernelName);
+	Free(os_info->KernelVersion);
+	Free(os_info);
+
+	os_info = NULL;
+}
+
+// Unicode コマンドライントークンの取得
+UNI_TOKEN_LIST *GetCommandLineUniToken()
+{
+	if (cmdline_uni_token == NULL)
+	{
+		return UniNullToken();
+	}
+	else
+	{
+		return UniCopyToken(cmdline_uni_token);
+	}
+}
+
+// コマンドライントークンの取得
+TOKEN_LIST *GetCommandLineToken()
+{
+	if (cmdline_token == NULL)
+	{
+		return NullToken();
+	}
+	else
+	{
+		return CopyToken(cmdline_token);
+	}
+}
+
+// コマンドライン文字列をトークンに変換する
+void ParseCommandLineTokens()
+{
+	if (cmdline_token != NULL)
+	{
+		FreeToken(cmdline_token);
+	}
+	cmdline_token = ParseCmdLine(cmdline);
+
+	if (cmdline_uni_token != NULL)
+	{
+		UniFreeToken(cmdline_uni_token);
+	}
+	cmdline_uni_token = UniParseCmdLine(uni_cmdline);
+}
+
+// コマンドライントークンを解放する
+void FreeCommandLineTokens()
+{
+	if (cmdline_token != NULL)
+	{
+		FreeToken(cmdline_token);
+	}
+	cmdline_token = NULL;
+
+	if (cmdline_uni_token != NULL)
+	{
+		UniFreeToken(cmdline_uni_token);
+	}
+	cmdline_uni_token = NULL;
+}
+
+// コマンドライン文字列の初期化
+void InitCommandLineStr(int argc, char **argv)
+{
+	if (argc >= 1)
+	{
+#ifdef	OS_UNIX
+		exename_w = CopyUtfToUni(argv[0]);
+		exename = CopyUniToStr(exename_w);
+#else	// OS_UNIX
+		exename = CopyStr(argv[0]);
+		exename_w = CopyStrToUni(exename);
+#endif	// OS_UNIX
+	}
+	if (argc < 2 || argv == NULL)
+	{
+		// コマンドライン文字列無し
+		SetCommandLineStr(NULL);
+	}
+	else
+	{
+		// コマンドライン文字列有り
+		int i, total_len = 1;
+		char *tmp;
+
+		for (i = 1;i < argc;i++)
+		{
+			total_len += StrLen(argv[i]) * 2 + 32;
+		}
+		tmp = ZeroMalloc(total_len);
+
+		for (i = 1;i < argc;i++)
+		{
+			UINT s_size = StrLen(argv[i]) * 2;
+			char *s = ZeroMalloc(s_size);
+			bool dq = (SearchStrEx(argv[i], " ", 0, true) != INFINITE);
+			ReplaceStrEx(s, s_size, argv[i], "\"", "\"\"", true);
+			if (dq)
+			{
+				StrCat(tmp, total_len, "\"");
+			}
+			StrCat(tmp, total_len, s);
+			if (dq)
+			{
+				StrCat(tmp, total_len, "\"");
+			}
+			StrCat(tmp, total_len, " ");
+			Free(s);
+		}
+
+		Trim(tmp);
+		SetCommandLineStr(tmp);
+		Free(tmp);
+	}
+}
+
+// コマンドライン文字列の解放
+void FreeCommandLineStr()
+{
+	SetCommandLineStr(NULL);
+
+	if (exename != NULL)
+	{
+		Free(exename);
+		exename = NULL;
+	}
+
+	if (exename_w != NULL)
+	{
+		Free(exename_w);
+		exename_w = NULL;
+	}
+}
+
+// Unicode コマンドライン文字列の取得
+wchar_t *GetCommandLineUniStr()
+{
+	if (uni_cmdline == NULL)
+	{
+		return UniCopyStr(L"");
+	}
+	else
+	{
+		return UniCopyStr(uni_cmdline);
+	}
+}
+
+// コマンドライン文字列の取得
+char *GetCommandLineStr()
+{
+	if (cmdline == NULL)
+	{
+		return CopyStr("");
+	}
+	else
+	{
+		return CopyStr(cmdline);
+	}
+}
+
+// Unicode コマンドライン文字列の設定
+void SetCommandLineUniStr(wchar_t *str)
+{
+	if (uni_cmdline != NULL)
+	{
+		Free(uni_cmdline);
+	}
+	if (str == NULL)
+	{
+		uni_cmdline = NULL;
+	}
+	else
+	{
+		uni_cmdline = CopyUniStr(str);
+	}
+
+	ParseCommandLineTokens();
+}
+
+// コマンドライン文字列の設定
+void SetCommandLineStr(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		if (cmdline != NULL)
+		{
+			Free(cmdline);
+		}
+		cmdline = NULL;
+	}
+	else
+	{
+		if (cmdline != NULL)
+		{
+			Free(cmdline);
+		}
+		cmdline = CopyStr(str);
+	}
+
+	if (cmdline == NULL)
+	{
+		if (uni_cmdline != NULL)
+		{
+			Free(uni_cmdline);
+			uni_cmdline = NULL;
+		}
+	}
+	else
+	{
+		if (uni_cmdline != NULL)
+		{
+			Free(uni_cmdline);
+		}
+		uni_cmdline = CopyStrToUni(cmdline);
+	}
+
+	ParseCommandLineTokens();
+}
+
+// カーネルステータスの表示
+void PrintKernelStatus()
+{
+	bool leaked = false;
+
+	Print("\n");
+	Print(
+		"     --------- Mayaqua Kernel Status ---------\n"
+		"        Malloc Count ............... %u\n"
+		"        ReAlloc Count .............. %u\n"
+		"        Free Count ................. %u\n"
+		"        Total Memory Size .......... %I64u bytes\n"
+		"      * Current Memory Blocks ...... %u Blocks (Peek: %u)\n"
+		"        Total Memory Blocks ........ %u Blocks\n"
+		"      * Current MemPool Blocks ..... %u Blocks (Peek: %u)\n"
+		"        Total MemPool Mallocs ...... %u Mallocs\n"
+		"        Total MemPool ReAllocs ..... %u ReAllocs\n"
+		"        NewLock Count .............. %u\n"
+		"        DeleteLock Count ........... %u\n"
+		"      * Current Lock Objects ....... %u Objects\n"
+		"      * Current Locked Objects ..... %u Objects\n"
+		"        NewRef Count ............... %u\n"
+		"        FreeRef Count .............. %u\n"
+		"      * Current Ref Objects ........ %u Objects\n"
+		"      * Current Ref Count .......... %u Refs\n"
+		"        GetTime Count .............. %u\n"
+		"        GetTick Count .............. %u\n"
+		"        NewThread Count ............ %u\n"
+		"        FreeThread Count ........... %u\n"
+		"      * Current Threads ............ %u Threads\n"
+		"        Wait For Event Count ....... %u\n\n",
+		KS_GET(KS_MALLOC_COUNT),
+		KS_GET(KS_REALLOC_COUNT),
+		KS_GET(KS_FREE_COUNT),
+		KS_GET64(KS_TOTAL_MEM_SIZE),
+		KS_GET(KS_CURRENT_MEM_COUNT),
+		KS_GETMAX(KS_CURRENT_MEM_COUNT),
+		KS_GET(KS_TOTAL_MEM_COUNT),
+		KS_GET(KS_MEMPOOL_CURRENT_NUM),
+		KS_GETMAX(KS_MEMPOOL_CURRENT_NUM),
+		KS_GET(KS_MEMPOOL_MALLOC_COUNT),
+		KS_GET(KS_MEMPOOL_REALLOC_COUNT),
+		KS_GET(KS_NEWLOCK_COUNT),
+		KS_GET(KS_DELETELOCK_COUNT),
+		KS_GET(KS_CURRENT_LOCK_COUNT),
+		KS_GET(KS_CURRENT_LOCKED_COUNT),
+		KS_GET(KS_NEWREF_COUNT),
+		KS_GET(KS_FREEREF_COUNT),
+		KS_GET(KS_CURRENT_REF_COUNT),
+		KS_GET(KS_CURRENT_REFED_COUNT),
+		KS_GET(KS_GETTIME_COUNT),
+		KS_GET(KS_GETTICK_COUNT),
+		KS_GET(KS_NEWTHREAD_COUNT),
+		KS_GET(KS_FREETHREAD_COUNT),
+		KS_GET(KS_NEWTHREAD_COUNT) - KS_GET(KS_FREETHREAD_COUNT),
+		KS_GET(KS_WAIT_COUNT)
+		);
+
+	if (KS_GET(KS_CURRENT_MEM_COUNT) != 0 || KS_GET(KS_CURRENT_LOCK_COUNT) != 0 ||
+		KS_GET(KS_MEMPOOL_CURRENT_NUM) != 0 ||
+		KS_GET(KS_CURRENT_LOCKED_COUNT) != 0 || KS_GET(KS_CURRENT_REF_COUNT) != 0)
+	{
+		leaked = true;
+	}
+
+	if (leaked)
+	{
+		Print("      !!! MEMORY LEAKS DETECTED !!!\n\n");
+		if (g_memcheck == false)
+		{
+			GetLine(NULL, 0);
+		}
+	}
+	else
+	{
+		Print("        @@@ NO MEMORY LEAKS @@@\n\n");
+	}
+}
+
+// カーネルステータスの初期化
+void InitKernelStatus()
+{
+	UINT i;
+
+	// メモリ初期化
+	Zero(kernel_status, sizeof(kernel_status));
+	Zero(kernel_status_max, sizeof(kernel_status_max));
+
+	// ロック初期化
+	for (i = 0;i < NUM_KERNEL_STATUS;i++)
+	{
+		kernel_status_lock[i] = OSNewLock();
+	}
+
+	kernel_status_inited = true;
+}
+
+// カーネルステータスの解放
+void FreeKernelStatus()
+{
+	UINT i;
+
+	kernel_status_inited = false;
+
+	// ロック解放
+	for (i = 0;i < NUM_KERNEL_STATUS;i++)
+	{
+		OSDeleteLock(kernel_status_lock[i]);
+	}
+}
+
+// カーネルステータスのロック
+void LockKernelStatus(UINT id)
+{
+	// 引数チェック
+	if (id >= NUM_KERNEL_STATUS)
+	{
+		return;
+	}
+
+	OSLock(kernel_status_lock[id]);
+}
+
+// カーネルステータスのロック解除
+void UnlockKernelStatus(UINT id)
+{
+	// 引数チェック
+	if (id >= NUM_KERNEL_STATUS)
+	{
+		return;
+	}
+
+	OSUnlock(kernel_status_lock[id]);
+}
+
+// デバッグ情報の表示
+void PrintDebugInformation()
+{
+	MEMORY_STATUS memory_status;
+	GetMemoryStatus(&memory_status);
+
+	// ヘッダ
+	Print("====== SoftEther UT-VPN System Debug Information ======\n");
+
+	// メモリ情報
+	Print(" <Memory Status>\n"
+		"       Number of Allocated Memory Blocks: %u\n"
+		"   Total Size of Allocated Memory Blocks: %u bytes\n",
+		memory_status.MemoryBlocksNum, memory_status.MemorySize);
+
+	// フッタ
+	Print("====================================================\n");
+
+	if (KS_GET(KS_CURRENT_MEM_COUNT) != 0 || KS_GET(KS_CURRENT_LOCK_COUNT) != 0 ||
+		KS_GET(KS_CURRENT_LOCKED_COUNT) != 0 || KS_GET(KS_CURRENT_REF_COUNT) != 0)
+	{
+		// メモリリークしている可能性があるのでデバッグメニューを出す
+		MemoryDebugMenu();
+	}
+}
+
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Mayaqua.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Mayaqua.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Mayaqua.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,554 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Mayaqua.h
+// Mayaqua Kernel ヘッダファイル
+
+#ifndef	MAYAQUA_H
+#define	MAYAQUA_H
+
+// PenCore.dll 関係
+#define	PENCORE_DLL_NAME		"|PenCore.dll"
+
+//#define	USE_PROBE						// Probe を使う
+
+// リリースフラグ用マクロ
+#ifdef	VPN_SPEED
+
+#define	DONT_USE_KERNEL_STATUS			// カーネルステータスを更新しない
+#define	WIN32_USE_HEAP_API_FOR_MEMORY	// メモリ確保にヒープ API を使用する
+#define	WIN32_NO_DEBUG_HELP_DLL			// デバッグ用 DLL を呼び出さない
+#define	DONT_CHECK_HEAP					// ヒープの状態をチェックしない
+
+#endif	// VPN_SPEED
+
+#ifdef	VPN_EXE
+// 実行可能ファイルビルド用
+#ifdef	WIN32
+#include <windows.h>
+#include "../PenCore/resource.h"
+int main(int argc, char *argv[]);
+int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, char *CmdLine, int CmdShow)
+{
+	return main(0, NULL);
+}
+#endif	// WIN32
+#endif	// VPN_EXE
+
+// 定数
+#define	DEFAULT_TABLE_FILE_NAME		"|strtable.stb"		// デフォルト文字列テーブル
+#define	STRTABLE_ID					"UT_VPN_20100520"	// 文字列テーブル識別子
+
+// OS の判別
+#ifdef	WIN32
+#define	OS_WIN32		// Microsoft Windows
+#else
+#define	OS_UNIX			// UNIX
+#endif	// WIN32
+
+// ディレクトリ区切り
+#ifdef	OS_WIN32
+#define	PATH_BACKSLASH	// バックスラッシュ (\)
+#else	// WIN32
+#define	PATH_SLASH		// スラッシュ (/)
+#endif	// WIN32
+
+// 文字コード
+#ifdef	OS_WIN32
+#define	CODE_SHIFTJIS	// Shift_JIS コード
+#else	// WIN32
+#define	CODE_EUC		// euc-jp コード
+#endif	// WIN32
+
+// エンディアン
+#define	IsBigEndian()		(g_little_endian ? false : true)
+#define	IsLittleEndian()	(g_little_endian)
+
+#ifdef	OS_WIN32
+// snprintf 関数の置換
+#define	snprintf	_snprintf
+#endif	// OS_WIN32
+
+// コンパイラ依存
+#ifndef	OS_WIN32
+// gcc コンパイラ
+#define	GCC_PACKED		__attribute__ ((__packed__))
+#else	// OS_WIN32
+// VC++ コンパイラ
+#define	GCC_PACKED
+#endif	// OS_WIN32
+
+// 現在のファイルと行番号を表示するマクロ
+#define	WHERE			printf("%s: %u\n", __FILE__, __LINE__); SleepThread(10);
+#define	WHERE32			{	\
+	char tmp[128]; sprintf(tmp, "%s: %u", __FILE__, __LINE__); Win32DebugAlert(tmp);	\
+	}
+#define TIMECHECK		printf("%-12s:%5u", __FILE__, __LINE__);TimeCheck();
+
+// プローブ関係
+#ifdef	USE_PROBE
+#define	PROBE_WHERE						WriteProbe(__FILE__, __LINE__, "");
+#define	PROBE_STR(str)					WriteProbe(__FILE__, __LINE__, (str));
+#define	PROBE_DATA2(str, data, size)	WriteProbeData(__FILE__, __LINE__, (str), (data), (size));
+#define	PROBE_DATA(data, size)			WriteProbeData(__FILE__, __LINE__, "", (data), (size));
+#else	// USE_PROBE
+#define	PROBE_WHERE
+#define	PROBE_STR(str)
+#define	PROBE_DATA2(str, data, size)
+#define	PROBE_DATA(data, size)
+#endif	// USE_PROBE
+
+// 現在の時間を表示するマクロ
+#ifdef	WIN32
+#define	WHEN			{WHERE; MsPrintTick();}
+#else	// WIN32
+#define	WHEN
+#endif	// WIN32
+
+#ifdef	OS_UNIX
+// UNIX 系 OS にのみ必要なヘッダ
+#include <sys/types.h>
+#include <unistd.h>
+#include <termios.h>
+#include <dirent.h>
+#ifdef	UNIX_LINUX
+#include <sys/vfs.h>
+#elif	UNIX_BSD
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+#ifdef	UNIX_SOLARIS
+#include <sys/statvfs.h>
+#define	USE_STATVFS
+#endif	// UNIX_SOLARIS
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#ifdef	UNIX_SOLARIS
+#include <sys/filio.h>
+#endif	// UNIX_SOLARIS
+#include <sys/poll.h>
+#include <sys/resource.h>
+#include <pthread.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+//#include <netinet/ip.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+//#include <curses.h>
+
+#ifdef	UNIX_LINUX
+typedef void *iconv_t;
+iconv_t iconv_open (__const char *__tocode, __const char *__fromcode);
+size_t iconv (iconv_t __cd, char **__restrict __inbuf,
+                     size_t *__restrict __inbytesleft,
+                     char **__restrict __outbuf,
+                     size_t *__restrict __outbytesleft);
+int iconv_close (iconv_t __cd);
+#else	// UNIX_LINUX
+#include <iconv.h>
+#endif	// UNIX_LINUX
+
+
+#ifdef	UNIX_LINUX
+#include <netinet/if_ether.h>
+#include <net/ethernet.h>
+#include <netpacket/packet.h>
+#endif	// UNIX_LINUX
+
+#ifdef	UNIX_SOLARIS
+#include <sys/dlpi.h>
+#include <sys/stropts.h>
+#include <sys/stream.h>
+#endif	// UNIX_SOLARIS
+
+#ifndef	NO_VLAN
+
+#include <Mayaqua/TunTap.h>
+
+#endif	// NO_VLAN
+
+#define	closesocket(s)		close(s)
+
+#else	// Win32 のみ
+
+#include <conio.h>
+
+#endif	// OS_UNIX
+
+// IPv6 サポートフラグ
+#ifndef	WIN32
+#ifndef	AF_INET6
+#define	NO_IPV6
+#endif	// AF_INET6
+#endif	// WIN32
+
+// 基本型宣言
+#include <Mayaqua/MayaType.h>
+
+// オブジェクト管理
+#include <Mayaqua/Object.h>
+
+// オブジェクト追跡
+#include <Mayaqua/Tracking.h>
+
+// ファイル入出力
+#include <Mayaqua/FileIO.h>
+
+// メモリ管理
+#include <Mayaqua/Memory.h>
+
+// 文字列処理
+#include <Mayaqua/Str.h>
+
+// 国際化文字列処理
+#include <Mayaqua/Internat.h>
+
+// 暗号化処理
+#include <Mayaqua/Encrypt.h>
+
+// セキュアトークン
+#include <Mayaqua/Secure.h>
+
+// カーネル
+#include <Mayaqua/Kernel.h>
+
+// パッケージ
+#include <Mayaqua/Pack.h>
+
+// 設定ファイル
+#include <Mayaqua/Cfg.h>
+
+// 文字列テーブル
+#include <Mayaqua/Table.h>
+
+// ネットワーク通信
+#include <Mayaqua/Network.h>
+
+// 64 bit リアルタイムクロック
+#include <Mayaqua/Tick64.h>
+
+// OS 依存コード
+#include <Mayaqua/OS.h>
+
+// Microsoft Windows 用コード
+#include <Mayaqua/Microsoft.h>
+
+
+// グローバル変数
+extern bool g_memcheck;
+extern bool g_debug;
+extern char *cmdline;
+extern wchar_t *uni_cmdline;
+extern bool g_little_endian;
+extern LOCK *tick_manual_lock;
+
+// カーネル状態
+#define	NUM_KERNEL_STATUS	128
+extern UINT64 kernel_status[NUM_KERNEL_STATUS];
+extern UINT64 kernel_status_max[NUM_KERNEL_STATUS];
+extern LOCK *kernel_status_lock[NUM_KERNEL_STATUS];
+extern BOOL kernel_status_inited;
+
+// カーネル状態操作マクロ
+#define	KS_LOCK(id)		LockKernelStatus(id)
+#define	KS_UNLOCK(id)	UnlockKernelStatus(id)
+#define	KS_GET64(id)	(kernel_status[id])
+#define	KS_GET(id)		((UINT)KS_GET64(id))
+#define	KS_GETMAX64(id)	(kernel_status_max[id])
+#define	KS_GETMAX(id)	((UINT)KS_GETMAX64(id))
+
+#ifdef	DONT_USE_KERNEL_STATUS
+// カーネルステータス操作を無効にする
+#define	KS_INC(id)
+#define	KS_DEC(id)
+#define	KS_ADD(id, n)
+#define	KS_SUB(id, n)
+#else	// DONT_USE_KERNEL_STATUS
+// カーネルステータス操作を有効にする
+#define	KS_INC(id)							\
+if (kernel_status_inited) {					\
+	KS_LOCK(id);							\
+	kernel_status[id]++;					\
+	kernel_status_max[id] = MAX(kernel_status_max[id], kernel_status[id]);	\
+	KS_UNLOCK(id);							\
+}
+#define	KS_DEC(id)							\
+if (kernel_status_inited) {					\
+	KS_LOCK(id);							\
+	kernel_status[id]--;					\
+	kernel_status_max[id] = MAX(kernel_status_max[id], kernel_status[id]);	\
+	KS_UNLOCK(id);							\
+}
+#define	KS_ADD(id, n)						\
+if (kernel_status_inited) {					\
+	KS_LOCK(id);							\
+	kernel_status[id] += n;					\
+	kernel_status_max[id] = MAX(kernel_status_max[id], kernel_status[id]);	\
+	KS_UNLOCK(id);							\
+}
+#define	KS_SUB(id, n)						\
+if (kernel_status_inited) {					\
+	KS_LOCK(id);							\
+	kernel_status[id] -= n;					\
+	kernel_status_max[id] = MAX(kernel_status_max[id], kernel_status[id]);	\
+	KS_UNLOCK(id);							\
+}
+#endif	// DONT_USE_KERNEL_STATUS
+
+// カーネル状態一覧
+// 文字列関係
+#define	KS_STRCPY_COUNT			0		// StrCpy 呼び出し回数
+#define	KS_STRLEN_COUNT			1		// StrLen 呼び出し回数
+#define	KS_STRCHECK_COUNT		2		// StrCheck 呼び出し回数
+#define	KS_STRCAT_COUNT			3		// StrCat 呼び出し回数
+#define	KS_FORMAT_COUNT			4		// Format 呼び出し回数
+// メモリ関係
+#define	KS_MALLOC_COUNT			5		// Malloc 呼び出し回数
+#define	KS_REALLOC_COUNT		6		// ReAlloc 呼び出し回数
+#define	KS_FREE_COUNT			7		// Free 呼び出し回数
+#define	KS_TOTAL_MEM_SIZE		8		// これまでに確保したメモリの合計サイズ
+#define	KS_CURRENT_MEM_COUNT	9		// 現在確保しているメモリブロック数
+#define	KS_TOTAL_MEM_COUNT		10		// これまでに確保したメモリブロック数の合計
+#define	KS_ZERO_COUNT			11		// Zero 呼び出し回数
+#define	KS_COPY_COUNT			12		// Copy 呼び出し回数
+// ロック関係
+#define	KS_NEWLOCK_COUNT		13		// NewLock を呼び出した回数
+#define	KS_DELETELOCK_COUNT		14		// DeleteLock を呼び出した回数
+#define	KS_LOCK_COUNT			15		// Lock を呼び出した回数
+#define	KS_UNLOCK_COUNT			16		// Unlock を呼び出した回数
+#define	KS_CURRENT_LOCK_COUNT	17		// 現在の LOCK オブジェクト数
+#define	KS_CURRENT_LOCKED_COUNT	18		// 現在のロックされている LOCK オブジェクト数
+// カウンタ情報
+#define	KS_NEW_COUNTER_COUNT	19		// NewCounter を呼び出した回数
+#define	KS_DELETE_COUNTER_COUNT	20		// DeleteCounter を呼び出した回数
+#define	KS_INC_COUNT			21		// Inc を呼び出した回数
+#define	KS_DEC_COUNT			22		// Dec を呼び出した回数
+#define	KS_CURRENT_COUNT		23		// 現在のカウント数の合計
+// 参照カウンタ情報
+#define	KS_NEWREF_COUNT			24		// NewRef を呼び出した回数
+#define	KS_FREEREF_COUNT		72		// REF オブジェクトを削除した回数
+#define	KS_ADDREF_COUNT			25		// AddRef を呼び出した回数
+#define	KS_RELEASE_COUNT		26		// Release を呼び出した回数
+#define	KS_CURRENT_REF_COUNT	27		// 現在の REF オブジェクト数
+#define	KS_CURRENT_REFED_COUNT	28		// 現在の参照数の合計
+// バッファ情報
+#define	KS_NEWBUF_COUNT			29		// NewBuf を呼び出した回数
+#define	KS_FREEBUF_COUNT		30		// FreeBuf を呼び出した回数
+#define	KS_CURRENT_BUF_COUNT	31		// 現在の BUF オブジェクトの数
+#define	KS_READ_BUF_COUNT		32		// ReadBuf を呼び出した回数
+#define	KS_WRITE_BUF_COUNT		33		// WriteBuf を呼び出した回数
+#define	KS_ADJUST_BUFSIZE_COUNT	34		// バッファサイズを調整した回数
+#define	KS_SEEK_BUF_COUNT		35		// SeekBuf を呼び出した回数
+// FIFO 情報
+#define	KS_NEWFIFO_COUNT		36		// NewFifo を呼び出した回数
+#define	KS_FREEFIFO_COUNT		37		// FIFO オブジェクトを削除した回数
+#define	KS_READ_FIFO_COUNT		38		// ReadFifo を呼び出した回数
+#define	KS_WRITE_FIFO_COUNT		39		// WriteFifo を呼び出した回数
+#define	KS_PEEK_FIFO_COUNT		40		// PeekFifo を呼び出した回数
+// リスト関係
+#define	KS_NEWLIST_COUNT		41		// NewList を呼び出した回数
+#define	KS_FREELIST_COUNT		42		// LIST オブジェクトを削除した回数
+#define	KS_INSERT_COUNT			43		// Add を呼び出した回数
+#define	KS_DELETE_COUNT			44		// Delete を呼び出した回数
+#define	KS_SORT_COUNT			45		// Sort を呼び出した回数
+#define	KS_SEARCH_COUNT			46		// Search を呼び出した回数
+#define	KS_TOARRAY_COUNT		47		// ToArray を呼び出した回数
+// キュー関係
+#define	KS_NEWQUEUE_COUNT		48		// NewQueue を呼び出した回数
+#define	KS_FREEQUEUE_COUNT		49		// QUEUE オブジェクトを削除した回数
+#define	KS_PUSH_COUNT			50		// Push を呼び出した回数
+#define	KS_POP_COUNT			51		// POP を呼び出した回数
+// スタック関係
+#define	KS_NEWSK_COUNT			52		// NewSk を呼び出した回数
+#define	KS_FREESK_COUNT			53		// SK オブジェクトを削除した回数
+#define	KS_INSERT_QUEUE_COUNT	54		// InsertQueue を呼び出した回数
+#define	KS_GETNEXT_COUNT		55		// GetNext を呼び出した回数
+// カーネル関係
+#define	KS_GETTIME_COUNT		56		// 時刻を取得した回数
+#define	KS_GETTICK_COUNT		57		// システムタイマを取得した回数
+#define	KS_NEWTHREAD_COUNT		58		// NewThread を呼び出した回数
+#define	KS_FREETHREAD_COUNT		59		// THREAD オブジェクトを削除した回数
+#define	KS_WAITFORTHREAD_COUNT	60		// WaitForThread を呼び出した回数
+#define	KS_NEWEVENT_COUNT		61		// NewEvent を呼び出した回数
+#define	KS_FREEEVENT_COUNT		62		// EVENT オブジェクトを削除した回数
+#define	KS_WAIT_COUNT			63		// Wait を呼び出した回数
+#define	KS_SLEEPTHREAD_COUNT	64		// SleepThread を呼び出した回数
+// IO 関係
+#define	KS_IO_OPEN_COUNT		65		// ファイルを開いた回数
+#define	KS_IO_CREATE_COUNT		66		// ファイルを作成した回数
+#define	KS_IO_CLOSE_COUNT		67		// ファイルを閉じた回数
+#define	KS_IO_READ_COUNT		68		// ファイルから読み込んだ回数
+#define	KS_IO_WRITE_COUNT		69		// ファイルに書き込んだ回数
+#define	KS_IO_TOTAL_READ_SIZE	70		// ファイルから読み込んだ合計バイト数
+#define	KS_IO_TOTAL_WRITE_SIZE	71		// ファイルに書き込んだ合計バイト数
+// メモリプール関係
+#define	KS_MEMPOOL_MALLOC_COUNT	75		// メモリプールを確保した回数
+#define	KS_MEMPOOL_FREE_COUNT	73		// メモリプールを解放した回数
+#define	KS_MEMPOOL_CURRENT_NUM	74		// 現在のメモリプールの個数
+#define	KS_MEMPOOL_REALLOC_COUNT	76	// メモリプールを ReAlloc した回数
+
+
+// マクロ
+#define	IsDebug()		(g_debug)		// デバッグモード
+#define	IsMemCheck()	(g_memcheck)	// メモリチェックモード
+
+// 関数プロトタイプ
+void InitMayaqua(bool memcheck, bool debug, int argc, char **argv);
+void FreeMayaqua();
+bool IsNt();
+bool IsUnicode();
+void MayaquaDotNetMode();
+bool MayaquaIsDotNetMode();
+void MayaquaMinimalMode();
+bool MayaquaIsMinimalMode();
+bool Is64();
+bool Is32();
+bool IsIA64();
+bool IsX64();
+void InitKernelStatus();
+void FreeKernelStatus();
+void PrintDebugInformation();
+void LockKernelStatus(UINT id);
+void UnlockKernelStatus(UINT id);
+void PrintKernelStatus();
+void InitCommandLineStr(int argc, char **argv);
+void FreeCommandLineStr();
+void SetCommandLineStr(char *str);
+void SetCommandLineUniStr(wchar_t *str);
+char *GetCommandLineStr();
+wchar_t *GetCommandLineUniStr();
+void ParseCommandLineTokens();
+void FreeCommandLineTokens();
+TOKEN_LIST *GetCommandLineToken();
+UNI_TOKEN_LIST *GetCommandLineUniToken();
+void InitOsInfo();
+void FreeOsInfo();
+void Alert(char *msg, char *caption);
+void AlertW(wchar_t *msg, wchar_t *caption);
+OS_INFO *GetOsInfo();
+UINT GetOsType();
+void PrintOsInfo(OS_INFO *info);
+void CheckEndian();
+void CheckUnixTempDir();
+void TimeCheck();
+void SetHamMode();
+bool IsHamMode();
+void InitProbe();
+void FreeProbe();
+void EnableProbe(bool enable);
+bool IsProbeEnabled();
+void WriteProbe(char *filename, UINT line, char *str);
+void WriteProbeData(char *filename, UINT line, char *str, void *data, UINT size);
+USHORT CalcChecksum16(void *buf, UINT size);
+
+#ifdef	OS_WIN32
+// インポートライブラリ (for Win32)
+#pragma comment(lib, "Ws2_32.lib")
+#pragma comment(lib, "winmm.lib")
+#pragma comment(lib, "kernel32.lib")
+#pragma comment(lib, "user32.lib")
+#pragma comment(lib, "gdi32.lib")
+#pragma comment(lib, "shell32.lib")
+#pragma comment(lib, "comctl32.lib")
+#pragma comment(lib, "dbghelp.lib")
+#pragma comment(lib, "Iphlpapi.lib")
+#pragma comment(lib, "setupapi.lib")
+#pragma comment(lib, "version.lib")
+#pragma comment(lib, "Netapi32.lib")
+#pragma comment(lib, "shlwapi.lib")
+#pragma warning( disable : 4099 )
+#endif	// OS_WIN32
+
+// デバッグ用
+#ifndef	ENCRYPT_C
+//#define	Disconnect(s)		{Debug("Disconnect() Called: %s %u\n", __FILE__, __LINE__);Disconnect(s);}
+#endif
+
+
+#endif	// MAYAQUA_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Memory.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Memory.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Memory.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2868 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Memory.c
+// メモリ管理プログラム
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <zlib/zlib.h>
+#include <Mayaqua/Mayaqua.h>
+
+#define	MEMORY_SLEEP_TIME		150
+#define	MEMORY_MAX_RETRY		30
+#define	INIT_BUF_SIZE			10240
+
+#define	FIFO_INIT_MEM_SIZE		4096
+#define	FIFO_REALLOC_MEM_SIZE	(65536 * 10)	// 絶妙な値
+#define FIFO_REALLOC_MEM_SIZE_SMALL	65536
+
+#define	INIT_NUM_RESERVED		32
+static UINT fifo_default_realloc_mem_size = FIFO_REALLOC_MEM_SIZE;
+
+// バイナリを検索
+UINT SearchBin(void *data, UINT data_start, UINT data_size, void *key, UINT key_size)
+{
+	UINT i;
+	// 引数チェック
+	if (data == NULL || key == NULL || key_size == 0 || data_size == 0 ||
+		(data_start >= data_size) || (data_start + key_size > data_size))
+	{
+		return INFINITE;
+	}
+
+	for (i = data_start;i < (data_size - key_size + 1);i++)
+	{
+		UCHAR *p = ((UCHAR *)data) + i;
+
+		if (Cmp(p, key, key_size) == 0)
+		{
+			return i;
+		}
+	}
+
+	return INFINITE;
+}
+
+// すぐにクラッシュする
+void CrashNow()
+{
+	// これでとりあえずどのような OS 上でもプロセスは落ちるはずである
+	while (true)
+	{
+		UINT r = Rand32();
+		UCHAR *c = (UCHAR *)r;
+
+		*c = Rand8();
+	}
+}
+
+// バッファを候補に変換
+LIST *BufToCandidate(BUF *b)
+{
+	LIST *o;
+	UINT i;
+	UINT num;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	num = ReadBufInt(b);
+	o = NewCandidateList();
+
+	for (i = 0;i < num;i++)
+	{
+		CANDIDATE *c;
+		wchar_t *s;
+		UINT64 sec64;
+		UINT len, size;
+		sec64 = ReadBufInt64(b);
+		len = ReadBufInt(b);
+		if (len >= 65536)
+		{
+			break;
+		}
+		size = (len + 1) * 2;
+		s = ZeroMalloc(size);
+		if (ReadBuf(b, s, size) != size)
+		{
+			Free(s);
+			break;
+		}
+		else
+		{
+			c = ZeroMalloc(sizeof(CANDIDATE));
+			c->LastSelectedTime = sec64;
+			c->Str = s;
+			Add(o, c);
+		}
+	}
+
+	Sort(o);
+	return o;
+}
+
+// 候補をバッファに変換
+BUF *CandidateToBuf(LIST *o)
+{
+	BUF *b;
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+	WriteBufInt(b, LIST_NUM(o));
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		CANDIDATE *c = LIST_DATA(o, i);
+		WriteBufInt64(b, c->LastSelectedTime);
+		WriteBufInt(b, UniStrLen(c->Str));
+		WriteBuf(b, c->Str, UniStrSize(c->Str));
+	}
+
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// 候補の追加
+void AddCandidate(LIST *o, wchar_t *str, UINT num_max)
+{
+	UINT i;
+	bool exists;
+	// 引数チェック
+	if (o == NULL || str == NULL)
+	{
+		return;
+	}
+	if (num_max == 0)
+	{
+		num_max = 0x7fffffff;
+	}
+
+	// 文字列コピー
+	str = UniCopyStr(str);
+	UniTrim(str);
+
+	exists = false;
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		CANDIDATE *c = LIST_DATA(o, i);
+		if (UniStrCmpi(c->Str, str) == 0)
+		{
+			// 既存のものを発見したので時刻を更新する
+			c->LastSelectedTime = SystemTime64();
+			exists = true;
+			break;
+		}
+	}
+
+	if (exists == false)
+	{
+		// 新しく挿入する
+		CANDIDATE *c = ZeroMalloc(sizeof(CANDIDATE));
+		c->LastSelectedTime = SystemTime64();
+		c->Str = UniCopyStr(str);
+		Insert(o, c);
+	}
+
+	// 文字列解放
+	Free(str);
+
+	// 現在の候補数を調べて、num_max より多ければ
+	// 古いものから順に削除する
+	if (LIST_NUM(o) > num_max)
+	{
+		while (LIST_NUM(o) > num_max)
+		{
+			UINT index = LIST_NUM(o) - 1;
+			CANDIDATE *c = LIST_DATA(o, index);
+			Delete(o, c);
+			Free(c->Str);
+			Free(c);
+		}
+	}
+}
+
+// 候補の比較
+int ComapreCandidate(void *p1, void *p2)
+{
+	CANDIDATE *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(CANDIDATE **)p1;
+	c2 = *(CANDIDATE **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+	if (c1->LastSelectedTime > c2->LastSelectedTime)
+	{
+		return -1;
+	}
+	else if (c1->LastSelectedTime < c2->LastSelectedTime)
+	{
+		return 1;
+	}
+	else
+	{
+		return UniStrCmpi(c1->Str, c2->Str);
+	}
+}
+
+// 候補リストの解放
+void FreeCandidateList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		CANDIDATE *c = LIST_DATA(o, i);
+		Free(c->Str);
+		Free(c);
+	}
+
+	ReleaseList(o);
+}
+
+// 新しい候補リストの作成
+LIST *NewCandidateList()
+{
+	return NewList(ComapreCandidate);
+}
+
+// 指定したアドレスがすべてゼロかどうか調べる
+bool IsZero(void *data, UINT size)
+{
+	UINT i;
+	UCHAR *c = (UCHAR *)data;
+	// 引数チェック
+	if (data == NULL || size == 0)
+	{
+		return true;
+	}
+
+	for (i = 0;i < size;i++)
+	{
+		if (c[i] != 0)
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// データを展開する
+UINT Uncompress(void *dst, UINT dst_size, void *src, UINT src_size)
+{
+	unsigned long dst_size_long = dst_size;
+	// 引数チェック
+	if (dst == NULL || dst_size_long == 0 || src == NULL)
+	{
+		return 0;
+	}
+
+	if (uncompress(dst, &dst_size_long, src, src_size) != Z_OK)
+	{
+		return 0;
+	}
+
+	return (UINT)dst_size_long;
+}
+
+// データを圧縮する
+UINT Compress(void *dst, UINT dst_size, void *src, UINT src_size)
+{
+	return CompressEx(dst, dst_size, src, src_size, Z_DEFAULT_COMPRESSION);
+}
+
+// データをオプション付きで圧縮する
+UINT CompressEx(void *dst, UINT dst_size, void *src, UINT src_size, UINT level)
+{
+	unsigned long dst_size_long = dst_size;
+	// 引数チェック
+	if (dst == NULL || dst_size_long == 0 || src == NULL)
+	{
+		return 0;
+	}
+
+	if (compress2(dst, &dst_size_long, src, src_size, (int)level) != Z_OK)
+	{
+		return 0;
+	}
+
+	return dst_size_long;
+}
+
+// src_size データを圧縮した場合の最大サイズを取得する
+UINT CalcCompress(UINT src_size)
+{
+	// あっ これは いい加減！
+	return src_size * 2 + 100;
+}
+
+// スタックの作成
+SK *NewSk()
+{
+	return NewSkEx(false);
+}
+SK *NewSkEx(bool no_compact)
+{
+	SK *s;
+
+	s = Malloc(sizeof(SK));
+	s->lock = NewLock();
+	s->ref = NewRef();
+	s->num_item = 0;
+	s->num_reserved = INIT_NUM_RESERVED;
+	s->p = Malloc(sizeof(void *) * s->num_reserved);
+	s->no_compact = no_compact;
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackNewObj(POINTER_TO_UINT64(s), "SK", 0);
+#endif	// DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_NEWSK_COUNT);
+
+	return s;
+}
+
+// スタックの解放
+void ReleaseSk(SK *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (Release(s->ref) == 0)
+	{
+		CleanupSk(s);
+	}
+}
+
+// スタックのクリーンアップ
+void CleanupSk(SK *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	// メモリ解放
+	Free(s->p);
+	DeleteLock(s->lock);
+	Free(s);
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackDeleteObj(POINTER_TO_UINT64(s));
+#endif	// DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_FREESK_COUNT);
+}
+
+// スタックのロック
+void LockSk(SK *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Lock(s->lock);
+}
+
+// スタックのロック解除
+void UnlockSk(SK *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Unlock(s->lock);
+}
+
+// スタックの Push
+void Push(SK *s, void *p)
+{
+	UINT i;
+	// 引数チェック
+	if (s == NULL || p == NULL)
+	{
+		return;
+	}
+
+	i = s->num_item;
+	s->num_item++;
+
+	// サイズ拡大
+	if (s->num_item > s->num_reserved)
+	{
+		s->num_reserved = s->num_reserved * 2;
+		s->p = ReAlloc(s->p, sizeof(void *) * s->num_reserved);
+	}
+	s->p[i] = p;
+
+	// KS
+	KS_INC(KS_PUSH_COUNT);
+}
+
+// スタックの Pop
+void *Pop(SK *s)
+{
+	void *ret;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+	if (s->num_item == 0)
+	{
+		return NULL;
+	}
+	ret = s->p[s->num_item - 1];
+	s->num_item--;
+
+	// サイズ縮小
+	if (s->no_compact == false)
+	{
+		// no_compact が true の場合は縮小しない
+		if ((s->num_item * 2) <= s->num_reserved)
+		{
+			if (s->num_reserved >= (INIT_NUM_RESERVED * 2))
+			{
+				s->num_reserved = s->num_reserved / 2;
+				s->p = ReAlloc(s->p, sizeof(void *) * s->num_reserved);
+			}
+		}
+	}
+
+	// KS
+	KS_INC(KS_POP_COUNT);
+
+	return ret;
+}
+
+// 1 つ取得
+void *GetNext(QUEUE *q)
+{
+	void *p = NULL;
+	// 引数チェック
+	if (q == NULL)
+	{
+		return NULL;
+	}
+
+	if (q->num_item == 0)
+	{
+		// アイテム無し
+		return NULL;
+	}
+
+	// FIFO から読み込む
+	ReadFifo(q->fifo, &p, sizeof(void *));
+	q->num_item--;
+
+	// KS
+	KS_INC(KS_GETNEXT_COUNT);
+
+	return p;
+}
+
+// キューに Int 型を挿入
+void InsertQueueInt(QUEUE *q, UINT value)
+{
+	UINT *p;
+	// 引数チェック
+	if (q == NULL)
+	{
+		return;
+	}
+
+	p = Clone(&value, sizeof(UINT));
+
+	InsertQueue(q, p);
+}
+
+// キューに挿入
+void InsertQueue(QUEUE *q, void *p)
+{
+	// 引数チェック
+	if (q == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// FIFO に書き込む
+	WriteFifo(q->fifo, &p, sizeof(void *));
+
+	q->num_item++;
+
+	// KS
+	KS_INC(KS_INSERT_QUEUE_COUNT);
+}
+
+// キューのロック
+void LockQueue(QUEUE *q)
+{
+	// 引数チェック
+	if (q == NULL)
+	{
+		return;
+	}
+
+	Lock(q->lock);
+}
+
+// キューのロック解除
+void UnlockQueue(QUEUE *q)
+{
+	// 引数チェック
+	if (q == NULL)
+	{
+		return;
+	}
+
+	Unlock(q->lock);
+}
+
+// キューの解放
+void ReleaseQueue(QUEUE *q)
+{
+	// 引数チェック
+	if (q == NULL)
+	{
+		return;
+	}
+
+	if (q->ref == NULL || Release(q->ref) == 0)
+	{
+		CleanupQueue(q);
+	}
+}
+
+// キューのクリーンアップ
+void CleanupQueue(QUEUE *q)
+{
+	// 引数チェック
+	if (q == NULL)
+	{
+		return;
+	}
+
+	// メモリ解放
+	ReleaseFifo(q->fifo);
+	DeleteLock(q->lock);
+	Free(q);
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackDeleteObj(POINTER_TO_UINT64(q));
+#endif	// DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_FREEQUEUE_COUNT);
+}
+
+// キューの作成
+QUEUE *NewQueue()
+{
+	QUEUE *q;
+
+	q = ZeroMalloc(sizeof(QUEUE));
+	q->lock = NewLock();
+	q->ref = NewRef();
+	q->num_item = 0;
+	q->fifo = NewFifo();
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackNewObj(POINTER_TO_UINT64(q), "QUEUE", 0);
+#endif	// DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_NEWQUEUE_COUNT);
+
+	return q;
+}
+QUEUE *NewQueueFast()
+{
+	QUEUE *q;
+
+	q = ZeroMalloc(sizeof(QUEUE));
+	q->lock = NULL;
+	q->ref = NULL;
+	q->num_item = 0;
+	q->fifo = NewFifoFast();
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackNewObj(POINTER_TO_UINT64(q), "QUEUE", 0);
+#endif	// DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_NEWQUEUE_COUNT);
+
+	return q;
+}
+
+// リストに比較関数をセットする
+void SetCmp(LIST *o, COMPARE *cmp)
+{
+	// 引数チェック
+	if (o == NULL || cmp == NULL)
+	{
+		return;
+	}
+
+	if (o->cmp != cmp)
+	{
+		o->cmp = cmp;
+		o->sorted = false;
+	}
+}
+
+// リストのクローン
+LIST *CloneList(LIST *o)
+{
+	LIST *n = NewList(o->cmp);
+
+	// メモリ再確保
+	Free(n->p);
+	n->p = ToArray(o);
+	n->num_item = n->num_reserved = LIST_NUM(o);
+	n->sorted = o->sorted;
+
+	return n;
+}
+
+// リストを配列にコピー
+void CopyToArray(LIST *o, void *p)
+{
+	// 引数チェック
+	if (o == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_TOARRAY_COUNT);
+
+	Copy(p, o->p, sizeof(void *) * o->num_item);
+}
+
+// リストを配列化する
+void *ToArray(LIST *o)
+{
+	return ToArrayEx(o, false);
+}
+void *ToArrayEx(LIST *o, bool fast)
+{
+	void *p;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	// メモリ確保
+	if (fast == false)
+	{
+		p = Malloc(sizeof(void *) * LIST_NUM(o));
+	}
+	else
+	{
+		p = MallocFast(sizeof(void *) * LIST_NUM(o));
+	}
+	// コピー
+	CopyToArray(o, p);
+
+	return p;
+}
+
+// リストのサーチ
+void *Search(LIST *o, void *target)
+{
+	void **ret;
+	// 引数チェック
+	if (o == NULL || target == NULL)
+	{
+		return NULL;
+	}
+	if (o->cmp == NULL)
+	{
+		return NULL;
+	}
+
+	// ソートのチェック
+	if (o->sorted == false)
+	{
+		// 未ソートなのでソートを行う
+		Sort(o);
+	}
+
+	// なんだ C ライブラリのバイナリサーチ関数を呼んでいるだけか
+	ret = (void **)bsearch(&target, o->p, o->num_item, sizeof(void *),
+		(int(*)(const void *, const void *))o->cmp);
+
+	// KS
+	KS_INC(KS_SEARCH_COUNT);
+
+	if (ret != NULL)
+	{
+		return *ret;
+	}
+	else
+	{
+		return NULL;
+	}
+}
+
+// リストに項目を挿入
+// 本当はもうちょっとましなデータ構造 & アルゴリズムにするべき
+void Insert(LIST *o, void *p)
+{
+	int low, high, middle;
+	UINT pos;
+	int i;
+	// 引数チェック
+	if (o == NULL || p == NULL)
+	{
+		return;
+	}
+
+	if (o->cmp == NULL)
+	{
+		// ソート関数が無い場合は単純に追加する
+		Add(o, p);
+		return;
+	}
+
+	// ソートされていない場合は直ちにソートする
+	if (o->sorted == false)
+	{
+		Sort(o);
+	}
+
+	low = 0;
+	high = LIST_NUM(o) - 1;
+
+	pos = INFINITE;
+
+	while (low <= high)
+	{
+		int ret;
+
+		middle = (low + high) / 2;
+		ret = o->cmp(&(o->p[middle]), &p);
+
+		if (ret == 0)
+		{
+			pos = middle;
+			break;
+		}
+		else if (ret > 0)
+		{
+			high = middle - 1;
+		}
+		else
+		{
+			low = middle + 1;
+		}
+	}
+
+	if (pos == INFINITE)
+	{
+		pos = low;
+	}
+
+	o->num_item++;
+	if (o->num_item > o->num_reserved)
+	{
+		o->num_reserved *= 2;
+		o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
+	}
+
+	if (LIST_NUM(o) >= 2)
+	{
+		for (i = (LIST_NUM(o) - 2);i >= (int)pos;i--)
+		{
+			o->p[i + 1] = o->p[i];
+		}
+	}
+
+	o->p[pos] = p;
+
+	// KS
+	KS_INC(KS_INSERT_COUNT);
+}
+
+// ソートフラグの設定
+void SetSortFlag(LIST *o, bool sorted)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	o->sorted = sorted;
+}
+
+// リストのソート
+void Sort(LIST *o)
+{
+	// 引数チェック
+	if (o == NULL || o->cmp == NULL)
+	{
+		return;
+	}
+
+	qsort(o->p, o->num_item, sizeof(void *), (int(*)(const void *, const void *))o->cmp);
+	o->sorted = true;
+
+	// KS
+	KS_INC(KS_SORT_COUNT);
+}
+
+// ある文字列項目がリスト内に存在しているかどうか調べる (Unicode 版)
+bool IsInListUniStr(LIST *o, wchar_t *str)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		wchar_t *s = LIST_DATA(o, i);
+
+		if (UniStrCmpi(s, str) == 0)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// リスト内のポインタを置換する
+bool ReplaceListPointer(LIST *o, void *oldptr, void *newptr)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || oldptr == NULL || newptr == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		void *p = LIST_DATA(o, i);
+
+		if (p == oldptr)
+		{
+			o->p[i] = newptr;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// ある文字列項目がリスト内に存在しているかどうか調べる
+bool IsInListStr(LIST *o, char *str)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		char *s = LIST_DATA(o, i);
+
+		if (StrCmpi(s, str) == 0)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// リスト内を UINT 形式のポインタで走査してポインタを取得する
+void *ListKeyToPointer(LIST *o, UINT key)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || key == 0)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		void *p = LIST_DATA(o, i);
+
+		if (POINTER_TO_KEY(p) == key)
+		{
+			return p;
+		}
+	}
+
+	return NULL;
+}
+
+// あるキーがリスト内に存在するかどうか調べる
+bool IsInListKey(LIST *o, UINT key)
+{
+	void *p;
+	// 引数チェック
+	if (o == NULL || key == 0)
+	{
+		return false;
+	}
+
+	p = ListKeyToPointer(o, key);
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ある項目がリスト内に存在するかどうか調べる
+bool IsInList(LIST *o, void *p)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		void *q = LIST_DATA(o, i);
+		if (p == q)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// リストへの要素の追加
+void Add(LIST *o, void *p)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || p == NULL)
+	{
+		return;
+	}
+
+	i = o->num_item;
+	o->num_item++;
+
+	if (o->num_item > o->num_reserved)
+	{
+		o->num_reserved = o->num_reserved * 2;
+		o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
+	}
+
+	o->p[i] = p;
+	o->sorted = false;
+
+	// KS
+	KS_INC(KS_INSERT_COUNT);
+}
+
+// リストからキーで指定した要素の削除
+bool DeleteKey(LIST *o, UINT key)
+{
+	void *p;
+	// 引数チェック
+	if (o == NULL || key == 0)
+	{
+		return false;
+	}
+
+	p = ListKeyToPointer(o, key);
+	if (p == NULL)
+	{
+		return false;
+	}
+
+	return Delete(o, p);
+}
+
+// リストから要素の削除
+bool Delete(LIST *o, void *p)
+{
+	UINT i, n;
+	// 引数チェック
+	if (o == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < o->num_item;i++)
+	{
+		if (o->p[i] == p)
+		{
+			break;
+		}
+	}
+	if (i == o->num_item)
+	{
+		return false;
+	}
+
+	n = i;
+	for (i = n;i < (o->num_item - 1);i++)
+	{
+		o->p[i] = o->p[i + 1];
+	}
+	o->num_item--;
+	if ((o->num_item * 2) <= o->num_reserved)
+	{
+		if (o->num_reserved > (INIT_NUM_RESERVED * 2))
+		{
+			o->num_reserved = o->num_reserved / 2;
+			o->p = ReAlloc(o->p, sizeof(void *) * o->num_reserved);
+		}
+	}
+
+	// KS
+	KS_INC(KS_DELETE_COUNT);
+
+	return true;
+}
+
+// リストからすべての要素の削除
+void DeleteAll(LIST *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	o->num_item = 0;
+	o->num_reserved = INIT_NUM_RESERVED;
+	o->p = ReAlloc(o->p, sizeof(void *) * INIT_NUM_RESERVED);
+}
+
+// リストのロック
+void LockList(LIST *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	Lock(o->lock);
+}
+
+// リストのロック解除
+void UnlockList(LIST *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	Unlock(o->lock);
+}
+
+// リストの解放
+void ReleaseList(LIST *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	if (o->ref == NULL || Release(o->ref) == 0)
+	{
+		CleanupList(o);
+	}
+}
+
+// リストのクリーンアップ
+void CleanupList(LIST *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	Free(o->p);
+	if (o->lock != NULL)
+	{
+		DeleteLock(o->lock);
+	}
+	Free(o);
+
+	// KS
+	KS_INC(KS_FREELIST_COUNT);
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackDeleteObj(POINTER_TO_UINT64(o));
+#endif	// DONT_USE_KERNEL_STATUS
+}
+
+// 文字列比較関数 (Unicode)
+int CompareUniStr(void *p1, void *p2)
+{
+	wchar_t *s1, *s2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(wchar_t **)p1;
+	s2 = *(wchar_t **)p2;
+
+	return UniStrCmp(s1, s2);
+}
+
+// 文字列をリストに挿入する
+bool InsertStr(LIST *o, char *str)
+{
+	// 引数チェック
+	if (o == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	if (Search(o, str) == NULL)
+	{
+		Insert(o, str);
+
+		return true;
+	}
+
+	return false;
+}
+
+// 文字列比較関数
+int CompareStr(void *p1, void *p2)
+{
+	char *s1, *s2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(char **)p1;
+	s2 = *(char **)p2;
+
+	return StrCmpi(s1, s2);
+}
+
+// 高速リスト (ロック無し) の作成
+LIST *NewListFast(COMPARE *cmp)
+{
+	return NewListEx(cmp, true);
+}
+
+// リストの作成
+LIST *NewList(COMPARE *cmp)
+{
+	return NewListEx(cmp, false);
+}
+LIST *NewListEx(COMPARE *cmp, bool fast)
+{
+	return NewListEx2(cmp, fast, false);
+}
+LIST *NewListEx2(COMPARE *cmp, bool fast, bool fast_malloc)
+{
+	LIST *o;
+
+	if (fast_malloc == false)
+	{
+		o = Malloc(sizeof(LIST));
+	}
+	else
+	{
+		o = MallocFast(sizeof(LIST));
+	}
+
+	if (fast == false)
+	{
+		o->lock = NewLock();
+		o->ref = NewRef();
+	}
+	else
+	{
+		o->lock = NULL;
+		o->ref = NULL;
+	}
+	o->num_item = 0;
+	o->num_reserved = INIT_NUM_RESERVED;
+
+	if (fast_malloc == false)
+	{
+		o->p = Malloc(sizeof(void *) * o->num_reserved);
+	}
+	else
+	{
+		o->p = MallocFast(sizeof(void *) * o->num_reserved);
+	}
+
+	o->cmp = cmp;
+	o->sorted = true;
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackNewObj(POINTER_TO_UINT64(o), "LIST", 0);
+#endif	//DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_NEWLIST_COUNT);
+
+	return o;
+}
+
+// FIFO から peek する
+UINT PeekFifo(FIFO *f, void *p, UINT size)
+{
+	UINT read_size;
+	if (f == NULL || size == 0)
+	{
+		return 0;
+	}
+
+	// KS
+	KS_INC(KS_PEEK_FIFO_COUNT);
+
+	read_size = MIN(size, f->size);
+	if (read_size == 0)
+	{
+		return 0;
+	}
+
+	if (p != NULL)
+	{
+		Copy(p, (UCHAR *)f->p + f->pos, read_size);
+	}
+
+	return read_size;
+}
+
+// FIFO から読み取る
+UINT ReadFifo(FIFO *f, void *p, UINT size)
+{
+	UINT read_size;
+	// 引数チェック
+	if (f == NULL || size == 0)
+	{
+		return 0;
+	}
+
+	read_size = MIN(size, f->size);
+	if (read_size == 0)
+	{
+		return 0;
+	}
+	if (p != NULL)
+	{
+		Copy(p, (UCHAR *)f->p + f->pos, read_size);
+	}
+	f->pos += read_size;
+	f->size -= read_size;
+
+	if (f->size == 0)
+	{
+		f->pos = 0;
+	}
+
+	// メモリの詰め直し
+	if (f->pos >= FIFO_INIT_MEM_SIZE &&
+		f->memsize >= f->realloc_mem_size &&
+		(f->memsize / 2) > f->size)
+	{
+		void *new_p;
+		UINT new_size;
+
+		new_size = MAX(f->memsize / 2, FIFO_INIT_MEM_SIZE);
+		new_p = Malloc(new_size);
+		Copy(new_p, (UCHAR *)f->p + f->pos, f->size);
+
+		Free(f->p);
+
+		f->memsize = new_size;
+		f->p = new_p;
+		f->pos = 0;
+	}
+
+	// KS
+	KS_INC(KS_READ_FIFO_COUNT);
+
+	return read_size;
+}
+
+// FIFO に書き込む
+void WriteFifo(FIFO *f, void *p, UINT size)
+{
+	UINT i, need_size;
+	bool realloc_flag;
+	// 引数チェック
+	if (f == NULL || size == 0)
+	{
+		return;
+	}
+
+	i = f->size;
+	f->size += size;
+	need_size = f->pos + f->size;
+	realloc_flag = false;
+
+	// メモリ拡張
+	while (need_size > f->memsize)
+	{
+		f->memsize = MAX(f->memsize, FIFO_INIT_MEM_SIZE) * 3;
+		realloc_flag = true;
+	}
+
+	if (realloc_flag)
+	{
+		f->p = ReAlloc(f->p, f->memsize);
+	}
+
+	// データ書き込み
+	if (p != NULL)
+	{
+		Copy((UCHAR *)f->p + f->pos + i, p, size);
+	}
+
+	// KS
+	KS_INC(KS_WRITE_FIFO_COUNT);
+}
+
+// FIFO のクリア
+void ClearFifo(FIFO *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	f->size = f->pos = 0;
+	f->memsize = FIFO_INIT_MEM_SIZE;
+	f->p = ReAlloc(f->p, f->memsize);
+}
+
+// FIFO のサイズ取得
+UINT FifoSize(FIFO *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return 0;
+	}
+
+	return f->size;
+}
+
+// FIFO のロック
+void LockFifo(FIFO *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	Lock(f->lock);
+}
+
+// FIFO のロック解除
+void UnlockFifo(FIFO *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	Unlock(f->lock);
+}
+
+// FIFO の解放
+void ReleaseFifo(FIFO *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	if (f->ref == NULL || Release(f->ref) == 0)
+	{
+		CleanupFifo(f);
+	}
+}
+
+// FIFO のクリーンアップ
+void CleanupFifo(FIFO *f)
+{
+	// 引数チェック
+	if (f == NULL)
+	{
+		return;
+	}
+
+	DeleteLock(f->lock);
+	Free(f->p);
+	Free(f);
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackDeleteObj(POINTER_TO_UINT64(f));
+#endif	//DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_FREEFIFO_COUNT);
+}
+
+// FIFO システムの初期化
+void InitFifo()
+{
+	fifo_default_realloc_mem_size = FIFO_REALLOC_MEM_SIZE;
+}
+
+// FIFO の作成
+FIFO *NewFifo()
+{
+	return NewFifoEx(0, false);
+}
+FIFO *NewFifoFast()
+{
+	return NewFifoEx(0, true);
+}
+FIFO *NewFifoEx(UINT realloc_mem_size, bool fast)
+{
+	FIFO *f;
+
+	// メモリ確保
+	f = Malloc(sizeof(FIFO));
+
+	if (fast == false)
+	{
+		f->lock = NewLock();
+		f->ref = NewRef();
+	}
+	else
+	{
+		f->lock = NULL;
+		f->ref = NULL;
+	}
+
+	f->size = f->pos = 0;
+	f->memsize = FIFO_INIT_MEM_SIZE;
+	f->p = Malloc(FIFO_INIT_MEM_SIZE);
+
+	if (realloc_mem_size == 0)
+	{
+		realloc_mem_size = fifo_default_realloc_mem_size;
+	}
+
+	f->realloc_mem_size = realloc_mem_size;
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackNewObj(POINTER_TO_UINT64(f), "FIFO", 0);
+#endif	// DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_NEWFIFO_COUNT);
+
+	return f;
+}
+
+// FIFO のデフォルトのメモリ再確保サイズを取得する
+UINT GetFifoDefaultReallocMemSize()
+{
+	return fifo_default_realloc_mem_size;
+}
+
+// FIFO のデフォルトのメモリ再確保サイズを設定する
+void SetFifoDefaultReallocMemSize(UINT size)
+{
+	if (size == 0)
+	{
+		size = FIFO_REALLOC_MEM_SIZE;
+	}
+
+	fifo_default_realloc_mem_size = size;
+}
+
+// バッファをファイルから読み込む
+BUF *FileToBuf(IO *o)
+{
+	UCHAR hash1[MD5_SIZE], hash2[MD5_SIZE];
+	UINT size;
+	void *buf;
+	BUF *b;
+
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	// サイズを読み込む
+	if (FileRead(o, &size, sizeof(size)) == false)
+	{
+		return NULL;
+	}
+	size = Endian32(size);
+
+	if (size > FileSize(o))
+	{
+		return NULL;
+	}
+
+	// ハッシュを読み込む
+	if (FileRead(o, hash1, sizeof(hash1)) == false)
+	{
+		return NULL;
+	}
+
+	// バッファを読み込む
+	buf = Malloc(size);
+	if (FileRead(o, buf, size) == false)
+	{
+		Free(buf);
+		return NULL;
+	}
+
+	// ハッシュをとる
+	Hash(hash2, buf, size, false);
+
+	// ハッシュを比較する
+	if (Cmp(hash1, hash2, sizeof(hash1)) != 0)
+	{
+		// ハッシュが異なる
+		Free(buf);
+		return NULL;
+	}
+
+	// バッファを作成する
+	b = NewBuf();
+	WriteBuf(b, buf, size);
+	Free(buf);
+	b->Current = 0;
+
+	return b;
+}
+
+// ダンプファイルをバッファに読み込む
+BUF *ReadDump(char *filename)
+{
+	IO *o;
+	BUF *b;
+	UINT size;
+	void *data;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	o = FileOpen(filename, false);
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	size = FileSize(o);
+	data = Malloc(size);
+	FileRead(o, data, size);
+	FileClose(o);
+
+	b = NewBuf();
+	WriteBuf(b, data, size);
+	b->Current = 0;
+	Free(data);
+
+	return b;
+}
+BUF *ReadDumpW(wchar_t *filename)
+{
+	IO *o;
+	BUF *b;
+	UINT size;
+	void *data;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	o = FileOpenW(filename, false);
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	size = FileSize(o);
+	data = Malloc(size);
+	FileRead(o, data, size);
+	FileClose(o);
+
+	b = NewBuf();
+	WriteBuf(b, data, size);
+	b->Current = 0;
+	Free(data);
+
+	return b;
+}
+
+// バッファ内容をファイルにダンプする
+bool DumpBuf(BUF *b, char *filename)
+{
+	IO *o;
+	// 引数チェック
+	if (b == NULL || filename == NULL)
+	{
+		return false;
+	}
+
+	o = FileCreate(filename);
+	if (o == NULL)
+	{
+		return false;
+	}
+	FileWrite(o, b->Buf, b->Size);
+	FileClose(o);
+
+	return true;
+}
+bool DumpBufW(BUF *b, wchar_t *filename)
+{
+	IO *o;
+	// 引数チェック
+	if (b == NULL || filename == NULL)
+	{
+		return false;
+	}
+
+	o = FileCreateW(filename);
+	if (o == NULL)
+	{
+		return false;
+	}
+	FileWrite(o, b->Buf, b->Size);
+	FileClose(o);
+
+	return true;
+}
+
+// バッファをファイルに書き込む
+bool BufToFile(IO *o, BUF *b)
+{
+	UCHAR hash[MD5_SIZE];
+	UINT size;
+
+	// 引数チェック
+	if (o == NULL || b == NULL)
+	{
+		return false;
+	}
+
+	// データをハッシュする
+	Hash(hash, b->Buf, b->Size, false);
+
+	size = Endian32(b->Size);
+
+	// サイズを書き込む
+	if (FileWrite(o, &size, sizeof(size)) == false)
+	{
+		return false;
+	}
+
+	// ハッシュを書き込む
+	if (FileWrite(o, hash, sizeof(hash)) == false)
+	{
+		return false;
+	}
+
+	// データを書き込む
+	if (FileWrite(o, b->Buf, b->Size) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// バッファの作成
+BUF *NewBuf()
+{
+	BUF *b;
+
+	// メモリ確保
+	b = Malloc(sizeof(BUF));
+	b->Buf = Malloc(INIT_BUF_SIZE);
+	b->Size = 0;
+	b->Current = 0;
+	b->SizeReserved = INIT_BUF_SIZE;
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackNewObj(POINTER_TO_UINT64(b), "BUF", 0);
+#endif	// DONT_USE_KERNEL_STATUS
+
+	// KS
+	KS_INC(KS_NEWBUF_COUNT);
+	KS_INC(KS_CURRENT_BUF_COUNT);
+
+	return b;
+}
+
+// バッファのクリア
+void ClearBuf(BUF *b)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	b->Size = 0;
+	b->Current = 0;
+}
+
+// バッファへ書き込み
+void WriteBuf(BUF *b, void *buf, UINT size)
+{
+	UINT new_size;
+	// 引数チェック
+	if (b == NULL || buf == NULL || size == 0)
+	{
+		return;
+	}
+
+	new_size = b->Current + size;
+	if (new_size > b->Size)
+	{
+		// サイズを調整する
+		AdjustBufSize(b, new_size);
+	}
+	if (b->Buf != NULL)
+	{
+		Copy((UCHAR *)b->Buf + b->Current, buf, size);
+	}
+	b->Current += size;
+	b->Size = new_size;
+
+	// KS
+	KS_INC(KS_WRITE_BUF_COUNT);
+}
+
+// バッファに文字列を追記
+void AddBufStr(BUF *b, char *str)
+{
+	// 引数チェック
+	if (b == NULL || str == NULL)
+	{
+		return;
+	}
+
+	WriteBuf(b, str, StrLen(str));
+}
+
+// バッファに 1 行書き込む
+void WriteBufLine(BUF *b, char *str)
+{
+	char *crlf = "\r\n";
+	// 引数チェック
+	if (b == NULL || str == NULL)
+	{
+		return;
+	}
+
+	WriteBuf(b, str, StrLen(str));
+	WriteBuf(b, crlf, StrLen(crlf));
+}
+
+// バッファに文字列を書き込む
+bool WriteBufStr(BUF *b, char *str)
+{
+	UINT len;
+	// 引数チェック
+	if (b == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	// 文字列長
+	len = StrLen(str);
+	if (WriteBufInt(b, len + 1) == false)
+	{
+		return false;
+	}
+
+	// 文字列本体
+	WriteBuf(b, str, len);
+
+	return true;
+}
+
+// バッファから文字列を読み込む
+bool ReadBufStr(BUF *b, char *str, UINT size)
+{
+	UINT len;
+	UINT read_size;
+	// 引数チェック
+	if (b == NULL || str == NULL || size == 0)
+	{
+		return false;
+	}
+
+	// 文字列長を読み込む
+	len = ReadBufInt(b);
+	if (len == 0)
+	{
+		return false;
+	}
+	len--;
+	if (len <= (size - 1))
+	{
+		size = len + 1;
+	}
+
+	read_size = MIN(len, (size - 1));
+
+	// 文字列本体を読み込む
+	if (ReadBuf(b, str, read_size) != read_size)
+	{
+		return false;
+	}
+	if (read_size < len)
+	{
+		ReadBuf(b, NULL, len - read_size);
+	}
+	str[read_size] = 0;
+
+	return true;
+}
+
+// バッファに 64 bit 整数を書き込む
+bool WriteBufInt64(BUF *b, UINT64 value)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	value = Endian64(value);
+
+	WriteBuf(b, &value, sizeof(UINT64));
+	return true;
+}
+
+// バッファに整数を書き込む
+bool WriteBufInt(BUF *b, UINT value)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	value = Endian32(value);
+
+	WriteBuf(b, &value, sizeof(UINT));
+	return true;
+}
+
+// バッファから 64bit 整数を読み込む
+UINT64 ReadBufInt64(BUF *b)
+{
+	UINT64 value;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return 0;
+	}
+
+	if (ReadBuf(b, &value, sizeof(UINT64)) != sizeof(UINT64))
+	{
+		return 0;
+	}
+	return Endian64(value);
+}
+
+// バッファから整数を読み込む
+UINT ReadBufInt(BUF *b)
+{
+	UINT value;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return 0;
+	}
+
+	if (ReadBuf(b, &value, sizeof(UINT)) != sizeof(UINT))
+	{
+		return 0;
+	}
+	return Endian32(value);
+}
+
+// バッファにバッファを書き込み
+void WriteBufBuf(BUF *b, BUF *bb)
+{
+	// 引数チェック
+	if (b == NULL || bb == NULL)
+	{
+		return;
+	}
+
+	WriteBuf(b, bb->Buf, bb->Size);
+}
+
+// バッファからバッファを読み込み
+BUF *ReadBufFromBuf(BUF *b, UINT size)
+{
+	BUF *ret;
+	UCHAR *data;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	data = Malloc(size);
+	if (ReadBuf(b, data, size) != size)
+	{
+		Free(data);
+		return NULL;
+	}
+
+	ret = NewBuf();
+	WriteBuf(ret, data, size);
+	SeekBuf(ret, 0, 0);
+
+	Free(data);
+
+	return ret;
+}
+
+// バッファから読み込み
+UINT ReadBuf(BUF *b, void *buf, UINT size)
+{
+	UINT size_read;
+	// 引数チェック
+	if (b == NULL || size == 0)
+	{
+		return 0;
+	}
+
+	if (b->Buf == NULL)
+	{
+		Zero(buf, size);
+		return 0;
+	}
+	size_read = size;
+	if ((b->Current + size) >= b->Size)
+	{
+		size_read = b->Size - b->Current;
+		if (buf != NULL)
+		{
+			Zero((UCHAR *)buf + size_read, size - size_read);
+		}
+	}
+
+	if (buf != NULL)
+	{
+		Copy(buf, (UCHAR *)b->Buf + b->Current, size_read);
+	}
+
+	b->Current += size_read;
+
+	// KS
+	KS_INC(KS_READ_BUF_COUNT);
+
+	return size_read;
+}
+
+// バッファサイズの調整
+void AdjustBufSize(BUF *b, UINT new_size)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	if (b->SizeReserved >= new_size)
+	{
+		return;
+	}
+
+	while (b->SizeReserved < new_size)
+	{
+		b->SizeReserved = b->SizeReserved * 2;
+	}
+	b->Buf = ReAlloc(b->Buf, b->SizeReserved);
+
+	// KS
+	KS_INC(KS_ADJUST_BUFSIZE_COUNT);
+}
+
+// バッファのシーク
+void SeekBuf(BUF *b, UINT offset, int mode)
+{
+	UINT new_pos;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	if (mode == 0)
+	{
+		// 絶対位置
+		new_pos = offset;
+	}
+	else
+	{
+		if (mode > 0)
+		{
+			// 右へ移動
+			new_pos = b->Current + offset;
+		}
+		else
+		{
+			// 左へ移動
+			if (b->Current >= offset)
+			{
+				new_pos = b->Current - offset;
+			}
+			else
+			{
+				new_pos = 0;
+			}
+		}
+	}
+	b->Current = MAKESURE(new_pos, 0, b->Size);
+
+	KS_INC(KS_SEEK_BUF_COUNT);
+}
+
+// バッファの解放
+void FreeBuf(BUF *b)
+{
+	// 引数チェック
+	if (b == NULL)
+	{
+		return;
+	}
+
+	// メモリ解放
+	Free(b->Buf);
+	Free(b);
+
+	// KS
+	KS_INC(KS_FREEBUF_COUNT);
+	KS_DEC(KS_CURRENT_BUF_COUNT);
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackDeleteObj(POINTER_TO_UINT64(b));
+#endif	// DONT_USE_KERNEL_STATUS
+}
+
+// Unicode 文字列のエンディアン変換
+void EndianUnicode(wchar_t *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	len = UniStrLen(str);
+
+	for (i = 0;i < len;i++)
+	{
+		str[i] = Endian16(str[i]);
+	}
+}
+
+// エンディアン変換 16bit
+USHORT Endian16(USHORT src)
+{
+	int x = 1;
+	if (*((char *)&x))
+	{
+		return Swap16(src);
+	}
+	else
+	{
+		return src;
+	}
+}
+
+// エンディアン変換 32bit
+UINT Endian32(UINT src)
+{
+	int x = 1;
+	if (*((char *)&x))
+	{
+		return Swap32(src);
+	}
+	else
+	{
+		return src;
+	}
+}
+
+// エンディアン変換 64bit
+UINT64 Endian64(UINT64 src)
+{
+	int x = 1;
+	if (*((char *)&x))
+	{
+		return Swap64(src);
+	}
+	else
+	{
+		return src;
+	}
+}
+
+// 任意のデータのスワップ
+void Swap(void *buf, UINT size)
+{
+	UCHAR *tmp, *src;
+	UINT i;
+	// 引数チェック
+	if (buf == NULL || size == 0)
+	{
+		return;
+	}
+
+	src = (UCHAR *)buf;
+	tmp = Malloc(size);
+	for (i = 0;i < size;i++)
+	{
+		tmp[size - i - 1] = src[i];
+	}
+
+	Copy(buf, tmp, size);
+	Free(buf);
+}
+
+// 16bit スワップ
+USHORT Swap16(USHORT value)
+{
+	USHORT r;
+	// 汚いコード
+	((BYTE *)&r)[0] = ((BYTE *)&value)[1];
+	((BYTE *)&r)[1] = ((BYTE *)&value)[0];
+	return r;
+}
+
+// 32bit スワップ
+UINT Swap32(UINT value)
+{
+	UINT r;
+	// 汚いコード
+	((BYTE *)&r)[0] = ((BYTE *)&value)[3];
+	((BYTE *)&r)[1] = ((BYTE *)&value)[2];
+	((BYTE *)&r)[2] = ((BYTE *)&value)[1];
+	((BYTE *)&r)[3] = ((BYTE *)&value)[0];
+	return r;
+}
+
+// 64bit スワップ
+UINT64 Swap64(UINT64 value)
+{
+	UINT64 r;
+	// 汚いコード
+	((BYTE *)&r)[0] = ((BYTE *)&value)[7];
+	((BYTE *)&r)[1] = ((BYTE *)&value)[6];
+	((BYTE *)&r)[2] = ((BYTE *)&value)[5];
+	((BYTE *)&r)[3] = ((BYTE *)&value)[4];
+	((BYTE *)&r)[4] = ((BYTE *)&value)[3];
+	((BYTE *)&r)[5] = ((BYTE *)&value)[2];
+	((BYTE *)&r)[6] = ((BYTE *)&value)[1];
+	((BYTE *)&r)[7] = ((BYTE *)&value)[0];
+	return r;
+}
+
+// Base64 エンコード
+UINT Encode64(char *dst, char *src)
+{
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return 0;
+	}
+
+	return B64_Encode(dst, src, StrLen(src));
+}
+
+// Base64 デコード
+UINT Decode64(char *dst, char *src)
+{
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return 0;
+	}
+
+	return B64_Decode(dst, src, StrLen(src));
+}
+
+// Base64 エンコード
+int B64_Encode(char *set, char *source, int len)
+{
+	BYTE *src;
+	int i,j;
+	src = (BYTE *)source;
+	j = 0;
+	i = 0;
+	if (!len)
+	{
+		return 0;
+	}
+	while (TRUE)
+	{
+		if (i >= len)
+		{
+			return j;
+		}
+		if (set)
+		{
+			set[j] = B64_CodeToChar((src[i]) >> 2);
+		}
+		if (i + 1 >= len)
+		{
+			if (set)
+			{
+				set[j + 1] = B64_CodeToChar((src[i] & 0x03) << 4);
+				set[j + 2] = '=';
+				set[j + 3] = '=';
+			}
+			return j + 4;
+		}
+		if (set)
+		{
+			set[j + 1] = B64_CodeToChar(((src[i] & 0x03) << 4) + ((src[i + 1] >> 4)));
+		}
+		if (i + 2 >= len)
+		{
+			if (set)
+			{
+				set[j + 2] = B64_CodeToChar((src[i + 1] & 0x0f) << 2);
+				set[j + 3] = '=';
+			}
+			return j + 4;
+		}
+		if (set)
+		{
+			set[j + 2] = B64_CodeToChar(((src[i + 1] & 0x0f) << 2) + ((src[i + 2] >> 6)));
+			set[j + 3] = B64_CodeToChar(src[i + 2] & 0x3f);
+		}
+		i += 3;
+		j += 4;
+	}
+}
+
+// Base64 デコード
+int B64_Decode(char *set, char *source, int len)
+{
+	int i,j;
+	char a1,a2,a3,a4;
+	char *src;
+	int f1,f2,f3,f4;
+	src = source;
+	i = 0;
+	j = 0;
+	while (TRUE)
+	{
+		f1 = f2 = f3 = f4 = 0;
+		if (i >= len)
+		{
+			break;
+		}
+		f1 = 1;
+		a1 = B64_CharToCode(src[i]);
+		if (a1 == -1)
+		{
+			f1 = 0;
+		}
+		if (i >= len + 1)
+		{
+			a2 = 0;
+		}
+		else
+		{
+			a2 = B64_CharToCode(src[i + 1]);
+			f2 = 1;
+			if (a2 == -1)
+			{
+				f2 = 0;
+			}
+		}
+		if (i >= len + 2)
+		{
+			a3 = 0;
+		}
+		else
+		{
+			a3 = B64_CharToCode(src[i + 2]);
+			f3 = 1;
+			if (a3 == -1)
+			{
+				f3 = 0;
+			}
+		}
+		if (i >= len + 3)
+		{
+			a4 = 0;
+		}
+		else
+		{
+			a4 = B64_CharToCode(src[i + 3]);
+			f4 = 1;
+			if (a4 == -1)
+			{
+				f4 = 0;
+			}
+		}
+		if (f1 && f2)
+		{
+			if (set)
+			{
+				set[j] = (a1 << 2) + (a2 >> 4);
+			}
+			j++;
+		}
+		if (f2 && f3)
+		{
+			if (set)
+			{
+				set[j] = (a2 << 4) + (a3 >> 2);
+			}
+			j++;
+		}
+		if (f3 && f4)
+		{
+			if (set)
+			{
+				set[j] = (a3 << 6) + a4;
+			}
+			j++;
+		}
+		i += 4;
+	}
+	return j;
+}
+
+// Base64 - コードを文字に変換
+char B64_CodeToChar(BYTE c)
+{
+	BYTE r;
+	r = '=';
+	if (c <= 0x19)
+	{
+		r = c + 'A';
+	}
+	if (c >= 0x1a && c <= 0x33)
+	{
+		r = c - 0x1a + 'a';
+	}
+	if (c >= 0x34 && c <= 0x3d)
+	{
+		r = c - 0x34 + '0';
+	}
+	if (c == 0x3e)
+	{
+		r = '+';
+	}
+	if (c == 0x3f)
+	{
+		r = '/';
+	}
+	return r;
+}
+
+// Base64 - 文字をコードに変換
+char B64_CharToCode(char c)
+{
+	if (c >= 'A' && c <= 'Z')
+	{
+		return c - 'A';
+	}
+	if (c >= 'a' && c <= 'z')
+	{
+		return c - 'a' + 0x1a;
+	}
+	if (c >= '0' && c <= '9')
+	{
+		return c - '0' + 0x34;
+	}
+	if (c == '+')
+	{
+		return 0x3e;
+	}
+	if (c == '/')
+	{
+		return 0x3f;
+	}
+	if (c == '=')
+	{
+		return -1;
+	}
+	return 0;
+}
+
+// 高速な Malloc (現在未実装)
+// 実は小さなバッファをたくさんまとめておいてそれを動的に割り当てるコードを昔
+// 書いたのだが、Windows, Linux, Solaris で試しても普通の malloc() と比べて
+// ほとんど速度に影響がなかったので、やめにした。
+void *MallocFast(UINT size)
+{
+	return Malloc(size);
+}
+
+// Malloc
+void *Malloc(UINT size)
+{
+	return MallocEx(size, false);
+}
+void *MallocEx(UINT size, bool zero_clear_when_free)
+{
+	MEMTAG *tag;
+	UINT real_size;
+
+	real_size = CALC_MALLOCSIZE(size);
+
+	tag = InternalMalloc(real_size);
+
+	Zero(tag, sizeof(MEMTAG));
+	tag->Magic = MEMTAG_MAGIC;
+	tag->Size = size;
+	tag->ZeroFree = zero_clear_when_free;
+
+	return MEMTAG_TO_POINTER(tag);
+}
+
+// ReAlloc
+void *ReAlloc(void *addr, UINT size)
+{
+	MEMTAG *tag;
+	bool zerofree;
+	// 引数チェック
+	if (IS_NULL_POINTER(addr))
+	{
+		return NULL;
+	}
+
+	tag = POINTER_TO_MEMTAG(addr);
+	CheckMemTag(tag);
+
+	zerofree = tag->ZeroFree;
+
+	if (tag->Size == size)
+	{
+		// サイズ変更無し
+		return addr;
+	}
+	else
+	{
+		if (zerofree)
+		{
+			// サイズ変更有り (ゼロクリア必須)
+			void *new_p = MallocEx(size, true);
+
+			if (tag->Size <= size)
+			{
+				// サイズ拡大
+				Copy(new_p, addr, tag->Size);
+			}
+			else
+			{
+				// サイズ縮小
+				Copy(new_p, addr, size);
+			}
+
+			// 古いブロックの解放
+			Free(addr);
+
+			return new_p;
+		}
+		else
+		{
+			// サイズ変更有り
+			MEMTAG *tag2 = InternalReAlloc(tag, CALC_MALLOCSIZE(size));
+
+			Zero(tag2, sizeof(MEMTAG));
+			tag2->Magic = MEMTAG_MAGIC;
+			tag2->Size = size;
+
+			return MEMTAG_TO_POINTER(tag2);
+		}
+	}
+}
+
+// Free
+void Free(void *addr)
+{
+	MEMTAG *tag;
+	// 引数チェック
+	if (IS_NULL_POINTER(addr))
+	{
+		return;
+	}
+
+	tag = POINTER_TO_MEMTAG(addr);
+	CheckMemTag(tag);
+
+	if (tag->ZeroFree)
+	{
+		// ゼロクリア
+		Zero(addr, tag->Size);
+	}
+
+	// メモリ解放
+	tag->Magic = 0;
+	InternalFree(tag);
+}
+
+// memtag をチェック
+void CheckMemTag(MEMTAG *tag)
+{
+#ifndef	DONT_CHECK_HEAP
+	// 引数チェック
+	if (tag == NULL)
+	{
+		AbortExitEx("CheckMemTag: tag == NULL");
+		return;
+	}
+
+	if (tag->Magic != MEMTAG_MAGIC)
+	{
+		AbortExitEx("CheckMemTag: tag->Magic != MEMTAG_MAGIC");
+		return;
+	}
+#endif	// DONT_CHECK_HEAP
+}
+
+// ZeroMalloc
+void *ZeroMalloc(UINT size)
+{
+	return ZeroMallocEx(size, false);
+}
+void *ZeroMallocEx(UINT size, bool zero_clear_when_free)
+{
+	void *p = MallocEx(size, zero_clear_when_free);
+	Zero(p, size);
+	return p;
+}
+void *ZeroMallocFast(UINT size)
+{
+	void *p = MallocFast(size);
+	Zero(p, size);
+	return p;
+}
+
+// メモリ確保
+void *InternalMalloc(UINT size)
+{
+	void *addr;
+	UINT retry = 0;
+	size = MORE(size, 1);
+
+	// KS
+	KS_INC(KS_MALLOC_COUNT);
+	KS_INC(KS_TOTAL_MEM_COUNT);
+	KS_ADD(KS_TOTAL_MEM_SIZE, size);
+	KS_INC(KS_CURRENT_MEM_COUNT);
+
+	// メモリが確保されるまで試行する
+	while (true)
+	{
+		if ((retry++) > MEMORY_MAX_RETRY)
+		{
+			AbortExitEx("InternalMalloc: error: malloc() failed.\n\n");
+		}
+		addr = OSMemoryAlloc(size);
+		if (addr != NULL)
+		{
+			break;
+		}
+
+		OSSleep(MEMORY_SLEEP_TIME);
+	}
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackNewObj(POINTER_TO_UINT64(addr), "MEM", size);
+#endif	//DONT_USE_KERNEL_STATUS
+
+	return addr;
+}
+
+// メモリ解放
+void InternalFree(void *addr)
+{
+	// 引数チェック
+	if (addr == NULL)
+	{
+		return;
+	}
+
+	// KS
+	KS_DEC(KS_CURRENT_MEM_COUNT);
+	KS_INC(KS_FREE_COUNT);
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackDeleteObj(POINTER_TO_UINT64(addr));
+#endif	// DONT_USE_KERNEL_STATUS
+
+	// メモリ解放
+	OSMemoryFree(addr);
+}
+
+// メモリ再確保
+void *InternalReAlloc(void *addr, UINT size)
+{
+	void *new_addr;
+	UINT retry = 0;
+	size = MORE(size, 1);
+
+	// KS
+	KS_INC(KS_REALLOC_COUNT);
+	KS_ADD(KS_TOTAL_MEM_SIZE, size);
+
+	// メモリが確保されるまで試行する
+	while (true)
+	{
+		if ((retry++) > MEMORY_MAX_RETRY)
+		{
+			AbortExitEx("InternalReAlloc: error: realloc() failed.\n\n");
+		}
+		new_addr = OSMemoryReAlloc(addr, size);
+		if (new_addr != NULL)
+		{
+			break;
+		}
+
+		OSSleep(MEMORY_SLEEP_TIME);
+	}
+
+#ifndef	DONT_USE_KERNEL_STATUS
+	TrackChangeObjSize((DWORD)addr, size, (DWORD)new_addr);
+#endif	// DONT_USE_KERNEL_STATUS
+
+	return new_addr;
+}
+
+// メモリ領域のクローン
+void *Clone(void *addr, UINT size)
+{
+	void *ret;
+	// 引数チェック
+	if (addr == NULL)
+	{
+		return NULL;
+	}
+
+	ret = Malloc(size);
+	Copy(ret, addr, size);
+
+	return ret;
+}
+
+// メモリコピー
+void Copy(void *dst, void *src, UINT size)
+{
+	// 引数チェック
+	if (dst == NULL || src == NULL || size == 0 || dst == src)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_COPY_COUNT);
+
+	memcpy(dst, src, size);
+}
+
+// メモリ比較
+int Cmp(void *p1, void *p2, UINT size)
+{
+	// 引数チェック
+	if (p1 == NULL || p2 == NULL || size == 0)
+	{
+		return 0;
+	}
+
+	return memcmp(p1, p2, (size_t)size);
+}
+
+// メモリのゼロクリア
+void Zero(void *addr, UINT size)
+{
+	ZeroMem(addr, size);
+}
+void ZeroMem(void *addr, UINT size)
+{
+	// 引数チェック
+	if (addr == NULL || size == 0)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_ZERO_COUNT);
+
+	memset(addr, 0, size);
+}
+
+// 文字列マップエントリの比較
+int StrMapCmp(void *p1, void *p2)
+{
+	STRMAP_ENTRY *s1, *s2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	s1 = *(STRMAP_ENTRY **)p1;
+	s2 = *(STRMAP_ENTRY **)p2;
+	if (s1 == NULL || s2 == NULL)
+	{
+		return 0;
+	}
+	return StrCmpi(s1->Name, s2->Name);
+}
+
+// 文字列マップ（文字列で検索できるデータ）の作成
+LIST *NewStrMap()
+{
+	return NewList(StrMapCmp);
+}
+
+// 文字列マップの検索
+void *StrMapSearch(LIST *map, char *key)
+{
+	STRMAP_ENTRY tmp, *result;
+	tmp.Name = key;
+	result = (STRMAP_ENTRY*)Search(map, &tmp);
+	if(result != NULL)
+	{
+		return result->Value;
+	}
+	return NULL;
+}
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Memory.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Memory.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Memory.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,325 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Memory.h
+// Memory.c のヘッダ
+
+#ifndef	MEMORY_H
+#define	MEMORY_H
+
+// 一度にカーネルに渡すことができるメモリサイズ
+#define	MAX_SEND_BUF_MEM_SIZE				(10 * 1024 * 1024)
+
+// メモリタグ用マジックナンバー
+#define	MEMTAG_MAGIC						0x49414449
+
+#define	CALC_MALLOCSIZE(size)				((MAX(size, 1)) + sizeof(MEMTAG))
+#define	MEMTAG_TO_POINTER(p)				((void *)(((UCHAR *)(p)) + sizeof(MEMTAG)))
+#define	POINTER_TO_MEMTAG(p)				((MEMTAG *)(((UCHAR *)(p)) - sizeof(MEMTAG)))
+#define	IS_NULL_POINTER(p)					(((p) == NULL) || ((POINTER_TO_UINT64(p) == (UINT64)sizeof(MEMTAG))))
+
+// メモリプールの 1 ブロックの固定サイズ
+#define	MEMPOOL_MAX_SIZE					3000
+
+
+// メモリタグ
+struct MEMTAG
+{
+	UINT Magic;
+	UINT Size;
+	bool ZeroFree;
+	UINT Padding;
+};
+
+// バッファ
+struct BUF
+{
+	void *Buf;
+	UINT Size;
+	UINT SizeReserved;
+	UINT Current;
+};
+
+// FIFO
+struct FIFO
+{
+	REF *ref;
+	LOCK *lock;
+	void *p;
+	UINT pos, size, memsize;
+	UINT realloc_mem_size;
+};
+
+// リスト
+struct LIST
+{
+	REF *ref;
+	UINT num_item, num_reserved;
+	void **p;
+	LOCK *lock;
+	COMPARE *cmp;
+	bool sorted;
+};
+
+// キュー
+struct QUEUE
+{
+	REF *ref;
+	UINT num_item;
+	FIFO *fifo;
+	LOCK *lock;
+};
+
+// スタック
+struct SK
+{
+	REF *ref;
+	UINT num_item, num_reserved;
+	void **p;
+	LOCK *lock;
+	bool no_compact;
+};
+
+// 候補リスト
+struct CANDIDATE
+{
+	wchar_t *Str;						// 文字列
+	UINT64 LastSelectedTime;			// 最後に選択された日時
+};
+
+struct STRMAP_ENTRY
+{
+	char *Name;
+	void *Value;
+};
+
+// マクロ
+#define	LIST_DATA(o, i)		(((o) != NULL) ? ((o)->p[(i)]) : NULL)
+#define	LIST_NUM(o)			(((o) != NULL) ? (o)->num_item : 0)
+
+
+// 関数プロトタイプ
+LIST *NewCandidateList();
+void FreeCandidateList(LIST *o);
+int ComapreCandidate(void *p1, void *p2);
+void AddCandidate(LIST *o, wchar_t *str, UINT num_max);
+BUF *CandidateToBuf(LIST *o);
+LIST *BufToCandidate(BUF *b);
+
+void *Malloc(UINT size);
+void *MallocEx(UINT size, bool zero_clear_when_free);
+void *MallocFast(UINT size);
+void *ZeroMalloc(UINT size);
+void *ZeroMallocFast(UINT size);
+void *ZeroMallocEx(UINT size, bool zero_clear_when_free);
+void *ReAlloc(void *addr, UINT size);
+void Free(void *addr);
+void CheckMemTag(MEMTAG *tag);
+
+void *InternalMalloc(UINT size);
+void *InternalReAlloc(void *addr, UINT size);
+void InternalFree(void *addr);
+
+void Copy(void *dst, void *src, UINT size);
+int Cmp(void *p1, void *p2, UINT size);
+void ZeroMem(void *addr, UINT size);
+void Zero(void *addr, UINT size);
+void *Clone(void *addr, UINT size);
+
+char B64_CodeToChar(BYTE c);
+char B64_CharToCode(char c);
+int B64_Encode(char *set, char *source, int len);
+int B64_Decode(char *set, char *source, int len);
+UINT Encode64(char *dst, char *src);
+UINT Decode64(char *dst, char *src);
+
+void Swap(void *buf, UINT size);
+USHORT Swap16(USHORT value);
+UINT Swap32(UINT value);
+UINT64 Swap64(UINT64 value);
+USHORT Endian16(USHORT src);
+UINT Endian32(UINT src);
+UINT64 Endian64(UINT64 src);
+void EndianUnicode(wchar_t *str);
+
+BUF *NewBuf();
+void ClearBuf(BUF *b);
+void WriteBuf(BUF *b, void *buf, UINT size);
+void WriteBufBuf(BUF *b, BUF *bb);
+UINT ReadBuf(BUF *b, void *buf, UINT size);
+BUF *ReadBufFromBuf(BUF *b, UINT size);
+void AdjustBufSize(BUF *b, UINT new_size);
+void SeekBuf(BUF *b, UINT offset, int mode);
+void FreeBuf(BUF *b);
+bool BufToFile(IO *o, BUF *b);
+BUF *FileToBuf(IO *o);
+UINT ReadBufInt(BUF *b);
+UINT64 ReadBufInt64(BUF *b);
+bool WriteBufInt(BUF *b, UINT value);
+bool WriteBufInt64(BUF *b, UINT64 value);
+bool ReadBufStr(BUF *b, char *str, UINT size);
+bool WriteBufStr(BUF *b, char *str);
+void WriteBufLine(BUF *b, char *str);
+void AddBufStr(BUF *b, char *str);
+bool DumpBuf(BUF *b, char *filename);
+bool DumpBufW(BUF *b, wchar_t *filename);
+BUF *ReadDump(char *filename);
+BUF *ReadDumpW(wchar_t *filename);
+
+UINT PeekFifo(FIFO *f, void *p, UINT size);
+UINT ReadFifo(FIFO *f, void *p, UINT size);
+void WriteFifo(FIFO *f, void *p, UINT size);
+void ClearFifo(FIFO *f);
+UINT FifoSize(FIFO *f);
+void LockFifo(FIFO *f);
+void UnlockFifo(FIFO *f);
+void ReleaseFifo(FIFO *f);
+void CleanupFifo(FIFO *f);
+FIFO *NewFifo();
+FIFO *NewFifoFast();
+FIFO *NewFifoEx(UINT realloc_mem_size, bool fast);
+void InitFifo();
+UINT GetFifoDefaultReallocMemSize();
+void SetFifoDefaultReallocMemSize(UINT size);
+
+void *Search(LIST *o, void *target);
+void Sort(LIST *o);
+void Add(LIST *o, void *p);
+void Insert(LIST *o, void *p);
+bool Delete(LIST *o, void *p);
+bool DeleteKey(LIST *o, UINT key);
+void DeleteAll(LIST *o);
+void LockList(LIST *o);
+void UnlockList(LIST *o);
+void ReleaseList(LIST *o);
+void CleanupList(LIST *o);
+LIST *NewList(COMPARE *cmp);
+LIST *NewListFast(COMPARE *cmp);
+LIST *NewListEx(COMPARE *cmp, bool fast);
+LIST *NewListEx2(COMPARE *cmp, bool fast, bool fast_malloc);
+void CopyToArray(LIST *o, void *p);
+void *ToArray(LIST *o);
+void *ToArrayEx(LIST *o, bool fast);
+LIST *CloneList(LIST *o);
+void SetCmp(LIST *o, COMPARE *cmp);
+void SetSortFlag(LIST *o, bool sorted);
+int CompareStr(void *p1, void *p2);
+bool InsertStr(LIST *o, char *str);
+int CompareUniStr(void *p1, void *p2);
+bool IsInList(LIST *o, void *p);
+bool IsInListKey(LIST *o, UINT key);
+void *ListKeyToPointer(LIST *o, UINT key);
+bool IsInListStr(LIST *o, char *str);
+bool IsInListUniStr(LIST *o, wchar_t *str);
+bool ReplaceListPointer(LIST *o, void *oldptr, void *newptr);
+
+void *GetNext(QUEUE *q);
+void InsertQueue(QUEUE *q, void *p);
+void InsertQueueInt(QUEUE *q, UINT value);
+void LockQueue(QUEUE *q);
+void UnlockQueue(QUEUE *q);
+void ReleaseQueue(QUEUE *q);
+void CleanupQueue(QUEUE *q);
+QUEUE *NewQueue();
+QUEUE *NewQueueFast();
+
+SK *NewSk();
+SK *NewSkEx(bool no_compact);
+void ReleaseSk(SK *s);
+void CleanupSk(SK *s);
+void LockSk(SK *s);
+void UnlockSk(SK *s);
+void Push(SK *s, void *p);
+void *Pop(SK *s);
+
+UINT Uncompress(void *dst, UINT dst_size, void *src, UINT src_size);
+UINT Compress(void *dst, UINT dst_size, void *src, UINT src_size);
+UINT CompressEx(void *dst, UINT dst_size, void *src, UINT src_size, UINT level);
+UINT CalcCompress(UINT src_size);
+
+bool IsZero(void *data, UINT size);
+
+void Crash();
+
+LIST *NewStrMap();
+void *StrMapSearch(LIST *map, char *key);
+
+UINT SearchBin(void *data, UINT data_start, UINT data_size, void *key, UINT key_size);
+void CrashNow();
+
+#endif	// MEMORY_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Microsoft.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Microsoft.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Microsoft.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,12112 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Microsoft.c
+// Microsoft Windows 用コード
+// (Windows 以外の環境ではコンパイルされない)
+
+#ifdef	WIN32
+
+#define	MICROSOFT_C
+
+typedef enum    _PNP_VETO_TYPE {
+    PNP_VetoTypeUnknown,            // Name is unspecified
+    PNP_VetoLegacyDevice,           // Name is an Instance Path
+    PNP_VetoPendingClose,           // Name is an Instance Path
+    PNP_VetoWindowsApp,             // Name is a Module
+    PNP_VetoWindowsService,         // Name is a Service
+    PNP_VetoOutstandingOpen,        // Name is an Instance Path
+    PNP_VetoDevice,                 // Name is an Instance Path
+    PNP_VetoDriver,                 // Name is a Driver Service Name
+    PNP_VetoIllegalDeviceRequest,   // Name is an Instance Path
+    PNP_VetoInsufficientPower,      // Name is unspecified
+    PNP_VetoNonDisableable,         // Name is an Instance Path
+    PNP_VetoLegacyDriver,           // Name is a Service
+    PNP_VetoInsufficientRights      // Name is unspecified
+}   PNP_VETO_TYPE, *PPNP_VETO_TYPE;
+
+#define	_WIN32_IE			0x0600
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#define   SECURITY_WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <Wintrust.h>
+#include <Softpub.h>
+#include <Iphlpapi.h>
+#include <tlhelp32.h>
+#include <wincon.h>
+#include <Nb30.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <setupapi.h>
+#include <regstr.h>
+#include <process.h>
+#include <psapi.h>
+#include <wtsapi32.h>
+#include <security.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <cfgmgr32.h>
+#include <sddl.h>
+#include <Aclapi.h>
+
+
+static MS *ms = NULL;
+
+// 関数プロトタイプ
+UINT MsgBox(HWND hWnd, UINT flag, wchar_t *msg);
+UINT MsgBoxEx(HWND hWnd, UINT flag, wchar_t *msg, ...);
+void ShowTcpIpConfigUtil(HWND hWnd, bool util_mode);
+void CmTraffic(HWND hWnd);
+void CnStart();
+void InitCedar();
+void FreeCedar();
+void InitWinUi(wchar_t *software_name, char *font, UINT fontsize);
+void FreeWinUi();
+
+// グローバル変数
+void *ms_critical_section = NULL;
+UINT64 ms_uint64_1 = 0;
+
+// アダプタリスト関係
+static LOCK *lock_adapter_list = NULL;
+static MS_ADAPTER_LIST *last_adapter_list = NULL;
+
+// サービス関係
+static SERVICE_STATUS_HANDLE ssh = NULL;
+static SERVICE_STATUS status;
+static char g_service_name[MAX_SIZE];
+static SERVICE_FUNCTION *g_start, *g_stop;
+static bool exiting = false;
+static bool wnd_end;
+static bool is_usermode = false;
+static HICON tray_icon;
+static NOTIFYICONDATA nid;
+static NOTIFYICONDATAW nid_nt;
+static bool service_for_9x_mode = false;
+static THREAD *starter_thread = NULL;
+static EVENT *server_stopped_event = NULL;
+static THREAD *service_stopper_thread = NULL;
+static bool tray_inited = false;
+static HWND hWndUsermode = NULL;
+
+// [ネットワーク接続] を開くためのショートカット (最新版では未使用)
+static UCHAR network_connection_link[] =
+{
+	0x4C, 0x00, 0x00, 0x00, 0x01, 0x14, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x46, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x14, 0x00, 
+	0x1F, 0x50, 0xE0, 0x4F, 0xD0, 0x20, 0xEA, 0x3A, 0x69, 0x10, 0xA2, 0xD8, 0x08, 0x00, 0x2B, 0x30, 
+	0x30, 0x9D, 0x14, 0x00, 0x2E, 0x00, 0x20, 0x20, 0xEC, 0x21, 0xEA, 0x3A, 0x69, 0x10, 0xA2, 0xDD, 
+	0x08, 0x00, 0x2B, 0x30, 0x30, 0x9D, 0x14, 0x00, 0x70, 0x00, 0xC7, 0xAC, 0x07, 0x70, 0x02, 0x32, 
+	0xD1, 0x11, 0xAA, 0xD2, 0x00, 0x80, 0x5F, 0xC1, 0x27, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+};
+
+// Windows Vista 関係の新しいセキュリティ構造体等
+#if	0
+typedef struct _TOKEN_MANDATORY_LABEL
+{
+	SID_AND_ATTRIBUTES Label;
+} TOKEN_MANDATORY_LABEL, *PTOKEN_MANDATORY_LABEL;
+#endif
+
+#define SE_GROUP_INTEGRITY                 (0x00000020L)
+
+typedef enum _TOKEN_INFORMATION_CLASS_VISTA
+{
+	VistaTokenUser = 1,
+	VistaTokenGroups,
+	VistaTokenPrivileges,
+	VistaTokenOwner,
+	VistaTokenPrimaryGroup,
+	VistaTokenDefaultDacl,
+	VistaTokenSource,
+	VistaTokenType,
+	VistaTokenImpersonationLevel,
+	VistaTokenStatistics,
+	VistaTokenRestrictedSids,
+	VistaTokenSessionId,
+	VistaTokenGroupsAndPrivileges,
+	VistaTokenSessionReference,
+	VistaTokenSandBoxInert,
+	VistaTokenAuditPolicy,
+	VistaTokenOrigin,
+	VistaTokenElevationType,
+	VistaTokenLinkedToken,
+	VistaTokenElevation,
+	VistaTokenHasRestrictions,
+	VistaTokenAccessInformation,
+	VistaTokenVirtualizationAllowed,
+	VistaTokenVirtualizationEnabled,
+	VistaTokenIntegrityLevel,
+	VistaTokenUIAccess,
+	VistaTokenMandatoryPolicy,
+	VistaTokenLogonSid,
+	VistaMaxTokenInfoClass
+} TOKEN_INFORMATION_CLASS_VISTA, *PTOKEN_INFORMATION_CLASS_VISTA;
+
+// エラーを表示しないモードにする
+void MsSetErrorModeToSilent()
+{
+	SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+}
+
+// ファイル情報の取得
+bool MsGetFileInformation(void *h, void *info)
+{
+	// 引数チェック
+	if (h == INVALID_HANDLE_VALUE || info == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return false;
+	}
+
+	if (ms->nt->GetFileInformationByHandle == NULL)
+	{
+		return false;
+	}
+
+	return ms->nt->GetFileInformationByHandle(h, info);
+}
+
+// プロセスのシャットダウンパラメータの設定
+void MsSetShutdownParameters(UINT level, UINT flag)
+{
+	if (MsIsNt() == false)
+	{
+		return;
+	}
+
+	if (ms->nt == false || ms->nt->SetProcessShutdownParameters == NULL)
+	{
+		return;
+	}
+
+	ms->nt->SetProcessShutdownParameters(level, flag);
+}
+
+// OS のバージョンが Windows XP または Windows Vista 以降かどうか取得する
+bool MsIsWinXPOrWinVista()
+{
+	OS_INFO *info = GetOsInfo();
+	if (info == NULL)
+	{
+		return false;
+	}
+
+	if (OS_IS_WINDOWS_NT(info->OsType) == false)
+	{
+		return false;
+	}
+
+	if (GET_KETA(info->OsType, 100) >= 3)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// イベントログに書き込む
+bool MsWriteEventLog(void *p, UINT type, wchar_t *str)
+{
+	MS_EVENTLOG *g = (MS_EVENTLOG *)p;
+	wchar_t *strings[2];
+	UINT id = 0;
+	UINT typeapi = 0;
+	// 引数チェック
+	if (g == NULL || type >= 5 || str == NULL)
+	{
+		return false;
+	}
+
+	strings[0] = str;
+
+	switch (type)
+	{
+	case MS_EVENTLOG_TYPE_INFORMATION:
+		id = MS_RC_EVENTLOG_TYPE_INFORMATION;
+		typeapi = EVENTLOG_INFORMATION_TYPE;
+		break;
+
+	case MS_EVENTLOG_TYPE_WARNING:
+		id = MS_RC_EVENTLOG_TYPE_WARNING;
+		typeapi = EVENTLOG_WARNING_TYPE;
+		break;
+
+	case MS_EVENTLOG_TYPE_ERROR:
+		id = MS_RC_EVENTLOG_TYPE_ERROR;
+		typeapi = EVENTLOG_ERROR_TYPE;
+		break;
+	}
+
+	return ms->nt->ReportEventW(g->hEventLog, typeapi, 0, id, NULL, 1, 0, strings, NULL);
+}
+
+// イベントログの解放
+void MsFreeEventLog(void *p)
+{
+	MS_EVENTLOG *g = (MS_EVENTLOG *)p;
+	// 引数チェック
+	if (g == NULL)
+	{
+		return;
+	}
+
+	ms->nt->DeregisterEventSource(g->hEventLog);
+
+	Free(g);
+}
+
+// イベントログの初期化
+void *MsInitEventLog(wchar_t *src_name)
+{
+	MS_EVENTLOG *g;
+	HANDLE h;
+	wchar_t keyname[MAX_PATH];
+	char keyname_a[MAX_PATH];
+	wchar_t *exename;
+	// 引数チェック
+	if (src_name == NULL)
+	{
+		return NULL;
+	}
+
+	// レジストリにキーを書き込む
+	exename = MsGetExeFileNameW();
+	UniFormat(keyname, sizeof(keyname),
+		L"SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\%s",
+		src_name);
+	UniToStr(keyname_a, sizeof(keyname_a), keyname);
+
+	MsRegWriteStrExpandExW(REG_LOCAL_MACHINE, keyname_a, "EventMessageFile",
+		exename, false);
+
+	MsRegWriteIntEx(REG_LOCAL_MACHINE, keyname_a, "TypesSupported", 7, false);
+
+	h = ms->nt->RegisterEventSourceW(NULL, src_name);
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	g = ZeroMalloc(sizeof(MS_EVENTLOG));
+
+	g->hEventLog = h;
+
+	return (void *)g;
+}
+
+// クリップボードを空にする
+void MsDeleteClipboard()
+{
+	OpenClipboard(NULL);
+
+	EmptyClipboard();
+
+	CloseClipboard();
+}
+
+// クリップボード所有者のプロセス ID を取得する
+UINT MsGetClipboardOwnerProcessId()
+{
+	HWND hWnd = GetClipboardOwner();
+	DWORD pid = 0;
+
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	GetWindowThreadProcessId(hWnd, &pid);
+
+	return pid;
+}
+
+// MMCSS の再起動
+// 注意: この実装は完璧ではない。
+void MsRestartMMCSS()
+{
+	MsStopService("CTAudSvcService");
+	MsStopService("audiosrv");
+	MsStopService("MMCSS");
+	MsStartService("MMCSS");
+	MsStartService("audiosrv");
+	MsStartService("CTAudSvcService");
+}
+
+// MMCSS によるネットワークスロットリングを有効 / 無効にする
+void MsSetMMCSSNetworkThrottlingEnable(bool enable)
+{
+	UINT value;
+	if (MsIsVista() == false)
+	{
+		return;
+	}
+
+	if (enable)
+	{
+		value = 0x0000000a;
+	}
+	else
+	{
+		value = 0xffffffff;
+	}
+
+	MsRegWriteIntEx2(REG_LOCAL_MACHINE, MMCSS_PROFILE_KEYNAME, "NetworkThrottlingIndex",
+		value,
+		false, true);
+
+	MsRestartMMCSS();
+}
+
+// MMCSS によるネットワークスロットリングが有効になっているかどうか調査
+bool MsIsMMCSSNetworkThrottlingEnabled()
+{
+	UINT value;
+	if (MsIsVista() == false)
+	{
+		return false;
+	}
+
+	if (MsRegIsKeyEx2(REG_LOCAL_MACHINE, MMCSS_PROFILE_KEYNAME, false, true) == false)
+	{
+		return false;
+	}
+
+	value = MsRegReadIntEx2(REG_LOCAL_MACHINE, MMCSS_PROFILE_KEYNAME,
+		"NetworkThrottlingIndex", false, true);
+
+	if (value == 0)
+	{
+		return false;
+	}
+
+	if (value == 0x0000000a)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// サブキーをすべて削除する
+void MsRegDeleteSubkeys(UINT root, char *keyname, bool force32bit, bool force64bit)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return;
+	}
+
+	t = MsRegEnumKeyEx2(root, keyname, force32bit, force64bit);
+	if (t == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char tmp[MAX_PATH];
+
+		Format(tmp, sizeof(tmp), "%s\\%s", keyname, t->Token[i]);
+
+		MsRegDeleteKeyEx2(root, tmp, force32bit, force64bit);
+	}
+
+	FreeToken(t);
+}
+
+// バッファのデータをレジストリのサブキーに変換する
+void MsBufToRegSubkeys(UINT root, char *keyname, BUF *b, bool overwrite, bool force32bit, bool force64bit)
+{
+	UINT i;
+	UINT a;
+	UINT num_keys;
+	// 引数チェック
+	if (keyname == NULL || b == NULL)
+	{
+		return;
+	}
+
+	SeekBuf(b, 0, 0);
+
+	num_keys = ReadBufInt(b);
+
+	for (i = 0;i < num_keys;i++)
+	{
+		char subkeyname[MAX_PATH];
+		char fullkeyname[MAX_PATH];
+		UINT j;
+		UINT num_values;
+
+		Zero(subkeyname, sizeof(subkeyname));
+		ReadBufStr(b, subkeyname, sizeof(subkeyname));
+
+		Format(fullkeyname, sizeof(fullkeyname), "%s\\%s", keyname, subkeyname);
+
+		num_values = ReadBufInt(b);
+
+		for (j = 0;j < num_values;j++)
+		{
+			char valuename[MAX_PATH];
+			char data[MAX_SIZE];
+
+			Zero(valuename, sizeof(valuename));
+			ReadBufStr(b, valuename, sizeof(valuename));
+
+			a = ReadBufInt(b);
+
+			if (a == 0)
+			{
+				Zero(data, sizeof(data));
+				ReadBufStr(b, data, sizeof(data));
+
+				if (overwrite || MsRegIsValueEx2(root, fullkeyname, valuename, force32bit, force64bit) == false)
+				{
+					MsRegWriteStrEx2(root, fullkeyname, valuename, data, force32bit, force64bit);
+				}
+			}
+			else
+			{
+				if (overwrite || MsRegIsValueEx2(root, fullkeyname, valuename, force32bit, force64bit) == false)
+				{
+					MsRegWriteIntEx2(root, fullkeyname, valuename, ReadBufInt(b), force32bit, force64bit);
+				}
+			}
+		}
+	}
+}
+
+// レジストリのサブキーのデータをバッファに変換する
+BUF *MsRegSubkeysToBuf(UINT root, char *keyname, bool force32bit, bool force64bit)
+{
+	TOKEN_LIST *t;
+	UINT i;
+	BUF *b;
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return NULL;
+	}
+
+	t = MsRegEnumKeyEx2(root, keyname, force32bit, force64bit);
+
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+
+	WriteBufInt(b, t->NumTokens);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *name = t->Token[i];
+		char tmp[MAX_PATH];
+		TOKEN_LIST *v;
+
+		Format(tmp, sizeof(tmp), "%s\\%s", keyname, name);
+
+		WriteBufStr(b, name);
+
+		v = MsRegEnumValueEx2(root, tmp, force32bit, force64bit);
+		if (v == NULL)
+		{
+			WriteBufInt(b, 0);
+		}
+		else
+		{
+			UINT j;
+
+			WriteBufInt(b, v->NumTokens);
+
+			for (j = 0;j < v->NumTokens;j++)
+			{
+				char *valuename = v->Token[j];
+				char *str;
+
+				WriteBufStr(b, valuename);
+
+				str = MsRegReadStrEx2(root, tmp, valuename, force32bit, force64bit);
+				if (str != NULL)
+				{
+					WriteBufInt(b, 0);
+					WriteBufStr(b, str);
+					Free(str);
+				}
+				else
+				{
+					WriteBufInt(b, 1);
+					WriteBufInt(b, MsRegReadIntEx2(root, tmp, valuename, force32bit, force64bit));
+				}
+			}
+
+			FreeToken(v);
+		}
+	}
+
+	FreeToken(t);
+
+	return b;
+}
+
+// 指定した EXE ファイル名のプロセスが存在しているかどうかチェック
+bool MsIsProcessExists(char *exename)
+{
+	LIST *o;
+	bool ret = false;
+	UINT i;
+	// 引数チェック
+	if (exename == NULL)
+	{
+		return false;
+	}
+
+	o = MsGetProcessList();
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		MS_PROCESS *proc = LIST_DATA(o, i);
+		char exe[MAX_PATH];
+
+		GetFileNameFromFilePath(exe, sizeof(exe), proc->ExeFilename);
+
+		if (StrCmpi(exename, exe) == 0)
+		{
+			ret = true;
+			break;
+		}
+	}
+
+	MsFreeProcessList(o);
+
+	return ret;
+}
+bool MsIsProcessExistsW(wchar_t *exename)
+{
+	LIST *o;
+	bool ret = false;
+	UINT i;
+	// 引数チェック
+	if (exename == NULL)
+	{
+		return false;
+	}
+
+	o = MsGetProcessList();
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		MS_PROCESS *proc = LIST_DATA(o, i);
+		wchar_t exe[MAX_PATH];
+
+		GetFileNameFromFilePathW(exe, sizeof(exe), proc->ExeFilenameW);
+
+		if (UniStrCmpi(exename, exe) == 0)
+		{
+			ret = true;
+			break;
+		}
+	}
+
+	MsFreeProcessList(o);
+
+	return ret;
+}
+
+typedef struct _ASTAT_
+{
+	ADAPTER_STATUS adapt;
+	NAME_BUFFER    NameBuff[30];
+} ASTAT, *PASTAT;
+
+// 高精度カウンタの値から精密な時間を取得する
+double MsGetHiResTimeSpan(UINT64 diff)
+{
+	LARGE_INTEGER t;
+	UINT64 freq;
+
+	if (QueryPerformanceFrequency(&t) == false)
+	{
+		freq = 1000ULL;
+	}
+	else
+	{
+		Copy(&freq, &t, sizeof(UINT64));
+	}
+
+	return (double)diff / (double)freq;
+}
+UINT64 MsGetHiResTimeSpanUSec(UINT64 diff)
+{
+	LARGE_INTEGER t;
+	UINT64 freq;
+
+	if (QueryPerformanceFrequency(&t) == false)
+	{
+		freq = 1000ULL;
+	}
+	else
+	{
+		Copy(&freq, &t, sizeof(UINT64));
+	}
+
+	return (UINT64)(diff) * 1000ULL * 1000ULL / (UINT64)freq;
+}
+
+// 高精度カウンタを取得する
+UINT64 MsGetHiResCounter()
+{
+	LARGE_INTEGER t;
+	UINT64 ret;
+
+	if (QueryPerformanceCounter(&t) == false)
+	{
+		return Tick64();
+	}
+
+	Copy(&ret, &t, sizeof(UINT64));
+
+	return ret;
+}
+
+// ようこそ画面を使用しているかどうか
+bool MsIsUseWelcomeLogin()
+{
+	UINT os_type;
+	if (MsIsNt() == false)
+	{
+		return false;
+	}
+
+	os_type = GetOsInfo()->OsType;
+
+	if (OS_IS_WINDOWS_NT(os_type))
+	{
+		if (GET_KETA(os_type, 100) == 3)
+		{
+			if (MsRegReadIntEx2(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
+				"LogonType", false, true) == 0)
+			{
+				return false;
+			}
+			else
+			{
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
+// コンピュータの物理的な MAC アドレスを 1 つ取得する
+bool MsGetPhysicalMacAddress(void *address)
+{
+	// 引数チェック
+	if (address == NULL)
+	{
+		return false;
+	}
+
+	if (MsGetPhysicalMacAddressFromApi(address))
+	{
+		return true;
+	}
+
+	if (MsGetPhysicalMacAddressFromNetbios(address))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// 物理的な MAC アドレスを取得する (API から)
+bool MsGetPhysicalMacAddressFromApi(void *address)
+{
+	MS_ADAPTER_LIST *o;
+	UINT i;
+	bool ret = false;
+	// 引数チェック
+	if (address == NULL)
+	{
+		return false;
+	}
+
+	Zero(address, 6);
+
+	o = MsCreateAdapterList();
+
+	for (i = 0;i < o->Num;i++)
+	{
+		MS_ADAPTER *a = o->Adapters[i];
+
+		if (a->AddressSize == 6 && a->Mtu == 1500)
+		{
+			bool b = false;
+			switch (a->Type)
+			{
+			case MIB_IF_TYPE_OTHER:
+			case MIB_IF_TYPE_ETHERNET:
+				b = true;
+				break;
+
+			case MIB_IF_TYPE_TOKENRING:
+			case MIB_IF_TYPE_FDDI:
+			case MIB_IF_TYPE_PPP:
+			case MIB_IF_TYPE_LOOPBACK:
+			case MIB_IF_TYPE_SLIP:
+				b = false;
+				break;
+
+			default:
+				b = true;
+				break;
+			}
+
+			if (b)
+			{
+				if (SearchStrEx(a->Title, "WAN", 0, false) == INFINITE)
+				{
+					if (a->Status == MIB_IF_OPER_STATUS_CONNECTED || a->Status == MIB_IF_OPER_STATUS_OPERATIONAL)
+					{
+						if (a->AddressSize == 6)
+						{
+							if (IsZero(a->Address, 6) == false)
+							{
+								if (Cmp(address, a->Address, 6) <= 0)
+								{
+									Copy(address, a->Address, 6);
+									ret = true;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	MsFreeAdapterList(o);
+
+	return ret;
+}
+
+// 物理的な MAC アドレスを取得する (NetBIOS から)
+bool MsGetPhysicalMacAddressFromNetbios(void *address)
+{
+	NCB ncb;
+	UCHAR ret;
+	LANA_ENUM lenum;
+	UINT i;
+	ASTAT adapter;
+	bool b = false;
+	// 引数チェック
+	if (address == NULL)
+	{
+		return false;
+	}
+
+	Zero(&ncb, sizeof(ncb));
+	Zero(&lenum, sizeof(lenum));
+
+	ncb.ncb_command = NCBENUM;
+	ncb.ncb_buffer = (UCHAR *)&lenum;
+	ncb.ncb_length = sizeof(lenum);
+	ret = Netbios(&ncb);
+
+	Zero(address, 6);
+
+	for (i = 0;i < lenum.length;i++)
+	{
+		Zero(&ncb, sizeof(ncb));
+		ncb.ncb_command = NCBRESET;
+		ncb.ncb_lana_num = lenum.lana[i];
+
+		ret = Netbios(&ncb);
+
+		Zero(&ncb, sizeof(ncb));
+		ncb.ncb_command = NCBASTAT;
+		ncb.ncb_lana_num = lenum.lana[i];
+
+		StrCpy(ncb.ncb_callname, sizeof(ncb.ncb_callname), "*               ");
+		Zero(&adapter, sizeof(adapter));
+		ncb.ncb_buffer = (char *)&adapter;
+		ncb.ncb_length = sizeof(adapter);
+
+		ret = Netbios(&ncb);
+
+		if (ret == 0)
+		{
+			if (Cmp(address, adapter.adapt.adapter_address, 6) <= 0)
+			{
+				Copy(address, adapter.adapt.adapter_address, 6);
+				b = true;
+			}
+		}
+	}
+
+	return b;
+}
+
+// システム全体のアップデート通知
+void MsUpdateSystem()
+{
+	static DWORD dw = 0;
+
+	SendMessageTimeoutA(HWND_BROADCAST, WM_WININICHANGE, 0, 0, SMTO_NORMAL, 1, (PDWORD_PTR)&dw);
+}
+
+// 指定されたパスがローカルドライブかどうか取得する
+bool MsIsLocalDrive(char *name)
+{
+	char tmp[MAX_PATH];
+	UINT ret;
+
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	Zero(tmp, sizeof(tmp));
+	InnerFilePath(tmp, sizeof(tmp), name);
+
+	if (StartWith(tmp, "\\\\"))
+	{
+		// ネットワークディレクトリ
+		return false;
+	}
+
+	if (tmp[1] != ':' || tmp[2] != '\\')
+	{
+		// ドライブ名でない
+		return false;
+	}
+
+	tmp[3] = 0;
+
+	ret = GetDriveType(tmp);
+
+	if (ret == DRIVE_REMOTE || ret == DRIVE_CDROM || ret == DRIVE_RAMDISK)
+	{
+		return false;
+	}
+
+	return true;
+}
+bool MsIsLocalDriveW(wchar_t *name)
+{
+	char name_a[MAX_PATH];
+
+	UniToStr(name_a, sizeof(name_a), name);
+
+	return MsIsLocalDrive(name_a);
+}
+
+// 指定されたファイルがロックされているかどうか取得する
+bool MsIsFileLocked(char *name)
+{
+	HANDLE h;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	InnerFilePath(tmp, sizeof(tmp), name);
+
+	h = CreateFile(tmp, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL);
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		return true;
+	}
+
+	CloseHandle(h);
+
+	return false;
+}
+bool MsIsFileLockedW(wchar_t *name)
+{
+	HANDLE h;
+	wchar_t tmp[MAX_PATH];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char name_a[MAX_SIZE];
+
+		UniToStr(name_a, sizeof(name_a), name);
+
+		return MsIsFileLocked(name_a);
+	}
+
+	InnerFilePathW(tmp, sizeof(tmp), name);
+
+	h = CreateFileW(tmp, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL);
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		return true;
+	}
+
+	CloseHandle(h);
+
+	return false;
+}
+
+// プロセスの終了を待機
+UINT MsWaitProcessExit(void *process_handle)
+{
+	HANDLE h = (HANDLE)process_handle;
+	UINT ret = 1;
+
+	if (h == NULL)
+	{
+		return 1;
+	}
+
+	while (true)
+	{
+		WaitForSingleObject(h, INFINITE);
+
+		ret = 1;
+		if (GetExitCodeProcess(h, &ret) == false)
+		{
+			break;
+		}
+
+		if (ret != STILL_ACTIVE)
+		{
+			break;
+		}
+	}
+
+	CloseHandle(h);
+
+	return ret;
+}
+
+// ファイルの実行 (プロセスハンドル取得)
+bool MsExecuteEx(char *exe, char *arg, void **process_handle)
+{
+	SHELLEXECUTEINFO info;
+	HANDLE h;
+	// 引数チェック
+	if (exe == NULL || process_handle == NULL)
+	{
+		return false;
+	}
+
+	Zero(&info, sizeof(info));
+	info.cbSize = sizeof(info);
+	info.lpVerb = "open";
+	info.lpFile = exe;
+	info.fMask = SEE_MASK_NOCLOSEPROCESS;
+	info.lpParameters = arg;
+	info.nShow = SW_SHOWNORMAL;
+	if (ShellExecuteEx(&info) == false)
+	{
+		return false;
+	}
+
+	h = info.hProcess;
+
+	*process_handle = (void *)h;
+
+	return true;
+}
+bool MsExecuteExW(wchar_t *exe, wchar_t *arg, void **process_handle)
+{
+	SHELLEXECUTEINFOW info;
+	HANDLE h;
+	// 引数チェック
+	if (exe == NULL || process_handle == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char exe_a[MAX_SIZE];
+		char arg_a[MAX_SIZE];
+
+		UniToStr(exe_a, sizeof(exe_a), exe);
+		UniToStr(arg_a, sizeof(arg_a), arg);
+
+		return MsExecuteEx(exe_a, arg_a, process_handle);
+	}
+
+	Zero(&info, sizeof(info));
+	info.cbSize = sizeof(info);
+	info.lpVerb = L"open";
+	info.lpFile = exe;
+	info.fMask = SEE_MASK_NOCLOSEPROCESS;
+	info.lpParameters = arg;
+	info.nShow = SW_SHOWNORMAL;
+	if (ShellExecuteExW(&info) == false)
+	{
+		return false;
+	}
+
+	h = info.hProcess;
+
+	*process_handle = (void *)h;
+
+	return true;
+}
+
+// ファイルの実行
+bool MsExecute(char *exe, char *arg)
+{
+	DWORD d;
+	// 引数チェック
+	if (exe == NULL)
+	{
+		return false;
+	}
+
+	d = (DWORD)ShellExecuteA(NULL, "open", exe, arg, MsGetExeDirName(), SW_SHOWNORMAL);
+
+	if (d > 32)
+	{
+		return true;
+	}
+
+	return false;
+}
+bool MsExecuteW(wchar_t *exe, wchar_t *arg)
+{
+	DWORD d;
+	// 引数チェック
+	if (exe == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char exe_a[MAX_SIZE];
+		char arg_a[MAX_SIZE];
+
+		UniToStr(exe_a, sizeof(exe_a), exe);
+		UniToStr(arg_a, sizeof(arg_a), arg);
+
+		return MsExecute(exe_a, arg_a);
+	}
+
+	d = (DWORD)ShellExecuteW(NULL, L"open", exe, arg, MsGetExeDirNameW(), SW_SHOWNORMAL);
+
+	if (d > 32)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// ディレクトリの再帰作成
+void MsUniMakeDirEx(wchar_t *name)
+{
+	UINT wp;
+	wchar_t *tmp;
+	UINT i, len;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	tmp = ZeroMalloc(UniStrSize(name) * 2);
+	wp = 0;
+	len = UniStrLen(name);
+	for (i = 0;i < len;i++)
+	{
+		wchar_t c = name[i];
+
+		if (c == '\\')
+		{
+			if (UniStrCmpi(tmp, L"\\\\") != 0 && UniStrCmpi(tmp, L"\\") != 0)
+			{
+				MsUniMakeDir(tmp);
+			}
+		}
+
+		tmp[wp++] = c;
+	}
+
+	Free(tmp);
+
+	MsUniMakeDir(name);
+}
+void MsMakeDirEx(char *name)
+{
+	wchar_t *name_w = CopyStrToUni(name);
+
+	MsUniMakeDirEx(name_w);
+
+	Free(name_w);
+}
+
+// ディレクトリの作成
+bool MsUniMakeDir(wchar_t *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(name);
+		bool ret = MsMakeDir(s);
+		Free(s);
+		return ret;
+	}
+
+	return CreateDirectoryW(name, NULL);
+}
+bool MsMakeDir(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	return CreateDirectoryA(name, NULL);
+}
+
+// ディレクトリの削除
+bool MsUniDirectoryDelete(wchar_t *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(name);
+		bool ret = MsDirectoryDelete(s);
+		Free(s);
+		return ret;
+	}
+
+	return RemoveDirectoryW(name);
+}
+bool MsDirectoryDelete(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	return RemoveDirectoryA(name);
+}
+
+// ファイルの削除
+bool MsUniFileDelete(wchar_t *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		bool ret;
+		char *s = CopyUniToStr(name);
+		ret = MsFileDelete(s);
+		Free(s);
+		return ret;
+	}
+
+	return DeleteFileW(name);
+}
+bool MsFileDelete(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	return DeleteFileA(name);
+}
+
+// 指定したファイル名がディレクトリかどうか取得する
+bool MsUniIsDirectory(wchar_t *name)
+{
+	DWORD ret;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		char *s = CopyUniToStr(name);
+		ret = MsIsDirectory(s);
+		Free(s);
+
+		return ret;
+	}
+
+	ret = GetFileAttributesW(name);
+	if (ret == 0xffffffff)
+	{
+		return false;
+	}
+
+	if (ret & FILE_ATTRIBUTE_DIRECTORY)
+	{
+		return true;
+	}
+
+	return false;
+}
+bool MsIsDirectoryW(wchar_t *name)
+{
+	return MsUniIsDirectory(name);
+}
+bool MsIsDirectory(char *name)
+{
+	DWORD ret;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	InnerFilePath(tmp, sizeof(tmp), name);
+
+	ret = GetFileAttributesA(tmp);
+	if (ret == 0xffffffff)
+	{
+		return false;
+	}
+
+	if (ret & FILE_ATTRIBUTE_DIRECTORY)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// MSI ファイルから Cabinet を取り出す
+bool MsExtractCabFromMsi(char *msi, char *cab)
+{
+	wchar_t msi_w[MAX_PATH];
+	wchar_t cab_w[MAX_PATH];
+
+	StrToUni(msi_w, sizeof(msi_w), msi);
+	StrToUni(cab_w, sizeof(cab_w), cab);
+
+	return MsExtractCabFromMsiW(msi_w, cab_w);
+}
+bool MsExtractCabFromMsiW(wchar_t *msi, wchar_t *cab)
+{
+	BUF *b;
+	bool ret = false;
+	UINT i;
+	char sign[] = {'M', 'S', 'C', 'F', 0, 0, 0, 0,};
+	void *pointer = NULL;
+	UINT current_pos = 0;
+	UINT sign_size;
+	// 引数チェック
+	if (msi == NULL || cab == NULL)
+	{
+		return false;
+	}
+
+	// MSI を読み込む
+	b = ReadDumpW(msi);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	if (b->Size < 128)
+	{
+		FreeBuf(b);
+		return false;
+	}
+
+	sign_size = sizeof(sign);
+
+	// "MSCF" を検索する
+	for (i = 0;i < (b->Size - sign_size);i++)
+	{
+		char *p = ((UCHAR *)b->Buf) + i;
+
+		if (Cmp(p, sign, sign_size) == 0)
+		{
+			pointer = p;
+			current_pos = i;
+		}
+	}
+
+	if (pointer != NULL)
+	{
+		UINT size = b->Size - current_pos;
+		BUF *b2 = NewBuf();
+
+		WriteBuf(b2, pointer, size);
+
+		ret = DumpBufW(b2, cab);
+
+		FreeBuf(b2);
+
+	}
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// Cabinet ファイルからファイルを取り出す
+bool MsExtractCab(char *cab_name, char *dest_dir_name)
+{
+	wchar_t cab_name_w[MAX_SIZE];
+	wchar_t dest_dir_name_w[MAX_SIZE];
+
+	StrToUni(cab_name_w, sizeof(cab_name_w), cab_name);
+	StrToUni(dest_dir_name_w, sizeof(dest_dir_name_w), dest_dir_name);
+
+	return MsExtractCabW(cab_name_w, dest_dir_name_w);
+}
+bool MsExtractCabW(wchar_t *cab_name, wchar_t *dest_dir_name)
+{
+	wchar_t cabarc[MAX_PATH];
+	wchar_t arg[MAX_PATH * 2];
+	wchar_t tmp[MAX_PATH];
+
+	// 引数チェック
+	if (cab_name == NULL || dest_dir_name == NULL)
+	{
+		return false;
+	}
+
+	if (MsGetCabarcExeFilenameW(cabarc, sizeof(cabarc)) == false)
+	{
+		return false;
+	}
+
+	UniStrCpy(tmp, sizeof(tmp), dest_dir_name);
+	if (UniEndWith(tmp, L"\\"))
+	{
+		tmp[UniStrLen(tmp) - 1] = 0;
+	}
+
+	UniFormat(arg, sizeof(arg),
+		L"-o X \"%s\" * \"%s\"\\",
+		cab_name,
+		tmp);
+
+	MakeDirW(dest_dir_name);
+
+	if (RunW(cabarc, arg, true, true) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// cabarc.exe の展開
+bool MsGetCabarcExeFilename(char *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	ConbinePath(name, size, MsGetMyTempDir(), "cabarc.exe");
+
+	if (IsFileExists(name))
+	{
+		return true;
+	}
+
+	if (FileCopy("|cabarc.exe", name) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+bool MsGetCabarcExeFilenameW(wchar_t *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	ConbinePathW(name, size, MsGetMyTempDirW(), L"cabarc.exe");
+
+	if (IsFileExistsW(name))
+	{
+		return true;
+	}
+
+	if (FileCopyW(L"|cabarc.exe", name) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// EXE ファイルから Cabinet ファイルを取り出す
+bool MsExtractCabinetFileFromExe(char *exe, char *cab)
+{
+	BUF *b;
+	// 引数チェック
+	if (exe == NULL || cab == NULL)
+	{
+		return false;
+	}
+
+	b = MsExtractResourceFromExe(exe, RT_RCDATA, "CABINET");
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	if (DumpBuf(b, cab) == false)
+	{
+		FreeBuf(b);
+
+		return false;
+	}
+
+	FreeBuf(b);
+
+	return true;
+}
+bool MsExtractCabinetFileFromExeW(wchar_t *exe, wchar_t *cab)
+{
+	BUF *b;
+	// 引数チェック
+	if (exe == NULL || cab == NULL)
+	{
+		return false;
+	}
+
+	b = MsExtractResourceFromExeW(exe, RT_RCDATA, "CABINET");
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	if (DumpBufW(b, cab) == false)
+	{
+		FreeBuf(b);
+
+		return false;
+	}
+
+	FreeBuf(b);
+
+	return true;
+}
+
+// EXE ファイルからリソースを取り出す
+BUF *MsExtractResourceFromExe(char *exe, char *type, char *name)
+{
+	HINSTANCE h;
+	HRSRC hr;
+	HGLOBAL hg;
+	UINT size;
+	void *data;
+	BUF *buf;
+	// 引数チェック
+	if (exe == NULL || type == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	h = LoadLibraryExA(exe, NULL, LOAD_LIBRARY_AS_DATAFILE);
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	hr = FindResourceA(h, name, type);
+	if (hr == NULL)
+	{
+		FreeLibrary(h);
+		return NULL;
+	}
+
+	hg = LoadResource(h, hr);
+	if (hg == NULL)
+	{
+		FreeLibrary(h);
+		return NULL;
+	}
+
+	size = SizeofResource(h, hr);
+	data = (void *)LockResource(hg);
+
+	buf = NewBuf();
+	WriteBuf(buf, data, size);
+
+	FreeResource(hg);
+	FreeLibrary(h);
+
+	SeekBuf(buf, 0, 0);
+
+	return buf;
+}
+BUF *MsExtractResourceFromExeW(wchar_t *exe, char *type, char *name)
+{
+	HINSTANCE h;
+	HRSRC hr;
+	HGLOBAL hg;
+	UINT size;
+	void *data;
+	BUF *buf;
+	// 引数チェック
+	if (exe == NULL || type == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	if (IsNt() == false)
+	{
+		char exe_a[MAX_PATH];
+
+		UniToStr(exe_a, sizeof(exe_a), exe);
+
+		return MsExtractResourceFromExe(exe_a, type, name);
+	}
+
+	h = LoadLibraryExW(exe, NULL, LOAD_LIBRARY_AS_DATAFILE);
+	if (h == NULL)
+	{
+		return NULL;
+	}
+
+	hr = FindResource(h, name, type);
+	if (hr == NULL)
+	{
+		FreeLibrary(h);
+		return NULL;
+	}
+
+	hg = LoadResource(h, hr);
+	if (hg == NULL)
+	{
+		FreeLibrary(h);
+		return NULL;
+	}
+
+	size = SizeofResource(h, hr);
+	data = (void *)LockResource(hg);
+
+	buf = NewBuf();
+	WriteBuf(buf, data, size);
+
+	FreeResource(hg);
+	FreeLibrary(h);
+
+	SeekBuf(buf, 0, 0);
+
+	return buf;
+}
+
+// ファイルのバージョン情報を取得する
+bool MsGetFileVersion(char *name, UINT *v1, UINT *v2, UINT *v3, UINT *v4)
+{
+	void *data;
+	UINT size;
+	DWORD h;
+	bool ret = false;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	h = 0;
+	size = GetFileVersionInfoSize(name, &h);
+	if (size == 0)
+	{
+		return false;
+	}
+
+	data = ZeroMalloc(size);
+
+	if (GetFileVersionInfoA(name, 0, size, data))
+	{
+		VS_FIXEDFILEINFO *info = NULL;
+		UINT info_size = 0;
+		if (VerQueryValueA(data, "\\", &info, &info_size))
+		{
+			if (v1 != NULL)
+			{
+				*v1 = HIWORD(info->dwFileVersionMS);
+			}
+
+			if (v2 != NULL)
+			{
+				*v2 = LOWORD(info->dwFileVersionMS);
+			}
+
+			if (v3 != NULL)
+			{
+				*v3 = HIWORD(info->dwFileVersionLS);
+			}
+
+			if (v4 != NULL)
+			{
+				*v4 = LOWORD(info->dwFileVersionLS);
+			}
+
+			ret = true;
+		}
+	}
+
+	Free(data);
+
+	return ret;
+}
+bool MsGetFileVersionW(wchar_t *name, UINT *v1, UINT *v2, UINT *v3, UINT *v4)
+{
+	void *data;
+	UINT size;
+	DWORD h;
+	bool ret = false;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char name_a[MAX_PATH];
+
+		UniToStr(name_a, sizeof(name_a), name);
+
+		return MsGetFileVersion(name_a, v1, v2, v3, v4);
+	}
+
+	h = 0;
+	size = GetFileVersionInfoSizeW(name, &h);
+	if (size == 0)
+	{
+		return false;
+	}
+
+	data = ZeroMalloc(size);
+
+	if (GetFileVersionInfoW(name, 0, size, data))
+	{
+		VS_FIXEDFILEINFO *info = NULL;
+		UINT info_size = 0;
+		if (VerQueryValue(data, "\\", &info, &info_size))
+		{
+			if (v1 != NULL)
+			{
+				*v1 = HIWORD(info->dwFileVersionMS);
+			}
+
+			if (v2 != NULL)
+			{
+				*v2 = LOWORD(info->dwFileVersionMS);
+			}
+
+			if (v3 != NULL)
+			{
+				*v3 = HIWORD(info->dwFileVersionLS);
+			}
+
+			if (v4 != NULL)
+			{
+				*v4 = LOWORD(info->dwFileVersionLS);
+			}
+
+			ret = true;
+		}
+	}
+
+	Free(data);
+
+	return ret;
+}
+
+// ファイルを隠しファイルにする
+void MsSetFileToHidden(char *name)
+{
+	char tmp[MAX_PATH];
+	DWORD d;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	NormalizePath(tmp, sizeof(tmp), name);
+
+	d = GetFileAttributesA(tmp);
+	if (d != INVALID_FILE_ATTRIBUTES)
+	{
+		d |= FILE_ATTRIBUTE_HIDDEN;
+
+		SetFileAttributesA(tmp, d);
+	}
+}
+void MsSetFileToHiddenW(wchar_t *name)
+{
+	wchar_t tmp[MAX_PATH];
+	DWORD d;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	if (IsNt() == false)
+	{
+		char name_a[MAX_SIZE];
+
+		UniToStr(name_a, sizeof(name_a), name);
+
+		MsSetFileToHidden(name_a);
+
+		return;
+	}
+
+	NormalizePathW(tmp, sizeof(tmp), name);
+
+	d = GetFileAttributesW(tmp);
+	if (d != INVALID_FILE_ATTRIBUTES)
+	{
+		d |= FILE_ATTRIBUTE_HIDDEN;
+
+		SetFileAttributesW(tmp, d);
+	}
+}
+
+// スリープ防止用スレッド
+void MsNoSleepThread(THREAD *thread, void *param)
+{
+	MS_NOSLEEP *e;
+	EXECUTION_STATE (WINAPI *_SetThreadExecutionState)(EXECUTION_STATE);
+	HINSTANCE hKernel32;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	hKernel32 = LoadLibrary("kernel32.dll");
+
+	_SetThreadExecutionState =
+		(EXECUTION_STATE (__stdcall *)(EXECUTION_STATE))
+		GetProcAddress(hKernel32, "SetThreadExecutionState");
+
+	e = (MS_NOSLEEP *)param;
+
+	while (e->Halt == false)
+	{
+		DWORD flag = ES_SYSTEM_REQUIRED;
+
+		if (e->NoScreenSaver)
+		{
+			flag |= ES_DISPLAY_REQUIRED;
+		}
+
+		if (_SetThreadExecutionState != NULL)
+		{
+			_SetThreadExecutionState(flag);
+		}
+
+		Wait(e->HaltEvent, 30 * 1000);
+	}
+
+	FreeLibrary(hKernel32);
+}
+
+// スリープ防止用スレッド (Windows Vista 用)
+void MsNoSleepThreadVista(THREAD *thread, void *param)
+{
+	MS_NOSLEEP *e;
+	char *key = "Control Panel\\Desktop";
+	UINT64 last_set_flag = 0;
+	UINT last_c_x = INFINITE, last_c_y = INFINITE;
+	UINT64 last_mouse_move_time = 0;
+	EXECUTION_STATE (WINAPI *_SetThreadExecutionState)(EXECUTION_STATE);
+	HINSTANCE hKernel32;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	hKernel32 = LoadLibrary("kernel32.dll");
+
+	_SetThreadExecutionState =
+		(EXECUTION_STATE (__stdcall *)(EXECUTION_STATE))
+		GetProcAddress(hKernel32, "SetThreadExecutionState");
+
+	e = (MS_NOSLEEP *)param;
+
+	while (e->Halt == false)
+	{
+		DWORD flag = ES_SYSTEM_REQUIRED;
+		UINT64 now = Tick64();
+		POINT p;
+		bool mouse_move = false;
+
+		Zero(&p, sizeof(p));
+		GetCursorPos(&p);
+
+		if (p.x != last_c_x || p.y != last_c_y)
+		{
+			if (last_c_x != INFINITE && last_c_y != INFINITE)
+			{
+				mouse_move = true;
+			}
+
+			last_c_x = p.x;
+			last_c_y = p.y;
+		}
+
+		if (mouse_move)
+		{
+			last_mouse_move_time = now;
+		}
+
+		if (last_mouse_move_time == 0 || (now > (last_mouse_move_time + 50000ULL)))
+		{
+			wchar_t *active;
+			wchar_t *exe;
+			// マウスが 50 秒以上動かない場合はスクリーンセーバーの設定を削除する
+
+			active = MsRegReadStrW(REG_CURRENT_USER, key, "ScreenSaveActive");
+			exe = MsRegReadStrW(REG_CURRENT_USER, key, "SCRNSAVE.EXE");
+
+			if (UniToInt(active) != 0 && UniIsEmptyStr(exe) == false)
+			{
+				// スクリーンセーバーが設定されている
+				UniStrCpy(e->ScreenSaveActive, sizeof(e->ScreenSaveActive), active);
+				UniStrCpy(e->SCRNSAVE_EXE, sizeof(e->SCRNSAVE_EXE), exe);
+
+				MsRegWriteStrW(REG_CURRENT_USER, key, "ScreenSaveActive", L"0");
+				MsRegDeleteValue(REG_CURRENT_USER, key, "SCRNSAVE.EXE");
+
+				Debug("Push SS Settings.\n");
+			}
+
+			Free(active);
+			Free(exe);
+
+			last_mouse_move_time = now;
+		}
+		else
+		{
+			if (mouse_move)
+			{
+				if (UniIsEmptyStr(e->ScreenSaveActive) == false && UniIsEmptyStr(e->SCRNSAVE_EXE) == false)
+				{
+					// マウスが動いた場合でスクリーンセーバーが設定されていない場合は
+					// スクリーンセーバーの設定を復元する
+					wchar_t *active;
+					wchar_t *exe;
+
+					active = MsRegReadStrW(REG_CURRENT_USER, key, "ScreenSaveActive");
+					exe = MsRegReadStrW(REG_CURRENT_USER, key, "SCRNSAVE.EXE");
+
+					if (UniToInt(active) != 0 && UniIsEmptyStr(exe) == false)
+					{
+					}
+					else
+					{
+						MsRegWriteStrW(REG_CURRENT_USER, key, "ScreenSaveActive", e->ScreenSaveActive);
+						MsRegWriteStrW(REG_CURRENT_USER, key, "SCRNSAVE.EXE", e->SCRNSAVE_EXE);
+
+						Zero(e->ScreenSaveActive, sizeof(e->ScreenSaveActive));
+						Zero(e->SCRNSAVE_EXE, sizeof(e->SCRNSAVE_EXE));
+
+						Debug("Pop SS Settings.\n");
+					}
+
+					Free(active);
+					Free(exe);
+				}
+			}
+		}
+
+		if (last_set_flag == 0 || (now > (last_set_flag + 50000ULL)))
+		{
+			// フラグセット (50 秒間隔)
+			last_set_flag = now;
+
+			if (_SetThreadExecutionState != NULL)
+			{
+				_SetThreadExecutionState(flag);
+			}
+		}
+
+		Wait(e->HaltEvent, 512);
+	}
+
+	if (true)
+	{
+		// スクリーンセーバーの設定を復元する
+		wchar_t *active;
+		wchar_t *exe;
+
+		if (UniIsEmptyStr(e->ScreenSaveActive) == false && UniIsEmptyStr(e->SCRNSAVE_EXE) == false)
+		{
+			active = MsRegReadStrW(REG_CURRENT_USER, key, "ScreenSaveActive");
+			exe = MsRegReadStrW(REG_CURRENT_USER, key, "SCRNSAVE.EXE");
+
+			if (UniToInt(active) != 0 && UniIsEmptyStr(exe) != 0)
+			{
+			}
+			else
+			{
+				MsRegWriteStrW(REG_CURRENT_USER, key, "ScreenSaveActive", e->ScreenSaveActive);
+				MsRegWriteStrW(REG_CURRENT_USER, key, "SCRNSAVE.EXE", e->SCRNSAVE_EXE);
+
+				Zero(e->ScreenSaveActive, sizeof(e->ScreenSaveActive));
+				Zero(e->SCRNSAVE_EXE, sizeof(e->SCRNSAVE_EXE));
+
+				Debug("Pop SS Settings.\n");
+			}
+
+			Free(active);
+			Free(exe);
+		}
+	}
+
+	FreeLibrary(hKernel32);
+}
+
+// スリープ防止の開始
+void *MsNoSleepStart(bool no_screensaver)
+{
+	MS_NOSLEEP *e;
+	bool is_vista = MsIsVista();
+	bool is_nt_4 = false;
+	UINT os_type = GetOsInfo()->OsType;
+
+	if (OS_IS_WINDOWS_NT(os_type))
+	{
+		if (GET_KETA(os_type, 100) == 1)
+		{
+			is_nt_4 = true;
+		}
+	}
+
+	e = ZeroMalloc(sizeof(MS_NOSLEEP));
+
+	e->HaltEvent = NewEvent();
+	e->NoScreenSaver = no_screensaver;
+
+	if (e->NoScreenSaver == false || (is_vista == false && is_nt_4 == false))
+	{
+		e->Thread = NewThread(MsNoSleepThread, e);
+	}
+	else
+	{
+		e->Thread = NewThread(MsNoSleepThreadVista, e);
+	}
+
+	return (void *)e;
+}
+
+// スリープ防止の停止
+void MsNoSleepEnd(void *p)
+{
+	MS_NOSLEEP *e;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	e = (MS_NOSLEEP *)p;
+
+	e->Halt = true;
+	Set(e->HaltEvent);
+
+	WaitThread(e->Thread, INFINITE);
+	ReleaseThread(e->Thread);
+	ReleaseEvent(e->HaltEvent);
+
+	Free(e);
+}
+
+// コンピュータ名の取得
+void MsGetComputerName(char *name, UINT size)
+{
+	DWORD sz;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	sz = size;
+	GetComputerName(name, &sz);
+}
+
+// マウスカーソルの位置のハッシュ値を取得
+UINT MsGetCursorPosHash()
+{
+	POINT p;
+
+	Zero(&p, sizeof(p));
+
+	if (GetCursorPos(&p) == false)
+	{
+		return 0;
+	}
+
+	return MAKELONG((USHORT)p.x, (USHORT)p.y);
+}
+
+// 一般ユーザー権限としてのプロセスの起動
+void *MsRunAsUserEx(char *filename, char *arg, bool hide)
+{
+	void *ret = MsRunAsUserExInner(filename, arg, hide);
+
+	if (ret == NULL)
+	{
+		Debug("MsRunAsUserExInner Failed.\n");
+		ret = Win32RunEx(filename, arg, hide);
+	}
+
+	return ret;
+}
+void *MsRunAsUserExW(wchar_t *filename, wchar_t *arg, bool hide)
+{
+	void *ret = MsRunAsUserExInnerW(filename, arg, hide);
+
+	if (ret == NULL)
+	{
+		Debug("MsRunAsUserExInner Failed.\n");
+		ret = Win32RunExW(filename, arg, hide);
+	}
+
+	return ret;
+}
+void *MsRunAsUserExInner(char *filename, char *arg, bool hide)
+{
+	void *ret;
+	wchar_t *filename_w;
+	wchar_t *arg_w;
+
+	filename_w = CopyStrToUni(filename);
+	arg_w = CopyStrToUni(arg);
+
+	ret = MsRunAsUserExInnerW(filename_w, arg_w, hide);
+
+	Free(filename_w);
+	Free(arg_w);
+
+	return ret;
+}
+void *MsRunAsUserExInnerW(wchar_t *filename, wchar_t *arg, bool hide)
+{
+	STARTUPINFOW info;
+	PROCESS_INFORMATION ret;
+	wchar_t cmdline[MAX_SIZE];
+	wchar_t name[MAX_PATH];
+	HANDLE hToken;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	if (MsIsVista() == false)
+	{
+		// Windows Vista 以外では使用できない
+		return NULL;
+	}
+
+	UniStrCpy(name, sizeof(name), filename);
+	UniTrim(name);
+
+	if (UniSearchStr(name, L"\"", 0) == INFINITE)
+	{
+		if (arg == NULL)
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"%s", name);
+		}
+		else
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"%s %s", name, arg);
+		}
+	}
+	else
+	{
+		if (arg == NULL)
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"\"%s\"", name);
+		}
+		else
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"\"%s\" %s", name, arg);
+		}
+	}
+
+	Zero(&info, sizeof(info));
+	Zero(&ret, sizeof(ret));
+	info.cb = sizeof(info);
+	info.dwFlags = STARTF_USESHOWWINDOW;
+	info.wShowWindow = (hide == false ? SW_SHOWDEFAULT : SW_HIDE);
+
+	UniTrim(cmdline);
+
+	hToken = MsCreateUserToken();
+
+	if (hToken == NULL)
+	{
+		return NULL;
+	}
+
+	if (ms->nt->CreateProcessAsUserW(hToken, NULL, cmdline, NULL, NULL, FALSE,
+		(hide == false ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW | CREATE_NEW_CONSOLE) | NORMAL_PRIORITY_CLASS,
+		NULL, NULL, &info, &ret) == FALSE)
+	{
+		return NULL;
+	}
+
+	CloseHandle(hToken);
+
+	CloseHandle(ret.hThread);
+	return ret.hProcess;
+}
+
+// アカウント名から SID を取得する
+SID *MsGetSidFromAccountName(char *name)
+{
+	SID *sid;
+	UINT sid_size = 4096;
+	char *domain_name;
+	UINT domain_name_size = 4096;
+	SID_NAME_USE use = SidTypeUser;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return NULL;
+	}
+
+	sid = ZeroMalloc(sid_size);
+	domain_name = ZeroMalloc(domain_name_size);
+
+	if (ms->nt->LookupAccountNameA(NULL, name, sid, &sid_size, domain_name, &domain_name_size, &use) == false)
+	{
+		Free(sid);
+		Free(domain_name);
+		return NULL;
+	}
+
+	Free(domain_name);
+
+	return sid;
+}
+
+// SID を解放する
+void MsFreeSid(SID *sid)
+{
+	// 引数チェック
+	if (sid == NULL)
+	{
+		return;
+	}
+
+	Free(sid);
+}
+
+// 一般ユーザーのトークンを作成する
+HANDLE MsCreateUserToken()
+{
+	char *medium_sid = "S-1-16-8192";
+	char *administrators_sid = "S-1-5-32-544";
+	SID *sid = NULL;
+	TOKEN_MANDATORY_LABEL til;
+	HANDLE hCurrentToken, hNewToken;
+	if (MsIsNt() == false)
+	{
+		return NULL;
+	}
+	if (ms->nt->ConvertStringSidToSidA == NULL ||
+		ms->nt->OpenProcessToken == NULL ||
+		ms->nt->DuplicateTokenEx == NULL ||
+		ms->nt->GetTokenInformation == NULL ||
+		ms->nt->SetTokenInformation == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&til, sizeof(til));
+
+	if (ms->nt->ConvertStringSidToSidA(medium_sid, &sid) == false)
+	{
+		return NULL;
+	}
+
+	til.Label.Attributes = SE_GROUP_INTEGRITY;
+	til.Label.Sid = sid;
+
+	if (ms->nt->OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &hCurrentToken) == false)
+	{
+		LocalFree(sid);
+		return NULL;
+	}
+
+	if (ms->nt->DuplicateTokenEx(hCurrentToken, MAXIMUM_ALLOWED, NULL,
+		SecurityImpersonation, TokenPrimary, &hNewToken) == false)
+	{
+		CloseHandle(hCurrentToken);
+		LocalFree(sid);
+		return NULL;
+	}
+
+	if (ms->nt->SetTokenInformation(hNewToken, VistaTokenIntegrityLevel, &til,
+		sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(sid)) == false)
+	{
+		CloseHandle(hNewToken);
+		CloseHandle(hCurrentToken);
+		LocalFree(sid);
+		return NULL;
+	}
+
+	CloseHandle(hCurrentToken);
+	LocalFree(sid);
+
+	return hNewToken;
+}
+
+// ファイルのデジタル署名をチェック
+bool MsCheckFileDigitalSignature(HWND hWnd, char *name, bool *danger)
+{
+	wchar_t tmp[MAX_PATH];
+
+	swprintf(tmp, sizeof(tmp), L"%S", name);
+
+	return MsCheckFileDigitalSignatureW(hWnd, tmp, danger);
+}
+bool MsCheckFileDigitalSignatureW(HWND hWnd, wchar_t *name, bool *danger)
+{
+	HRESULT ret = S_OK;
+	wchar_t *tmp;
+	LONG (WINAPI *_WinVerifyTrust)(HWND, GUID *, LPVOID) = NULL;
+	HINSTANCE hDll;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (danger != NULL)
+	{
+		*danger = false;
+	}
+
+	tmp = name;
+
+	hDll = LoadLibrary("Wintrust.dll");
+	if (hDll == NULL)
+	{
+		return false;
+	}
+
+	_WinVerifyTrust =
+		(LONG (__stdcall *)(HWND,GUID *,LPVOID))
+		GetProcAddress(hDll, "WinVerifyTrust");
+	if (_WinVerifyTrust == NULL)
+	{
+		FreeLibrary(hDll);
+		return false;
+	}
+	else
+	{
+		GUID action_id = WINTRUST_ACTION_GENERIC_VERIFY_V2;
+		WINTRUST_FILE_INFO file;
+		WINTRUST_DATA data;
+
+		Zero(&file, sizeof(file));
+		file.cbStruct = sizeof(file);
+		file.pcwszFilePath = tmp;
+
+		Zero(&data, sizeof(data));
+		data.cbStruct = sizeof(data);
+		data.fdwRevocationChecks = WTD_REVOKE_WHOLECHAIN;
+		data.dwUIChoice = (hWnd != NULL ? WTD_UI_NOGOOD : WTD_UI_NONE);
+		data.dwProvFlags = WTD_REVOCATION_CHECK_CHAIN;
+		data.dwUnionChoice = WTD_CHOICE_FILE;
+		data.pFile = &file;
+
+		ret = _WinVerifyTrust(hWnd, &action_id, &data);
+
+		if (ret == ERROR_SUCCESS && danger != NULL)
+		{
+			if (hWnd != NULL)
+			{
+				if (MsCheckFileDigitalSignatureW(NULL, name, NULL) == false)
+				{
+					// 危険なファイルだがユーザーが [OK] を選択してしまった
+					*danger = true;
+				}
+			}
+		}
+	}
+
+	FreeLibrary(hDll);
+
+	if (ret != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// WoW64 リダイレクションを有効または無効にする
+void MsSetWow64FileSystemRedirectionEnable(bool enable)
+{
+	if (MsIs64BitWindows() == false)
+	{
+		return;
+	}
+
+	if (ms->nt->Wow64EnableWow64FsRedirection == NULL)
+	{
+		return;
+	}
+
+	ms->nt->Wow64EnableWow64FsRedirection(enable ? 1 : 0);
+}
+
+// WoW64 リダイレクションを無効にする
+void *MsDisableWow64FileSystemRedirection()
+{
+	void *p = NULL;
+	if (MsIs64BitWindows() == false)
+	{
+		return NULL;
+	}
+
+	if (ms->nt->Wow64DisableWow64FsRedirection == NULL ||
+		ms->nt->Wow64RevertWow64FsRedirection == NULL)
+	{
+		return NULL;
+	}
+
+	if (ms->nt->Wow64DisableWow64FsRedirection(&p) == false)
+	{
+		return NULL;
+	}
+
+	if (p == NULL)
+	{
+		p = (void *)0x12345678;
+	}
+
+	return p;
+}
+
+// WoW64 リダイレクションを元に戻す
+void MsRestoreWow64FileSystemRedirection(void *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+	if (p == (void *)0x12345678)
+	{
+		p = NULL;
+	}
+	if (MsIs64BitWindows() == false)
+	{
+		return;
+	}
+
+	if (ms->nt->Wow64DisableWow64FsRedirection == NULL ||
+		ms->nt->Wow64RevertWow64FsRedirection == NULL)
+	{
+		return;
+	}
+
+	ms->nt->Wow64RevertWow64FsRedirection(p);
+}
+
+// 現在 x64 版 Windows が動作しているかどうか取得
+bool MsIsX64()
+{
+	SYSTEM_INFO info;
+
+	if (MsIs64BitWindows() == false)
+	{
+		return false;
+	}
+	if (ms->nt->GetNativeSystemInfo == NULL)
+	{
+		return false;
+	}
+
+	Zero(&info, sizeof(info));
+	ms->nt->GetNativeSystemInfo(&info);
+
+	if (info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// 現在 IA64 版 Windows が動作しているかどうか取得
+bool MsIsIA64()
+{
+	if (MsIs64BitWindows() == false)
+	{
+		return false;
+	}
+
+	if (MsIsX64())
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 64bit Windows かどうか取得
+bool MsIs64BitWindows()
+{
+	if (Is64())
+	{
+		return true;
+	}
+	else
+	{
+		if (MsIsNt() == false)
+		{
+			return false;
+		}
+		else
+		{
+			if (ms == NULL || ms->nt == NULL)
+			{
+				return false;
+			}
+
+			if (ms->nt->IsWow64Process == NULL)
+			{
+				return false;
+			}
+			else
+			{
+				bool b = false;
+				if (ms->nt->IsWow64Process(GetCurrentProcess(), &b) == false)
+				{
+					return false;
+				}
+				return b;
+			}
+		}
+	}
+}
+
+// Windows ファイアウォール登録
+void MsRegistWindowsFirewallEx2(char *title, char *exe)
+{
+	char *dir = MsGetExeDirName();
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (title == NULL || exe == NULL)
+	{
+		return;
+	}
+
+	ConbinePath(tmp, sizeof(tmp), dir, exe);
+
+	if (IsFileExists(tmp) == false)
+	{
+		return;
+	}
+
+	MsRegistWindowsFirewallEx(title, tmp);
+}
+void MsRegistWindowsFirewall(char *title)
+{
+	// 引数チェック
+	if (title == NULL)
+	{
+		return;
+	}
+
+	MsRegistWindowsFirewallEx(title, MsGetExeFileName());
+}
+void MsRegistWindowsFirewallEx(char *title, char *exe)
+{
+	char *data =
+		"Option Explicit\r\nConst NET_FW_PROFILE_DOMAIN = 0\r\nConst NET_FW_PROFILE_STANDARD = 1\r\n"
+		"Const NET_FW_SCOPE_ALL = 0\r\nConst NET_FW_IP_VERSION_ANY = 2\r\nDim fwMgr\r\n"
+		"Set fwMgr = CreateObject(\"HNetCfg.FwMgr\")\r\nDim profile\r\n"
+		"Set profile = fwMgr.LocalPolicy.CurrentProfile\r\nDim app\r\n"
+		"Set app = CreateObject(\"HNetCfg.FwAuthorizedApplication\")\r\n"
+		"app.ProcessImageFileName = \"$PATH$\"\r\napp.Name = \"$TITLE$\"\r\n"
+		"app.Scope = NET_FW_SCOPE_ALL\r\napp.IpVersion = NET_FW_IP_VERSION_ANY\r\n"
+		"app.Enabled = TRUE\r\nOn Error Resume Next\r\nprofile.AuthorizedApplications."
+		"Add app\r\n";
+	char *tmp;
+	UINT tmp_size;
+	char filename[MAX_PATH];
+	char cscript[MAX_PATH];
+	char arg[MAX_PATH];
+	UINT ostype;
+	IO *o;
+	char hash[MAX_PATH];
+	UCHAR hashbin[SHA1_SIZE];
+	// 引数チェック
+	if (title == NULL || exe == NULL)
+	{
+		return;
+	}
+
+	// OS チェック (Windows XP, Windows Server 2003, Windows Vista, Windows 7 以外では実施しない)
+	ostype = GetOsInfo()->OsType;
+	if (OS_IS_WINDOWS_NT(ostype) == false)
+	{
+		return;
+	}
+	if (GET_KETA(ostype, 100) != 3 && GET_KETA(ostype, 100) != 4 && GET_KETA(ostype, 100) != 5 && GET_KETA(ostype, 100) != 6)
+	{
+		return;
+	}
+
+	tmp_size = StrLen(data) * 4;
+	tmp = ZeroMalloc(tmp_size);
+
+	HashSha1(hashbin, exe, StrLen(exe));
+	BinToStr(hash, sizeof(hash), hashbin, 6);
+
+	ReplaceStrEx(tmp, tmp_size, data, "$TITLE$", title, false);
+	ReplaceStrEx(tmp, tmp_size, tmp, "$PATH$", exe, false);
+
+	Format(filename, sizeof(filename), "%s\\winfire_%s.vbs", MsGetMyTempDir(), hash);
+	o = FileCreate(filename);
+	FileWrite(o, tmp, StrLen(tmp));
+	FileClose(o);
+
+	Format(cscript, sizeof(cscript), "%s\\cscript.exe", MsGetSystem32Dir());
+	Format(arg, sizeof(arg), "\"%s\"", filename);
+
+	Run(cscript, arg, true, false);
+
+	Debug("cscript %s\n", arg);
+
+	Free(tmp);
+}
+
+// Vista 用ドライバインストーラの実行
+bool MsExecDriverInstaller(char *arg)
+{
+	wchar_t tmp[MAX_PATH];
+	wchar_t hamcore_dst[MAX_PATH];
+	wchar_t hamcore_src[MAX_PATH];
+	HANDLE h;
+	UINT retcode;
+	SHELLEXECUTEINFOW info;
+	wchar_t *src_exe;
+	wchar_t *arg_w;
+	// 引数チェック
+	if (arg == NULL)
+	{
+		return false;
+	}
+
+	UniFormat(hamcore_dst, sizeof(hamcore_dst), L"%s\\hamcore.utvpn", MsGetMyTempDirW());
+	UniFormat(hamcore_src, sizeof(hamcore_src), L"%s\\hamcore.utvpn", MsGetExeDirNameW());
+
+	// ファイル展開
+	src_exe = VISTA_DRIVER_INSTALLER_SRC;
+
+	if (MsIsX64())
+	{
+		src_exe = VISTA_DRIVER_INSTALLER_SRC_X64;
+	}
+	if (MsIsIA64())
+	{
+		src_exe = VISTA_DRIVER_INSTALLER_SRC_IA64;
+	}
+
+	UniFormat(tmp, sizeof(tmp), VISTA_DRIVER_INSTALLER_DST, MsGetMyTempDirW());
+
+	if (FileCopyW(src_exe, tmp) == false)
+	{
+		return false;
+	}
+
+	if (FileCopyW(hamcore_src, hamcore_dst) == false)
+	{
+		return false;
+	}
+
+	arg_w = CopyStrToUni(arg);
+
+	// 実行
+	Zero(&info, sizeof(info));
+	info.cbSize = sizeof(info);
+	info.lpVerb = L"open";
+	info.lpFile = tmp;
+	info.fMask = SEE_MASK_NOCLOSEPROCESS;
+	info.lpParameters = arg_w;
+	info.nShow = SW_SHOWNORMAL;
+	if (ShellExecuteExW(&info) == false)
+	{
+		Free(arg_w);
+		return false;
+	}
+
+	Free(arg_w);
+
+	h = info.hProcess;
+	retcode = 1;
+
+	while (true)
+	{
+		// 完了まで待機
+		WaitForSingleObject(h, INFINITE);
+
+		// 終了コードを取得
+		retcode = 1;
+		if (GetExitCodeProcess(h, &retcode) == false)
+		{
+			break;
+		}
+
+		if (retcode != STILL_ACTIVE)
+		{
+			break;
+		}
+	}
+
+	CloseHandle(h);
+
+	if (retcode & 1)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 現在のスレッドのロケールを取得
+UINT MsGetThreadLocale()
+{
+	return (UINT)GetThreadLocale();
+}
+
+// 現在のコンソールの横幅を設定する
+UINT MsSetConsoleWidth(UINT size)
+{
+	HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+	CONSOLE_SCREEN_BUFFER_INFO info;
+	COORD c;
+	UINT old_x, old_y;
+	// 引数チェック
+	if (size == 0)
+	{
+		return 0;
+	}
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		return 0;
+	}
+
+	Zero(&info, sizeof(info));
+	if (GetConsoleScreenBufferInfo(h, &info) == false)
+	{
+		return 0;
+	}
+
+	old_x = info.dwSize.X;
+	old_y = info.dwSize.Y;
+
+	c.X = size;
+	c.Y = old_y;
+
+	SetConsoleScreenBufferSize(h, c);
+
+	return old_x;
+}
+
+// 現在のコンソールの横幅を取得する
+UINT MsGetConsoleWidth()
+{
+	HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+	CONSOLE_SCREEN_BUFFER_INFO info;
+
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		return 80;
+	}
+
+	Zero(&info, sizeof(info));
+	if (GetConsoleScreenBufferInfo(h, &info) == false)
+	{
+		return 80;
+	}
+
+	return info.dwSize.X;
+}
+
+// MS-IME を無効にする
+bool MsDisableIme()
+{
+	HINSTANCE h;
+	bool ret = false;
+	char dll_name[MAX_PATH];
+	BOOL (WINAPI *_ImmDisableIME)(DWORD);
+
+	Format(dll_name, sizeof(dll_name), "%s\\imm32.dll", MsGetSystem32Dir());
+	h = MsLoadLibrary(dll_name);
+	if (h == NULL)
+	{
+		return false;
+	}
+
+	_ImmDisableIME = (BOOL (__stdcall *)(DWORD))GetProcAddress(h, "ImmDisableIME");
+
+	if (_ImmDisableIME != NULL)
+	{
+		ret = _ImmDisableIME(-1);
+	}
+
+	FreeLibrary(h);
+
+	return ret;
+}
+
+// 現在時刻を表示する
+void MsPrintTick()
+{
+	UINT tick = timeGetTime();
+	static UINT tick_init = 0;
+	if (tick_init == 0)
+	{
+		tick_init = tick;
+		tick = 0;
+	}
+	else
+	{
+		tick -= tick_init;
+	}
+
+	printf("[%u]\n", tick);
+}
+
+// LoadLibrary の hamcore 対応版 (データファイルとして読み込み)
+void *MsLoadLibraryAsDataFileW(wchar_t *name)
+{
+	BUF *b;
+	wchar_t tmp_dll_name[MAX_SIZE];
+	char hash_str[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	Hash(hash, name, UniStrLen(name), true);
+
+	BinToStr(hash_str, sizeof(hash_str), hash, 4);
+
+	UniFormat(tmp_dll_name, sizeof(tmp_dll_name), L"%s\\%S.dll", MsGetMyTempDirW(), hash_str);
+
+	if (IsFileExistsW(tmp_dll_name) == false)
+	{
+		b = ReadDumpW(name);
+		if (b == NULL)
+		{
+			return NULL;
+		}
+
+		DumpBufW(b, tmp_dll_name);
+		FreeBuf(b);
+	}
+
+	return LoadLibraryExW(tmp_dll_name, NULL, LOAD_LIBRARY_AS_DATAFILE);
+}
+void *MsLoadLibraryAsDataFile(char *name)
+{
+	wchar_t name_w[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	StrToUni(name_w, sizeof(name_w), name);
+
+	return MsLoadLibraryAsDataFileW(name_w);
+}
+
+// LoadLibrary の hamcore 対応版
+void *MsLoadLibraryW(wchar_t *name)
+{
+	BUF *b;
+	wchar_t tmp_dll_name[MAX_SIZE];
+	char hash_str[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	Hash(hash, name, UniStrSize(name), true);
+
+	BinToStr(hash_str, sizeof(hash_str), hash, 4);
+
+	UniFormat(tmp_dll_name, sizeof(tmp_dll_name), L"%s\\%S.dll", MsGetMyTempDirW(), hash_str);
+
+	if (IsFileExistsW(tmp_dll_name) == false)
+	{
+		b = ReadDumpW(name);
+		if (b == NULL)
+		{
+			return NULL;
+		}
+
+		DumpBufW(b, tmp_dll_name);
+		FreeBuf(b);
+	}
+
+	if (IsNt())
+	{
+		return LoadLibraryW(tmp_dll_name);
+	}
+	else
+	{
+		char tmp_dll_name_a[MAX_SIZE];
+		HINSTANCE ret;
+
+		UniToStr(tmp_dll_name_a, sizeof(tmp_dll_name_a), tmp_dll_name);
+
+		ret = LoadLibraryA(tmp_dll_name_a);
+
+		return ret;
+	}
+}
+void *MsLoadLibrary(char *name)
+{
+	wchar_t name_w[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	StrToUni(name_w, sizeof(name_w), name);
+
+	return MsLoadLibraryW(name_w);
+}
+
+// 単一のアダプタの取得
+MS_ADAPTER *MsGetAdapter(char *title)
+{
+	MS_ADAPTER_LIST *o;
+	MS_ADAPTER *ret = NULL;
+	UINT i;
+	// 引数チェック
+	if (title == NULL)
+	{
+		return NULL;
+	}
+
+	o = MsCreateAdapterList();
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < o->Num;i++)
+	{
+		if (StrCmpi(o->Adapters[i]->Title, title) == 0)
+		{
+			ret = MsCloneAdapter(o->Adapters[i]);
+			break;
+		}
+	}
+
+	MsFreeAdapterList(o);
+
+	return ret;
+}
+
+// 32 ビットオーバーフローチェック
+#define	CHECK_32BIT_OVERFLOW(old_value, new_value)				\
+{																\
+	if ((old_value) > (new_value))								\
+	{															\
+		(new_value) += ((UINT64)4294967296ULL);					\
+	}															\
+}
+
+// 指定したアダプタの TCP/IP 情報を取得する
+void MsGetAdapterTcpIpInformation(MS_ADAPTER *a)
+{
+	IP_ADAPTER_INFO *info, *info_top;
+	UINT info_size;
+	UINT ret;
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	if (w32net->GetAdaptersInfo == NULL)
+	{
+		return;
+	}
+
+	info_top = ZeroMalloc(sizeof(IP_ADAPTER_INFO));
+	info_size = sizeof(IP_ADAPTER_INFO);
+
+	ret = w32net->GetAdaptersInfo(info_top, &info_size);
+	if (ret == ERROR_INSUFFICIENT_BUFFER || ret == ERROR_BUFFER_OVERFLOW)
+	{
+		Free(info_top);
+		info_size *= 2;
+		info_top = ZeroMalloc(info_size);
+
+		if (w32net->GetAdaptersInfo(info_top, &info_size) != NO_ERROR)
+		{
+			Free(info_top);
+			return;
+		}
+	}
+	else if (ret != NO_ERROR)
+	{
+		Free(info_top);
+		return;
+	}
+
+	// 自分のエントリを検索する
+	info = info_top;
+
+	while (info != NULL)
+	{
+		if (info->Index == a->Index)
+		{
+			IP_ADDR_STRING *s;
+
+			// IP アドレス
+			a->NumIpAddress = 0;
+			s = &info->IpAddressList;
+			while (s != NULL)
+			{
+				if (a->NumIpAddress < MAX_MS_ADAPTER_IP_ADDRESS)
+				{
+					StrToIP(&a->IpAddresses[a->NumIpAddress], s->IpAddress.String);
+					StrToIP(&a->SubnetMasks[a->NumIpAddress], s->IpMask.String);
+					a->NumIpAddress++;
+				}
+				s = s->Next;
+			}
+
+			// ゲートウェイ
+			a->NumGateway = 0;
+			s = &info->GatewayList;
+			while (s != NULL)
+			{
+				if (a->NumGateway < MAX_MS_ADAPTER_IP_ADDRESS)
+				{
+					StrToIP(&a->Gateways[a->NumGateway], s->IpAddress.String);
+					a->NumGateway++;
+				}
+				s = s->Next;
+			}
+
+			// DHCP サーバー
+			a->UseDhcp = (info->DhcpEnabled == 0 ? false : true);
+			if (a->UseDhcp)
+			{
+				SYSTEMTIME st;
+
+				StrToIP(&a->DhcpServer, info->DhcpServer.IpAddress.String);
+				TimeToSystem(&st, info->LeaseObtained);
+				a->DhcpLeaseStart = SystemToUINT64(&st);
+
+				TimeToSystem(&st, info->LeaseExpires);
+				a->DhcpLeaseExpires = SystemToUINT64(&st);
+			}
+
+			// WINS サーバー
+			a->UseWins = info->HaveWins;
+			if (a->UseWins)
+			{
+				StrToIP(&a->PrimaryWinsServer, info->PrimaryWinsServer.IpAddress.String);
+				StrToIP(&a->SecondaryWinsServer, info->SecondaryWinsServer.IpAddress.String);
+			}
+
+			StrCpy(a->Guid, sizeof(a->Guid), info->AdapterName);
+
+			a->Info = true;
+
+			break;
+		}
+
+		info = info->Next;
+	}
+
+	Free(info_top);
+}
+
+// アダプタリストの生成
+MS_ADAPTER_LIST *MsCreateAdapterList()
+{
+	return MsCreateAdapterListEx(false);
+}
+MS_ADAPTER_LIST *MsCreateAdapterListEx(bool no_info)
+{
+	MS_ADAPTER_LIST *ret;
+
+	if (no_info)
+	{
+		ret = MsCreateAdapterListInnerEx(true);
+
+		return ret;
+	}
+
+	Lock(lock_adapter_list);
+	{
+		MS_ADAPTER_LIST *old = last_adapter_list;
+		UINT i;
+
+		// 新しくアダプタリストを取ってくる
+		ret = MsCreateAdapterListInner();
+
+		if (ret == NULL)
+		{
+			Unlock(lock_adapter_list);
+			return NULL;
+		}
+
+		// 取ってきたアダプタリストの各エントリについて、前回取得したものが
+		// 存在するかどうかチェックする
+		for (i = 0;i < ret->Num;i++)
+		{
+			UINT j;
+			for (j = 0;j < old->Num;j++)
+			{
+				MS_ADAPTER *o = old->Adapters[j];
+				MS_ADAPTER *n = ret->Adapters[i];
+
+				if (StrCmpi(o->Title, n->Title) == 0)
+				{
+					// 古いもののほうが値が小さい場合、インクリメントする
+					CHECK_32BIT_OVERFLOW(o->RecvBytes, n->RecvBytes);
+					CHECK_32BIT_OVERFLOW(o->RecvPacketsBroadcast, n->RecvPacketsBroadcast);
+					CHECK_32BIT_OVERFLOW(o->RecvPacketsUnicast, n->RecvPacketsUnicast);
+					CHECK_32BIT_OVERFLOW(o->SendBytes, n->SendBytes);
+					CHECK_32BIT_OVERFLOW(o->SendPacketsBroadcast, n->SendPacketsBroadcast);
+					CHECK_32BIT_OVERFLOW(o->SendPacketsUnicast, n->SendPacketsUnicast);
+					break;
+				}
+			}
+		}
+
+		// 古いアダプタリストを解放する
+		MsFreeAdapterList(old);
+
+		// 新しく取得したアダプタリストのクローンを保存しておく
+		last_adapter_list = MsCloneAdapterList(ret);
+	}
+	Unlock(lock_adapter_list);
+
+	return ret;
+}
+
+// アダプタリストモジュールの初期化
+void MsInitAdapterListModule()
+{
+	lock_adapter_list = NewLock(NULL);
+
+	last_adapter_list = MsCreateAdapterListInner();
+}
+
+// アダプタリストモジュールの解放
+void MsFreeAdapterListModule()
+{
+	if (last_adapter_list != NULL)
+	{
+		MsFreeAdapterList(last_adapter_list);
+		last_adapter_list = NULL;
+	}
+
+	DeleteLock(lock_adapter_list);
+	lock_adapter_list = NULL;
+}
+
+// アダプタリストのクローン
+MS_ADAPTER_LIST *MsCloneAdapterList(MS_ADAPTER_LIST *o)
+{
+	MS_ADAPTER_LIST *ret;
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(MS_ADAPTER_LIST));
+	ret->Num = o->Num;
+	ret->Adapters = ZeroMalloc(sizeof(MS_ADAPTER *) * ret->Num);
+
+	for (i = 0;i < ret->Num;i++)
+	{
+		ret->Adapters[i] = ZeroMalloc(sizeof(MS_ADAPTER));
+		Copy(ret->Adapters[i], o->Adapters[i], sizeof(MS_ADAPTER));
+	}
+
+	return ret;
+}
+
+// アダプタのクローン
+MS_ADAPTER *MsCloneAdapter(MS_ADAPTER *a)
+{
+	MS_ADAPTER *ret;
+	// 引数チェック
+	if (a == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(MS_ADAPTER));
+	Copy(ret, a, sizeof(MS_ADAPTER));
+
+	return ret;
+}
+
+// アダプタリストの作成
+MS_ADAPTER_LIST *MsCreateAdapterListInner()
+{
+	return MsCreateAdapterListInnerEx(false);
+}
+MS_ADAPTER_LIST *MsCreateAdapterListInnerEx(bool no_info)
+{
+	LIST *o;
+	UINT i;
+	UINT retcode;
+	MIB_IFTABLE *table;
+	UINT table_size = sizeof(MIB_IFTABLE);
+	MS_ADAPTER_LIST *ret;
+
+	table = ZeroMalloc(table_size);
+
+	if (w32net->GetIfTable == NULL)
+	{
+		return ZeroMalloc(sizeof(MS_ADAPTER_LIST));
+	}
+
+	retcode = w32net->GetIfTable(table, &table_size, TRUE);
+	if (retcode == ERROR_INSUFFICIENT_BUFFER || retcode == ERROR_BUFFER_OVERFLOW)
+	{
+		Free(table);
+		table_size *= 2;
+		table = ZeroMalloc(table_size);
+		if (w32net->GetIfTable(table, &table_size, TRUE) != NO_ERROR)
+		{
+			Free(table);
+			return NULL;
+		}
+	}
+	else if (retcode != NO_ERROR)
+	{
+		Free(table);
+		return NULL;
+	}
+
+	o = NewListFast(NULL);
+
+	for (i = 0;i < table->dwNumEntries;i++)
+	{
+		MIB_IFROW *r = &table->table[i];
+		char title[MAX_PATH];
+		UINT num = 0;
+		MS_ADAPTER *a;
+		UINT j;
+
+		//if (r->dwOperStatus == MIB_IF_OPER_STATUS_CONNECTED || r->dwOperStatus == MIB_IF_OPER_STATUS_OPERATIONAL)
+		{
+			//if (r->dwType & IF_TYPE_ETHERNET_CSMACD)
+			{
+				for (j = 1;;j++)
+				{
+					UINT k;
+					bool exists;
+					if (j == 1)
+					{
+						StrCpy(title, sizeof(title), (char *)r->bDescr);
+					}
+					else
+					{
+						Format(title, sizeof(title), "%s (%u)", (char *)r->bDescr, j);
+					}
+
+					exists = false;
+
+					for (k = 0;k < LIST_NUM(o);k++)
+					{
+						MS_ADAPTER *a = LIST_DATA(o, k);
+
+						if (StrCmpi(a->Title, title) == 0)
+						{
+							exists = true;
+							break;
+						}
+					}
+
+					if (exists == false)
+					{
+						break;
+					}
+				}
+
+				a = ZeroMalloc(sizeof(MS_ADAPTER));
+
+				// アダプタ情報作成
+				StrCpy(a->Title, sizeof(a->Title), title);
+				a->Index = r->dwIndex;
+				a->Type = r->dwType;
+				a->Status = r->dwOperStatus;
+				a->Mtu = r->dwMtu;
+				a->Speed = r->dwSpeed;
+				a->AddressSize = MIN(sizeof(a->Address), r->dwPhysAddrLen);
+				Copy(a->Address, r->bPhysAddr, a->AddressSize);
+				a->RecvBytes = r->dwInOctets;
+				a->RecvPacketsBroadcast = r->dwInNUcastPkts;
+				a->RecvPacketsUnicast = r->dwInUcastPkts;
+				a->SendBytes = r->dwOutOctets;
+				a->SendPacketsBroadcast = r->dwOutNUcastPkts;
+				a->SendPacketsUnicast = r->dwOutUcastPkts;
+
+				// TCP/IP 情報取得
+				if (no_info == false)
+				{
+					MsGetAdapterTcpIpInformation(a);
+				}
+
+				Add(o, a);
+			}
+		}
+	}
+
+	ret = ZeroMalloc(sizeof(MS_ADAPTER_LIST));
+	ret->Num = LIST_NUM(o);
+	ret->Adapters = ToArray(o);
+
+	ReleaseList(o);
+	Free(table);
+
+	return ret;
+}
+
+// アダプタリストの解放
+void MsFreeAdapterList(MS_ADAPTER_LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < o->Num;i++)
+	{
+		MsFreeAdapter(o->Adapters[i]);
+	}
+	Free(o->Adapters);
+
+	Free(o);
+}
+
+// アダプタ情報の解放
+void MsFreeAdapter(MS_ADAPTER *a)
+{
+	// 引数チェック
+	if (a == NULL)
+	{
+		return;
+	}
+
+	Free(a);
+}
+
+// アダプタの状態文字列を取得する
+wchar_t *MsGetAdapterStatusStr(UINT status)
+{
+	wchar_t *ret;
+
+	switch (status)
+	{
+	case MIB_IF_OPER_STATUS_NON_OPERATIONAL:
+		ret = _UU("MS_NON_OPERATIONAL");
+		break;
+
+	case MIB_IF_OPER_STATUS_UNREACHABLE:
+		ret = _UU("MS_UNREACHABLE");
+		break;
+
+	case MIB_IF_OPER_STATUS_DISCONNECTED:
+		ret = _UU("MS_DISCONNECTED");
+		break;
+
+	case MIB_IF_OPER_STATUS_CONNECTING:
+		ret = _UU("MS_CONNECTING");
+		break;
+
+	case MIB_IF_OPER_STATUS_CONNECTED:
+		ret = _UU("MS_CONNECTED");
+		break;
+
+	default:
+		ret = _UU("MS_OPERATIONAL");
+		break;
+	}
+
+	return ret;
+}
+
+// アダプタの種類文字列を取得する
+wchar_t *MsGetAdapterTypeStr(UINT type)
+{
+	wchar_t *ret;
+
+	switch (type)
+	{
+	case MIB_IF_TYPE_ETHERNET:
+		ret = _UU("MS_ETHERNET");
+		break;
+
+	case MIB_IF_TYPE_TOKENRING:
+		ret = _UU("MS_TOKENRING");
+		break;
+
+	case MIB_IF_TYPE_FDDI:
+		ret = _UU("MS_FDDI");
+		break;
+
+	case MIB_IF_TYPE_PPP:
+		ret = _UU("MS_PPP");
+		break;
+
+	case MIB_IF_TYPE_LOOPBACK:
+		ret = _UU("MS_LOOPBACK");
+		break;
+
+	case MIB_IF_TYPE_SLIP:
+		ret = _UU("MS_SLIP");
+		break;
+
+	default:
+		ret = _UU("MS_OTHER");
+		break;
+	}
+
+	return ret;
+}
+
+// 自分自身の EXE の自分以外のインスタンスをすべて終了する
+void MsKillOtherInstance()
+{
+	MsKillOtherInstanceEx(NULL);
+}
+void MsKillOtherInstanceEx(char *exclude_svcname)
+{
+	UINT me, i;
+	wchar_t me_path[MAX_PATH];
+	wchar_t me_path_short[MAX_PATH];
+	LIST *o = MsGetProcessList();
+	UINT e_procid = 0;
+	UINT e_procid2 = 0;
+
+	if (exclude_svcname != NULL)
+	{
+		e_procid = MsReadCallingServiceManagerProcessId(exclude_svcname, false);
+		e_procid2 = MsReadCallingServiceManagerProcessId(exclude_svcname, true);
+	}
+
+	me = MsGetProcessId();
+
+	MsGetCurrentProcessExeNameW(me_path, sizeof(me_path));
+	MsGetShortPathNameW(me_path, me_path_short, sizeof(me_path_short));
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		MS_PROCESS *p = LIST_DATA(o, i);
+		if (p->ProcessId != me)
+		{
+			if ((e_procid == 0 || (e_procid != p->ProcessId)) && (e_procid2 == 0 || (e_procid2 != p->ProcessId)))
+			{
+				wchar_t tmp[MAX_PATH];
+				MsGetShortPathNameW(p->ExeFilenameW, tmp, sizeof(tmp));
+				if (UniStrCmpi(me_path_short, tmp) == 0)
+				{
+					MsKillProcess(p->ProcessId);
+				}
+			}
+		}
+	}
+
+	MsFreeProcessList(o);
+}
+
+// 短いファイル名を取得する
+bool MsGetShortPathNameA(char *long_path, char *short_path, UINT short_path_size)
+{
+	// 引数チェック
+	if (long_path == NULL || short_path == NULL)
+	{
+		return false;
+	}
+
+	if (GetShortPathNameA(long_path, short_path, short_path_size) == 0)
+	{
+		StrCpy(short_path, short_path_size, long_path);
+		return false;
+	}
+
+	return true;
+}
+bool MsGetShortPathNameW(wchar_t *long_path, wchar_t *short_path, UINT short_path_size)
+{
+	// 引数チェック
+	if (long_path == NULL || short_path == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char short_path_a[MAX_SIZE];
+		char long_path_a[MAX_SIZE];
+		bool ret;
+
+		UniToStr(long_path_a, sizeof(long_path_a), long_path);
+
+		ret = MsGetShortPathNameA(long_path_a, short_path_a, sizeof(short_path_a));
+
+		StrToUni(short_path, short_path_size, short_path_a);
+
+		return ret;
+	}
+
+	if (GetShortPathNameW(long_path, short_path, short_path_size) == 0)
+	{
+		UniStrCpy(short_path, short_path_size, long_path);
+		return false;
+	}
+
+	return true;
+}
+
+// 指定したプロセスの強制終了
+bool MsKillProcess(UINT id)
+{
+	HANDLE h;
+	// 引数チェック
+	if (id == 0)
+	{
+		return false;
+	}
+
+	h = OpenProcess(PROCESS_TERMINATE, FALSE, id);
+	if (h == NULL)
+	{
+		return false;
+	}
+
+	if (TerminateProcess(h, 0) == FALSE)
+	{
+		CloseHandle(h);
+		return false;
+	}
+
+	CloseHandle(h);
+
+	return true;
+}
+
+// 現在の EXE ファイル名を取得
+void MsGetCurrentProcessExeName(char *name, UINT size)
+{
+	UINT id;
+	LIST *o;
+	MS_PROCESS *p;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	id = MsGetCurrentProcessId();
+	o = MsGetProcessList();
+	p = MsSearchProcessById(o, id);
+	if (p != NULL)
+	{
+		p = MsSearchProcessById(o, id);
+		StrCpy(name, size, p->ExeFilename);
+	}
+	else
+	{
+		StrCpy(name, size, MsGetExeFileName());
+	}
+	MsFreeProcessList(o);
+}
+void MsGetCurrentProcessExeNameW(wchar_t *name, UINT size)
+{
+	UINT id;
+	LIST *o;
+	MS_PROCESS *p;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	id = MsGetCurrentProcessId();
+	o = MsGetProcessList();
+	p = MsSearchProcessById(o, id);
+	if (p != NULL)
+	{
+		p = MsSearchProcessById(o, id);
+		UniStrCpy(name, size, p->ExeFilenameW);
+	}
+	else
+	{
+		UniStrCpy(name, size, MsGetExeFileNameW());
+	}
+	MsFreeProcessList(o);
+}
+
+// プロセスをプロセス ID から検索する
+MS_PROCESS *MsSearchProcessById(LIST *o, UINT id)
+{
+	MS_PROCESS *p, t;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	t.ProcessId = id;
+
+	p = Search(o, &t);
+
+	return p;
+}
+
+// プロセスリスト比較
+int MsCompareProcessList(void *p1, void *p2)
+{
+	MS_PROCESS *e1, *e2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	e1 = *(MS_PROCESS **)p1;
+	e2 = *(MS_PROCESS **)p2;
+	if (e1 == NULL || e2 == NULL)
+	{
+		return 0;
+	}
+
+	if (e1->ProcessId > e2->ProcessId)
+	{
+		return 1;
+	}
+	else if (e1->ProcessId < e2->ProcessId)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// プロセスリストの表示
+void MsPrintProcessList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		MS_PROCESS *p = LIST_DATA(o, i);
+		UniPrint(L"%-4u: %s\n", p->ProcessId, p->ExeFilenameW);
+	}
+}
+
+// プロセスリストの解放
+void MsFreeProcessList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		MS_PROCESS *p = LIST_DATA(o, i);
+		Free(p);
+	}
+
+	ReleaseList(o);
+}
+
+// プロセスリストの取得 (WinNT 用)
+LIST *MsGetProcessListNt()
+{
+	LIST *o;
+	UINT max = 16384;
+	DWORD *processes;
+	UINT needed, num;
+	UINT i;
+
+	o = NewListFast(MsCompareProcessList);
+
+	if (ms->nt->EnumProcesses == NULL)
+	{
+		return o;
+	}
+
+	processes = ZeroMalloc(sizeof(DWORD) * max);
+
+	if (ms->nt->EnumProcesses(processes, sizeof(DWORD) * max, &needed) == FALSE)
+	{
+		Free(processes);
+		return NULL;
+	}
+
+	num = needed / sizeof(DWORD);
+
+	for (i = 0;i < num;i++)
+	{
+		UINT id = processes[i];
+		HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+			false, id);
+
+		if (h != NULL)
+		{
+			HINSTANCE hInst = NULL;
+			DWORD needed;
+			if (ms->nt->EnumProcessModules(h, &hInst, sizeof(hInst), &needed))
+			{
+				MS_PROCESS *p = ZeroMalloc(sizeof(MS_PROCESS));
+				ms->nt->GetModuleFileNameExA(h, hInst, p->ExeFilename, sizeof(p->ExeFilename) - 1);
+				ms->nt->GetModuleFileNameExW(h, hInst, p->ExeFilenameW, sizeof(p->ExeFilenameW) / sizeof(wchar_t) - 1);
+				p->ProcessId = id;
+				Add(o, p);
+			}
+			CloseHandle(h);
+		}
+	}
+
+	Sort(o);
+
+	Free(processes);
+
+	return o;
+}
+
+// プロセスリストの取得 (Win9x 用)
+LIST *MsGetProcessList9x()
+{
+	HANDLE h;
+	LIST *o;
+	HANDLE (WINAPI *CreateToolhelp32Snapshot)(DWORD, DWORD);
+	BOOL (WINAPI *Process32First)(HANDLE, LPPROCESSENTRY32);
+	BOOL (WINAPI *Process32Next)(HANDLE, LPPROCESSENTRY32);
+
+	CreateToolhelp32Snapshot =
+		(HANDLE (__stdcall *)(DWORD,DWORD))
+		GetProcAddress(ms->hKernel32, "CreateToolhelp32Snapshot");
+	Process32First =
+		(BOOL (__stdcall *)(HANDLE,LPPROCESSENTRY32))
+		GetProcAddress(ms->hKernel32, "Process32First");
+	Process32Next =
+		(BOOL (__stdcall *)(HANDLE,LPPROCESSENTRY32))
+		GetProcAddress(ms->hKernel32, "Process32Next");
+
+	o = NewListFast(MsCompareProcessList);
+
+	if (CreateToolhelp32Snapshot != NULL && Process32First != NULL && Process32Next != NULL)
+	{
+		h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+		if (h != INVALID_HANDLE_VALUE)
+		{
+			PROCESSENTRY32 e;
+			Zero(&e, sizeof(e));
+			e.dwSize = sizeof(e);
+
+			if (Process32First(h, &e))
+			{
+				while (true)
+				{
+					MS_PROCESS *p = ZeroMalloc(sizeof(MS_PROCESS));
+					StrCpy(p->ExeFilename, sizeof(p->ExeFilename), e.szExeFile);
+					StrToUni(p->ExeFilenameW, sizeof(p->ExeFilenameW), p->ExeFilename);
+					p->ProcessId = e.th32ProcessID;
+					Add(o, p);
+					if (Process32Next(h, &e) == false)
+					{
+						break;
+					}
+				}
+			}
+			CloseHandle(h);
+		}
+	}
+
+	Sort(o);
+
+	return o;
+}
+
+// プロセスリストの取得
+LIST *MsGetProcessList()
+{
+	if (MsIsNt() == false)
+	{
+		// Windows 9x
+		return MsGetProcessList9x();
+	}
+	else
+	{
+		// Windows NT, 2000, XP
+		return MsGetProcessListNt();
+	}
+}
+
+// 現在のスレッドを 1 つの CPU で動作するように強制する
+void MsSetThreadSingleCpu()
+{
+	SetThreadAffinityMask(GetCurrentThread(), 1);
+}
+
+// サウンドの再生
+void MsPlaySound(char *name)
+{
+	char tmp[MAX_SIZE];
+	char wav[MAX_SIZE];
+	char *temp;
+	BUF *b;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	Format(tmp, sizeof(tmp), "|%s", name);
+
+	b = ReadDump(tmp);
+	if (b == NULL)
+	{
+		return;
+	}
+
+	temp = MsGetMyTempDir();
+	Format(wav, sizeof(tmp), "%s\\%s", temp, name);
+	DumpBuf(b, wav);
+
+	PlaySound(wav, NULL, SND_ASYNC | SND_FILENAME | SND_NODEFAULT);
+
+	FreeBuf(b);
+}
+
+// タスクトレイにアイコンを表示する
+void MsShowIconOnTray(HWND hWnd, HICON icon, wchar_t *tooltip, UINT msg)
+{
+	// 引数チェック
+	if (hWnd == NULL || icon == NULL)
+	{
+		return;
+	}
+
+	if (MsIsNt() == false)
+	{
+		Zero(&nid, sizeof(nid));
+		nid.cbSize = sizeof(nid);
+		nid.hWnd = hWnd;
+		nid.uID = 1;
+		nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO;
+		nid.uCallbackMessage = msg;
+		nid.hIcon = icon;
+		UniToStr(nid.szTip, sizeof(nid.szTip), tooltip);
+		Shell_NotifyIcon(NIM_ADD, &nid);
+	}
+	else
+	{
+		Zero(&nid_nt, sizeof(nid_nt));
+		nid_nt.cbSize = sizeof(nid_nt);
+		nid_nt.hWnd = hWnd;
+		nid_nt.uID = 1;
+		nid_nt.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO;
+		nid_nt.uCallbackMessage = msg;
+		nid_nt.hIcon = icon;
+		UniStrCpy(nid_nt.szTip, sizeof(nid_nt.szTip), tooltip);
+		Shell_NotifyIconW(NIM_ADD, &nid_nt);
+	}
+
+	tray_inited = true;
+}
+
+// タスクトレイが初期化されているかどうか確認する
+bool MsIsTrayInited()
+{
+	return tray_inited;
+}
+
+// タスクトレイのアイコンを復元する
+void MsRestoreIconOnTray()
+{
+	if (tray_inited == false)
+	{
+		return;
+	}
+
+	if (MsIsNt() == false)
+	{
+		Shell_NotifyIcon(NIM_ADD, &nid);
+	}
+	else
+	{
+		Shell_NotifyIconW(NIM_ADD, &nid_nt);
+	}
+}
+
+// タスクトレイのアイコンを変更する (いけー)
+void MsChangeIconOnTrayEx2(void *icon, wchar_t *tooltip, wchar_t *info_title, wchar_t *info, UINT info_flags)
+{
+	MsChangeIconOnTrayEx((HICON)icon, tooltip, info_title, info, info_flags);
+}
+
+// タスクトレイのアイコンを変更する
+void MsChangeIconOnTray(HICON icon, wchar_t *tooltip)
+{
+	MsChangeIconOnTrayEx(icon, tooltip, NULL, NULL, NIIF_NONE);
+}
+void MsChangeIconOnTrayEx(HICON icon, wchar_t *tooltip, wchar_t *info_title, wchar_t *info, UINT info_flags)
+{
+	bool changed = false;
+
+	if (tray_inited == false)
+	{
+		return;
+	}
+
+	if (icon != NULL)
+	{
+		if (MsIsNt() == false)
+		{
+			if (nid.hIcon != icon)
+			{
+				changed = true;
+				nid.hIcon = icon;
+			}
+		}
+		else
+		{
+			if (nid_nt.hIcon != icon)
+			{
+				changed = true;
+				nid_nt.hIcon = icon;
+			}
+		}
+	}
+
+	if (tooltip != NULL)
+	{
+		if (MsIsNt() == false)
+		{
+			char tmp[MAX_SIZE];
+
+			UniToStr(tmp, sizeof(tmp), tooltip);
+
+			if (StrCmp(nid.szTip, tmp) != 0)
+			{
+				StrCpy(nid.szTip, sizeof(nid.szTip), tmp);
+				changed = true;
+			}
+		}
+		else
+		{
+			wchar_t tmp[MAX_SIZE];
+
+			UniStrCpy(tmp, sizeof(tmp), tooltip);
+
+			if (UniStrCmp(nid_nt.szTip, tmp) != 0)
+			{
+				UniStrCpy(nid_nt.szTip, sizeof(nid_nt.szTip), tmp);
+				changed = true;
+			}
+		}
+	}
+
+	if (info_title != NULL && info != NULL)
+	{
+		if (MsIsNt() == false)
+		{
+			char tmp1[MAX_SIZE];
+			char tmp2[MAX_PATH];
+
+			UniToStr(tmp1, sizeof(tmp1), info_title);
+			UniToStr(tmp2, sizeof(tmp2), info);
+
+			if (StrCmp(nid.szInfo, tmp1) != 0 ||
+				StrCmp(nid.szInfoTitle, tmp2) != 0)
+			{
+				StrCpy(nid.szInfo, sizeof(nid.szInfo), tmp1);
+				StrCpy(nid.szInfoTitle, sizeof(nid.szInfoTitle), tmp2);
+				nid.dwInfoFlags = info_flags;
+
+				changed = true;
+			}
+		}
+		else
+		{
+			wchar_t tmp1[MAX_SIZE];
+			wchar_t tmp2[MAX_PATH];
+
+			UniStrCpy(tmp1, sizeof(tmp1), info_title);
+			UniStrCpy(tmp2, sizeof(tmp2), info);
+
+			if (UniStrCmp(nid_nt.szInfo, tmp1) != 0 ||
+				UniStrCmp(nid_nt.szInfoTitle, tmp2) != 0)
+			{
+				UniStrCpy(nid_nt.szInfo, sizeof(nid_nt.szInfo), tmp1);
+				UniStrCpy(nid_nt.szInfoTitle, sizeof(nid_nt.szInfoTitle), tmp2);
+				nid_nt.dwInfoFlags = info_flags;
+
+				changed = true;
+			}
+		}
+	}
+
+	if (changed)
+	{
+		if (MsIsNt() == false)
+		{
+			Shell_NotifyIcon(NIM_MODIFY, &nid);
+		}
+		else
+		{
+			Shell_NotifyIconW(NIM_MODIFY, &nid_nt);
+		}
+	}
+}
+
+// タスクトレイのアイコンを削除する
+void MsHideIconOnTray()
+{
+	if (MsIsNt() == false)
+	{
+		Shell_NotifyIcon(NIM_DELETE, &nid);
+	}
+	else
+	{
+		Shell_NotifyIconW(NIM_DELETE, &nid_nt);
+	}
+
+	tray_inited = false;
+}
+
+// メニュー項目の挿入
+bool MsInsertMenu(HMENU hMenu, UINT pos, UINT flags, UINT_PTR id_new_item, wchar_t *lp_new_item)
+{
+	bool ret;
+
+	if (MsIsNt())
+	{
+		ret = InsertMenuW(hMenu, pos, flags, id_new_item, lp_new_item);
+	}
+	else
+	{
+		char *s = CopyUniToStr(lp_new_item);
+		ret = InsertMenuA(hMenu, pos, flags, id_new_item, s);
+		Free(s);
+	}
+
+	return ret;
+}
+
+// メニュー項目の追加
+bool MsAppendMenu(HMENU hMenu, UINT flags, UINT_PTR id, wchar_t *str)
+{
+	bool ret;
+
+	if (MsIsNt())
+	{
+		ret = AppendMenuW(hMenu, flags, id, str);
+	}
+	else
+	{
+		char *s = CopyUniToStr(str);
+		ret = AppendMenuA(hMenu, flags, id, s);
+		Free(s);
+	}
+
+	return ret;
+}
+
+// メニュー表示
+void MsUserModeTrayMenu(HWND hWnd)
+{
+	HMENU h;
+	POINT p;
+	wchar_t tmp[MAX_SIZE];
+	wchar_t caption[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	// メニューを作成する
+	h = CreatePopupMenu();
+	MsAppendMenu(h, MF_ENABLED | MF_STRING, 10001, _UU("SVC_USERMODE_MENU_1"));
+	MsAppendMenu(h, MF_SEPARATOR, 10002, NULL);
+
+	if (MsIsNt())
+	{
+		GetWindowTextW(hWnd, caption, sizeof(caption));
+	}
+	else
+	{
+		char tmp[MAX_SIZE];
+		GetWindowTextA(hWnd, tmp, sizeof(tmp));
+		StrToUni(caption, sizeof(caption), tmp);
+	}
+
+	UniFormat(tmp, sizeof(tmp), _UU("SVC_USERMODE_MENU_2"), caption);
+	MsAppendMenu(h, MF_ENABLED | MF_STRING, 10003, tmp);
+
+	// メニューを表示する
+	GetCursorPos(&p);
+
+	SetForegroundWindow(hWnd);
+	TrackPopupMenu(h, TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
+	PostMessage(hWnd, WM_NULL, 0, 0);
+
+	DestroyMenu(h);
+}
+
+// ユーザーモード用ウインドウプロシージャ
+LRESULT CALLBACK MsUserModeWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+	wchar_t tmp[MAX_SIZE];
+	char title[MAX_SIZE];
+	wchar_t title_w[MAX_SIZE];
+	char value_name[MAX_SIZE];
+	static UINT taskbar_msg = 0;
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return 0;
+	}
+
+	if (msg == taskbar_msg && taskbar_msg != 0)
+	{
+		// タスクバーが再生成された
+		if (MsRegReadInt(REG_CURRENT_USER, SVC_USERMODE_SETTING_KEY, value_name) == 0 &&
+			service_for_9x_mode == false)
+		{
+			MsRestoreIconOnTray();
+		}
+	}
+
+	switch (msg)
+	{
+	case WM_ENDSESSION:
+		// 再開
+		if (wParam == false)
+		{
+			break;
+		}
+	case WM_CREATE:
+		// 開始
+		exiting = false;
+		g_start();
+		GetWindowText(hWnd, title, sizeof(title));
+		StrToUni(title_w, sizeof(title_w), title);
+		UniFormat(tmp, sizeof(tmp), _UU("SVC_TRAY_TOOLTIP"), title);
+
+		if (taskbar_msg == 0)
+		{
+			taskbar_msg = RegisterWindowMessage("TaskbarCreated");
+		}
+
+		Format(value_name, sizeof(value_name), SVC_HIDETRAY_REG_VALUE, title_w);
+		if (MsRegReadInt(REG_CURRENT_USER, SVC_USERMODE_SETTING_KEY, value_name) == 0 &&
+			service_for_9x_mode == false)
+		{
+			MsShowIconOnTray(hWnd, tray_icon, tmp, WM_APP + 33);
+		}
+
+		break;
+	case WM_APP + 33:
+		if (wParam == 1)
+		{
+			// タスクトレイのアイコンに対する操作
+			switch (lParam)
+			{
+			case WM_RBUTTONDOWN:
+				// 右クリック
+				MsUserModeTrayMenu(hWnd);
+				break;
+			case WM_LBUTTONDBLCLK:
+				// 左ダブルクリック
+				break;
+			}
+		}
+		break;
+	case WM_LBUTTONDOWN:
+		MsUserModeTrayMenu(hWnd);
+		break;
+	case WM_QUERYENDSESSION:
+		if (exiting == false)
+		{
+			exiting = true;
+			MsHideIconOnTray();
+			g_stop();
+			DestroyWindow(hWnd);
+		}
+		return TRUE;
+	case WM_CLOSE:
+		// 停止
+		if (exiting == false)
+		{
+			exiting = true;
+			g_stop();
+			MsHideIconOnTray();
+			DestroyWindow(hWnd);
+		}
+		break;
+	case WM_DESTROY:
+		wnd_end = true;
+		break;
+	case WM_COMMAND:
+		switch (wParam)
+		{
+		case 10001:
+			GetWindowText(hWnd, title, sizeof(title));
+			StrToUni(title_w, sizeof(title_w), title);
+			// 確認メッセージの表示
+			if (MsgBoxEx(hWnd, MB_ICONINFORMATION | MB_OKCANCEL | MB_DEFBUTTON2 |
+				MB_SYSTEMMODAL, _UU("SVC_HIDE_TRAY_MSG"), title, title) == IDOK)
+			{
+				char tmp[MAX_SIZE];
+				Format(tmp, sizeof(tmp), SVC_HIDETRAY_REG_VALUE, title_w);
+				// レジストリに書き込む
+				MsRegWriteInt(REG_CURRENT_USER, SVC_USERMODE_SETTING_KEY, tmp, 1);
+				// アイコンを消す
+				MsHideIconOnTray();
+			}
+			break;
+		case 10003:
+			SendMessage(hWnd, WM_CLOSE, 0, 0);
+			break;
+		}
+		break;
+	}
+	return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+// PenCore.dll の名前の取得
+char *MsGetPenCoreDllFileName()
+{
+	return PENCORE_DLL_NAME;
+}
+
+// これがユーザーモードかどうか取得
+bool MsIsUserMode()
+{
+	return is_usermode;
+}
+
+// サービス側からユーザーモードの終了を指示
+void MsStopUserModeFromService()
+{
+	if (hWndUsermode != NULL)
+	{
+		PostMessage(hWndUsermode, WM_CLOSE, 0, 0);
+	}
+}
+
+// テストのみ実行 (デバッグ用)
+void MsTestOnly()
+{
+	g_start();
+	GetLine(NULL, 0);
+	g_stop();
+
+	_exit(0);
+}
+
+// ユーザーモードとして起動
+void MsUserMode(char *title, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop, UINT icon)
+{
+	wchar_t *title_w = CopyStrToUni(title);
+
+	MsUserModeW(title_w, start, stop, icon);
+
+	Free(title_w);
+}
+void MsUserModeW(wchar_t *title, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop, UINT icon)
+{
+	WNDCLASS wc;
+	HINSTANCE hDll;
+	HWND hWnd;
+	MSG msg;
+	INSTANCE *inst;
+	char title_a[MAX_PATH];
+	// 引数チェック
+	if (title == NULL || start == NULL || stop == NULL)
+	{
+		return;
+	}
+
+	UniToStr(title_a, sizeof(title_a), title);
+
+	is_usermode = true;
+	g_start = start;
+	g_stop = stop;
+
+	inst = NewSingleInstance(NULL);
+	if (inst == NULL)
+	{
+		if (service_for_9x_mode == false)
+		{
+			// Win9x サービスモードの場合はエラーを表示しない
+			MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVC_USERMODE_MUTEX"), ms->ExeFileNameW);
+		}
+		return;
+	}
+
+	if (Is64())
+	{
+		hDll = MsLoadLibraryAsDataFile(MsGetPenCoreDllFileName());
+	}
+	else
+	{
+		hDll = MsLoadLibrary(MsGetPenCoreDllFileName());
+	}
+
+	// アイコン読み込み
+	tray_icon = LoadImage(hDll, MAKEINTRESOURCE(icon), IMAGE_ICON, 16, 16,
+		(MsIsNt() ? LR_SHARED : 0) | LR_VGACOLOR);
+
+	// メインウインドウの作成
+	Zero(&wc, sizeof(wc));
+	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+	wc.hCursor = LoadCursor(NULL,IDC_ARROW);
+	wc.hIcon = LoadIcon(hDll, MAKEINTRESOURCE(icon));
+	wc.hInstance = ms->hInst;
+	wc.lpfnWndProc = MsUserModeWindowProc;
+	wc.lpszClassName = title_a;
+	if (RegisterClass(&wc) == 0)
+	{
+		return;
+	}
+
+	hWnd = CreateWindow(title_a, title_a, WS_OVERLAPPEDWINDOW,
+		CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
+		NULL, NULL, ms->hInst, NULL);
+
+	if (hWnd == NULL)
+	{
+		return;
+	}
+
+	hWndUsermode = hWnd;
+
+	wnd_end = false;
+	// ウインドウループ
+	while (wnd_end == false)
+	{
+		GetMessage(&msg, NULL, 0, 0);
+		TranslateMessage(&msg);
+		DispatchMessage(&msg);
+	}
+
+	FreeSingleInstance(inst);
+
+	hWndUsermode = NULL;
+
+	// 強制終了して良い
+	_exit(0);
+}
+
+// サービス停止処理メインスレッド
+void MsServiceStoperMainThread(THREAD *t, void *p)
+{
+	// 停止処理
+	g_stop();
+}
+
+// サービス停止処理用スレッド
+void MsServiceStoperThread(THREAD *t, void *p)
+{
+	THREAD *thread;
+	UINT64 selfkill_timeout = Tick64() + SVC_SELFKILL_TIMEOUT;
+
+	thread = NewThread(MsServiceStoperMainThread, NULL);
+
+	// まだ開始中の場合は開始スレッドの終了を待つ
+	while (WaitThread(starter_thread, 250) == false)
+	{
+		if (Tick64() >= selfkill_timeout)
+		{
+			// フリーズ時用の自殺
+			_exit(0);
+		}
+		// 開始処理が完了するまでの間、一定時間ごとに SetServiceStatus を呼び出す
+		status.dwWin32ExitCode = 0;
+		status.dwWaitHint = 100000;
+		status.dwCheckPoint++;
+		status.dwCurrentState = SERVICE_STOP_PENDING;
+		ms->nt->SetServiceStatus(ssh, &status);
+	}
+
+	ReleaseThread(starter_thread);
+	starter_thread = NULL;
+
+	while (WaitThread(thread, 250) == false)
+	{
+		if (Tick64() >= selfkill_timeout)
+		{
+			// フリーズ時用の自殺
+			_exit(0);
+		}
+		// 停止処理が完了するまでの間、一定時間ごとに SetServiceStatus を呼び出す
+		status.dwWin32ExitCode = 0;
+		status.dwWaitHint = 100000;
+		status.dwCheckPoint++;
+		status.dwCurrentState = SERVICE_STOP_PENDING;
+		ms->nt->SetServiceStatus(ssh, &status);
+	}
+
+	ReleaseThread(thread);
+
+	// 停止が完了したことを報告する
+	status.dwWin32ExitCode = 0;
+	status.dwWaitHint = 0;
+	status.dwCheckPoint = 0;
+	status.dwCurrentState = SERVICE_STOPPED;
+	ms->nt->SetServiceStatus(ssh, &status);
+
+	Set(server_stopped_event);
+}
+
+// サービスハンドラ
+void CALLBACK MsServiceHandler(DWORD opcode)
+{
+	switch (opcode)
+	{
+	case SERVICE_CONTROL_SHUTDOWN:
+	case SERVICE_CONTROL_STOP:
+		// 停止要求
+		status.dwWin32ExitCode = 0;
+		status.dwWaitHint = 100000;
+		status.dwCheckPoint = 0;
+		status.dwCurrentState = SERVICE_STOP_PENDING;
+
+		// 停止用スレッドを立てる
+		service_stopper_thread = NewThread(MsServiceStoperThread, NULL);
+		break;
+	}
+
+	ms->nt->SetServiceStatus(ssh, &status);
+}
+
+// サービス開始用スレッド
+void MsServiceStarterMainThread(THREAD *t, void *p)
+{
+	// 開始
+	g_start();
+}
+
+// サービスのディスパッチ関数
+void CALLBACK MsServiceDispatcher(DWORD argc, LPTSTR *argv)
+{
+	// サービスの準備
+	Zero(&status, sizeof(status));
+	status.dwServiceType = SERVICE_WIN32;
+	status.dwCurrentState = SERVICE_START_PENDING;
+	status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
+
+	ssh = ms->nt->RegisterServiceCtrlHandler(g_service_name, MsServiceHandler);
+
+	if (ssh == NULL)
+	{
+		Alert("RegisterServiceCtrlHandler() Failed.", "MsServiceDispatcher()");
+		return;
+	}
+
+	status.dwWaitHint = 10000;
+	status.dwCheckPoint = 0;
+	status.dwCurrentState = SERVICE_START_PENDING;
+	ms->nt->SetServiceStatus(ssh, &status);
+
+	// サービス開始用スレッドを作成する
+	starter_thread = NewThread(MsServiceStarterMainThread, NULL);
+
+	// 開始完了を報告する
+	status.dwWaitHint = 0;
+	status.dwCheckPoint = 0;
+	status.dwCurrentState = SERVICE_RUNNING;
+	ms->nt->SetServiceStatus(ssh, &status);
+}
+
+// サービスとして動作
+void MsServiceMode(SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
+{
+	SERVICE_TABLE_ENTRY dispatch_table[] =
+	{
+		{"", MsServiceDispatcher},
+		{NULL, NULL},
+	};
+	INSTANCE *inst;
+	// 引数チェック
+	if (start == NULL || stop == NULL)
+	{
+		return;
+	}
+
+	MsSetErrorModeToSilent();
+
+	g_start = start;
+	g_stop = stop;
+
+	server_stopped_event = NewEvent();
+
+	inst = NewSingleInstance(NULL);
+	if (inst == NULL)
+	{
+		MsgBoxEx(NULL, MB_SETFOREGROUND | MB_TOPMOST | MB_SERVICE_NOTIFICATION | MB_OK | MB_ICONEXCLAMATION,
+			_UU("SVC_SERVICE_MUTEX"), g_service_name, ms->ExeFileNameW);
+		return;
+	}
+
+	// サービス設定を更新する
+	MsUpdateServiceConfig(g_service_name);
+
+	if (ms->nt->StartServiceCtrlDispatcher(dispatch_table) == false)
+	{
+		Alert("StartServiceCtrlDispatcher() Failed.", "MsServiceMode()");
+		return;
+	}
+
+	MsUpdateServiceConfig(g_service_name);
+
+	FreeSingleInstance(inst);
+
+	// サービス終了後は直ちにプロセスを終了する
+	Wait(server_stopped_event, INFINITE);
+	ReleaseEvent(server_stopped_event);
+	WaitThread(service_stopper_thread, INFINITE);
+	ReleaseThread(service_stopper_thread);
+	server_stopped_event = NULL;
+
+	_exit(0);
+}
+
+// テストモードとして起動
+void MsTestMode(char *title, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
+{
+	wchar_t *title_w = CopyStrToUni(title);
+
+	MsTestModeW(title_w, start, stop);
+	Free(title_w);
+}
+void MsTestModeW(wchar_t *title, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
+{
+	INSTANCE *inst;
+	// 引数チェック
+	if (title == NULL || start == NULL || stop == NULL)
+	{
+		return;
+	}
+
+	is_usermode = true;
+
+	inst = NewSingleInstance(NULL);
+	if (inst == NULL)
+	{
+		// すでに起動している
+		MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVC_TEST_MUTEX"), ms->ExeFileNameW);
+		return;
+	}
+
+	// 起動
+	start();
+
+	// メッセージ表示
+	MsgBoxEx(NULL, MB_ICONINFORMATION | MB_SYSTEMMODAL, _UU("SVC_TEST_MSG"), title);
+
+	// 停止
+	stop();
+
+	FreeSingleInstance(inst);
+}
+
+// サービスマネージャを呼び出し中のプロセスのプロセス ID を書き込む
+void MsWriteCallingServiceManagerProcessId(char *svcname, UINT pid)
+{
+	char tmp[MAX_PATH];
+
+	Format(tmp, sizeof(tmp), SVC_CALLING_SM_PROCESS_ID_KEY, svcname);
+
+	if (pid != 0)
+	{
+		MsRegWriteInt(REG_LOCAL_MACHINE, tmp, SVC_CALLING_SM_PROCESS_ID_VALUE, pid);
+		MsRegWriteInt(REG_CURRENT_USER, tmp, SVC_CALLING_SM_PROCESS_ID_VALUE, pid);
+	}
+	else
+	{
+		MsRegDeleteValue(REG_LOCAL_MACHINE, tmp, SVC_CALLING_SM_PROCESS_ID_VALUE);
+		MsRegDeleteKey(REG_LOCAL_MACHINE, tmp);
+
+		MsRegDeleteValue(REG_CURRENT_USER, tmp, SVC_CALLING_SM_PROCESS_ID_VALUE);
+		MsRegDeleteKey(REG_CURRENT_USER, tmp);
+	}
+}
+
+// サービスマネージャを呼び出し中のプロセス ID を取得する
+UINT MsReadCallingServiceManagerProcessId(char *svcname, bool current_user)
+{
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (svcname == NULL)
+	{
+		return 0;
+	}
+
+	Format(tmp, sizeof(tmp), SVC_CALLING_SM_PROCESS_ID_KEY, svcname);
+
+	return MsRegReadInt(current_user ? REG_CURRENT_USER : REG_LOCAL_MACHINE, tmp, SVC_CALLING_SM_PROCESS_ID_VALUE);
+}
+
+// サービスメイン関数
+UINT MsService(char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop, UINT icon)
+{
+	UINT mode;
+	UINT ret = 0;
+	char *arg;
+	wchar_t *arg_w;
+	TOKEN_LIST *t = NULL;
+	UNI_TOKEN_LIST *ut = NULL;
+	char *service_name;
+	wchar_t *service_title;
+	wchar_t *service_description;
+	wchar_t *service_title_uni;
+	char tmp[MAX_SIZE];
+	bool restoreReg = false;
+	bool silent = false;
+	// 引数チェック
+	if (name == NULL || start == NULL || stop == NULL)
+	{
+		return ret;
+	}
+
+	// Mayaqua の開始
+	InitMayaqua(false, false, 0, NULL);
+
+	// MS-IME の停止
+	MsDisableIme();
+
+	// サービスに関する情報を string table から取得
+	Format(tmp, sizeof(tmp), SVC_NAME, name);
+	service_name = _SS(tmp);
+	Format(tmp, sizeof(tmp), SVC_TITLE, name);
+	service_title = _UU(tmp);
+	service_title_uni = _UU(tmp);
+	Format(tmp, sizeof(tmp), SVC_DESCRIPT, name);
+	service_description = _UU(tmp);
+
+	if (StrLen(service_name) == 0 || UniStrLen(service_title) == 0)
+	{
+		// サービス情報が見つからない
+		MsgBoxEx(NULL, MB_ICONSTOP, _UU("SVC_NOT_FOUND"), name);
+	}
+	else
+	{
+		wchar_t path[MAX_SIZE];
+		// 引数のチェック
+		mode = SVC_MODE_NONE;
+
+		t = GetCommandLineToken();
+		arg = NULL;
+
+		ut = GetCommandLineUniToken();
+		arg_w = NULL;
+
+		if (t->NumTokens >= 1)
+		{
+			arg = t->Token[0];
+		}
+		if(t->NumTokens >= 2)
+		{
+			if(StrCmpi(t->Token[1], SVC_ARG_SILENT) == 0)
+			{
+				silent = true;
+			}
+		}
+
+		if (ut->NumTokens >= 1)
+		{
+			arg_w = ut->Token[0];
+		}
+
+		if (arg != NULL)
+		{
+			if (StrCmpi(arg, SVC_ARG_INSTALL) == 0)
+			{
+				mode = SVC_MODE_INSTALL;
+			}
+			if (StrCmpi(arg, SVC_ARG_UNINSTALL) == 0)
+			{
+				mode = SVC_MODE_UNINSTALL;
+			}
+			if (StrCmpi(arg, SVC_ARG_START) == 0)
+			{
+				mode = SVC_MODE_START;
+			}
+			if (StrCmpi(arg, SVC_ARG_STOP) == 0)
+			{
+				mode = SVC_MODE_STOP;
+			}
+			if (StrCmpi(arg, SVC_ARG_TEST) == 0)
+			{
+				mode = SVC_MODE_TEST;
+			}
+			if (StrCmpi(arg, SVC_ARG_USERMODE) == 0)
+			{
+				mode = SVC_MODE_USERMODE;
+			}
+			if (StrCmpi(arg, SVC_ARG_SETUP_INSTALL) == 0)
+			{
+				mode = SVC_MODE_SETUP_INSTALL;
+			}
+			if (StrCmpi(arg, SVC_ARG_SETUP_UNINSTALL) == 0)
+			{
+				mode = SVC_MODE_SETUP_UNINSTALL;
+			}
+			if (StrCmpi(arg, SVC_ARG_WIN9X_SERVICE) == 0)
+			{
+				mode = SVC_MODE_WIN9X_SERVICE;
+			}
+			if (StrCmpi(arg, SVC_ARG_WIN9X_INSTALL) == 0)
+			{
+				mode = SVC_MODE_WIN9X_INSTALL;
+			}
+			if (StrCmpi(arg, SVC_ARG_WIN9X_UNINSTALL) == 0)
+			{
+				mode = SVC_MODE_WIN9X_UNINSTALL;
+			}
+			if (StrCmpi(arg, SVC_ARG_TCP) == 0)
+			{
+				mode = SVC_MODE_TCP;
+			}
+			if (StrCmpi(arg, SVC_ARG_TCP_SETUP) == 0)
+			{
+				mode = SVC_MODE_TCPSETUP;
+			}
+			if (StrCmpi(arg, SVC_ARG_TRAFFIC) == 0)
+			{
+				mode = SVC_MODE_TRAFFIC;
+			}
+			if (StrCmpi(arg, SVC_ARG_UIHELP) == 0)
+			{
+				mode = SVC_MODE_UIHELP;
+			}
+			if (StrCmpi(arg, SVC_ARG_USERMODE_SHOWTRAY) == 0)
+			{
+				char tmp[MAX_SIZE];
+				mode = SVC_MODE_USERMODE;
+				Format(tmp, sizeof(tmp), SVC_HIDETRAY_REG_VALUE, service_title);
+				MsRegDeleteValue(REG_CURRENT_USER, SVC_USERMODE_SETTING_KEY, tmp);
+			}
+			if (StrCmpi(arg, SVC_ARG_USERMODE_HIDETRAY) == 0)
+			{
+				char tmp[MAX_SIZE];
+				mode = SVC_MODE_USERMODE;
+				Format(tmp, sizeof(tmp), SVC_HIDETRAY_REG_VALUE, service_title);
+				MsRegWriteInt(REG_CURRENT_USER, SVC_USERMODE_SETTING_KEY, tmp, 1);
+			}
+			if (StrCmpi(arg, SVC_ARG_SERVICE) == 0)
+			{
+				mode = SVC_MODE_SERVICE;
+			}
+
+			if (mode != SVC_MODE_NONE)
+			{
+				// Network Config
+				MsInitGlobalNetworkConfig();
+			}
+		}
+
+		// サービスとして実行する際のコマンドライン名を取得する
+		UniFormat(path, sizeof(path), SVC_RUN_COMMANDLINE, ms->ExeFileNameW);
+
+		if ((mode == SVC_MODE_INSTALL || mode == SVC_MODE_UNINSTALL || mode == SVC_MODE_START ||
+			mode == SVC_MODE_STOP || mode == SVC_MODE_SERVICE) &&
+			(ms->IsNt == false))
+		{
+			// Windows NT 以外で NT 系のコマンドを使用しようとした
+			MsgBox(NULL, MB_ICONSTOP, _UU("SVC_NT_ONLY"));
+		}
+		else if ((mode == SVC_MODE_INSTALL || mode == SVC_MODE_UNINSTALL || mode == SVC_MODE_START ||
+			mode == SVC_MODE_STOP || mode == SVC_MODE_SERVICE) &&
+			(ms->IsAdmin == false))
+		{
+			// Administrators 権限が無い
+			MsgBox(NULL, MB_ICONEXCLAMATION, _UU("SVC_NOT_ADMIN"));
+		}
+		else
+		{
+			// モードごとに処理を行う
+			switch (mode)
+			{
+			case SVC_MODE_NONE:
+				// 案内メッセージを表示して終了する
+				if (arg_w != NULL && UniEndWith(arg_w, L".uvpn"))
+				{
+					if (MsgBox(NULL, MB_ICONQUESTION | MB_YESNO, _UU("CM_VPN_FILE_CLICKED")) == IDYES)
+					{
+						wchar_t vpncmgr[MAX_PATH];
+						wchar_t filename[MAX_PATH];
+
+						UniFormat(filename, sizeof(filename), L"\"%s\"", arg_w);
+
+						if (Is64() == false)
+						{
+							UniFormat(vpncmgr, sizeof(vpncmgr), L"%s\\utvpncmgr.exe", MsGetExeDirNameW());
+						}
+						else
+						{
+							UniFormat(vpncmgr, sizeof(vpncmgr), L"%s\\utvpncmgr_x64.exe", MsGetExeDirNameW());
+						}
+
+						RunW(vpncmgr, filename, false, false);
+					}
+				}
+				else
+				{
+					MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVC_HELP"),
+						service_title, service_name, service_title, service_title, service_name, service_title, service_name, service_title, service_name, service_title, service_name, service_title, service_title);
+				}
+				break;
+
+			case SVC_MODE_SETUP_INSTALL:
+				// setup.exe インストール モード
+				// 古いものをアンインストールする
+				MsWriteCallingServiceManagerProcessId(service_name, MsGetCurrentProcessId());
+				restoreReg = true;
+
+				if (MsIsServiceInstalled(service_name))
+				{
+					if (MsIsServiceRunning(service_name))
+					{
+						MsStopService(service_name);
+					}
+					MsUninstallService(service_name);
+				}
+				if (MsInstallServiceW(service_name, service_title, service_description, path) == false)
+				{
+					ret = 1;
+				}
+				MsStartService(service_name);
+				MsWriteCallingServiceManagerProcessId(service_name, 0);
+				break;
+
+			case SVC_MODE_SETUP_UNINSTALL:
+				// setup.exe アンインストール モード
+				MsWriteCallingServiceManagerProcessId(service_name, MsGetCurrentProcessId());
+				restoreReg = true;
+
+				if (MsIsServiceInstalled(service_name))
+				{
+					if (MsIsServiceRunning(service_name))
+					{
+						MsStopService(service_name);
+					}
+					if (MsUninstallService(service_name) == false)
+					{
+						ret = 1;
+					}
+				}
+				break;
+
+			case SVC_MODE_INSTALL:
+				// サービスのインストール
+				// すでにインストールされているかどうか確認する
+				MsWriteCallingServiceManagerProcessId(service_name, MsGetCurrentProcessId());
+				restoreReg = true;
+
+				if (MsIsServiceInstalled(service_name))
+				{
+					// すでにインストールされている
+					// アンインストールするかどうか確認のメッセージを表示する
+					if (silent == false)
+					{
+						if (MsgBoxEx(NULL, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SVC_ALREADY_INSTALLED"),
+							service_title, service_name) == IDNO)
+						{
+							// 処理をキャンセルする
+							break;
+						}
+					}
+					// 既存のサービスが動作しているか?
+					if (MsIsServiceRunning(service_name))
+					{
+						// 停止を試みる
+						if (MsStopService(service_name) == false)
+						{
+							// 停止に失敗した
+							MsgBoxEx(NULL, MB_ICONSTOP, _UU("SVC_STOP_FAILED"),
+								service_title, service_name);
+							break;
+						}
+					}
+					// アンインストールする
+					if (MsUninstallService(service_name) == false)
+					{
+						// アンインストールに失敗した
+						MsgBoxEx(NULL, MB_ICONSTOP, _UU("SVC_UNINSTALL_FAILED"),
+							service_title, service_name);
+						break;
+					}
+				}
+
+				// インストールを行う
+				if (MsInstallServiceW(service_name, service_title, service_description, path) == false)
+				{
+					// インストールに失敗した
+					MsgBoxEx(NULL, MB_ICONSTOP, _UU("SVC_INSTALL_FAILED"),
+						service_title, service_name);
+					break;
+				}
+
+				// サービスを開始する
+				if (MsStartService(service_name) == false)
+				{
+					// 開始に失敗した
+					MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("SVC_INSTALL_FAILED_2"),
+						service_title, service_name, path);
+					break;
+				}
+
+				// すべて成功した
+				if(silent == false)
+				{
+					MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVC_INSTALL_OK"),
+						service_title, service_name, path);
+				}
+				break;
+
+			case SVC_MODE_UNINSTALL:
+				// サービスのアンインストール
+				// すでにインストールされているかどうか確認する
+				MsWriteCallingServiceManagerProcessId(service_name, MsGetCurrentProcessId());
+				restoreReg = true;
+
+				if (MsIsServiceInstalled(service_name) == false)
+				{
+					if(silent == false)
+					{
+						MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("SVC_NOT_INSTALLED"),
+							service_title, service_name, path);
+					}
+					break;
+				}
+
+				// サービスが起動中の場合は停止する
+				if (MsIsServiceRunning(service_name))
+				{
+					// サービスを停止する
+					if (MsStopService(service_name) == false)
+					{
+						// 停止に失敗した
+						MsgBoxEx(NULL, MB_ICONSTOP, _UU("SVC_STOP_FAILED"),
+							service_title, service_name);
+						break;
+					}
+				}
+
+				// サービスをアンインストールする
+				if (MsUninstallService(service_name) == false)
+				{
+					MsgBoxEx(NULL, MB_ICONSTOP, _UU("SVC_UNINSTALL_FAILED"),
+						service_title, service_name);
+					break;
+				}
+
+				// すべて成功した
+				if(silent == false)
+				{
+					MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVC_UNINSTALL_OK"),
+						service_title, service_name);
+				}
+				break;
+
+			case SVC_MODE_START:
+				// サービスの開始
+				MsWriteCallingServiceManagerProcessId(service_name, MsGetCurrentProcessId());
+				restoreReg = true;
+
+				if (MsIsServiceInstalled(service_name) == false)
+				{
+					// サービスはインストールされていない
+					MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("SVC_NOT_INSTALLED"),
+						service_title, service_name);
+					break;
+				}
+
+				// サービスが起動中かどうか確認する
+				if (MsIsServiceRunning(service_name))
+				{
+					// サービスが起動中
+					if(silent == false)
+					{
+						MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVR_ALREADY_START"),
+							service_title, service_name);
+					}
+					break;
+				}
+
+				// サービスを起動する
+				if (MsStartService(service_name) == false)
+				{
+					// 開始に失敗した
+					MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("SVC_START_FAILED"),
+						service_title, service_name);
+					break;
+				}
+
+				// すべて成功した
+				if(silent == false)
+				{
+					MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVC_START_OK"),
+						service_title, service_name);
+				}
+				break;
+
+			case SVC_MODE_STOP:
+				// サービスの停止
+				MsWriteCallingServiceManagerProcessId(service_name, MsGetCurrentProcessId());
+				restoreReg = true;
+
+				if (MsIsServiceInstalled(service_name) == false)
+				{
+					// サービスはインストールされていない
+					if(silent == false)
+					{
+						MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("SVC_NOT_INSTALLED"),
+							service_title, service_name);
+					}
+					break;
+				}
+
+				// サービスが起動中かどうか確認する
+				if (MsIsServiceRunning(service_name) == false)
+				{
+					// サービスが停止中
+					if(silent == false)
+					{
+						MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVC_ALREADY_STOP"),
+							service_title, service_name);
+					}
+					break;
+				}
+				// サービスを停止する
+				if (MsStopService(service_name) == false)
+				{
+					// 停止に失敗した
+					MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("SVC_STOP_FAILED"),
+						service_title, service_name);
+					break;
+				}
+
+				// すべて成功した
+				if(silent == false)
+				{
+					MsgBoxEx(NULL, MB_ICONINFORMATION, _UU("SVC_STOP_OK"),
+						service_title, service_name);
+				}
+				break;
+
+			case SVC_MODE_TEST:
+				// テストモード
+				MsTestModeW(service_title, start, stop);
+				break;
+
+			case SVC_MODE_WIN9X_SERVICE:
+				// Win9x サービスモード
+				// (タスクトレイのアイコンを無条件で非表示にする)
+				if (MsIsNt())
+				{
+					// Windows 2000 以降では動作させない
+					break;
+				}
+				service_for_9x_mode = true;
+			case SVC_MODE_USERMODE:
+				// ユーザーモード
+				MsUserModeW(service_title, start, stop, icon);
+				break;
+
+			case SVC_MODE_WIN9X_INSTALL:
+				// Win9x インストールモード
+				MsWriteCallingServiceManagerProcessId(service_name, MsGetCurrentProcessId());
+				restoreReg = true;
+
+				if (MsIsNt() == false)
+				{
+					// レジストリキーの追加
+					char cmdline[MAX_PATH];
+					Format(cmdline, sizeof(cmdline), "\"%s\" %s",
+						MsGetExeFileName(), SVC_ARG_WIN9X_SERVICE);
+					MsRegWriteStr(REG_LOCAL_MACHINE, WIN9X_SVC_REGKEY_1,
+						name, cmdline);
+					MsRegWriteStr(REG_LOCAL_MACHINE, WIN9X_SVC_REGKEY_2,
+						name, cmdline);
+
+					// 実行
+					Run(MsGetExeFileName(), SVC_ARG_WIN9X_SERVICE, false, false);
+				}
+				break;
+
+			case SVC_MODE_WIN9X_UNINSTALL:
+				// Win9x アンインストールモード
+				MsWriteCallingServiceManagerProcessId(service_name, MsGetCurrentProcessId());
+				restoreReg = true;
+
+				if (MsIsNt() == false)
+				{
+					// レジストリキーの削除
+					MsRegDeleteValue(REG_LOCAL_MACHINE, WIN9X_SVC_REGKEY_1,
+						name);
+					MsRegDeleteValue(REG_LOCAL_MACHINE, WIN9X_SVC_REGKEY_2,
+						name);
+
+					// 自分以外のすべてのプロセスを終了
+					MsKillOtherInstance();
+				}
+				break;
+
+			case SVC_MODE_SERVICE:
+				// サービスとして動作
+				StrCpy(g_service_name, sizeof(g_service_name), service_name);
+				MsServiceMode(start, stop);
+				break;
+
+			case SVC_MODE_TCP:
+				// TCP ユーティリティ
+				InitCedar();
+				InitWinUi(service_title_uni, NULL, 0);
+				ShowTcpIpConfigUtil(NULL, true);
+				FreeWinUi();
+				FreeCedar();
+				break;
+
+			case SVC_MODE_TCPSETUP:
+				// TCP 最適化モード (インストーラから呼ばれる)
+				InitCedar();
+				InitWinUi(service_title_uni, NULL, 0);
+				ShowTcpIpConfigUtil(NULL, false);
+				FreeWinUi();
+				FreeCedar();
+				break;
+
+			case SVC_MODE_TRAFFIC:
+				// 通信スループット測定ツール
+				InitCedar();
+				InitWinUi(service_title_uni, NULL, 0);
+				CmTraffic(NULL);
+				FreeWinUi();
+				FreeCedar();
+				break;
+
+			case SVC_MODE_UIHELP:
+				// UI Helper の起動
+				CnStart();
+				break;
+			}
+
+		}
+		FreeToken(t);
+		UniFreeToken(ut);
+
+		if (restoreReg)
+		{
+			MsWriteCallingServiceManagerProcessId(service_name, 0);
+		}
+	}
+
+	FreeMayaqua();
+
+	return 0;
+}
+
+// 指定したセッションのユーザー名を取得する
+wchar_t *MsGetSessionUserName(UINT session_id)
+{
+	if (MsIsTerminalServiceInstalled() || MsIsUserSwitchingInstalled())
+	{
+		wchar_t *ret;
+		wchar_t *name;
+		UINT size = 0;
+		if (ms->nt->WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session_id,
+			WTSUserName, (wchar_t *)&name, &size) == false)
+		{
+			return NULL;
+		}
+
+		if (name == NULL || UniStrLen(name) == 0)
+		{
+			ret = NULL;
+		}
+		else
+		{
+			ret = UniCopyStr(name);
+		}
+
+		ms->nt->WTSFreeMemory(name);
+
+		return ret;
+	}
+	return NULL;
+}
+
+// 現在のデスクトップが VNC で利用可能かどうか取得する
+bool MsIsCurrentDesktopAvailableForVnc()
+{
+	if (MsIsNt() == false)
+	{
+		return true;
+	}
+
+	if (MsIsCurrentTerminalSessionActive() == false)
+	{
+		return false;
+	}
+
+	if (ms->nt->OpenDesktopA == NULL ||
+		ms->nt->CloseDesktop == NULL ||
+		ms->nt->SwitchDesktop == NULL)
+	{
+		return true;
+	}
+	else
+	{
+		HDESK hDesk = ms->nt->OpenDesktopA("default", 0, false, DESKTOP_SWITCHDESKTOP);
+		bool ret;
+
+		if (hDesk == NULL)
+		{
+			return false;
+		}
+
+		ret = ms->nt->SwitchDesktop(hDesk);
+		ms->nt->CloseDesktop(hDesk);
+
+		return ret;
+	}
+}
+
+// 現在のターミナルセッションがアクティブかどうか取得する
+bool MsIsCurrentTerminalSessionActive()
+{
+	return MsIsTerminalSessionActive(MsGetCurrentTerminalSessionId());
+}
+
+// 指定したターミナルセッションがアクティブかどうか取得する
+bool MsIsTerminalSessionActive(UINT session_id)
+{
+	if (MsIsTerminalServiceInstalled() || MsIsUserSwitchingInstalled())
+	{
+		UINT *status = NULL;
+		UINT size = sizeof(status);
+		bool active = true;
+
+		if (ms->nt->WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, session_id,
+			WTSConnectState, (wchar_t *)&status, &size) == false)
+		{
+			return true;
+		}
+
+		switch (*status)
+		{
+		case WTSDisconnected:
+		case WTSShadow:
+		case WTSIdle:
+		case WTSDown:
+		case WTSReset:
+			active = false;
+			break;
+		}
+
+		ms->nt->WTSFreeMemory(status);
+
+		return active;
+	}
+
+	return true;
+}
+
+// 現在のターミナルセッション ID を取得する
+UINT MsGetCurrentTerminalSessionId()
+{
+	if (MsIsTerminalServiceInstalled() || MsIsUserSwitchingInstalled())
+	{
+		UINT ret;
+		UINT *session_id = NULL;
+		UINT size = sizeof(session_id);
+		if (ms->nt->WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION,
+			WTSSessionId, (wchar_t *)&session_id, &size) == false)
+		{
+			return 0;
+		}
+
+		ret = *session_id;
+
+		ms->nt->WTSFreeMemory(session_id);
+
+		return ret;
+	}
+
+	return 0;
+}
+
+// ターミナルサービスがインストールされていて複数セッションがログイン可能かどうか調べる
+bool MsIsTerminalServiceMultiUserInstalled()
+{
+	OS_INFO *info = GetOsInfo();
+	OSVERSIONINFOEX i;
+	if (MsIsTerminalServiceInstalled() == false)
+	{
+		return false;
+	}
+
+	if (OS_IS_SERVER(info->OsType) == false)
+	{
+		return false;
+	}
+
+	Zero(&i, sizeof(i));
+	i.dwOSVersionInfoSize = sizeof(i);
+	if (GetVersionEx((OSVERSIONINFO *)&i) == false)
+	{
+		return false;
+	}
+
+	if (i.wSuiteMask & VER_SUITE_SINGLEUSERTS)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ユーザー切り替えがインストールされているかどうか調べる
+bool MsIsUserSwitchingInstalled()
+{
+	OS_INFO *info = GetOsInfo();
+	OSVERSIONINFOEX i;
+
+	if (OS_IS_WINDOWS_NT(info->OsType) == false)
+	{
+		return false;
+	}
+
+	if (ms->nt->WTSDisconnectSession == NULL ||
+		ms->nt->WTSFreeMemory == NULL ||
+		ms->nt->WTSQuerySessionInformation == NULL)
+	{
+		return false;
+	}
+
+	if (GET_KETA(info->OsType, 100) < 2)
+	{
+		return false;
+	}
+
+	Zero(&i, sizeof(i));
+	i.dwOSVersionInfoSize = sizeof(i);
+	if (GetVersionEx((OSVERSIONINFO *)&i) == false)
+	{
+		return false;
+	}
+
+	if (i.wSuiteMask & VER_SUITE_SINGLEUSERTS)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// リモートデスクトップを有効にする
+bool MsEnableRemoteDesktop()
+{
+	OS_INFO *info = GetOsInfo();
+
+	if (MsIsRemoteDesktopAvailable() == false)
+	{
+		return false;
+	}
+
+	if (MsIsRemoteDesktopEnabled())
+	{
+		return true;
+	}
+
+	if (GET_KETA(info->OsType, 100) == 2)
+	{
+		// Windows 2000
+		return false;
+	}
+
+	if (MsRegWriteInt(REG_LOCAL_MACHINE,
+		"SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
+		"fDenyTSConnections", 0) == false)
+	{
+		return false;
+	}
+
+	if (MsIsVista())
+	{
+		if (MsRegWriteInt(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp",
+			"UserAuthentication", 0) == false)
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// リモートデスクトップが有効かどうか調べる
+bool MsIsRemoteDesktopEnabled()
+{
+	OS_INFO *info = GetOsInfo();
+
+	if (MsIsRemoteDesktopAvailable() == false)
+	{
+		return false;
+	}
+
+	if (GET_KETA(info->OsType, 100) == 2)
+	{
+		// Windows 2000
+		return MsIsServiceRunning("TermService");
+	}
+	else
+	{
+		// Windows XP 以降
+		bool b = MsRegReadInt(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Terminal Server",
+			"fDenyTSConnections");
+
+		if (MsIsVista() == false)
+		{
+			return b ? false : true;
+		}
+		else
+		{
+			if (b)
+			{
+				return false;
+			}
+			else
+			{
+				if (MsRegReadInt(REG_LOCAL_MACHINE,
+					"SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\WinStations\\RDP-Tcp",
+					"UserAuthentication"))
+				{
+					return false;
+				}
+				else
+				{
+					return true;
+				}
+			}
+		}
+	}
+}
+
+// レジストリ操作によってリモートデスクトップが利用可能になるかどうか調べる
+bool MsIsRemoteDesktopCanEnableByRegistory()
+{
+	OS_INFO *info = GetOsInfo();
+	if (MsIsRemoteDesktopAvailable() == false)
+	{
+		return false;
+	}
+
+	if (GET_KETA(info->OsType, 100) == 2)
+	{
+		// Windows 2000
+		return false;
+	}
+	else
+	{
+		// それ以外
+		return true;
+	}
+}
+
+// Windows 2000 かどうか調べる
+bool MsIsWin2000()
+{
+	OS_INFO *info = GetOsInfo();
+
+	if (OS_IS_WINDOWS_NT(info->OsType) == false)
+	{
+		return false;
+	}
+
+	if (GET_KETA(info->OsType, 100) == 2)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// Windows 2000 以降かどうか調べる
+bool MsIsWin2000OrGreater()
+{
+	OS_INFO *info = GetOsInfo();
+
+	if (OS_IS_WINDOWS_NT(info->OsType) == false)
+	{
+		return false;
+	}
+
+	if (GET_KETA(info->OsType, 100) >= 2)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// リモートデスクトップが利用可能かどうか調べる
+bool MsIsRemoteDesktopAvailable()
+{
+	OS_INFO *info = GetOsInfo();
+	if (MsIsTerminalServiceInstalled() == false)
+	{
+		return false;
+	}
+
+	if (GET_KETA(info->OsType, 100) == 2)
+	{
+		// Windows 2000
+		if (info->OsType == 2200)
+		{
+			// Windows 2000 Professional
+			return false;
+		}
+		else
+		{
+			// Windows 2000 サーバー系
+			return true;
+		}
+	}
+	else if (GET_KETA(info->OsType, 100) == 3)
+	{
+		// Windows XP
+		if (info->OsType == OSTYPE_WINDOWS_XP_HOME)
+		{
+			// Home Edition
+			return false;
+		}
+		else
+		{
+			// Professional Edition
+			return true;
+		}
+	}
+	else if (GET_KETA(info->OsType, 100) == 4)
+	{
+		// Windows Server 2003
+		return true;
+	}
+	else if (GET_KETA(info->OsType, 100) >= 5)
+	{
+		// Windows Vista 以降
+		OSVERSIONINFOEX i;
+
+		Zero(&i, sizeof(i));
+		i.dwOSVersionInfoSize = sizeof(i);
+		if (GetVersionEx((OSVERSIONINFO *)&i) == false)
+		{
+			return false;
+		}
+
+		if (i.wSuiteMask & VER_SUITE_PERSONAL)
+		{
+			// Home 系
+			return false;
+		}
+		else
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// ターミナルサービスがインストールされているかどうか調べる
+bool MsIsTerminalServiceInstalled()
+{
+	OS_INFO *info = GetOsInfo();
+	OSVERSIONINFOEX i;
+
+	if (OS_IS_WINDOWS_NT(info->OsType) == false)
+	{
+		return false;
+	}
+
+	if (ms->nt->WTSDisconnectSession == NULL ||
+		ms->nt->WTSFreeMemory == NULL ||
+		ms->nt->WTSQuerySessionInformation == NULL)
+	{
+		return false;
+	}
+
+	if (GET_KETA(info->OsType, 100) < 2)
+	{
+		return false;
+	}
+
+	Zero(&i, sizeof(i));
+	i.dwOSVersionInfoSize = sizeof(i);
+	if (GetVersionEx((OSVERSIONINFO *)&i) == false)
+	{
+		return false;
+	}
+
+	if (i.wSuiteMask & VER_SUITE_TERMINAL || i.wSuiteMask & VER_SUITE_SINGLEUSERTS)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// サービスを停止する
+bool MsStopService(char *name)
+{
+	SC_HANDLE sc, service;
+	bool ret = false;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+	if (ms->IsNt == false)
+	{
+		return false;
+	}
+
+	sc = ms->nt->OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+	if (sc == NULL)
+	{
+		return false;
+	}
+
+	service = ms->nt->OpenService(sc, name, SERVICE_ALL_ACCESS);
+	if (service != NULL)
+	{
+		SERVICE_STATUS st;
+		ret = ms->nt->ControlService(service, SERVICE_CONTROL_STOP, &st);
+
+		ms->nt->CloseServiceHandle(service);
+	}
+
+	if (ret)
+	{
+		UINT64 end = Tick64() + 10000ULL;
+		while (Tick64() < end)
+		{
+			if (MsIsServiceRunning(name) == false)
+			{
+				break;
+			}
+
+			SleepThread(250);
+		}
+	}
+
+	ms->nt->CloseServiceHandle(sc);
+	return ret;
+}
+
+// サービスを起動する
+bool MsStartService(char *name)
+{
+	return MsStartServiceEx(name, NULL);
+}
+bool MsStartServiceEx(char *name, UINT *error_code)
+{
+	SC_HANDLE sc, service;
+	bool ret = false;
+	static UINT dummy = 0;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+	if (ms->IsNt == false)
+	{
+		return false;
+	}
+	if (error_code == NULL)
+	{
+		error_code = &dummy;
+	}
+
+	*error_code = 0;
+
+	sc = ms->nt->OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+	if (sc == NULL)
+	{
+		*error_code = GetLastError();
+		return false;
+	}
+
+	service = ms->nt->OpenService(sc, name, SERVICE_ALL_ACCESS);
+	if (service != NULL)
+	{
+		ret = ms->nt->StartService(service, 0, NULL);
+
+		ms->nt->CloseServiceHandle(service);
+	}
+	else
+	{
+		*error_code = GetLastError();
+	}
+
+	if (ret)
+	{
+		UINT64 end = Tick64() + 10000ULL;
+		while (Tick64() < end)
+		{
+			if (MsIsServiceRunning(name))
+			{
+				break;
+			}
+
+			SleepThread(250);
+		}
+	}
+
+	ms->nt->CloseServiceHandle(sc);
+	return ret;
+}
+
+// サービスが起動しているかどうか取得する
+bool MsIsServiceRunning(char *name)
+{
+	SC_HANDLE sc, service;
+	bool ret = false;
+	// 引数チェック
+	if (name == NULL || IsEmptyStr(name))
+	{
+		return false;
+	}
+	if (ms->IsNt == false)
+	{
+		return false;
+	}
+
+	sc = ms->nt->OpenSCManager(NULL, NULL, GENERIC_READ);
+	if (sc == NULL)
+	{
+		return false;
+	}
+
+	service = ms->nt->OpenService(sc, name, GENERIC_READ);
+	if (service != NULL)
+	{
+		SERVICE_STATUS st;
+		Zero(&st, sizeof(st));
+		if (ms->nt->QueryServiceStatus(service, &st))
+		{
+			switch (st.dwCurrentState)
+			{
+			case SERVICE_CONTINUE_PENDING:
+			case SERVICE_PAUSE_PENDING:
+			case SERVICE_PAUSED:
+			case SERVICE_RUNNING:
+			case SERVICE_START_PENDING:
+			case SERVICE_STOP_PENDING:
+				ret = true;
+				break;
+			}
+		}
+
+		ms->nt->CloseServiceHandle(service);
+	}
+
+	ms->nt->CloseServiceHandle(sc);
+	return ret;
+}
+
+// サービスをアンインストールする
+bool MsUninstallService(char *name)
+{
+	SC_HANDLE sc, service;
+	bool ret = false;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+	if (ms->IsNt == false)
+	{
+		return false;
+	}
+
+	MsStopService(name);
+
+	sc = ms->nt->OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+	if (sc == NULL)
+	{
+		return false;
+	}
+
+	service = ms->nt->OpenService(sc, name, SERVICE_ALL_ACCESS);
+	if (service != NULL)
+	{
+		if (ms->nt->DeleteService(service))
+		{
+			ret = true;
+		}
+		ms->nt->CloseServiceHandle(service);
+	}
+
+	ms->nt->CloseServiceHandle(sc);
+
+	if (ret)
+	{
+		SleepThread(2000);
+	}
+
+	return ret;
+}
+
+// サービス設定を更新する
+bool MsUpdateServiceConfig(char *name)
+{
+	SC_HANDLE sc, service;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	// Windows 起動直後かどうか (デッドロック防止)
+	if (timeGetTime() <= (60 * 30 * 1000))
+	{
+		if (MsRegReadInt(REG_LOCAL_MACHINE, "Software\\SoftEther Corporation\\Update Service Config", name) != 0)
+		{
+			return false;
+		}
+	}
+
+	sc = ms->nt->OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+	if (sc == NULL)
+	{
+		return false;
+	}
+
+	service = ms->nt->OpenService(sc, name, SERVICE_ALL_ACCESS);
+	if (service != NULL)
+	{
+		if (GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+		{
+			SERVICE_FAILURE_ACTIONS action;
+			SC_ACTION *e;
+			Zero(&action, sizeof(action));
+			e = ZeroMalloc(sizeof(SC_ACTION) * 3);
+			e[0].Delay = 10000; e[0].Type = SC_ACTION_RESTART;
+			e[1].Delay = 10000; e[1].Type = SC_ACTION_RESTART;
+			e[2].Delay = 10000; e[2].Type = SC_ACTION_RESTART;
+			action.cActions = 3;
+			action.lpsaActions = e;
+			action.dwResetPeriod = 1 * 60 * 60 * 24;
+			ms->nt->ChangeServiceConfig2(service, SERVICE_CONFIG_FAILURE_ACTIONS, &action);
+
+			MsRegWriteInt(REG_LOCAL_MACHINE, "Software\\SoftEther Corporation\\Update Service Config", name, 1);
+		}
+		ms->nt->CloseServiceHandle(service);
+	}
+
+	ms->nt->CloseServiceHandle(sc);
+
+	return true;
+}
+
+// サービスをインストールする
+bool MsInstallService(char *name, char *title, wchar_t *description, char *path)
+{
+	wchar_t title_w[MAX_PATH];
+	wchar_t path_w[MAX_PATH];
+	// 引数チェック
+	if (name == NULL || title == NULL || path == NULL)
+	{
+		return false;
+	}
+
+	StrToUni(title_w, sizeof(title_w), title);
+	StrToUni(path_w, sizeof(path_w), path);
+
+	return MsInstallServiceW(name, title_w, description, path_w);
+}
+bool MsInstallServiceW(char *name, wchar_t *title, wchar_t *description, wchar_t *path)
+{
+	return MsInstallServiceExW(name, title, description, path, NULL);
+}
+bool MsInstallServiceExW(char *name, wchar_t *title, wchar_t *description, wchar_t *path, UINT *error_code)
+{
+	SC_HANDLE sc, service;
+	bool ret = false;
+	wchar_t name_w[MAX_SIZE];
+	static UINT temp_int = 0;
+	// 引数チェック
+	if (name == NULL || title == NULL || path == NULL)
+	{
+		return false;
+	}
+	if (ms->IsNt == false)
+	{
+		return false;
+	}
+	if (error_code == NULL)
+	{
+		error_code = &temp_int;
+	}
+
+	*error_code = 0;
+
+	StrToUni(name_w, sizeof(name_w), name);
+
+	sc = ms->nt->OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+	if (sc == NULL)
+	{
+		*error_code = GetLastError();
+		return false;
+	}
+
+	service = ms->nt->CreateServiceW(sc, name_w, title, SERVICE_ALL_ACCESS,
+		SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS , SERVICE_AUTO_START,
+		SERVICE_ERROR_NORMAL, path, NULL, NULL, NULL, NULL, NULL);
+
+	if (service != NULL)
+	{
+		ret = true;
+
+		if (GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+		{
+			SERVICE_DESCRIPTIONW d;
+			SERVICE_FAILURE_ACTIONS action;
+			SC_ACTION *e;
+			Zero(&d, sizeof(d));
+			d.lpDescription = description;
+			ms->nt->ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &d);
+			Zero(&action, sizeof(action));
+			e = ZeroMalloc(sizeof(SC_ACTION) * 3);
+			e[0].Delay = 10000; e[0].Type = SC_ACTION_RESTART;
+			e[1].Delay = 10000; e[1].Type = SC_ACTION_RESTART;
+			e[2].Delay = 10000; e[2].Type = SC_ACTION_RESTART;
+			action.cActions = 3;
+			action.lpsaActions = e;
+			action.dwResetPeriod = 1 * 60 * 60 * 24;
+			ms->nt->ChangeServiceConfig2(service, SERVICE_CONFIG_FAILURE_ACTIONS, &action);
+
+			Free(e);
+		}
+
+		ms->nt->CloseServiceHandle(service);
+	}
+	else
+	{
+		*error_code = GetLastError();
+	}
+
+	ms->nt->CloseServiceHandle(sc);
+
+	if (ret)
+	{
+		SleepThread(2000);
+	}
+
+	return ret;
+}
+
+// 指定したサービスがインストールされているかどうか調べる
+bool MsIsServiceInstalled(char *name)
+{
+	SC_HANDLE sc;
+	SC_HANDLE service;
+	bool ret = false;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+	if (ms->IsNt == false)
+	{
+		return false;
+	}
+
+	sc = ms->nt->OpenSCManager(NULL, NULL, GENERIC_READ);
+	if (sc == NULL)
+	{
+		return false;
+	}
+
+	service = ms->nt->OpenService(sc, name, GENERIC_READ);
+	if (service != NULL)
+	{
+		ret = true;
+	}
+
+	ms->nt->CloseServiceHandle(service);
+	ms->nt->CloseServiceHandle(sc);
+
+	return ret;
+}
+
+// プロセスの強制終了
+void MsTerminateProcess()
+{
+	TerminateProcess(GetCurrentProcess(), 0);
+	_exit(0);
+}
+
+// プロセス ID の取得
+UINT MsGetProcessId()
+{
+	return GetCurrentProcessId();
+}
+
+// MS 構造体の取得
+MS *MsGetMs()
+{
+	return ms;
+}
+
+// スレッドの優先順位を最低にする
+void MsSetThreadPriorityIdle()
+{
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
+}
+
+// スレッドの優先順位を上げる
+void MsSetThreadPriorityHigh()
+{
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
+}
+
+// スレッドの優先順位を下げる
+void MsSetThreadPriorityLow()
+{
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
+}
+
+// スレッドの優先順位を最高にする
+void MsSetThreadPriorityRealtime()
+{
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+}
+
+// スレッドの優先順位を戻す
+void MsRestoreThreadPriority()
+{
+	SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
+}
+
+// TCP 設定アプリケーションを表示するべきかどうかチェックする
+bool MsIsShouldShowTcpConfigApp()
+{
+	MS_TCP tcp1, tcp2;
+	if (MsIsTcpConfigSupported() == false)
+	{
+		return false;
+	}
+
+	MsGetTcpConfig(&tcp1);
+	if (MsLoadTcpConfigReg(&tcp2) == false)
+	{
+		return true;
+	}
+
+	if (Cmp(&tcp1, &tcp2, sizeof(MS_TCP) != 0))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// レジストリの一時設定内容データを Windows の TCP パラメータに適用する
+void MsApplyTcpConfig()
+{
+	if (MsIsTcpConfigSupported())
+	{
+		MS_TCP tcp;
+
+		if (MsLoadTcpConfigReg(&tcp))
+		{
+			MsSetTcpConfig(&tcp);
+		}
+	}
+}
+
+// 現在の状態で TCP の動的構成がサポートされているかどうかチェックする
+bool MsIsTcpConfigSupported()
+{
+	if (MsIsNt() && MsIsAdmin())
+	{
+		UINT type = GetOsInfo()->OsType;
+
+		if (GET_KETA(type, 100) >= 2)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// TCP 設定をレジストリ設定から読み込む
+bool MsLoadTcpConfigReg(MS_TCP *tcp)
+{
+	// 引数チェック
+	if (tcp == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt())
+	{
+		Zero(tcp, sizeof(MS_TCP));
+
+		if (MsRegIsValueEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "RecvWindowSize", true) == false ||
+			MsRegIsValueEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "SendWindowSize", true) == false)
+		{
+			return false;
+		}
+
+		tcp->RecvWindowSize = MsRegReadIntEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "RecvWindowSize", true);
+		tcp->SendWindowSize = MsRegReadIntEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "SendWindowSize", true);
+
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// TCP 設定をレジストリから削除する
+void MsDeleteTcpConfigReg()
+{
+	if (MsIsNt() && MsIsAdmin())
+	{
+		MsRegDeleteKeyEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, true);
+	}
+}
+
+// TCP 設定をレジストリ設定に書き込む
+void MsSaveTcpConfigReg(MS_TCP *tcp)
+{
+	// 引数チェック
+	if (tcp == NULL)
+	{
+		return;
+	}
+
+	if (MsIsNt() && MsIsAdmin())
+	{
+		MsRegWriteIntEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "RecvWindowSize", tcp->RecvWindowSize, true);
+		MsRegWriteIntEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "SendWindowSize", tcp->SendWindowSize, true);
+	}
+}
+
+// 現在の TCP 設定を取得する
+void MsGetTcpConfig(MS_TCP *tcp)
+{
+	// 引数チェック
+	if (tcp == NULL)
+	{
+		return;
+	}
+
+	Zero(tcp, sizeof(MS_TCP));
+
+	if (MsIsNt())
+	{
+		// ネットワーク設定初期化
+		MsInitGlobalNetworkConfig();
+
+		// GlobalMaxTcpWindowSize または TcpWindowSize の値が存在すれば読み込む
+		tcp->RecvWindowSize = MAX(tcp->RecvWindowSize, MsRegReadInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", "TcpWindowSize"));
+		tcp->RecvWindowSize = MAX(tcp->RecvWindowSize, MsRegReadInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", "GlobalMaxTcpWindowSize"));
+		tcp->RecvWindowSize = MAX(tcp->RecvWindowSize, MsRegReadInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters", "DefaultReceiveWindow"));
+
+		// DefaultSendWindow の値が存在すれば読み込む
+		tcp->SendWindowSize = MsRegReadInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters", "DefaultSendWindow");
+	}
+}
+
+// TCP 設定を書き込む
+void MsSetTcpConfig(MS_TCP *tcp)
+{
+	// 引数チェック
+	if (tcp == NULL)
+	{
+		return;
+	}
+
+	if (MsIsNt() && MsIsAdmin())
+	{
+		bool window_scaling = false;
+		UINT tcp1323opts;
+
+		if (tcp->RecvWindowSize >= 65536 || tcp->SendWindowSize >= 65536)
+		{
+			window_scaling = true;
+		}
+
+		// Tcp1323Opts の設定
+		tcp1323opts = MsRegReadInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", "Tcp1323Opts");
+		if (window_scaling)
+		{
+			if (tcp1323opts == 0)
+			{
+				tcp1323opts = 1;
+			}
+			if (tcp1323opts == 2)
+			{
+				tcp1323opts = 3;
+			}
+		}
+		else
+		{
+			if (tcp1323opts == 1)
+			{
+				tcp1323opts = 0;
+			}
+			if (tcp1323opts == 3)
+			{
+				tcp1323opts = 2;
+			}
+		}
+		MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", "Tcp1323Opts", tcp1323opts);
+
+		// 受信ウインドウの設定
+		if (tcp->RecvWindowSize == 0)
+		{
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters",
+				"DefaultReceiveWindow");
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"TcpWindowSize");
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"GlobalMaxTcpWindowSize");
+		}
+		else
+		{
+			MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters",
+				"DefaultReceiveWindow", tcp->RecvWindowSize);
+			MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"TcpWindowSize", tcp->RecvWindowSize);
+			MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"GlobalMaxTcpWindowSize", tcp->RecvWindowSize);
+		}
+
+		// 送信ウインドウの設定
+		if (tcp->SendWindowSize == 0)
+		{
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters",
+				"DefaultSendWindow");
+		}
+		else
+		{
+			MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters",
+				"DefaultSendWindow", tcp->SendWindowSize);
+		}
+	}
+}
+
+// グローバルなネットワーク設定を初期化する
+void MsInitGlobalNetworkConfig()
+{
+	if (MsIsNt())
+	{
+		UINT current_window_size;
+
+		if (MsRegReadInt(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+			"packetix_no_optimize") == 0)
+
+		{
+			// TCP コネクション数を最大にする
+			MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"TcpNumConnections", TCP_MAX_NUM_CONNECTIONS);
+
+			// タスク オフロードを無効化する
+			MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"DisableTaskOffload", 1);
+		}
+
+		current_window_size = MsRegReadInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", "TcpWindowSize");
+
+		if (current_window_size == 65535 || current_window_size == 5980160 ||
+			current_window_size == 16777216 || current_window_size == 16777214)
+		{
+			// 古いバージョンの VPN が書き込んでしまった変な値を削除する
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters",
+				"DefaultReceiveWindow");
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters",
+				"DefaultSendWindow");
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"Tcp1323Opts");
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"TcpWindowSize");
+			MsRegDeleteValue(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"GlobalMaxTcpWindowSize");
+
+			// vpn_no_change = true にする
+			MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters", "vpn_no_change", 1);
+			MsRegWriteInt(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\AFD\\Parameters", "vpn_no_change", 1);
+		}
+	}
+	else
+	{
+		if (MsRegReadInt(REG_LOCAL_MACHINE,
+			"System\\CurrentControlSet\\Services\\VxD\\MSTCP",
+			"packetix_no_optimize") == 0)
+		{
+			// DeadGWDetect を無効にする
+			MsRegWriteStr(REG_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\VxD\\MSTCP",
+				"DeadGWDetect", "0");
+		}
+	}
+
+	MsApplyTcpConfig();
+}
+
+// 仮想 LAN カードをアップグレードする
+bool MsUpgradeVLan(char *tag_name, char *connection_tag_name, char *instance_name)
+{
+	wchar_t infpath[MAX_PATH];
+	char hwid[MAX_PATH];
+	wchar_t hwid_w[MAX_PATH];
+	bool ret = false;
+	bool need_reboot;
+	bool before_status;
+	UCHAR old_mac_address[6];
+	char *s;
+	NO_WARNING *nw;
+	char sen_sys[MAX_PATH];
+	// 引数チェック
+	if (instance_name == NULL || tag_name == NULL || connection_tag_name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		// Windows 9x ではアップグレードできない
+		return false;
+	}
+
+	Zero(hwid, sizeof(hwid));
+	Format(hwid, sizeof(hwid), DRIVER_DEVICE_ID_TAG, instance_name);
+	StrToUni(hwid_w, sizeof(hwid_w), hwid);
+
+	// 指定された名前の仮想 LAN カードがすでに登録されているかどうかを調べる
+	if (MsIsVLanExists(tag_name, instance_name) == false)
+	{
+		// 登録されていない
+		return false;
+	}
+
+	// 現在使用している .sys ファイル名を取得する
+	if (MsGetSenDeiverFilename(sen_sys, sizeof(sen_sys), instance_name) == false)
+	{
+		// 不明なので新しいファイル名を作成する
+		if (MsMakeNewSenDriverFilename(sen_sys, sizeof(sen_sys)) == false)
+		{
+			// 失敗
+			return false;
+		}
+	}
+
+	// 現在の動作状況を取得する
+	before_status = MsIsVLanEnabled(instance_name);
+
+	// 以前の MAC アドレスを取得する
+	s = MsGetMacAddress(tag_name, instance_name);
+	if (s == NULL)
+	{
+		Zero(old_mac_address, 6);
+	}
+	else
+	{
+		BUF *b;
+		b = StrToBin(s);
+		Free(s);
+
+		if (b->Size == 6)
+		{
+			Copy(old_mac_address, b->Buf, b->Size);
+		}
+		else
+		{
+			Zero(old_mac_address, 6);
+		}
+
+		FreeBuf(b);
+	}
+
+	// インストール開始
+	if (MsStartDriverInstall(instance_name, IsZero(old_mac_address, 6) ? NULL : old_mac_address, sen_sys) == false)
+	{
+		return false;
+	}
+	MsGetDriverPath(instance_name, NULL, NULL, infpath, NULL, sen_sys);
+
+	nw = NULL;
+
+	//if (MsIsVista() == false)
+	{
+		nw = MsInitNoWarning();
+	}
+
+	// インストールを行う
+	if (ms->nt->UpdateDriverForPlugAndPlayDevicesW(
+		NULL, hwid_w, infpath, 1, &need_reboot))
+	{
+		ret = true;
+	}
+	MsFreeNoWarning(nw);
+
+	// インストール完了
+	MsFinishDriverInstall(instance_name, sen_sys);
+
+	MsInitNetworkConfig(tag_name, instance_name, connection_tag_name);
+
+	// 動作を復元する
+	if (before_status)
+	{
+		MsEnableVLan(instance_name);
+	}
+	else
+	{
+		MsDisableVLan(instance_name);
+	}
+
+	return ret;
+}
+
+// Windows 9x 用テスト
+void MsWin9xTest()
+{
+}
+
+// 仮想 LAN カードの CompatibleIDs を更新する
+void MsUpdateCompatibleIDs(char *instance_name)
+{
+	TOKEN_LIST *t;
+	char id[MAX_SIZE];
+	char device_title[MAX_SIZE];
+	char device_title_old[MAX_SIZE];
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return;
+	}
+
+	Format(id, sizeof(id), DRIVER_DEVICE_ID_TAG, instance_name);
+	Format(device_title, sizeof(device_title), VLAN_ADAPTER_NAME_TAG, instance_name);
+	Format(device_title_old, sizeof(device_title_old), "---dummy-string-ut--", instance_name);
+
+	t = MsRegEnumKey(REG_LOCAL_MACHINE, "Enum\\Root\\Net");
+	if (t != NULL)
+	{
+		UINT i;
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			char keyname[MAX_PATH];
+			char *str;
+			char *title;
+
+			Format(keyname, sizeof(keyname), "Enum\\Root\\Net\\%s", t->Token[i]);
+
+			title = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "DeviceDesc");
+
+			if (title != NULL)
+			{
+				if (StrCmpi(title, device_title) == 0 || StrCmpi(title, device_title_old) == 0)
+				{
+					Format(keyname, sizeof(keyname), "Enum\\Root\\Net\\%s",t->Token[i]);
+					str = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "CompatibleIDs");
+					if (str != NULL)
+					{
+						Free(str);
+					}
+					else
+					{
+						MsRegWriteStr(REG_LOCAL_MACHINE, keyname, "CompatibleIDs", id);
+					}
+				}
+				Free(title);
+			}
+		}
+
+		FreeToken(t);
+	}
+
+	MsRegWriteStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Setup", "SourcePath",
+		ms->System32Dir);
+}
+
+// 仮想 LAN カードをインストールする (Win9x 用)
+bool MsInstallVLan9x(char *instance_name)
+{
+	char sysdir[MAX_PATH];
+	char infdir[MAX_PATH];
+	char otherdir[MAX_PATH];
+	char syspath[MAX_PATH];
+	char syspath2[MAX_PATH];
+	char infpath[MAX_PATH];
+	char vpn16[MAX_PATH];
+	char infpath_src[MAX_PATH];
+	char syspath_src[MAX_PATH];
+	char sen_sys[MAX_PATH];
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(sysdir, sizeof(sysdir), MsGetSystem32Dir());
+	Format(infdir, sizeof(infdir), "%s\\inf", MsGetWindowsDir());
+	Format(otherdir, sizeof(otherdir), "%s\\other", infdir);
+	Format(syspath, sizeof(syspath), "%s\\Sen_%s.sys", sysdir, instance_name);
+	Format(syspath2, sizeof(syspath2), "%s\\Sen_%s.sys", infdir, instance_name);
+	Format(infpath, sizeof(infpath), "%s\\Sen_%s.inf", infdir, instance_name);
+	Format(vpn16, sizeof(vpn16), "%s\\vpn16.exe", MsGetMyTempDir());
+
+	MakeDir(otherdir);
+
+	Format(sen_sys, sizeof(sen_sys), DRIVER_INSTALL_SYS_NAME_TAG, instance_name);
+
+	// vpn16.exe のコピー
+	FileCopy("|vpn16.exe", vpn16);
+
+	// インストール開始
+	if (MsStartDriverInstall(instance_name, NULL, sen_sys) == false)
+	{
+		return false;
+	}
+	MsGetDriverPathA(instance_name, NULL, NULL, infpath_src, syspath_src, sen_sys);
+
+	// inf ファイルのコピー
+	FileCopy(infpath_src, infpath);
+
+	// sys ファイルのコピー
+	FileCopy(syspath_src, syspath);
+
+	// デバイスドライバのインストール
+	if (Run(vpn16, instance_name, false, true) == false)
+	{
+		return false;
+	}
+
+	// CompatibleIDs の更新
+	MsUpdateCompatibleIDs(instance_name);
+
+	return true;
+}
+
+// 子ウインドウ列挙プロシージャ
+bool CALLBACK MsEnumChildWindowProc(HWND hWnd, LPARAM lParam)
+{
+	LIST *o = (LIST *)lParam;
+
+	if (o != NULL)
+	{
+		MsEnumChildWindows(o, hWnd);
+	}
+
+	return true;
+}
+
+// 指定したウインドウとその子ウインドウをすべて列挙する
+LIST *MsEnumChildWindows(LIST *o, HWND hWnd)
+{
+	// 引数チェック
+	if (hWnd == NULL)
+	{
+		return NULL;
+	}
+
+	if (o == NULL)
+	{
+		o = NewListFast(NULL);
+	}
+
+	MsAddWindowToList(o, hWnd);
+
+	EnumChildWindows(hWnd, MsEnumChildWindowProc, (LPARAM)o);
+
+	return o;
+}
+
+// ウインドウをリストに追加する
+void MsAddWindowToList(LIST *o, HWND hWnd)
+{
+	// 引数チェック
+	if (o == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	if (IsInList(o, hWnd) == false)
+	{
+		Add(o, hWnd);
+	}
+}
+
+// スレッドの所有するウインドウの列挙
+bool CALLBACK MsEnumThreadWindowProc(HWND hWnd, LPARAM lParam)
+{
+	LIST *o = (LIST *)lParam;
+
+	if (o == NULL)
+	{
+		return false;
+	}
+
+	MsEnumChildWindows(o, hWnd);
+
+	return true;
+}
+
+// ウインドウ列挙プロシージャ
+BOOL CALLBACK EnumTopWindowProc(HWND hWnd, LPARAM lParam)
+{
+	LIST *o = (LIST *)lParam;
+	HWND hParent;
+	char c1[MAX_SIZE], c2[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || o == NULL)
+	{
+		return TRUE;
+	}
+
+	Zero(c1, sizeof(c1));
+	Zero(c2, sizeof(c2));
+
+	hParent = GetParent(hWnd);
+
+	GetClassName(hWnd, c1, sizeof(c1));
+
+	if (hParent != NULL)
+	{
+		GetClassName(hParent, c2, sizeof(c2));
+	}
+
+	if (StrCmpi(c1, "SysIPAddress32") != 0 && (IsEmptyStr(c2) || StrCmpi(c2, "SysIPAddress32") != 0))
+	{
+		AddWindow(o, hWnd);
+	}
+
+	return TRUE;
+}
+
+// 子ウインドウ列挙プロシージャ
+BOOL CALLBACK EnumChildWindowProc(HWND hWnd, LPARAM lParam)
+{
+	ENUM_CHILD_WINDOW_PARAM *p = (ENUM_CHILD_WINDOW_PARAM *)lParam;
+	LIST *o;
+	HWND hParent;
+	char c1[MAX_SIZE], c2[MAX_SIZE];
+	// 引数チェック
+	if (hWnd == NULL || p == NULL)
+	{
+		return TRUE;
+	}
+
+	o = p->o;
+
+	Zero(c1, sizeof(c1));
+	Zero(c2, sizeof(c2));
+
+	hParent = GetParent(hWnd);
+
+	GetClassName(hWnd, c1, sizeof(c1));
+
+	if (hParent != NULL)
+	{
+		GetClassName(hParent, c2, sizeof(c2));
+	}
+
+	if (p->include_ipcontrol || (StrCmpi(c1, "SysIPAddress32") != 0 && (IsEmptyStr(c2) || StrCmpi(c2, "SysIPAddress32") != 0)))
+	{
+		AddWindow(o, hWnd);
+
+		if (p->no_recursion == false)
+		{
+			EnumChildWindows(hWnd, EnumChildWindowProc, (LPARAM)p);
+		}
+	}
+
+	return TRUE;
+}
+LIST *EnumAllWindow()
+{
+	return EnumAllWindowEx(false, false);
+}
+LIST *EnumAllWindowEx(bool no_recursion, bool include_ipcontrol)
+{
+	ENUM_CHILD_WINDOW_PARAM p;
+	LIST *o = NewWindowList();
+
+	Zero(&p, sizeof(p));
+	p.o = o;
+	p.no_recursion = no_recursion;
+	p.include_ipcontrol = include_ipcontrol;
+
+	EnumWindows(EnumChildWindowProc, (LPARAM)&p);
+
+	return o;
+}
+LIST *EnumAllTopWindow()
+{
+	LIST *o = NewWindowList();
+
+	EnumWindows(EnumTopWindowProc, (LPARAM)o);
+
+	return o;
+}
+
+// 特定のウインドウの中にあるすべての子ウインドウを列挙する
+LIST *EnumAllChildWindow(HWND hWnd)
+{
+	return EnumAllChildWindowEx(hWnd, false, false, false);
+}
+LIST *EnumAllChildWindowEx(HWND hWnd, bool no_recursion, bool include_ipcontrol, bool no_self)
+{
+	ENUM_CHILD_WINDOW_PARAM p;
+	LIST *o = NewWindowList();
+
+	Zero(&p, sizeof(p));
+	p.include_ipcontrol = include_ipcontrol;
+	p.no_recursion = no_recursion;
+	p.o = o;
+
+	if (no_self == false)
+	{
+		AddWindow(o, hWnd);
+	}
+
+	EnumChildWindows(hWnd, EnumChildWindowProc, (LPARAM)&p);
+
+	return o;
+}
+
+// ウインドウリストの解放
+void FreeWindowList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		HWND *e = LIST_DATA(o, i);
+
+		Free(e);
+	}
+
+	ReleaseList(o);
+}
+
+// ウインドウリストにウインドウを追加
+void AddWindow(LIST *o, HWND hWnd)
+{
+	HWND t, *e;
+	// 引数チェック
+	if (o == NULL || hWnd == NULL)
+	{
+		return;
+	}
+
+	t = hWnd;
+
+	if (Search(o, &t) != NULL)
+	{
+		return;
+	}
+
+	e = ZeroMalloc(sizeof(HWND));
+	*e = hWnd;
+
+	Insert(o, e);
+}
+
+// ウインドウリストの比較
+int CmpWindowList(void *p1, void *p2)
+{
+	HWND *h1, *h2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	h1 = *(HWND **)p1;
+	h2 = *(HWND **)p2;
+	if (h1 == NULL || h2 == NULL)
+	{
+		return 0;
+	}
+
+	return Cmp(h1, h2, sizeof(HWND));
+}
+
+// 新しいウインドウリストの作成
+LIST *NewWindowList()
+{
+	return NewListFast(CmpWindowList);
+}
+
+// Windows Vista かどうか判別
+bool MsIsVista()
+{
+	OS_INFO *info = GetOsInfo();
+
+	if (info == NULL)
+	{
+		return false;
+	}
+
+	if (OS_IS_WINDOWS_NT(info->OsType))
+	{
+		if (GET_KETA(info->OsType, 100) >= 5)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// ウインドウの所有者のプロセスパスを取得する
+bool MsGetWindowOwnerProcessExeName(char *path, UINT size, HWND hWnd)
+{
+	DWORD procId = 0;
+	// 引数チェック
+	if (path == NULL || hWnd == NULL)
+	{
+		return false;
+	}
+
+	GetWindowThreadProcessId(hWnd, &procId);
+	if (procId == 0)
+	{
+		return false;
+	}
+
+	if (MsGetProcessExeName(path, size, procId) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+bool MsGetWindowOwnerProcessExeNameW(wchar_t *path, UINT size, HWND hWnd)
+{
+	DWORD procId = 0;
+	// 引数チェック
+	if (path == NULL || hWnd == NULL)
+	{
+		return false;
+	}
+
+	GetWindowThreadProcessId(hWnd, &procId);
+	if (procId == 0)
+	{
+		return false;
+	}
+
+	if (MsGetProcessExeNameW(path, size, procId) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// プロセス ID からプロセスパスを取得する
+bool MsGetProcessExeName(char *path, UINT size, UINT id)
+{
+	LIST *o;
+	MS_PROCESS *proc;
+	bool ret = false;
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	o = MsGetProcessList();
+	proc = MsSearchProcessById(o, id);
+
+	if (proc != NULL)
+	{
+		ret = true;
+		StrCpy(path, size, proc->ExeFilename);
+	}
+
+	MsFreeProcessList(o);
+
+	return ret;
+}
+bool MsGetProcessExeNameW(wchar_t *path, UINT size, UINT id)
+{
+	LIST *o;
+	MS_PROCESS *proc;
+	bool ret = false;
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	o = MsGetProcessList();
+	proc = MsSearchProcessById(o, id);
+
+	if (proc != NULL)
+	{
+		ret = true;
+		UniStrCpy(path, size, proc->ExeFilenameW);
+	}
+
+	MsFreeProcessList(o);
+
+	return ret;
+}
+
+// 警告ダイアログを閉じる
+bool MsCloseWarningWindow(UINT thread_id)
+{
+	UINT i;
+	LIST *o;
+	bool ret = false;
+
+	if (MsIsVista() == false)
+	{
+		o = NewListFast(NULL);
+		EnumThreadWindows(thread_id, MsEnumThreadWindowProc, (LPARAM)o);
+	}
+	else
+	{
+		o = EnumAllTopWindow();
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		HWND hWnd;
+		
+		if (MsIsVista() == false)
+		{
+			hWnd = LIST_DATA(o, i);
+		}
+		else
+		{
+			hWnd = *((HWND *)LIST_DATA(o, i));
+		}
+
+		if (hWnd != NULL)
+		{
+			OS_INFO *info = GetOsInfo();
+
+			if (MsIsNt())
+			{
+				// このウインドウがドライバの警告画面かどうかを取得する
+				if (MsIsVista() == false)
+				{
+					// Windows Vista 以外
+					HWND hStatic, hOk, hCancel, hDetail;
+
+					hStatic = GetDlgItem(hWnd, 0x14C1);
+					hOk = GetDlgItem(hWnd, 0x14B7);
+					hCancel = GetDlgItem(hWnd, 0x14BA);
+					hDetail = GetDlgItem(hWnd, 0x14B9);
+
+					if ((hStatic != NULL || hDetail != NULL) && hOk != NULL && hCancel != NULL)
+					{
+						char tmp[MAX_SIZE];
+						bool b = false;
+
+						if (GetClassName(hStatic, tmp, sizeof(tmp)) != 0)
+						{
+							if (StrCmpi(tmp, "static") == 0)
+							{
+								b = true;
+							}
+						}
+
+						if (GetClassName(hDetail, tmp, sizeof(tmp)) != 0)
+						{
+							if (StrCmpi(tmp, "button") == 0)
+							{
+								b = true;
+							}
+						}
+
+						if (b)
+						{
+							if (GetClassName(hOk, tmp, sizeof(tmp)) != 0)
+							{
+								if (StrCmpi(tmp, "button") == 0)
+								{
+									if (GetClassName(hCancel, tmp, sizeof(tmp)) != 0)
+									{
+										if (StrCmpi(tmp, "button") == 0)
+										{
+											// 発見したので OK ボタンを押す
+											PostMessage(hWnd, WM_COMMAND, 0x14B7, 0);
+
+											ret = true;
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+				else
+				{
+					// Windows Vista
+					char exe[MAX_PATH];
+
+					if (MsGetWindowOwnerProcessExeName(exe, sizeof(exe), hWnd))
+					{
+						if (EndWith(exe, "rundll32.exe"))
+						{
+							LIST *o;
+							HWND h;
+							UINT i;
+
+							o = EnumAllChildWindow(hWnd);
+
+							if (o != NULL)
+							{
+								for (i = 0;i < LIST_NUM(o);i++)
+								{
+									char tmp[MAX_SIZE];
+
+									h = *((HWND *)LIST_DATA(o, i));
+
+									Zero(tmp, sizeof(tmp));
+									GetClassNameA(h, tmp, sizeof(tmp));
+
+									if (StrCmpi(tmp, "DirectUIHWND") == 0)
+									{
+										LIST *o = EnumAllChildWindow(h);
+
+										if (o != NULL)
+										{
+											UINT j;
+											UINT numDirectUIHWND = 0;
+											UINT numButton = 0;
+											HWND hButton1 = NULL;
+											HWND hButton2 = NULL;
+
+											for (j = 0;j < LIST_NUM(o);j++)
+											{
+												HWND hh;
+												char tmp[MAX_SIZE];
+
+												hh = *((HWND *)LIST_DATA(o, j));
+
+												Zero(tmp, sizeof(tmp));
+												GetClassNameA(hh, tmp, sizeof(tmp));
+
+												if (StrCmpi(tmp, "DirectUIHWND") == 0)
+												{
+													numDirectUIHWND++;
+												}
+
+												if (StrCmpi(tmp, "button") == 0)
+												{
+													numButton++;
+													if (hButton1 == NULL)
+													{
+														hButton1 = hh;
+													}
+													else
+													{
+														hButton2 = hh;
+													}
+												}
+											}
+
+											if (numDirectUIHWND == 1 && numButton == 2)
+											{
+												if (hButton1 != NULL && hButton2 != NULL)
+												{
+													HWND hButton;
+													HWND hParent;
+													RECT r1, r2;
+
+													GetWindowRect(hButton1, &r1);
+													GetWindowRect(hButton2, &r2);
+
+													hButton = hButton1;
+
+													if (r1.top < r2.top)
+													{
+														hButton = hButton2;
+													}
+
+													hParent = GetParent(hButton);
+
+													// 発見したので OK ボタンを押す
+													PostMessage(hParent, WM_COMMAND, 1, 0);
+
+													ret = true;
+												}
+											}
+
+											FreeWindowList(o);
+										}
+									}
+								}
+
+								FreeWindowList(o);
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if (MsIsVista() == false)
+	{
+		ReleaseList(o);
+	}
+	else
+	{
+		FreeWindowList(o);
+	}
+
+	return ret;
+}
+
+// 警告を出さないようにするためのスレッド
+void MsNoWarningThreadProc(THREAD *thread, void *param)
+{
+	NO_WARNING *nw;
+	UINT interval;
+	UINT i;
+	bool found0 = false;
+	// 引数チェック
+	if (thread == NULL)
+	{
+		return;
+	}
+
+	nw = (NO_WARNING *)param;
+
+	nw->NoWarningThread = thread;
+	AddRef(thread->ref);
+
+	NoticeThreadInit(thread);
+
+	interval = 50;
+
+	if (MsIsVista())
+	{
+		interval = 1000;
+	}
+
+	i = 0;
+
+	while (nw->Halt == false)
+	{
+		bool found;
+
+		// 警告ダイアログを閉じる
+		found = MsCloseWarningWindow(nw->ThreadId);
+		if (i == 0)
+		{
+			found0 = found;
+		}
+		else
+		{
+			if (found0 == false && found)
+			{
+				break;
+			}
+		}
+		i++;
+
+		// 親スレッドが指示するまでループする
+		Wait(nw->HaltEvent, interval);
+	}
+}
+
+// 警告音を消す処理の初期化
+char *MsNoWarningSoundInit()
+{
+	char *ret = MsRegReadStr(REG_CURRENT_USER, "AppEvents\\Schemes\\Apps\\.Default\\SystemAsterisk\\.Current", "");
+
+	if (IsEmptyStr(ret))
+	{
+		Free(ret);
+		ret = NULL;
+	}
+	else
+	{
+		MsRegWriteStr(REG_CURRENT_USER,
+			"AppEvents\\Schemes\\Apps\\.Default\\SystemAsterisk\\.Current",
+			"", "");
+	}
+
+	return ret;
+}
+
+// 警告音を消す処理の解放
+void MsNoWarningSoundFree(char *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	MsRegWriteStrExpand(REG_CURRENT_USER,
+		"AppEvents\\Schemes\\Apps\\.Default\\SystemAsterisk\\.Current",
+		"", s);
+
+	Free(s);
+}
+
+// 警告を出さないようにする処理の開始
+NO_WARNING *MsInitNoWarning()
+{
+	wchar_t *tmp;
+	THREAD *thread;
+	NO_WARNING *nw = ZeroMalloc(sizeof(NO_WARNING));
+
+	// 現在のサウンドファイル名を取得する
+	tmp = MsRegReadStrW(REG_CURRENT_USER, "AppEvents\\Schemes\\Apps\\.Default\\SystemAsterisk\\.Current", "");
+	if (UniIsEmptyStr(tmp) == false)
+	{
+		nw->SoundFileName = CopyUniStr(tmp);
+
+		MsRegWriteStrW(REG_CURRENT_USER,
+			"AppEvents\\Schemes\\Apps\\.Default\\SystemAsterisk\\.Current",
+			"", L"");
+	}
+
+	Free(tmp);
+
+	nw->ThreadId = GetCurrentThreadId();
+	nw->HaltEvent = NewEvent();
+
+	thread = NewThread(MsNoWarningThreadProc, nw);
+	WaitThreadInit(thread);
+
+	ReleaseThread(thread);
+
+	return nw;
+}
+
+// 警告を出さないようにする処理の終了
+void MsFreeNoWarning(NO_WARNING *nw)
+{
+	// 引数チェック
+	if (nw == NULL)
+	{
+		return;
+	}
+
+	nw->Halt = true;
+	Set(nw->HaltEvent);
+
+	WaitThread(nw->NoWarningThread, INFINITE);
+	ReleaseThread(nw->NoWarningThread);
+
+	ReleaseEvent(nw->HaltEvent);
+
+	if (nw->SoundFileName != NULL)
+	{
+		MsRegWriteStrExpandW(REG_CURRENT_USER,
+			"AppEvents\\Schemes\\Apps\\.Default\\SystemAsterisk\\.Current",
+			"", nw->SoundFileName);
+
+		Free(nw->SoundFileName);
+	}
+
+	Free(nw);
+}
+
+// 仮想 LAN カードをインストールする
+bool MsInstallVLan(char *tag_name, char *connection_tag_name, char *instance_name)
+{
+	wchar_t infpath[MAX_PATH];
+	wchar_t inf_class_name[MAX_PATH];
+	GUID inf_class_guid;
+	HDEVINFO device_info;
+	SP_DEVINFO_DATA device_info_data;
+	char hwid[MAX_PATH];
+	wchar_t hwid_w[MAX_PATH];
+	bool ret = false;
+	bool need_reboot;
+	char sen_sys[MAX_PATH];
+	UINT i;
+	// 引数チェック
+	if (instance_name == NULL || tag_name == NULL || connection_tag_name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		// Windows 9x 用
+		return MsInstallVLan9x(instance_name);
+	}
+
+	Zero(hwid, sizeof(hwid));
+	Format(hwid, sizeof(hwid), DRIVER_DEVICE_ID_TAG, instance_name);
+	StrToUni(hwid_w, sizeof(hwid_w), hwid);
+
+	// 指定された名前の仮想 LAN カードがすでに登録されているかどうかを調べる
+	if (MsIsVLanExists(tag_name, instance_name))
+	{
+		// すでに登録されている
+		return false;
+	}
+
+	// インストール先 .sys ファイル名の決定
+	if (MsMakeNewSenDriverFilename(sen_sys, sizeof(sen_sys)) == false)
+	{
+		return false;
+	}
+
+	// インストール開始
+	if (MsStartDriverInstall(instance_name, NULL, sen_sys) == false)
+	{
+		return false;
+	}
+	MsGetDriverPath(instance_name, NULL, NULL, infpath, NULL, sen_sys);
+
+	// inf ファイルのクラス GUID を取得する
+	if (SetupDiGetINFClassW(infpath, &inf_class_guid, inf_class_name, sizeof(inf_class_name), NULL))
+	{
+		// デバイス情報セットを取得する
+		device_info = SetupDiCreateDeviceInfoList(&inf_class_guid, NULL);
+		if (device_info != INVALID_HANDLE_VALUE)
+		{
+			// Windows 2000 以降
+			Zero(&device_info_data, sizeof(device_info_data));
+			device_info_data.cbSize = sizeof(device_info_data);
+			if (SetupDiCreateDeviceInfoW(device_info, inf_class_name, &inf_class_guid,
+				NULL, NULL, DICD_GENERATE_ID, &device_info_data))
+			{
+				// レジストリ情報を設定する
+				if (SetupDiSetDeviceRegistryProperty(device_info, &device_info_data,
+					SPDRP_HARDWAREID, (BYTE *)hwid, sizeof(hwid)))
+				{
+					NO_WARNING *nw = NULL;
+					
+					//if (MsIsVista() == false)
+					{
+						nw = MsInitNoWarning();
+					}
+
+					// クラスインストーラを起動する
+					if (SetupDiCallClassInstaller(DIF_REGISTERDEVICE, device_info,
+						&device_info_data))
+					{
+						// インストールを行う
+						if (ms->nt->UpdateDriverForPlugAndPlayDevicesW(
+							NULL, hwid_w, infpath, 1, &need_reboot))
+						{
+							ret = true;
+						}
+						else
+						{
+							// インストール失敗
+							SetupDiCallClassInstaller(DIF_REMOVE, device_info,
+								&device_info_data);
+						}
+					}
+					else
+					{
+						Debug("SetupDiCallClassInstaller Error: %X\n", GetLastError());
+					}
+
+					MsFreeNoWarning(nw);
+				}
+			}
+			// デバイス情報セットを削除する
+			SetupDiDestroyDeviceInfoList(device_info);
+		}
+	}
+
+	// インストール完了
+	MsFinishDriverInstall(instance_name, sen_sys);
+
+	for (i = 0;i < 5;i++)
+	{
+		MsInitNetworkConfig(tag_name, instance_name, connection_tag_name);
+		SleepThread(MsIsVista() ? 1000 : 300);
+	}
+
+	if (ret)
+	{
+		MsDisableVLan(instance_name);
+		MsEnableVLan(instance_name);
+	}
+
+	return ret;
+}
+
+// デバイス ID からデバイス情報を取得する
+HDEVINFO MsGetDevInfoFromDeviceId(SP_DEVINFO_DATA *dev_info_data, char *device_id)
+{
+	HDEVINFO dev_info;
+	SP_DEVINFO_LIST_DETAIL_DATA detail_data;
+	SP_DEVINFO_DATA data;
+	UINT i;
+	bool found;
+	char target_name[MAX_SIZE];
+	// 引数チェック
+	if (dev_info_data == NULL || device_id == NULL)
+	{
+		return NULL;
+	}
+
+	StrCpy(target_name, sizeof(target_name), device_id);
+
+	// デバイス情報リストを作成
+	dev_info = SetupDiGetClassDevsEx(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT, NULL, NULL, NULL);
+	if (dev_info == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&detail_data, sizeof(detail_data));
+	detail_data.cbSize = sizeof(detail_data);
+	if (SetupDiGetDeviceInfoListDetail(dev_info, &detail_data) == false)
+	{
+		MsDestroyDevInfo(dev_info);
+		return NULL;
+	}
+
+	Zero(&data, sizeof(data));
+	data.cbSize = sizeof(data);
+
+	// 列挙開始
+	found = false;
+	for (i = 0;SetupDiEnumDeviceInfo(dev_info, i, &data);i++)
+	{
+		char *buffer;
+		UINT buffer_size = 8092;
+		DWORD data_type;
+
+		buffer = ZeroMalloc(buffer_size);
+
+		if (SetupDiGetDeviceRegistryProperty(dev_info, &data, SPDRP_HARDWAREID, &data_type, (PBYTE)buffer, buffer_size, NULL))
+		{
+			if (StrCmpi(buffer, target_name) == 0)
+			{
+				// 発見
+				found = true;
+			}
+		}
+
+		Free(buffer);
+
+		if (found)
+		{
+			break;
+		}
+	}
+
+	if (found == false)
+	{
+		MsDestroyDevInfo(dev_info);
+		return NULL;
+	}
+	else
+	{
+		Copy(dev_info_data, &data, sizeof(data));
+		return dev_info;
+	}
+}
+
+// 指定したデバイスが動作中かどうかを調べる
+bool MsIsDeviceRunning(HDEVINFO info, SP_DEVINFO_DATA *dev_info_data)
+{
+	SP_DEVINFO_LIST_DETAIL_DATA detail;
+	UINT status = 0, problem = 0;
+	// 引数チェック
+	if (info == NULL || dev_info_data == NULL)
+	{
+		return false;
+	}
+
+	Zero(&detail, sizeof(detail));
+	detail.cbSize = sizeof(detail);
+
+	if (SetupDiGetDeviceInfoListDetail(info, &detail) == false ||
+		ms->nt->CM_Get_DevNode_Status_Ex(&status, &problem, dev_info_data->DevInst,
+		0, detail.RemoteMachineHandle) != CR_SUCCESS)
+	{
+		return false;
+	}
+
+	if (status & 8)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// 指定したデバイスを開始させる
+bool MsStartDevice(HDEVINFO info, SP_DEVINFO_DATA *dev_info_data)
+{
+	SP_PROPCHANGE_PARAMS p;
+	// 引数チェック
+	if (info == NULL || dev_info_data == NULL)
+	{
+		return false;
+	}
+
+	Zero(&p, sizeof(p));
+	p.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+	p.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
+	p.StateChange = DICS_ENABLE;
+	p.Scope = DICS_FLAG_GLOBAL;
+	if (SetupDiSetClassInstallParams(info, dev_info_data, &p.ClassInstallHeader, sizeof(p)))
+	{
+		SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, info, dev_info_data);
+	}
+
+	Zero(&p, sizeof(p));
+	p.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+	p.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
+	p.StateChange = DICS_ENABLE;
+	p.Scope = DICS_FLAG_CONFIGSPECIFIC;
+
+	if (SetupDiSetClassInstallParams(info, dev_info_data, &p.ClassInstallHeader, sizeof(p)) == false ||
+		SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, info, dev_info_data) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 指定したデバイスを停止させる
+bool MsStopDevice(HDEVINFO info, SP_DEVINFO_DATA *dev_info_data)
+{
+	SP_PROPCHANGE_PARAMS p;
+	// 引数チェック
+	if (info == NULL || dev_info_data == NULL)
+	{
+		return false;
+	}
+
+	Zero(&p, sizeof(p));
+	p.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+	p.ClassInstallHeader.InstallFunction = DIF_PROPERTYCHANGE;
+	p.StateChange = DICS_DISABLE;
+	p.Scope = DICS_FLAG_CONFIGSPECIFIC;
+
+	if (SetupDiSetClassInstallParams(info, dev_info_data, &p.ClassInstallHeader, sizeof(p)) == false ||
+		SetupDiCallClassInstaller(DIF_PROPERTYCHANGE, info, dev_info_data) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 指定したデバイスを削除する
+bool MsDeleteDevice(HDEVINFO info, SP_DEVINFO_DATA *dev_info_data)
+{
+	SP_REMOVEDEVICE_PARAMS p;
+	SP_DEVINFO_LIST_DETAIL_DATA detail;
+	char device_id[MAX_PATH];
+	// 引数チェック
+	if (info == NULL || dev_info_data == NULL)
+	{
+		return false;
+	}
+
+	Zero(&detail, sizeof(detail));
+	detail.cbSize = sizeof(detail);
+
+	if (SetupDiGetDeviceInfoListDetail(info, &detail) == false ||
+		ms->nt->CM_Get_Device_ID_Ex(dev_info_data->DevInst, device_id, sizeof(device_id),
+		0, detail.RemoteMachineHandle) != CR_SUCCESS)
+	{
+		return false;
+	}
+
+	Zero(&p, sizeof(p));
+	p.ClassInstallHeader.cbSize = sizeof(SP_CLASSINSTALL_HEADER);
+	p.ClassInstallHeader.InstallFunction = DIF_REMOVE;
+	p.Scope = DI_REMOVEDEVICE_GLOBAL;
+
+	if (SetupDiSetClassInstallParams(info, dev_info_data, &p.ClassInstallHeader, sizeof(p)) == false)
+	{
+		Debug("SetupDiSetClassInstallParams Failed. Err=%u\n", GetLastError());
+		return false;
+	}
+
+	if (SetupDiCallClassInstaller(DIF_REMOVE, info, dev_info_data) == false)
+	{
+		Debug("SetupDiCallClassInstaller Failed. Err=%u\n", GetLastError());
+		return false;
+	}
+
+	return true;
+}
+
+// 仮想 LAN カードを有効にする
+bool MsEnableVLan(char *instance_name)
+{
+	char tmp[MAX_PATH];
+	HDEVINFO h;
+	bool ret;
+	SP_DEVINFO_DATA data;
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return false;
+	}
+
+	Format(tmp, sizeof(tmp), DRIVER_DEVICE_ID_TAG, instance_name);
+
+	h = MsGetDevInfoFromDeviceId(&data, tmp);
+	if (h == NULL)
+	{
+		return false;
+	}
+
+	ret = MsStartDevice(h, &data);
+
+	MsDestroyDevInfo(h);
+
+	return ret;
+}
+
+// 仮想 LAN カードを無効にする
+bool MsDisableVLan(char *instance_name)
+{
+	char tmp[MAX_PATH];
+	HDEVINFO h;
+	bool ret;
+	SP_DEVINFO_DATA data;
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return false;
+	}
+
+	Format(tmp, sizeof(tmp), DRIVER_DEVICE_ID_TAG, instance_name);
+
+	h = MsGetDevInfoFromDeviceId(&data, tmp);
+	if (h == NULL)
+	{
+		return false;
+	}
+
+	ret = MsStopDevice(h, &data);
+
+	MsDestroyDevInfo(h);
+
+	return ret;
+}
+
+// 仮想 LAN カードを再起動する
+void MsRestartVLan(char *instance_name)
+{
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return;
+	}
+
+	if (MsIsVLanEnabled(instance_name) == false)
+	{
+		return;
+	}
+
+	MsDisableVLan(instance_name);
+	MsEnableVLan(instance_name);
+}
+
+// 仮想 LAN カードが動作しているかどうか取得する
+bool MsIsVLanEnabled(char *instance_name)
+{
+	char tmp[MAX_PATH];
+	HDEVINFO h;
+	bool ret;
+	SP_DEVINFO_DATA data;
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return true;
+	}
+
+	Format(tmp, sizeof(tmp), DRIVER_DEVICE_ID_TAG, instance_name);
+
+	h = MsGetDevInfoFromDeviceId(&data, tmp);
+	if (h == NULL)
+	{
+		return false;
+	}
+
+	ret = MsIsDeviceRunning(h, &data);
+
+	MsDestroyDevInfo(h);
+
+	return ret;
+}
+
+// 仮想 LAN カードをアンインストールする
+bool MsUninstallVLan(char *instance_name)
+{
+	char tmp[MAX_PATH];
+	HDEVINFO h;
+	bool ret;
+	SP_DEVINFO_DATA data;
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return false;
+	}
+
+	Format(tmp, sizeof(tmp), DRIVER_DEVICE_ID_TAG, instance_name);
+
+	h = MsGetDevInfoFromDeviceId(&data, tmp);
+	if (h == NULL)
+	{
+		return false;
+	}
+
+	ret = MsDeleteDevice(h, &data);
+
+	MsDestroyDevInfo(h);
+
+	return ret;
+}
+
+// 汎用テスト関数
+void MsTest()
+{
+}
+
+// デバイス情報の破棄
+void MsDestroyDevInfo(HDEVINFO info)
+{
+	// 引数チェック
+	if (info == NULL)
+	{
+		return;
+	}
+
+	SetupDiDestroyDeviceInfoList(info);
+}
+
+// ドライバインストールの開始
+bool MsStartDriverInstall(char *instance_name, UCHAR *mac_address, char *sen_sys)
+{
+	wchar_t src_inf[MAX_PATH];
+	wchar_t src_sys[MAX_PATH];
+	wchar_t dest_inf[MAX_PATH];
+	wchar_t dest_sys[MAX_PATH];
+	UCHAR mac_address_bin[6];
+	char mac_address_str[32];
+	UINT size;
+	char *tmp;
+	BUF *b;
+	IO *io;
+	// 引数チェック
+	if (instance_name == NULL || sen_sys == NULL)
+	{
+		return false;
+	}
+
+	MsGetDriverPath(instance_name, src_inf, src_sys, dest_inf, dest_sys, sen_sys);
+
+	// INF ファイルの処理
+	io = FileOpenW(src_inf, false);
+	if (io == NULL)
+	{
+		return false;
+	}
+
+	size = FileSize(io);
+	tmp = ZeroMalloc(size * 2);
+	if (FileRead(io, tmp, size) == false)
+	{
+		FileClose(io);
+		Free(tmp);
+		return false;
+	}
+
+	FileClose(io);
+
+	if (mac_address == NULL)
+	{
+		MsGenMacAddress(mac_address_bin);
+	}
+	else
+	{
+		Copy(mac_address_bin, mac_address, 6);
+	}
+
+	BinToStr(mac_address_str, sizeof(mac_address_str), mac_address_bin, sizeof(mac_address_bin));
+
+	//ReplaceStrEx(tmp, size * 2, tmp, "$TAG_DRIVER_VER$", DRIVER_VER_STR, false);
+	ReplaceStrEx(tmp, size * 2, tmp, "$TAG_INSTANCE_NAME$", instance_name, false);
+	ReplaceStrEx(tmp, size * 2, tmp, "$TAG_MAC_ADDRESS$", mac_address_str, false);
+	ReplaceStrEx(tmp, size * 2, tmp, "$TAG_SYS_NAME$", sen_sys, false);
+
+	if (MsIsVista())
+	{
+		//ReplaceStrEx(tmp, size * 2, tmp, "\"100\"", "\"2000\"", false);
+	}
+
+	io = FileCreateW(dest_inf);
+	if (io == NULL)
+	{
+		Free(tmp);
+		return false;
+	}
+
+	FileWrite(io, tmp, StrLen(tmp));
+	FileClose(io);
+
+	Free(tmp);
+
+	// SYS ファイルの処理
+	b = ReadDumpW(src_sys);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	if (DumpBufW(b, dest_sys) == false)
+	{
+		FreeBuf(b);
+		return false;
+	}
+
+	FreeBuf(b);
+
+	return true;
+}
+
+// MAC アドレスの生成
+void MsGenMacAddress(UCHAR *mac)
+{
+	UCHAR hash_src[40];
+	UCHAR hash[20];
+	UINT64 now;
+	// 引数チェック
+	if (mac == NULL)
+	{
+		return;
+	}
+
+	Rand(hash_src, 40);
+	now = SystemTime64();
+	Copy(hash_src, &now, sizeof(now));
+
+	Hash(hash, hash_src, sizeof(hash_src), true);
+
+	mac[0] = 0x00;
+	mac[1] = 0xAC;
+	mac[2] = hash[0];
+	mac[3] = hash[1];
+	mac[4] = hash[2];
+	mac[5] = hash[3];
+}
+
+// ドライバインストールの完了
+void MsFinishDriverInstall(char *instance_name, char *sen_sys)
+{
+	wchar_t src_inf[MAX_PATH];
+	wchar_t src_sys[MAX_PATH];
+	wchar_t dest_inf[MAX_PATH];
+	wchar_t dest_sys[MAX_PATH];
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return;
+	}
+
+	MsGetDriverPath(instance_name, src_inf, src_sys, dest_inf, dest_sys, sen_sys);
+
+	// ファイル削除
+	FileDeleteW(dest_inf);
+	FileDeleteW(dest_sys);
+}
+
+// ドライバファイルのパスの取得
+void MsGetDriverPath(char *instance_name, wchar_t *src_inf, wchar_t *src_sys, wchar_t *dest_inf, wchar_t *dest_sys, char *sen_sys)
+{
+	wchar_t *src_filename;
+	wchar_t *src_sys_filename;
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return;
+	}
+
+	src_filename = DRIVER_INF_FILE_NAME;
+	src_sys_filename = DRIVER_SYS_FILE_NAME;
+
+	if (MsIsNt() == false)
+	{
+		src_filename = DRIVER_INF_FILE_NAME_9X;
+		src_sys_filename = DRIVER_SYS_FILE_NAME_9X;
+	}
+	else if (MsIsIA64() || MsIsX64())
+	{
+		if (MsIsX64())
+		{
+			src_filename = DRIVER_INF_FILE_NAME_X64;
+			src_sys_filename = DRIVER_SYS_FILE_NAME_X64;
+		}
+		else
+		{
+			src_filename = DRIVER_INF_FILE_NAME_IA64;
+			src_sys_filename = DRIVER_SYS_FILE_NAME_IA64;
+		}
+	}
+
+	if (src_inf != NULL)
+	{
+		UniStrCpy(src_inf, MAX_PATH, src_filename);
+	}
+
+	if (src_sys != NULL)
+	{
+		UniStrCpy(src_sys, MAX_PATH, src_sys_filename);
+	}
+
+	if (dest_inf != NULL)
+	{
+		char inf_name[MAX_PATH];
+		Format(inf_name, sizeof(inf_name), DRIVER_INSTALL_INF_NAME_TAG, instance_name);
+		UniFormat(dest_inf, MAX_PATH, L"%s\\%S", ms->MyTempDirW, inf_name);
+	}
+
+	if (dest_sys != NULL)
+	{
+		char sys_name[MAX_PATH];
+		StrCpy(sys_name, sizeof(sys_name), sen_sys);
+		UniFormat(dest_sys, MAX_PATH, L"%s\\%S", ms->MyTempDirW, sys_name);
+	}
+}
+void MsGetDriverPathA(char *instance_name, char *src_inf, char *src_sys, char *dest_inf, char *dest_sys, char *sen_sys)
+{
+	wchar_t src_inf_w[MAX_PATH];
+	wchar_t src_sys_w[MAX_PATH];
+	wchar_t dest_inf_w[MAX_PATH];
+	wchar_t dest_sys_w[MAX_PATH];
+
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		return;
+	}
+
+	MsGetDriverPath(instance_name, src_inf_w, src_sys_w, dest_inf_w, dest_sys_w, sen_sys);
+
+	UniToStr(src_inf, MAX_PATH, src_inf_w);
+	UniToStr(src_sys, MAX_PATH, src_sys_w);
+	UniToStr(dest_inf, MAX_PATH, dest_inf_w);
+	UniToStr(dest_sys, MAX_PATH, dest_sys_w);
+}
+
+// 指定された名前の仮想 LAN カードがすでに登録されているかどうかを調べる
+bool MsIsVLanExists(char *tag_name, char *instance_name)
+{
+	char *guid;
+	// 引数チェック
+	if (instance_name == NULL || tag_name == NULL)
+	{
+		return false;
+	}
+
+	guid = MsGetNetworkAdapterGuid(tag_name, instance_name);
+	if (guid == NULL)
+	{
+		return false;
+	}
+
+	Free(guid);
+	return true;
+}
+
+// ネットワーク設定ダイアログを表示する
+// ※ これはもう使っていない。うまく動かないからである。
+//    代わりに ShowWindowsNetworkConnectionDialog() を使うこと。
+bool MsShowNetworkConfiguration(HWND hWnd)
+{
+	IO *link_file = MsCreateTempFileByExt(".lnk");
+	char name[MAX_PATH];
+	SHELLEXECUTEINFO info;
+
+	// ファイル名確保
+	StrCpy(name, sizeof(name), link_file->Name);
+
+	// ショートカット作成
+	if (FileWrite(link_file, network_connection_link, sizeof(network_connection_link)) == false)
+	{
+		FileCloseAndDelete(link_file);
+		return false;
+	}
+
+	FileClose(link_file);
+
+	// ショートカットの実行
+	Zero(&info, sizeof(info));
+	info.cbSize = sizeof(info);
+	info.hwnd = (HWND)hWnd;
+	info.lpVerb = "open";
+	info.lpFile = name;
+	info.nShow = SW_SHOWDEFAULT;
+	info.fMask = SEE_MASK_NOCLOSEPROCESS;
+	if (ShellExecuteEx(&info) == false)
+	{
+		FileDelete(name);
+		return false;
+	}
+
+	// プロセス終了まで待機
+	WaitForSingleObject(info.hProcess, INFINITE);
+	CloseHandle(info.hProcess);
+
+	// ファイルの削除
+	FileDelete(name);
+
+	return true;
+}
+
+// 拡張子を元に一時ファイルを作成する
+IO *MsCreateTempFileByExt(char *ext)
+{
+	char *tmp = MsCreateTempFileNameByExt(ext);
+	IO *ret;
+
+	if (tmp == NULL)
+	{
+		return NULL;
+	}
+
+	ret = FileCreate(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// 拡張子を指定するとその拡張子を持つ一時ファイルを作成する
+char *MsCreateTempFileNameByExt(char *ext)
+{
+	UCHAR rand[2];
+	char *ret = NULL;
+	// 引数チェック
+	if (ext == NULL)
+	{
+		ext = "tmp";
+	}
+	if (ext[0] == '.')
+	{
+		ext++;
+	}
+	if (StrLen(ext) == 0)
+	{
+		ext = "tmp";
+	}
+
+	while (true)
+	{
+		char new_filename[MAX_PATH];
+		char *fullpath;
+		char rand_str[MAX_PATH];
+		IO *io;
+		Rand(rand, sizeof(rand));
+
+		BinToStr(rand_str, sizeof(rand_str), rand, sizeof(rand));
+		Format(new_filename, sizeof(new_filename), "__%s.%s", rand_str, ext);
+
+		fullpath = MsCreateTempFileName(new_filename);
+		io = FileOpen(fullpath, false);
+		if (io == NULL)
+		{
+			ret = fullpath;
+			break;
+		}
+		FileClose(io);
+
+		Free(fullpath);
+	}
+
+	return ret;
+}
+
+// 一時ファイルを作成する
+IO *MsCreateTempFile(char *name)
+{
+	IO *ret;
+	char *tmp;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	tmp = MsCreateTempFileName(name);
+	if (tmp == NULL)
+	{
+		return NULL;
+	}
+
+	ret = FileCreate(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// 一時ファイル名を作成する
+char *MsCreateTempFileName(char *name)
+{
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	Format(tmp, sizeof(tmp), "%s\\%s", ms->MyTempDir, name);
+
+	return CopyStr(tmp);
+}
+
+// システムに残っているが使用されていない VPN 用一時ディレクトリを削除する
+void MsDeleteTempDir()
+{
+	HANDLE h;
+	wchar_t dir_mask[MAX_PATH];
+	WIN32_FIND_DATAA data_a;
+	WIN32_FIND_DATAW data_w;
+
+	Zero(&data_a, sizeof(data_a));
+	Zero(&data_w, sizeof(data_w));
+
+	UniFormat(dir_mask, sizeof(dir_mask), L"%s\\*", ms->TempDirW);
+
+	if (IsNt())
+	{
+		h = FindFirstFileW(dir_mask, &data_w);
+	}
+	else
+	{
+		char *tmp_a = CopyUniToStr(dir_mask);
+
+		h = FindFirstFileA(tmp_a, &data_a);
+
+		Free(tmp_a);
+	}
+
+	if (h != INVALID_HANDLE_VALUE)
+	{
+		bool b = true;
+
+		do
+		{
+			if (IsNt() == false)
+			{
+				Zero(&data_w, sizeof(data_w));
+				StrToUni(data_w.cFileName, sizeof(data_w.cFileName), data_a.cFileName);
+				data_w.dwFileAttributes = data_a.dwFileAttributes;
+				data_w.ftCreationTime = data_a.ftCreationTime;
+				data_w.ftLastWriteTime = data_a.ftLastWriteTime;
+				data_w.nFileSizeHigh = data_a.nFileSizeHigh;
+				data_w.nFileSizeLow = data_a.nFileSizeLow;
+			}
+
+			if (UniStrCmpi(data_w.cFileName, L".") != 0 &&
+				UniStrCmpi(data_w.cFileName, L"..") != 0)
+			{
+				if (data_w.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+				{
+					if (UniStartWith(data_w.cFileName, L"VPN_") && UniStrLen(data_w.cFileName) == 8)
+					{
+						wchar_t lock_file_name[MAX_PATH];
+						wchar_t dir_name[MAX_PATH];
+						bool delete_now = false;
+						IO *io;
+
+						UniFormat(dir_name, sizeof(dir_name), L"%s\\%s",
+							ms->TempDirW, data_w.cFileName);
+						MsGenLockFile(lock_file_name, sizeof(lock_file_name), dir_name);
+
+						io = FileOpenExW(lock_file_name, false, false);
+						if (io != NULL)
+						{
+							// ロックファイルがロックされていなければ削除マーク
+							FileClose(io);
+							io = FileOpenW(lock_file_name, true);
+							if (io != NULL)
+							{
+								delete_now = true;
+								FileClose(io);
+							}
+						}
+						else
+						{
+							DIRLIST *d;
+
+							// 中にあるすべてのファイルがロックされていなければ削除マーク
+							delete_now = true;
+
+							d = EnumDirW(dir_name);
+							if (d != NULL)
+							{
+								UINT i;
+
+								for (i = 0;i < d->NumFiles;i++)
+								{
+									wchar_t full_path[MAX_PATH];
+
+									UniFormat(full_path, sizeof(full_path), L"%s\\%s", dir_name, d->File[i]->FileNameW);
+
+									io = FileOpenW(full_path, true);
+									if (io != NULL)
+									{
+										delete_now = true;
+										FileClose(io);
+									}
+								}
+								FreeDir(d);
+							}
+						}
+						if (delete_now)
+						{
+							MsDeleteAllFileW(dir_name);
+
+							Win32DeleteDirW(dir_name);
+						}
+					}
+				}
+			}
+
+
+			Zero(&data_w, sizeof(data_w));
+			Zero(&data_a, sizeof(data_a));
+
+			if (IsNt())
+			{
+				b = FindNextFileW(h, &data_w);
+			}
+			else
+			{
+				b = FindNextFileA(h, &data_a);
+			}
+		}
+		while (b);
+
+		FindClose(h);
+	}
+}
+
+// 指定したディレクトリ内のファイルをすべて削除する
+void MsDeleteAllFile(char *dir)
+{
+	HANDLE h;
+	char file_mask[MAX_PATH];
+	WIN32_FIND_DATA data;
+	// 引数チェック
+	if (dir == NULL || IsEmptyStr(dir))
+	{
+		return;
+	}
+
+	Format(file_mask, sizeof(file_mask), "%s\\*.*", dir);
+
+	h = FindFirstFile(file_mask, &data);
+	if (h != INVALID_HANDLE_VALUE)
+	{
+		do
+		{
+			if (StrCmpi(data.cFileName, ".") != 0 &&
+				StrCmpi(data.cFileName, "..") != 0)
+			{
+				char fullpath[MAX_PATH];
+				Format(fullpath, sizeof(fullpath), "%s\\%s", dir, data.cFileName);
+				if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == false)
+				{
+					DeleteFile(fullpath);
+				}
+				else
+				{
+					MsDeleteAllFile(fullpath);
+					RemoveDirectory(fullpath);
+				}
+			}
+		}
+		while (FindNextFile(h, &data));
+
+		FindClose(h);
+	}
+}
+void MsDeleteAllFileW(wchar_t *dir)
+{
+	HANDLE h;
+	wchar_t file_mask[MAX_PATH];
+	WIN32_FIND_DATAW data;
+	// 引数チェック
+	if (dir == NULL || UniIsEmptyStr(dir))
+	{
+		return;
+	}
+
+	if (IsNt() == false)
+	{
+		char *dir_a = CopyUniToStr(dir);
+
+		MsDeleteAllFile(dir_a);
+
+		Free(dir_a);
+
+		return;
+	}
+
+	UniFormat(file_mask, sizeof(file_mask), L"%s\\*.*", dir);
+
+	h = FindFirstFileW(file_mask, &data);
+	if (h != INVALID_HANDLE_VALUE)
+	{
+		do
+		{
+			if (UniStrCmpi(data.cFileName, L".") != 0 &&
+				UniStrCmpi(data.cFileName, L"..") != 0)
+			{
+				wchar_t fullpath[MAX_PATH];
+
+				UniFormat(fullpath, sizeof(fullpath), L"%s\\%s", dir, data.cFileName);
+
+				if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == false)
+				{
+					DeleteFileW(fullpath);
+				}
+				else
+				{
+					MsDeleteAllFileW(fullpath);
+					RemoveDirectoryW(fullpath);
+				}
+			}
+		}
+		while (FindNextFileW(h, &data));
+
+		FindClose(h);
+	}
+}
+
+// 一時ディレクトリを初期化する
+void MsInitTempDir()
+{
+	wchar_t tmp[MAX_PATH];
+	wchar_t tmp2[16];
+	UCHAR random[2];
+	wchar_t lockfilename[MAX_PATH];
+	UINT num = 0;
+
+	// 使われていない一時ディレクトリの削除
+	MsDeleteTempDir();
+
+	// 一時ディレクトリ名の決定
+	while (true)
+	{
+		random[0] = rand() % 256;
+		random[1] = rand() % 256;
+		BinToStrW(tmp2, sizeof(tmp2), random, sizeof(random));
+
+		UniFormat(tmp, sizeof(tmp), L"%s\\VPN_%s", ms->TempDirW, tmp2);
+
+		// ディレクトリの作成
+		if (MakeDirW(tmp))
+		{
+			break;
+		}
+
+		if ((num++) >= 100)
+		{
+			// 何度も失敗する
+			char msg[MAX_SIZE];
+			Format(msg, sizeof(msg),
+				"Couldn't create Temporary Directory: %s\r\n\r\n"
+				"Please contact your system administrator.",
+				tmp);
+			exit(0);
+		}
+	}
+
+	ms->MyTempDirW = CopyUniStr(tmp);
+	ms->MyTempDir = CopyUniToStr(tmp);
+
+	// ロックファイルの作成
+	MsGenLockFile(lockfilename, sizeof(lockfilename), ms->MyTempDirW);
+	ms->LockFile = FileCreateW(lockfilename);
+}
+
+// 一時ディレクトリを解放する
+void MsFreeTempDir()
+{
+	wchar_t lock_file_name[MAX_SIZE];
+
+	// ロックファイルの削除
+	MsGenLockFile(lock_file_name, sizeof(lock_file_name), ms->MyTempDirW);
+	FileClose(ms->LockFile);
+
+	// メモリ解放
+	Free(ms->MyTempDir);
+	Free(ms->MyTempDirW);
+	ms->MyTempDir = NULL;
+	ms->MyTempDirW = NULL;
+
+	// ディレクトリ削除
+	MsDeleteTempDir();
+}
+
+// ロックファイル名の生成
+void MsGenLockFile(wchar_t *name, UINT size, wchar_t *temp_dir)
+{
+	// 引数チェック
+	if (name == NULL || temp_dir == NULL)
+	{
+		return;
+	}
+
+	UniFormat(name, size, L"%s\\VPN_Lock.dat", temp_dir);
+}
+
+// ネットワーク設定の初期化
+void MsInitNetworkConfig(char *tag_name, char *instance_name, char *connection_tag_name)
+{
+	char tmp[MAX_SIZE];
+	char *config_str;
+	// 引数チェック
+	if (tag_name == NULL || instance_name == NULL || connection_tag_name == NULL)
+	{
+		return;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return;
+	}
+
+	// 文字列などの設定
+	Format(tmp, sizeof(tmp), connection_tag_name, instance_name);
+	MsSetNetworkConfig(tag_name, instance_name, tmp, true);
+
+	// インターフェイス・メトリック値の設定
+	config_str = MsGetNetworkAdapterGuid(tag_name, instance_name);
+	if (config_str != NULL)
+	{
+		Format(tmp, sizeof(tmp), "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
+			config_str);
+
+		MsRegWriteInt(REG_LOCAL_MACHINE, tmp, "InterfaceMetric", 1);
+		MsRegWriteInt(REG_LOCAL_MACHINE, tmp, "EnableDeadGWDetect", 0);
+
+		if (MsRegReadInt(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+			"packetix_no_optimize") == 0)
+		{
+			MsRegWriteInt(REG_LOCAL_MACHINE,
+				"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
+				"EnableDeadGWDetect",
+				0);
+		}
+
+		Free(config_str);
+	}
+}
+
+// ネットワーク設定を行う
+void MsSetNetworkConfig(char *tag_name, char *instance_name, char *friendly_name, bool show_icon)
+{
+	char *key;
+	char *old_name;
+	// 引数チェック
+	if (tag_name == NULL || instance_name == NULL || friendly_name == NULL)
+	{
+		return;
+	}
+
+	key = MsGetNetworkConfigRegKeyNameFromInstanceName(tag_name, instance_name);
+	if (key == NULL)
+	{
+		return;
+	}
+
+	old_name = MsRegReadStr(REG_LOCAL_MACHINE, key, "Name");
+	if (old_name != NULL)
+	{
+		if (MsIsVista())
+		{
+			char arg[MAX_PATH];
+			char netsh[MAX_PATH];
+
+			Format(netsh, sizeof(netsh), "%s\\netsh.exe", MsGetSystem32Dir());
+
+			if (StrCmp(old_name, friendly_name) != 0)
+			{
+				Format(arg, sizeof(arg), "interface set interface name=\"%s\" newname=\"%s\"",
+					old_name, friendly_name);
+
+				Run(netsh, arg, true, true);
+			}
+
+			Format(arg, sizeof(arg), "netsh interface ipv4 set interface interface=\"%s\" metric=1",
+				friendly_name);
+
+			Run(netsh, arg, true, true);
+		}
+	}
+
+	if (StrCmp(old_name, friendly_name) != 0)
+	{
+		MsRegWriteStr(REG_LOCAL_MACHINE, key, "Name", friendly_name);
+	}
+
+	MsRegWriteInt(REG_LOCAL_MACHINE, key, "ShowIcon", show_icon ? 1 : 0);
+
+	Free(key);
+
+	Free(old_name);
+}
+
+// ネットワーク設定キー名をインスタンス名から取得
+char *MsGetNetworkConfigRegKeyNameFromInstanceName(char *tag_name, char *instance_name)
+{
+	char *guid, *ret;
+	// 引数チェック
+	if (tag_name == NULL || instance_name == NULL)
+	{
+		return NULL;
+	}
+
+	guid = MsGetNetworkAdapterGuid(tag_name, instance_name);
+	if (guid == NULL)
+	{
+		return NULL;
+	}
+
+	ret = MsGetNetworkConfigRegKeyNameFromGuid(guid);
+
+	Free(guid);
+
+	return ret;
+}
+
+// ネットワーク設定キー名を GUID から取得
+char *MsGetNetworkConfigRegKeyNameFromGuid(char *guid)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (guid == NULL)
+	{
+		return NULL;
+	}
+
+	Format(tmp, sizeof(tmp),
+		"SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection",
+		guid);
+
+	return CopyStr(tmp);
+}
+
+// MAC アドレスの設定
+void MsSetMacAddress(char *tag_name, char *instance_name, char *mac_address)
+{
+	TOKEN_LIST *key_list;
+	UINT i;
+	char dest_name[MAX_SIZE];
+	char mac_str[MAX_SIZE];
+	// 引数チェック
+	if (tag_name == NULL || instance_name == NULL)
+	{
+		return;
+	}
+
+	// MAC アドレスの正規化
+	if (NormalizeMacAddress(mac_str, sizeof(mac_str), mac_address) == false)
+	{
+		return;
+	}
+
+	// 目的の名前を生成
+	Format(dest_name, sizeof(dest_name), tag_name, instance_name);
+
+	// キーを列挙
+	if (MsIsNt())
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}");
+	}
+	else
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"System\\CurrentControlSet\\Services\\Class\\Net");
+	}
+	if (key_list == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < key_list->NumTokens;i++)
+	{
+		char *key_name = key_list->Token[i];
+		char full_key_name[MAX_SIZE];
+		char *driver_desc;
+
+		if (MsIsNt())
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\%s",
+				key_name);
+		}
+		else
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"System\\CurrentControlSet\\Services\\Class\\Net\\%s",
+				key_name);
+		}
+
+		// DriverDesc を読み込む
+		driver_desc = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DriverDesc");
+		if (driver_desc != NULL)
+		{
+			if (StrCmpi(dest_name, driver_desc) == 0)
+			{
+				// MAC アドレスの書き込み
+				MsRegWriteStr(REG_LOCAL_MACHINE, full_key_name, "NetworkAddress", mac_str);
+				Free(driver_desc);
+
+				// ドライバの再起動
+				MsRestartVLan(instance_name);
+				break;
+			}
+			Free(driver_desc);
+		}
+	}
+
+	FreeToken(key_list);
+
+	return;
+}
+
+// デバイスドライバのファイル名の取得
+char *MsGetDriverFileName(char *tag_name, char *instance_name)
+{
+	TOKEN_LIST *key_list;
+	UINT i;
+	char *ret = NULL;
+	char dest_name[MAX_SIZE];
+	// 引数チェック
+	if (tag_name == NULL || instance_name == NULL)
+	{
+		return NULL;
+	}
+
+	// 目的の名前を生成
+	Format(dest_name, sizeof(dest_name), tag_name, instance_name);
+
+	// キーを列挙
+	if (MsIsNt())
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}");
+	}
+	else
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"System\\CurrentControlSet\\Services\\Class\\Net");
+	}
+	if (key_list == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < key_list->NumTokens;i++)
+	{
+		char *key_name = key_list->Token[i];
+		char full_key_name[MAX_SIZE];
+		char *driver_desc;
+
+		if (MsIsNt())
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\%s",
+				key_name);
+		}
+		else
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"System\\CurrentControlSet\\Services\\Class\\Net\\%s",
+				key_name);
+		}
+
+		// DriverDesc を読み込む
+		driver_desc = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DriverDesc");
+		if (driver_desc != NULL)
+		{
+			if (StrCmpi(dest_name, driver_desc) == 0)
+			{
+				// ファイル名を読み込む
+				ret = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DeviceVxDs");
+				Free(driver_desc);
+				break;
+			}
+			Free(driver_desc);
+		}
+	}
+
+	FreeToken(key_list);
+
+	return ret;
+}
+
+// デバイスドライバのバージョンの取得
+char *MsGetDriverVersion(char *tag_name, char *instance_name)
+{
+	TOKEN_LIST *key_list;
+	TOKEN_LIST *t;
+	UINT i;
+	char *ret = NULL;
+	char dest_name[MAX_SIZE];
+	// 引数チェック
+	if (tag_name == NULL || instance_name == NULL)
+	{
+		return NULL;
+	}
+
+	// 目的の名前を生成
+	Format(dest_name, sizeof(dest_name), tag_name, instance_name);
+
+	// キーを列挙
+	if (MsIsNt())
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}");
+	}
+	else
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"System\\CurrentControlSet\\Services\\Class\\Net");
+	}
+	if (key_list == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < key_list->NumTokens;i++)
+	{
+		char *key_name = key_list->Token[i];
+		char full_key_name[MAX_SIZE];
+		char *driver_desc;
+
+		if (MsIsNt())
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\%s",
+				key_name);
+		}
+		else
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"System\\CurrentControlSet\\Services\\Class\\Net\\%s",
+				key_name);
+		}
+
+		// DriverDesc を読み込む
+		driver_desc = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DriverDesc");
+		if (driver_desc != NULL)
+		{
+			if (StrCmpi(dest_name, driver_desc) == 0)
+			{
+				// バージョン情報を読み込む
+				ret = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DriverVersion");
+				if (ret == NULL)
+				{
+					ret = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "SenVersion");
+				}
+				Free(driver_desc);
+				break;
+			}
+			Free(driver_desc);
+		}
+	}
+
+	FreeToken(key_list);
+
+	if (ret == NULL)
+	{
+		return NULL;
+	}
+
+	t = ParseToken(ret, ", ");
+	if (t->NumTokens == 2)
+	{
+		Free(ret);
+		ret = CopyStr(t->Token[1]);
+	}
+	FreeToken(t);
+
+	return ret;
+}
+
+// MAC アドレスの取得
+char *MsGetMacAddress(char *tag_name, char *instance_name)
+{
+	TOKEN_LIST *key_list;
+	UINT i;
+	char *ret = NULL;
+	char dest_name[MAX_SIZE];
+	// 引数チェック
+	if (tag_name == NULL || instance_name == NULL)
+	{
+		return NULL;
+	}
+
+	// 目的の名前を生成
+	Format(dest_name, sizeof(dest_name), tag_name, instance_name);
+
+	// キーを列挙
+	if (MsIsNt())
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}");
+	}
+	else
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"System\\CurrentControlSet\\Services\\Class\\Net");
+	}
+
+	if (key_list == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < key_list->NumTokens;i++)
+	{
+		char *key_name = key_list->Token[i];
+		char full_key_name[MAX_SIZE];
+		char *driver_desc;
+
+		if (MsIsNt())
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\%s",
+				key_name);
+		}
+		else
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"System\\CurrentControlSet\\Services\\Class\\Net\\%s",
+				key_name);
+		}
+
+		// DriverDesc を読み込む
+		driver_desc = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DriverDesc");
+		if (driver_desc != NULL)
+		{
+			if (StrCmpi(dest_name, driver_desc) == 0)
+			{
+				// MAC アドレスを読み込む
+				ret = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "NetworkAddress");
+
+				if (IsEmptyStr(ret) == false)
+				{
+					// MAC アドレスにハイフンを入れる
+					BUF *b = StrToBin(ret);
+					if (b != NULL && b->Size == 6)
+					{
+						char tmp[MAX_SIZE];
+						MacToStr(tmp, sizeof(tmp), b->Buf);
+
+						Free(ret);
+						ret = CopyStr(tmp);
+					}
+					FreeBuf(b);
+				}
+
+				Free(driver_desc);
+				break;
+			}
+			Free(driver_desc);
+		}
+	}
+
+	FreeToken(key_list);
+
+	return ret;
+}
+
+// 仮想 LAN カードのデバイス名が本当に存在するかどうかチェックする
+bool MsCheckVLanDeviceIdFromRootEnum(char *name)
+{
+	TOKEN_LIST *t;
+	char *root;
+	char *keyname;
+	UINT i;
+	bool ret;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt())
+	{
+		root = "SYSTEM\\CurrentControlSet\\Enum\\Root\\NET";
+		keyname = "HardwareID";
+	}
+	else
+	{
+		root = "Enum\\Root\\Net";
+		keyname = "CompatibleIDs";
+	}
+
+	t = MsRegEnumKey(REG_LOCAL_MACHINE, root);
+	if (t == NULL)
+	{
+		return false;
+	}
+
+	ret = false;
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		char *subname = t->Token[i];
+		char fullname[MAX_SIZE];
+		char *value;
+
+		Format(fullname, sizeof(fullname), "%s\\%s", root, subname);
+
+		value = MsRegReadStr(REG_LOCAL_MACHINE, fullname, keyname);
+		if (value != NULL)
+		{
+			if (StrCmpi(value, name) == 0)
+			{
+				ret = true;
+			}
+			Free(value);
+		}
+
+		if (ret)
+		{
+			break;
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// ネットワークアダプタの GUID の取得
+char *MsGetNetworkAdapterGuid(char *tag_name, char *instance_name)
+{
+	TOKEN_LIST *key_list;
+	UINT i;
+	char *ret = NULL;
+	char dest_name[MAX_SIZE];
+	// 引数チェック
+	if (tag_name == NULL || instance_name == NULL)
+	{
+		return NULL;
+	}
+
+	// 目的の名前を生成
+	Format(dest_name, sizeof(dest_name), tag_name, instance_name);
+
+	// キーを列挙
+	if (MsIsNt())
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}");
+	}
+	else
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"System\\CurrentControlSet\\Services\\Class\\Net");
+	}
+	if (key_list == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < key_list->NumTokens;i++)
+	{
+		char *key_name = key_list->Token[i];
+		char full_key_name[MAX_SIZE];
+		char *driver_desc;
+		char *device_id;
+
+		if (MsIsNt())
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\%s",
+				key_name);
+		}
+		else
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"System\\CurrentControlSet\\Services\\Class\\Net\\%s",
+				key_name);
+		}
+
+		device_id = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "MatchingDeviceId");
+
+		if (device_id != NULL)
+		{
+			if (MsCheckVLanDeviceIdFromRootEnum(device_id))
+			{
+				// DriverDesc を読み込む
+				driver_desc = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DriverDesc");
+				if (driver_desc != NULL)
+				{
+					if (StrCmpi(dest_name, driver_desc) == 0)
+					{
+						// NetCfgInstanceId を読み込む
+						if (MsIsNt())
+						{
+							ret = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "NetCfgInstanceId");
+						}
+						else
+						{
+							ret = CopyStr("");
+						}
+						Free(driver_desc);
+						Free(device_id);
+						break;
+					}
+					Free(driver_desc);
+				}
+			}
+			Free(device_id);
+		}
+	}
+
+	FreeToken(key_list);
+
+	return ret;
+}
+// ネットワーク接続名の取得
+wchar_t *MsGetNetworkConnectionName(char *guid)
+{
+	wchar_t *ncname = NULL;
+	// 引数チェック
+	if (guid == NULL)
+	{
+		return NULL;
+	}
+
+	// ネットワーク接続名を取得
+	if (IsNt() != false && GetOsInfo()->OsType >= OSTYPE_WINDOWS_2000_PROFESSIONAL)
+	{
+		char tmp[MAX_SIZE];
+		Format(tmp, sizeof(tmp), "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", guid);
+		ncname = MsRegReadStrW(REG_LOCAL_MACHINE, tmp, "Name");
+	}
+
+	return ncname;
+}
+
+// 新しい Sen のドライバファイル名を生成
+bool MsMakeNewSenDriverFilename(char *name, UINT size)
+{
+	TOKEN_LIST *t = MsEnumSenDriverFilenames();
+	UINT i;
+	bool ret = false;
+
+	i = 0;
+	while (true)
+	{
+		char tmp[MAX_PATH];
+		UINT n;
+
+		i++;
+		if (i >= 10000)
+		{
+			break;
+		}
+
+		n = Rand32() % DRIVER_INSTALL_SYS_NAME_TAG_MAXID;
+
+		MsGenerateSenDriverFilenameFromInt(tmp, sizeof(tmp), n);
+
+		if (IsInToken(t, tmp) == false)
+		{
+			StrCpy(name, size, tmp);
+			ret = true;
+			break;
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// Sen のドライバファイル名を整数から生成
+void MsGenerateSenDriverFilenameFromInt(char *name, UINT size, UINT n)
+{
+	Format(name, size, DRIVER_INSTALL_SYS_NAME_TAG_NEW, n);
+}
+
+// インストールされている Sen のドライバファイル名の列挙
+TOKEN_LIST *MsEnumSenDriverFilenames()
+{
+	TOKEN_LIST *neos = MsEnumNetworkAdaptersSen();
+	LIST *o = NewListFast(NULL);
+	TOKEN_LIST *ret;
+	UINT i;
+
+	for (i = 0;i < neos->NumTokens;i++)
+	{
+		char filename[MAX_PATH];
+		if (MsGetSenDeiverFilename(filename, sizeof(filename), neos->Token[i]))
+		{
+			Add(o, CopyStr(filename));
+		}
+	}
+
+	FreeToken(neos);
+
+	ret = ListToTokenList(o);
+	FreeStrList(o);
+
+	return ret;
+}
+
+// Sen のドライバファイル名を取得
+bool MsGetSenDeiverFilename(char *name, UINT size, char *instance_name)
+{
+	char tmp[MAX_SIZE];
+	char *ret;
+	// 引数チェック
+	if (name == NULL || instance_name == NULL)
+	{
+		return false;
+	}
+
+	Format(tmp, sizeof(tmp), "SYSTEM\\CurrentControlSet\\Services\\Sen_%s", instance_name);
+
+	ret = MsRegReadStr(REG_LOCAL_MACHINE, tmp, "ImagePath");
+	if (ret == NULL)
+	{
+		return false;
+	}
+
+	GetFileNameFromFilePath(name, size, ret);
+	Free(ret);
+
+	return true;
+}
+
+// ネットワークアダプタの列挙 (Sen のみ)
+TOKEN_LIST *MsEnumNetworkAdaptersSen()
+{
+	TOKEN_LIST *key_list;
+	TOKEN_LIST *ret;
+	LIST *o;
+	UINT i;
+
+	// キーを列挙
+	if (MsIsNt())
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}");
+	}
+	else
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"System\\CurrentControlSet\\Services\\Class\\Net");
+	}
+	if (key_list == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(CompareStr);
+
+	for (i = 0;i < key_list->NumTokens;i++)
+	{
+		char *key_name = key_list->Token[i];
+		char full_key_name[MAX_SIZE];
+		char *driver_desc;
+		char *device_id;
+
+		if (MsIsNt())
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\%s",
+				key_name);
+		}
+		else
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"System\\CurrentControlSet\\Services\\Class\\Net\\%s",
+				key_name);
+		}
+
+		// DriverDesc を読み込む
+		driver_desc = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DriverDesc");
+		if (driver_desc != NULL)
+		{
+			// 特定の名前で始まっているかどうか確認する
+			device_id = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "MatchingDeviceId");
+
+			if (device_id != NULL)
+			{
+				if (MsCheckVLanDeviceIdFromRootEnum(device_id))
+				{
+					char *tag = "senadapter_";
+					if (StartWith(device_id, tag))
+					{
+						char tmp[MAX_SIZE];
+						StrCpy(tmp, sizeof(tmp), &device_id[StrLen(tag)]);
+
+						Add(o, CopyStr(tmp));
+					}
+				}
+				Free(device_id);
+			}
+
+			Free(driver_desc);
+		}
+	}
+
+	FreeToken(key_list);
+
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->NumTokens = LIST_NUM(o);
+	ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+	for (i = 0;i < ret->NumTokens;i++)
+	{
+		ret->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+
+	return ret;
+}
+
+// ネットワークアダプタの列挙
+TOKEN_LIST *MsEnumNetworkAdapters(char *start_with_name, char *start_with_name_2)
+{
+	TOKEN_LIST *key_list;
+	TOKEN_LIST *ret;
+	LIST *o;
+	UINT i;
+
+	// キーを列挙
+	if (MsIsNt())
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}");
+	}
+	else
+	{
+		key_list = MsRegEnumKey(REG_LOCAL_MACHINE,
+			"System\\CurrentControlSet\\Services\\Class\\Net");
+	}
+	if (key_list == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(CompareStr);
+
+	for (i = 0;i < key_list->NumTokens;i++)
+	{
+		char *key_name = key_list->Token[i];
+		char full_key_name[MAX_SIZE];
+		char *driver_desc;
+		char *device_id;
+
+		if (MsIsNt())
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002bE10318}\\%s",
+				key_name);
+		}
+		else
+		{
+			Format(full_key_name, sizeof(full_key_name),
+				"System\\CurrentControlSet\\Services\\Class\\Net\\%s",
+				key_name);
+		}
+
+		// DriverDesc を読み込む
+		driver_desc = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "DriverDesc");
+		if (driver_desc != NULL)
+		{
+			// 特定の名前で始まっているかどうか確認する
+			if ((IsEmptyStr(start_with_name) && IsEmptyStr(start_with_name_2)) ||
+				(StartWith(driver_desc, start_with_name) || StartWith(driver_desc, start_with_name_2)))
+			{
+				device_id = MsRegReadStr(REG_LOCAL_MACHINE, full_key_name, "MatchingDeviceId");
+
+				if (device_id != NULL)
+				{
+					if (MsCheckVLanDeviceIdFromRootEnum(device_id))
+					{
+						char instance_name[MAX_SIZE];
+						// 名前からインスタンス名だけを抽出する
+						if (StartWith(driver_desc, start_with_name))
+						{
+							if (StrLen(driver_desc) > (StrLen(start_with_name) + 3))
+							{
+								StrCpy(instance_name, sizeof(instance_name),
+									driver_desc + StrLen(start_with_name) + 3);
+								Add(o, CopyStr(instance_name));
+							}
+						}
+						else
+						{
+							if (StrLen(driver_desc) > (StrLen(start_with_name_2) + 3))
+							{
+								StrCpy(instance_name, sizeof(instance_name),
+									driver_desc + StrLen(start_with_name_2) + 3);
+								Add(o, CopyStr(instance_name));
+							}
+						}
+					}
+					Free(device_id);
+				}
+			}
+
+			Free(driver_desc);
+		}
+	}
+
+	FreeToken(key_list);
+
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->NumTokens = LIST_NUM(o);
+	ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+	for (i = 0;i < ret->NumTokens;i++)
+	{
+		ret->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+
+	return ret;
+}
+
+// ドメインへのログオンを試行する
+bool MsCheckLogon(wchar_t *username, char *password)
+{
+	wchar_t password_unicode[MAX_SIZE];
+	HANDLE h;
+	// 引数チェック
+	if (username == NULL || password == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return false;
+	}
+
+	StrToUni(password_unicode, sizeof(password_unicode), password);
+
+	if (GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+	{
+		if (ms->nt->LogonUserW(username, NULL, password_unicode, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &h) == false)
+		{
+			// ログオン失敗
+			return false;
+		}
+	}
+	else
+	{
+		char username_ansi[MAX_SIZE];
+		UniToStr(username_ansi, sizeof(username_ansi), username);
+
+		if (ms->nt->LogonUserA(username_ansi, NULL, password, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &h) == false)
+		{
+			// ログオン失敗
+			return false;
+		}
+	}
+
+	CloseHandle(h);
+
+	return true;
+}
+
+// ドメインへのログオンを試行する
+bool MsIsPasswordEmpty(wchar_t *username)
+{
+	HANDLE h;
+	// 引数チェック
+	if (username == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() == false)
+	{
+		return false;
+	}
+
+	if (GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+	{
+		if (ms->nt->LogonUserW(username, NULL, L"", LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &h) == false)
+		{
+			// ログオン失敗
+			if (GetLastError() == 1327)
+			{
+				// パスワードが空
+				return true;
+			}
+			else
+			{
+				// パスワードが間違っている
+				return false;
+			}
+		}
+	}
+	else
+	{
+		char username_ansi[MAX_SIZE];
+		UniToStr(username_ansi, sizeof(username_ansi), username);
+
+		if (ms->nt->LogonUserA(username_ansi, NULL, "", LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &h) == false)
+		{
+			// ログオン失敗
+			if (GetLastError() == 1327)
+			{
+				// パスワードが空
+				return true;
+			}
+			else
+			{
+				// パスワードが間違っている
+				return false;
+			}
+		}
+	}
+
+	CloseHandle(h);
+
+	// ログオン成功ということはパスワードが空ということになる
+	return false;
+}
+
+// シャットダウンの実行 (NT)
+bool MsShutdownEx(bool reboot, bool force, UINT time_limit, char *message)
+{
+	if (MsIsNt() == false)
+	{
+		return MsShutdown(reboot, force);
+	}
+
+	// 特権の取得
+	if (MsEnablePrivilege(SE_SHUTDOWN_NAME, true) == false)
+	{
+		return false;
+	}
+
+	// シャットダウンの実行
+	if (ms->nt->InitiateSystemShutdown(NULL, message, time_limit, force, reboot) == false)
+	{
+		MsEnablePrivilege(SE_SHUTDOWN_NAME, false);
+		return false;
+	}
+
+	// 特権の解放
+	MsEnablePrivilege(SE_SHUTDOWN_NAME, false);
+
+	return true;
+}
+
+// シャットダウンの実行
+bool MsShutdown(bool reboot, bool force)
+{
+	UINT flag = 0;
+	// 特権の取得
+	if (MsEnablePrivilege(SE_SHUTDOWN_NAME, true) == false)
+	{
+		return false;
+	}
+
+	flag |= (reboot ? EWX_REBOOT : EWX_SHUTDOWN);
+	flag |= (force ? EWX_FORCE : 0);
+
+	// シャットダウンの実行
+	if (ExitWindowsEx(flag, 0) == false)
+	{
+		MsEnablePrivilege(SE_SHUTDOWN_NAME, false);
+		return false;
+	}
+
+	// 特権の解放
+	MsEnablePrivilege(SE_SHUTDOWN_NAME, false);
+
+	return true;
+}
+
+// 特権を有効または無効にする
+bool MsEnablePrivilege(char *name, bool enable)
+{
+	HANDLE hToken;
+	NT_API *nt = ms->nt;
+	LUID luid;
+	TOKEN_PRIVILEGES *tp;
+	bool ret;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+	if (MsIsNt() == false)
+	{
+		return true;
+	}
+
+	// プロセストークンを開く
+	if (nt->OpenProcessToken(ms->hCurrentProcess, TOKEN_ADJUST_PRIVILEGES, &hToken) == false)
+	{
+		return false;
+	}
+
+	// ローカル一意識別子を取得する
+	if (nt->LookupPrivilegeValue(NULL, name, &luid) == FALSE)
+	{
+		CloseHandle(hToken);
+		return false;
+	}
+
+	// 特権を有効 / 無効にするための構造体を作成する
+	tp = ZeroMalloc(sizeof(TOKEN_PRIVILEGES));
+	tp->PrivilegeCount = 1;
+	tp->Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
+	Copy(&tp->Privileges[0].Luid, &luid, sizeof(LUID));
+
+	// 特権を操作する
+	ret = nt->AdjustTokenPrivileges(hToken, false, tp, sizeof(TOKEN_PRIVILEGES), 0, 0);
+
+	Free(tp);
+	CloseHandle(hToken);
+
+	return ret;
+}
+
+// 現在の OS が NT 系かどうか取得
+bool MsIsNt()
+{
+	if (ms == NULL)
+	{
+		OSVERSIONINFO os;
+		Zero(&os, sizeof(os));
+		os.dwOSVersionInfoSize = sizeof(os);
+		GetVersionEx(&os);
+		if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	return ms->IsNt;
+}
+
+// 現在のユーザーが Admin かどうか取得
+bool MsIsAdmin()
+{
+	return ms->IsAdmin;
+}
+
+// NT 系関数のロード
+NT_API *MsLoadNtApiFunctions()
+{
+	NT_API *nt = ZeroMalloc(sizeof(NT_API));
+	OSVERSIONINFO info;
+
+	Zero(&info, sizeof(info));
+	info.dwOSVersionInfoSize = sizeof(info);
+	GetVersionEx(&info);
+
+	nt->hKernel32 = LoadLibrary("kernel32.dll");
+	if (nt->hKernel32 == NULL)
+	{
+		Free(nt);
+		return NULL;
+	}
+
+	nt->hAdvapi32 = LoadLibrary("advapi32.dll");
+	if (nt->hAdvapi32 == NULL)
+	{
+		Free(nt);
+		return NULL;
+	}
+
+	nt->hShell32 = LoadLibrary("shell32.dll");
+	if (nt->hShell32 == NULL)
+	{
+		FreeLibrary(nt->hAdvapi32);
+		Free(nt);
+		return NULL;
+	}
+
+	nt->hPsApi = LoadLibrary("psapi.dll");
+
+	if (info.dwMajorVersion >= 5)
+	{
+		nt->hNewDev = LoadLibrary("newdev.dll");
+		if (nt->hNewDev == NULL)
+		{
+			FreeLibrary(nt->hShell32);
+			FreeLibrary(nt->hAdvapi32);
+			Free(nt);
+			return NULL;
+		}
+
+		nt->hSetupApi = LoadLibrary("setupapi.dll");
+	}
+
+	nt->hSecur32 = LoadLibrary("secur32.dll");
+
+	nt->hUser32 = LoadLibrary("user32.dll");
+
+	nt->hDbgHelp = LoadLibrary("dbghelp.dll");
+
+	// 関数の読み込み
+	nt->IsWow64Process =
+		(BOOL (__stdcall *)(HANDLE,BOOL *))
+		GetProcAddress(nt->hKernel32, "IsWow64Process");
+
+	nt->GetFileInformationByHandle =
+		(BOOL (__stdcall *)(HANDLE,LPBY_HANDLE_FILE_INFORMATION))
+		GetProcAddress(nt->hKernel32, "GetFileInformationByHandle");
+
+	nt->GetProcessHeap =
+		(HANDLE (__stdcall *)())
+		GetProcAddress(nt->hKernel32, "GetProcessHeap");
+
+	nt->SetProcessShutdownParameters =
+		(BOOL (__stdcall *)(DWORD,DWORD))
+		GetProcAddress(nt->hKernel32, "SetProcessShutdownParameters");
+
+	nt->GetNativeSystemInfo =
+		(void (__stdcall *)(SYSTEM_INFO *))
+		GetProcAddress(nt->hKernel32, "GetNativeSystemInfo");
+
+	nt->AdjustTokenPrivileges =
+		(BOOL (__stdcall *)(HANDLE,BOOL,PTOKEN_PRIVILEGES,DWORD,PTOKEN_PRIVILEGES,PDWORD))
+		GetProcAddress(nt->hAdvapi32, "AdjustTokenPrivileges");
+
+	nt->LookupPrivilegeValue =
+		(BOOL (__stdcall *)(char *,char *,PLUID))
+		GetProcAddress(nt->hAdvapi32, "LookupPrivilegeValueA");
+
+	nt->OpenProcessToken =
+		(BOOL (__stdcall *)(HANDLE,DWORD,PHANDLE))
+		GetProcAddress(nt->hAdvapi32, "OpenProcessToken");
+
+	nt->InitiateSystemShutdown =
+		(BOOL (__stdcall *)(LPTSTR,LPTSTR,DWORD,BOOL,BOOL))
+		GetProcAddress(nt->hAdvapi32, "InitiateSystemShutdownA");
+
+	nt->LogonUserW =
+		(BOOL (__stdcall *)(wchar_t *,wchar_t *,wchar_t *,DWORD,DWORD,HANDLE *))
+		GetProcAddress(nt->hAdvapi32, "LogonUserW");
+
+	nt->LogonUserA =
+		(BOOL (__stdcall *)(char *,char *,char *,DWORD,DWORD,HANDLE * ))
+		GetProcAddress(nt->hAdvapi32, "LogonUserA");
+
+	nt->DuplicateTokenEx =
+		(BOOL (__stdcall *)(HANDLE,DWORD,SECURITY_ATTRIBUTES *,SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,HANDLE *))
+		GetProcAddress(nt->hAdvapi32, "DuplicateTokenEx");
+
+	nt->ConvertStringSidToSidA =
+		(BOOL (__stdcall *)(LPCSTR,PSID *))
+		GetProcAddress(nt->hAdvapi32, "ConvertStringSidToSidA");
+
+	nt->GetTokenInformation =
+		(BOOL (__stdcall *)(HANDLE,TOKEN_INFORMATION_CLASS,void *,DWORD,PDWORD))
+		GetProcAddress(nt->hAdvapi32, "GetTokenInformation");
+
+	nt->SetTokenInformation =
+		(BOOL (__stdcall *)(HANDLE,TOKEN_INFORMATION_CLASS,void *,DWORD))
+		GetProcAddress(nt->hAdvapi32, "SetTokenInformation");
+
+	nt->CreateProcessAsUserA =
+		(BOOL (__stdcall *)(HANDLE,LPCSTR,LPSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,void *,LPCSTR,LPSTARTUPINFOA,LPPROCESS_INFORMATION))
+		GetProcAddress(nt->hAdvapi32, "CreateProcessAsUserA");
+
+	nt->CreateProcessAsUserW =
+		(BOOL (__stdcall *)(HANDLE,LPCWSTR,LPWSTR,LPSECURITY_ATTRIBUTES,LPSECURITY_ATTRIBUTES,BOOL,DWORD,void *,LPCWSTR,LPSTARTUPINFOW,LPPROCESS_INFORMATION))
+		GetProcAddress(nt->hAdvapi32, "CreateProcessAsUserW");
+
+	nt->LookupAccountSidA =
+		(BOOL (__stdcall *)(LPCSTR,PSID,LPSTR,LPDWORD,LPSTR,LPDWORD,PSID_NAME_USE))
+		GetProcAddress(nt->hAdvapi32, "LookupAccountSidA");
+
+	nt->LookupAccountNameA =
+		(BOOL (__stdcall *)(LPCSTR,LPCSTR,PSID,LPDWORD,LPSTR,LPDWORD,PSID_NAME_USE))
+		GetProcAddress(nt->hAdvapi32, "LookupAccountNameA");
+
+	if (info.dwMajorVersion >= 5)
+	{
+		nt->UpdateDriverForPlugAndPlayDevicesW =
+			(BOOL (__stdcall *)(HWND,wchar_t *,wchar_t *,UINT,BOOL *))
+			GetProcAddress(nt->hNewDev, "UpdateDriverForPlugAndPlayDevicesW");
+
+		nt->CM_Get_Device_ID_ExA =
+			(UINT (__stdcall *)(DWORD,char *,UINT,UINT,HANDLE))
+			GetProcAddress(nt->hSetupApi, "CM_Get_Device_ID_ExA");
+
+		nt->CM_Get_DevNode_Status_Ex =
+			(UINT (__stdcall *)(UINT *,UINT *,DWORD,UINT,HANDLE))
+			GetProcAddress(nt->hSetupApi, "CM_Get_DevNode_Status_Ex");
+	}
+
+	nt->hWtsApi32 = LoadLibrary("wtsapi32.dll");
+	if (nt->hWtsApi32 != NULL)
+	{
+		// ターミナルサービス関係の API
+		nt->WTSQuerySessionInformation =
+			(UINT (__stdcall *)(HANDLE,DWORD,WTS_INFO_CLASS,wchar_t *,DWORD *))
+			GetProcAddress(nt->hWtsApi32, "WTSQuerySessionInformationW");
+		nt->WTSFreeMemory =
+			(void (__stdcall *)(void *))
+			GetProcAddress(nt->hWtsApi32, "WTSFreeMemory");
+		nt->WTSDisconnectSession =
+			(BOOL (__stdcall *)(HANDLE,DWORD,BOOL))
+			GetProcAddress(nt->hWtsApi32, "WTSDisconnectSession");
+		nt->WTSEnumerateSessionsA =
+			(BOOL (__stdcall *)(HANDLE,DWORD,DWORD,PWTS_SESSION_INFOA *,DWORD *))
+			GetProcAddress(nt->hWtsApi32, "WTSEnumerateSessionsA");
+	}
+
+	// サービス系 API
+	nt->OpenSCManager =
+		(SC_HANDLE (__stdcall *)(LPCTSTR,LPCTSTR,DWORD))
+		GetProcAddress(nt->hAdvapi32, "OpenSCManagerA");
+	nt->CreateServiceA =
+		(SC_HANDLE (__stdcall *)(SC_HANDLE,LPCTSTR,LPCTSTR,DWORD,DWORD,DWORD,DWORD,LPCTSTR,LPCTSTR,LPDWORD,LPCTSTR,LPCTSTR,LPCTSTR))
+		GetProcAddress(nt->hAdvapi32, "CreateServiceA");
+	nt->CreateServiceW =
+		(SC_HANDLE (__stdcall *)(SC_HANDLE,LPCWSTR,LPCWSTR,DWORD,DWORD,DWORD,DWORD,LPCWSTR,LPCWSTR,LPDWORD,LPCWSTR,LPCWSTR,LPCWSTR))
+		GetProcAddress(nt->hAdvapi32, "CreateServiceW");
+	nt->ChangeServiceConfig2 =
+		(BOOL (__stdcall *)(SC_HANDLE,DWORD,LPVOID))
+		GetProcAddress(nt->hAdvapi32, "ChangeServiceConfig2W");
+	nt->CloseServiceHandle =
+		(BOOL (__stdcall *)(SC_HANDLE))
+		GetProcAddress(nt->hAdvapi32, "CloseServiceHandle");
+	nt->OpenService =
+		(SC_HANDLE (__stdcall *)(SC_HANDLE,LPCTSTR,DWORD))
+		GetProcAddress(nt->hAdvapi32, "OpenServiceA");
+	nt->QueryServiceStatus =
+		(BOOL (__stdcall *)(SC_HANDLE,LPSERVICE_STATUS))
+		GetProcAddress(nt->hAdvapi32, "QueryServiceStatus");
+	nt->StartService =
+		(BOOL (__stdcall *)(SC_HANDLE,DWORD,LPCTSTR))
+		GetProcAddress(nt->hAdvapi32, "StartServiceA");
+	nt->ControlService =
+		(BOOL (__stdcall *)(SC_HANDLE,DWORD,LPSERVICE_STATUS))
+		GetProcAddress(nt->hAdvapi32, "ControlService");
+	nt->SetServiceStatus =
+		(BOOL (__stdcall *)(SERVICE_STATUS_HANDLE,LPSERVICE_STATUS))
+		GetProcAddress(nt->hAdvapi32, "SetServiceStatus");
+	nt->RegisterServiceCtrlHandler =
+		(SERVICE_STATUS_HANDLE (__stdcall *)(LPCTSTR,LPHANDLER_FUNCTION))
+		GetProcAddress(nt->hAdvapi32, "RegisterServiceCtrlHandlerW");
+	nt->StartServiceCtrlDispatcher =
+		(BOOL (__stdcall *)(const LPSERVICE_TABLE_ENTRY))
+		GetProcAddress(nt->hAdvapi32, "StartServiceCtrlDispatcherW");
+	nt->DeleteService =
+		(BOOL (__stdcall *)(SC_HANDLE))
+		GetProcAddress(nt->hAdvapi32, "DeleteService");
+	nt->RegisterEventSourceW =
+		(HANDLE (__stdcall *)(LPCWSTR,LPCWSTR))
+		GetProcAddress(nt->hAdvapi32, "RegisterEventSourceW");
+	nt->ReportEventW =
+		(BOOL (__stdcall *)(HANDLE,WORD,WORD,DWORD,PSID,WORD,DWORD,LPCWSTR *,LPVOID))
+		GetProcAddress(nt->hAdvapi32, "ReportEventW");
+	nt->DeregisterEventSource =
+		(BOOL (__stdcall *)(HANDLE))
+		GetProcAddress(nt->hAdvapi32, "DeregisterEventSource");
+	nt->Wow64DisableWow64FsRedirection =
+		(BOOL (__stdcall *)(void **))
+		GetProcAddress(nt->hKernel32, "Wow64DisableWow64FsRedirection");
+	nt->Wow64EnableWow64FsRedirection =
+		(BOOLEAN (__stdcall *)(BOOLEAN))
+		GetProcAddress(nt->hKernel32, "Wow64EnableWow64FsRedirection");
+	nt->Wow64RevertWow64FsRedirection =
+		(BOOL (__stdcall *)(void *))
+		GetProcAddress(nt->hKernel32, "Wow64RevertWow64FsRedirection");
+
+	if (nt->hPsApi != NULL)
+	{
+		// プロセス系 API
+		nt->EnumProcesses =
+			(BOOL (__stdcall *)(DWORD *,DWORD,DWORD *))
+			GetProcAddress(nt->hPsApi, "EnumProcesses");
+
+		nt->EnumProcessModules =
+			(BOOL (__stdcall *)(HANDLE,HMODULE * ,DWORD,DWORD *))
+			GetProcAddress(nt->hPsApi, "EnumProcessModules");
+
+		nt->GetModuleFileNameExA =
+			(DWORD (__stdcall *)(HANDLE,HMODULE,LPSTR,DWORD))
+			GetProcAddress(nt->hPsApi, "GetModuleFileNameExA");
+
+		nt->GetModuleFileNameExW =
+			(DWORD (__stdcall *)(HANDLE,HMODULE,LPWSTR,DWORD))
+			GetProcAddress(nt->hPsApi, "GetModuleFileNameExW");
+	}
+
+	// レジストリ系 API
+	nt->RegDeleteKeyExA =
+		(LONG (__stdcall *)(HKEY,LPCTSTR,REGSAM,DWORD))
+		GetProcAddress(nt->hAdvapi32, "RegDeleteKeyExA");
+
+	// セキュリティ系 API
+	if (nt->hSecur32 != NULL)
+	{
+		nt->GetUserNameExA =
+			(BOOL (__stdcall *)(EXTENDED_NAME_FORMAT,LPSTR,PULONG))
+			GetProcAddress(nt->hSecur32, "GetUserNameExA");
+
+		nt->GetUserNameExW =
+			(BOOL (__stdcall *)(EXTENDED_NAME_FORMAT,LPWSTR,PULONG))
+			GetProcAddress(nt->hSecur32, "GetUserNameExW");
+	}
+
+	// デスクトップ系 API
+	if (nt->hUser32 != NULL)
+	{
+		nt->SwitchDesktop =
+			(BOOL (__stdcall *)(HDESK))
+			GetProcAddress(nt->hUser32, "SwitchDesktop");
+		nt->OpenDesktopA =
+			(HDESK (__stdcall *)(LPTSTR,DWORD,BOOL,ACCESS_MASK))
+			GetProcAddress(nt->hUser32, "OpenDesktopA");
+		nt->CloseDesktop =
+			(BOOL (__stdcall *)(HDESK))
+			GetProcAddress(nt->hUser32, "CloseDesktop");
+	}
+
+	// デバッグ系 API
+	if (nt->hDbgHelp != NULL)
+	{
+		nt->MiniDumpWriteDump =
+			(BOOL (__stdcall *)(HANDLE,DWORD,HANDLE,MINIDUMP_TYPE,PMINIDUMP_EXCEPTION_INFORMATION,PMINIDUMP_USER_STREAM_INFORMATION,PMINIDUMP_CALLBACK_INFORMATION))
+			GetProcAddress(nt->hDbgHelp, "MiniDumpWriteDump");
+	}
+
+	return nt;
+}
+
+// NT 系関数の解放
+void MsFreeNtApiFunctions(NT_API *nt)
+{
+	// 引数チェック
+	if (nt == NULL)
+	{
+		return;
+	}
+
+	if (nt->hSecur32 != NULL)
+	{
+		FreeLibrary(nt->hSecur32);
+	}
+
+	if (nt->hNewDev != NULL)
+	{
+		FreeLibrary(nt->hSetupApi);
+		FreeLibrary(nt->hNewDev);
+	}
+
+	FreeLibrary(nt->hAdvapi32);
+
+	FreeLibrary(nt->hShell32);
+
+	if (nt->hWtsApi32 != NULL)
+	{
+		FreeLibrary(nt->hWtsApi32);
+	}
+
+	if (nt->hPsApi != NULL)
+	{
+		FreeLibrary(nt->hPsApi);
+	}
+
+	if (nt->hUser32 != NULL)
+	{
+		FreeLibrary(nt->hUser32);
+	}
+
+	if (nt->hDbgHelp != NULL)
+	{
+		FreeLibrary(nt->hDbgHelp);
+	}
+
+	FreeLibrary(nt->hKernel32);
+
+	Free(nt);
+}
+
+// 64 bit アプリケーションのために 32 bit レジストリキーへのアクセスを強制するアクセスマスクを生成する
+DWORD MsRegAccessMaskFor64Bit(bool force32bit)
+{
+	return MsRegAccessMaskFor64BitEx(force32bit, false);
+}
+DWORD MsRegAccessMaskFor64BitEx(bool force32bit, bool force64bit)
+{
+	if (MsIs64BitWindows() == false)
+	{
+		return 0;
+	}
+	if (force32bit)
+	{
+		return KEY_WOW64_32KEY;
+	}
+	if (force64bit)
+	{
+		return KEY_WOW64_64KEY;
+	}
+
+	return 0;
+}
+
+// 値の削除
+bool MsRegDeleteValue(UINT root, char *keyname, char *valuename)
+{
+	return MsRegDeleteValueEx(root, keyname, valuename, false);
+}
+bool MsRegDeleteValueEx(UINT root, char *keyname, char *valuename, bool force32bit)
+{
+	return MsRegDeleteValueEx2(root, keyname, valuename, force32bit, false);
+}
+bool MsRegDeleteValueEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	bool ret;
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return false;
+	}
+
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_ALL_ACCESS | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	if (RegDeleteValue(h, valuename) != ERROR_SUCCESS)
+	{
+		ret = false;
+	}
+	else
+	{
+		ret = true;
+	}
+
+	RegCloseKey(h);
+
+	return ret;
+}
+
+// キーの削除
+bool MsRegDeleteKey(UINT root, char *keyname)
+{
+	return MsRegDeleteKeyEx(root, keyname, false);
+}
+bool MsRegDeleteKeyEx(UINT root, char *keyname, bool force32bit)
+{
+	return MsRegDeleteKeyEx2(root, keyname, force32bit, false);
+}
+bool MsRegDeleteKeyEx2(UINT root, char *keyname, bool force32bit, bool force64bit)
+{
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return false;
+	}
+
+	if (MsIsNt() && ms->nt->RegDeleteKeyExA != NULL)
+	{
+		if (ms->nt->RegDeleteKeyExA(MsGetRootKeyFromInt(root), keyname, MsRegAccessMaskFor64BitEx(force32bit, force64bit), 0) != ERROR_SUCCESS)
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if (RegDeleteKey(MsGetRootKeyFromInt(root), keyname) != ERROR_SUCCESS)
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// 値の列挙
+TOKEN_LIST *MsRegEnumValue(UINT root, char *keyname)
+{
+	return MsRegEnumValueEx(root, keyname, false);
+}
+TOKEN_LIST *MsRegEnumValueEx(UINT root, char *keyname, bool force32bit)
+{
+	return MsRegEnumValueEx2(root, keyname, force32bit, false);
+}
+TOKEN_LIST *MsRegEnumValueEx2(UINT root, char *keyname, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	UINT i;
+	TOKEN_LIST *t;
+	LIST *o;
+
+	if (keyname == NULL)
+	{
+		h = MsGetRootKeyFromInt(root);
+	}
+	else
+	{
+		if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_READ | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+		{
+			return NULL;
+		}
+	}
+
+	o = NewListFast(CompareStr);
+
+	for (i = 0;;i++)
+	{
+		char tmp[MAX_SIZE];
+		UINT ret;
+		UINT size = sizeof(tmp);
+
+		Zero(tmp, sizeof(tmp));
+		ret = RegEnumValue(h, i, tmp, &size, NULL, NULL, NULL, NULL);
+		if (ret == ERROR_NO_MORE_ITEMS)
+		{
+			break;
+		}
+		else if (ret != ERROR_SUCCESS)
+		{
+			break;
+		}
+
+		Add(o, CopyStr(tmp));
+	}
+
+	Sort(o);
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+
+	if (keyname != NULL)
+	{
+		RegCloseKey(h);
+	}
+
+	return t;
+}
+
+// キーの列挙
+TOKEN_LIST *MsRegEnumKey(UINT root, char *keyname)
+{
+	return MsRegEnumKeyEx(root, keyname, false);
+}
+TOKEN_LIST *MsRegEnumKeyEx(UINT root, char *keyname, bool force32bit)
+{
+	return MsRegEnumKeyEx2(root, keyname, force32bit, false);
+}
+TOKEN_LIST *MsRegEnumKeyEx2(UINT root, char *keyname, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	UINT i;
+	TOKEN_LIST *t;
+	LIST *o;
+
+	if (keyname == NULL)
+	{
+		h = MsGetRootKeyFromInt(root);
+	}
+	else
+	{
+		if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_READ | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+		{
+			return NULL;
+		}
+	}
+
+	o = NewListFast(CompareStr);
+
+	for (i = 0;;i++)
+	{
+		char tmp[MAX_SIZE];
+		UINT ret;
+		UINT size = sizeof(tmp);
+		FILETIME ft;
+
+		Zero(tmp, sizeof(tmp));
+		ret = RegEnumKeyEx(h, i, tmp, &size, NULL, NULL, NULL, &ft);
+		if (ret == ERROR_NO_MORE_ITEMS)
+		{
+			break;
+		}
+		else if (ret != ERROR_SUCCESS)
+		{
+			break;
+		}
+
+		Add(o, CopyStr(tmp));
+	}
+
+	Sort(o);
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+
+	if (keyname != NULL)
+	{
+		RegCloseKey(h);
+	}
+
+	return t;
+}
+
+// バイナリデータを設定する
+bool MsRegWriteBin(UINT root, char *keyname, char *valuename, void *data, UINT size)
+{
+	return MsRegWriteBinEx(root, keyname, valuename, data, size, false);
+}
+bool MsRegWriteBinEx(UINT root, char *keyname, char *valuename, void *data, UINT size, bool force32bit)
+{
+	return MsRegWriteBinEx2(root, keyname, valuename, data, size, force32bit, false);
+}
+bool MsRegWriteBinEx2(UINT root, char *keyname, char *valuename, void *data, UINT size, bool force32bit, bool force64bit)
+{
+	// 引数チェック
+	if (keyname == NULL || (size != 0 && data == NULL))
+	{
+		return false;
+	}
+
+	return MsRegWriteValueEx2(root, keyname, valuename, REG_BINARY, data, size, force32bit, force64bit);
+}
+
+// 整数値を設定する
+bool MsRegWriteInt(UINT root, char *keyname, char *valuename, UINT value)
+{
+	return MsRegWriteIntEx(root, keyname, valuename, value, false);
+}
+bool MsRegWriteIntEx(UINT root, char *keyname, char *valuename, UINT value, bool force32bit)
+{
+	return MsRegWriteIntEx2(root, keyname, valuename, value, force32bit, false);
+}
+bool MsRegWriteIntEx2(UINT root, char *keyname, char *valuename, UINT value, bool force32bit, bool force64bit)
+{
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return false;
+	}
+
+	// エンディアン補正
+	if (IsBigEndian())
+	{
+		value = Swap32(value);
+	}
+
+	return MsRegWriteValueEx2(root, keyname, valuename, REG_DWORD_LITTLE_ENDIAN, &value, sizeof(UINT), force32bit, force64bit);
+}
+
+// 文字列を設定する
+bool MsRegWriteStrExpand(UINT root, char *keyname, char *valuename, char *str)
+{
+	return MsRegWriteStrExpandEx(root, keyname, valuename, str, false);
+}
+bool MsRegWriteStrExpandEx(UINT root, char *keyname, char *valuename, char *str, bool force32bit)
+{
+	return MsRegWriteStrExpandEx2(root, keyname, valuename, str, force32bit, false);
+}
+bool MsRegWriteStrExpandEx2(UINT root, char *keyname, char *valuename, char *str, bool force32bit, bool force64bit)
+{
+	// 引数チェック
+	if (keyname == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	return MsRegWriteValueEx2(root, keyname, valuename, REG_EXPAND_SZ, str, StrSize(str), force32bit, force64bit);
+}
+bool MsRegWriteStrExpandW(UINT root, char *keyname, char *valuename, wchar_t *str)
+{
+	return MsRegWriteStrExpandExW(root, keyname, valuename, str, false);
+}
+bool MsRegWriteStrExpandExW(UINT root, char *keyname, char *valuename, wchar_t *str, bool force32bit)
+{
+	return MsRegWriteStrExpandEx2W(root, keyname, valuename, str, force32bit, false);
+}
+bool MsRegWriteStrExpandEx2W(UINT root, char *keyname, char *valuename, wchar_t *str, bool force32bit, bool force64bit)
+{
+	// 引数チェック
+	if (keyname == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	return MsRegWriteValueEx2W(root, keyname, valuename, REG_EXPAND_SZ, str, UniStrSize(str), force32bit, force64bit);
+}
+
+bool MsRegWriteStr(UINT root, char *keyname, char *valuename, char *str)
+{
+	return MsRegWriteStrEx(root, keyname, valuename, str, false);
+}
+bool MsRegWriteStrEx(UINT root, char *keyname, char *valuename, char *str, bool force32bit)
+{
+	return MsRegWriteStrEx2(root, keyname, valuename, str, force32bit, false);
+}
+bool MsRegWriteStrEx2(UINT root, char *keyname, char *valuename, char *str, bool force32bit, bool force64bit)
+{
+	// 引数チェック
+	if (keyname == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	return MsRegWriteValueEx2(root, keyname, valuename, REG_SZ, str, StrSize(str), force32bit, force64bit);
+}
+bool MsRegWriteStrW(UINT root, char *keyname, char *valuename, wchar_t *str)
+{
+	return MsRegWriteStrExW(root, keyname, valuename, str, false);
+}
+bool MsRegWriteStrExW(UINT root, char *keyname, char *valuename, wchar_t *str, bool force32bit)
+{
+	return MsRegWriteStrEx2W(root, keyname, valuename, str, force32bit, false);
+}
+bool MsRegWriteStrEx2W(UINT root, char *keyname, char *valuename, wchar_t *str, bool force32bit, bool force64bit)
+{
+	// 引数チェック
+	if (keyname == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	return MsRegWriteValueEx2W(root, keyname, valuename, REG_SZ, str, UniStrSize(str), force32bit, force64bit);
+}
+
+// 値を設定する
+bool MsRegWriteValue(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size)
+{
+	return MsRegWriteValueEx(root, keyname, valuename, type, data, size, false);
+}
+bool MsRegWriteValueEx(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size, bool force32bit)
+{
+	return MsRegWriteValueEx2(root, keyname, valuename, type, data, size, force32bit, false);
+}
+bool MsRegWriteValueEx2(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	// 引数チェック
+	if (keyname == NULL || (size != 0 && data == NULL))
+	{
+		return false;
+	}
+
+	// キーを作成する
+	MsRegNewKeyEx2(root, keyname, force32bit, force64bit);
+
+	// キーを開く
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_ALL_ACCESS | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	// 値を書き込む
+	if (RegSetValueEx(h, valuename, 0, type, data, size) != ERROR_SUCCESS)
+	{
+		RegCloseKey(h);
+		return false;
+	}
+
+	// キーを閉じる
+	RegCloseKey(h);
+
+	return true;
+}
+bool MsRegWriteValueW(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size)
+{
+	return MsRegWriteValueExW(root, keyname, valuename, type, data, size, false);
+}
+bool MsRegWriteValueExW(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size, bool force32bit)
+{
+	return MsRegWriteValueEx2W(root, keyname, valuename, type, data, size, force32bit, false);
+}
+bool MsRegWriteValueEx2W(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	wchar_t valuename_w[MAX_SIZE];
+	// 引数チェック
+	if (keyname == NULL || (size != 0 && data == NULL))
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		UINT size_a;
+		void *data_a;
+		bool ret;
+
+		if (type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ)
+		{
+			data_a = CopyUniToStr(data);
+			size_a = StrSize(data_a);
+		}
+		else
+		{
+			data_a = Clone(data, size);
+			size_a = size;
+		}
+
+		ret = MsRegWriteValueEx2(root, keyname, valuename, type, data_a, size_a, force32bit, force64bit);
+
+		Free(data_a);
+
+		return ret;
+	}
+
+	StrToUni(valuename_w, sizeof(valuename_w), valuename);
+
+	// キーを作成する
+	MsRegNewKeyEx2(root, keyname, force32bit, force64bit);
+
+	// キーを開く
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_ALL_ACCESS | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	// 値を書き込む
+	if (RegSetValueExW(h, valuename_w, 0, type, data, size) != ERROR_SUCCESS)
+	{
+		RegCloseKey(h);
+		return false;
+	}
+
+	// キーを閉じる
+	RegCloseKey(h);
+
+	return true;
+}
+
+// バイナリデータを取得する
+BUF *MsRegReadBin(UINT root, char *keyname, char *valuename)
+{
+	return MsRegReadBinEx(root, keyname, valuename, false);
+}
+BUF *MsRegReadBinEx(UINT root, char *keyname, char *valuename, bool force32bit)
+{
+	return MsRegReadBinEx2(root, keyname, valuename, force32bit, false);
+}
+BUF *MsRegReadBinEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit)
+{
+	char *ret;
+	UINT type, size;
+	BUF *b;
+	// 引数チェック
+	if (keyname == NULL || valuename == NULL)
+	{
+		return 0;
+	}
+
+	// 値を読み込む
+	if (MsRegReadValueEx2(root, keyname, valuename, &ret, &type, &size, force32bit, force64bit) == false)
+	{
+		return 0;
+	}
+
+	b = NewBuf();
+
+	WriteBuf(b, ret, size);
+	SeekBuf(b, 0, 0);
+
+	Free(ret);
+
+	return b;
+}
+
+// 整数値を取得する
+UINT MsRegReadInt(UINT root, char *keyname, char *valuename)
+{
+	return MsRegReadIntEx(root, keyname, valuename, false);
+}
+UINT MsRegReadIntEx(UINT root, char *keyname, char *valuename, bool force32bit)
+{
+	return MsRegReadIntEx2(root, keyname, valuename, force32bit, false);
+}
+UINT MsRegReadIntEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit)
+{
+	char *ret;
+	UINT type, size;
+	UINT value;
+	// 引数チェック
+	if (keyname == NULL || valuename == NULL)
+	{
+		return 0;
+	}
+
+	// 値を読み込む
+	if (MsRegReadValueEx2(root, keyname, valuename, &ret, &type, &size, force32bit, force64bit) == false)
+	{
+		return 0;
+	}
+
+	// 種類をチェックする
+	if (type != REG_DWORD_LITTLE_ENDIAN && type != REG_DWORD_BIG_ENDIAN)
+	{
+		// DWORD 以外である
+		Free(ret);
+		return 0;
+	}
+
+	// サイズをチェックする
+	if (size != sizeof(UINT))
+	{
+		Free(ret);
+		return 0;
+	}
+
+	Copy(&value, ret, sizeof(UINT));
+
+	Free(ret);
+
+	// エンディアン変換
+	if (IsLittleEndian())
+	{
+#ifdef	REG_DWORD_BIG_ENDIAN
+		if (type == REG_DWORD_BIG_ENDIAN)
+		{
+			value = Swap32(value);
+		}
+#endif	// REG_DWORD_BIG_ENDIAN
+	}
+	else
+	{
+#ifdef	REG_DWORD_LITTLE_ENDIAN_FLAG
+		if (type == REG_DWORD_LITTLE_ENDIAN_FLAG)
+		{
+			value = Swap32(value);
+		}
+#endif	// REG_DWORD_LITTLE_ENDIAN_FLAG
+	}
+
+	return value;
+}
+
+// 文字列リストを取得する
+LIST *MsRegReadStrList(UINT root, char *keyname, char *valuename)
+{
+	return MsRegReadStrListEx(root, keyname, valuename, false);
+}
+LIST *MsRegReadStrListEx(UINT root, char *keyname, char *valuename, bool force32bit)
+{
+	return MsRegReadStrListEx2(root, keyname, valuename, force32bit, false);
+}
+LIST *MsRegReadStrListEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit)
+{
+	LIST *o;
+	char *ret;
+	UINT type, size;
+	// 引数チェック
+	if (keyname == NULL || valuename == NULL)
+	{
+		return NULL;
+	}
+
+	// 値を読み込む
+	if (MsRegReadValueEx2(root, keyname, valuename, &ret, &type, &size, force32bit, force64bit) == false)
+	{
+		return NULL;
+	}
+
+	// 種類をチェックする
+	if (type != REG_MULTI_SZ)
+	{
+		// 文字列リスト以外である
+		Free(ret);
+		return NULL;
+	}
+
+	if (size < 2)
+	{
+		// サイズ不正
+		Free(ret);
+		return NULL;
+	}
+
+	if (ret[size - 1] != 0)
+	{
+		// データ不正
+		Free(ret);
+		return NULL;
+	}
+
+	// リスト作成
+	o = StrToStrList(ret, size);
+
+	Free(ret);
+
+	return o;
+}
+
+// 文字列を取得する
+char *MsRegReadStr(UINT root, char *keyname, char *valuename)
+{
+	return MsRegReadStrEx(root, keyname, valuename, false);
+}
+char *MsRegReadStrEx(UINT root, char *keyname, char *valuename, bool force32bit)
+{
+	return MsRegReadStrEx2(root, keyname, valuename, force32bit, false);
+}
+char *MsRegReadStrEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit)
+{
+	char *ret;
+	UINT type, size;
+	// 引数チェック
+	if (keyname == NULL || valuename == NULL)
+	{
+		return NULL;
+	}
+
+	// 値を読み込む
+	if (MsRegReadValueEx2(root, keyname, valuename, &ret, &type, &size, force32bit, force64bit) == false)
+	{
+		return NULL;
+	}
+
+	// 種類をチェックする
+	if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ)
+	{
+		// 文字列以外である
+		Free(ret);
+
+		if (type == REG_MULTI_SZ)
+		{
+			// 文字列リストである
+			LIST *o = MsRegReadStrList(root, keyname, valuename);
+			if (o != NULL)
+			{
+				if (LIST_NUM(o) >= 1)
+				{
+					ret = CopyStr(LIST_DATA(o, 0));
+					FreeStrList(o);
+					return ret;
+				}
+			}
+		}
+		return NULL;
+	}
+
+	if (size == 0)
+	{
+		// サイズ不正
+		Free(ret);
+
+		return CopyStr("");
+	}
+
+	if (ret[size - 1] != 0)
+	{
+		// データ不正
+		Free(ret);
+		return NULL;
+	}
+
+	return ret;
+}
+wchar_t *MsRegReadStrW(UINT root, char *keyname, char *valuename)
+{
+	return MsRegReadStrExW(root, keyname, valuename, false);
+}
+wchar_t *MsRegReadStrExW(UINT root, char *keyname, char *valuename, bool force32bit)
+{
+	return MsRegReadStrEx2W(root, keyname, valuename, force32bit, false);
+}
+wchar_t *MsRegReadStrEx2W(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit)
+{
+	wchar_t *ret;
+	UINT type, size;
+	// 引数チェック
+	if (keyname == NULL || valuename == NULL)
+	{
+		return NULL;
+	}
+
+	// 値を読み込む
+	if (MsRegReadValueEx2W(root, keyname, valuename, &ret, &type, &size, force32bit, force64bit) == false)
+	{
+		return NULL;
+	}
+
+	// 種類をチェックする
+	if (type != REG_SZ && type != REG_EXPAND_SZ)
+	{
+		// 文字列以外である
+		Free(ret);
+
+		return NULL;
+	}
+
+	if (ret[size / sizeof(wchar_t) - 1] != 0)
+	{
+		// データ不正
+		Free(ret);
+		return NULL;
+	}
+
+	return ret;
+}
+
+// 値を読み込む
+bool MsRegReadValue(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size)
+{
+	return MsRegReadValueEx(root, keyname, valuename, data, type, size, false);
+}
+bool MsRegReadValueEx(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size, bool force32bit)
+{
+	return MsRegReadValueEx2(root, keyname, valuename, data, type, size, force32bit, false);
+}
+bool MsRegReadValueEx2(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	UINT ret;
+	// 引数チェック
+	if (keyname == NULL || data == NULL || type == NULL || size == NULL)
+	{
+		return false;
+	}
+	*type = 0;
+	*size = 0;
+
+	// キーを開く
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_READ | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	// 値を開く
+	*data = ZeroMalloc(*size);
+	ret = RegQueryValueEx(h, valuename, 0, type, *data, size);
+
+	if (ret == ERROR_SUCCESS)
+	{
+		// 読み取り完了
+		RegCloseKey(h);
+		return true;
+	}
+
+	if (ret != ERROR_MORE_DATA)
+	{
+		// 変なエラーが発生した
+		Free(*data);
+		*data = NULL;
+		RegCloseKey(h);
+		return false;
+	}
+
+	// メモリを再確保してデータを取得
+	*data = ReAlloc(*data, *size);
+	ret = RegQueryValueEx(h, valuename, 0, type, *data, size);
+	if (ret != ERROR_SUCCESS)
+	{
+		// エラー発生
+		Free(*data);
+		*data = NULL;
+		RegCloseKey(h);
+	}
+
+	RegCloseKey(h);
+
+	return true;
+}
+bool MsRegReadValueW(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size)
+{
+	return MsRegReadValueExW(root, keyname, valuename, data, type, size, false);
+}
+bool MsRegReadValueExW(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size, bool force32bit)
+{
+	return MsRegReadValueEx2W(root, keyname, valuename, data, type, size, force32bit, false);
+}
+bool MsRegReadValueEx2W(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	UINT ret;
+	wchar_t valuename_w[MAX_SIZE];
+	// 引数チェック
+	if (keyname == NULL || data == NULL || type == NULL || size == NULL)
+	{
+		return false;
+	}
+	*type = 0;
+	*size = 0;
+
+	if (IsNt() == false)
+	{
+		bool ret;
+		void *data_a = NULL;
+		UINT type_a = 0, size_a = 0;
+
+		ret = MsRegReadValueEx2(root, keyname, valuename, &data_a, &type_a, &size_a, force32bit, force64bit);
+
+		if (ret != false)
+		{
+			if (type_a == REG_SZ || type_a == REG_MULTI_SZ || type_a == REG_EXPAND_SZ)
+			{
+				*data = CopyStrToUni(data_a);
+				Free(data_a);
+
+				size_a = UniStrSize(*data);
+			}
+			else
+			{
+				*data = data_a;
+			}
+
+			*type = type_a;
+			*size = size_a;
+		}
+
+		return ret;
+	}
+
+	StrToUni(valuename_w, sizeof(valuename_w), valuename);
+
+	// キーを開く
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_READ | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	// 値を開く
+	*data = ZeroMalloc(*size);
+	ret = RegQueryValueExW(h, valuename_w, 0, type, *data, size);
+
+	if (ret == ERROR_SUCCESS)
+	{
+		// 読み取り完了
+		RegCloseKey(h);
+		return true;
+	}
+
+	if (ret != ERROR_MORE_DATA)
+	{
+		// 変なエラーが発生した
+		Free(*data);
+		*data = NULL;
+		RegCloseKey(h);
+		return false;
+	}
+
+	// メモリを再確保してデータを取得
+	*data = ReAlloc(*data, *size);
+	ret = RegQueryValueExW(h, valuename_w, 0, type, *data, size);
+	if (ret != ERROR_SUCCESS)
+	{
+		// エラー発生
+		Free(*data);
+		*data = NULL;
+		RegCloseKey(h);
+	}
+
+	RegCloseKey(h);
+
+	return true;
+}
+
+// 値の種類とサイズを取得する
+bool MsRegGetValueTypeAndSize(UINT root, char *keyname, char *valuename, UINT *type, UINT *size)
+{
+	return MsRegGetValueTypeAndSizeEx(root, keyname, valuename, type, size, false);
+}
+bool MsRegGetValueTypeAndSizeEx(UINT root, char *keyname, char *valuename, UINT *type, UINT *size, bool force32bit)
+{
+	return MsRegGetValueTypeAndSizeEx2(root, keyname, valuename, type, size, force32bit, false);
+}
+bool MsRegGetValueTypeAndSizeEx2(UINT root, char *keyname, char *valuename, UINT *type, UINT *size, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	UINT ret;
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return false;
+	}
+	if (type != NULL)
+	{
+		*type = 0;
+	}
+	if (size != NULL)
+	{
+		*size = 0;
+	}
+
+	// キーを開く
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_READ | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	// 値を開く
+	ret = RegQueryValueEx(h, valuename, 0, type, NULL, size);
+
+	if (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA)
+	{
+		RegCloseKey(h);
+		return true;
+	}
+
+	RegCloseKey(h);
+
+	return false;
+}
+bool MsRegGetValueTypeAndSizeW(UINT root, char *keyname, char *valuename, UINT *type, UINT *size)
+{
+	return MsRegGetValueTypeAndSizeExW(root, keyname, valuename, type, size, false);
+}
+bool MsRegGetValueTypeAndSizeExW(UINT root, char *keyname, char *valuename, UINT *type, UINT *size, bool force32bit)
+{
+	return MsRegGetValueTypeAndSizeEx2W(root, keyname, valuename, type, size, force32bit, false);
+}
+bool MsRegGetValueTypeAndSizeEx2W(UINT root, char *keyname, char *valuename, UINT *type, UINT *size, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	UINT ret;
+	wchar_t valuename_w[MAX_SIZE];
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return false;
+	}
+	if (type != NULL)
+	{
+		*type = 0;
+	}
+	if (size != NULL)
+	{
+		*size = 0;
+	}
+	if (IsNt() == false)
+	{
+		UINT type_a = 0;
+		UINT size_a = 0;
+
+		bool ret = MsRegGetValueTypeAndSizeEx2(root, keyname, valuename, &type_a, &size_a, force32bit, force64bit);
+
+		if (type_a == REG_SZ || type_a == REG_MULTI_SZ || type_a == REG_EXPAND_SZ)
+		{
+			size_a = size_a * sizeof(wchar_t);
+		}
+
+		if (type != NULL)
+		{
+			*type = type_a;
+		}
+
+		if (size != NULL)
+		{
+			*size = size_a;
+		}
+
+		return ret;
+	}
+
+	StrToUni(valuename_w, sizeof(valuename_w), valuename);
+
+	// キーを開く
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_READ | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	// 値を開く
+	ret = RegQueryValueExW(h, valuename_w, 0, type, NULL, size);
+
+	if (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA)
+	{
+		RegCloseKey(h);
+		return true;
+	}
+
+	RegCloseKey(h);
+
+	return false;
+}
+
+// 指定された値がレジストリに存在するかどうか確認する
+bool MsRegIsValue(UINT root, char *keyname, char *valuename)
+{
+	return MsRegIsValueEx(root, keyname, valuename, false);
+}
+bool MsRegIsValueEx(UINT root, char *keyname, char *valuename, bool force32bit)
+{
+	return MsRegIsValueEx2(root, keyname, valuename, force32bit, false);
+}
+bool MsRegIsValueEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	UINT type, size;
+	UINT ret;
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return false;
+	}
+
+	// キーを開く
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), keyname, 0, KEY_READ | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	// 値を開く
+	size = 0;
+	ret = RegQueryValueEx(h, valuename, 0, &type, NULL, &size);
+
+	if (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA)
+	{
+		RegCloseKey(h);
+		return true;
+	}
+
+	RegCloseKey(h);
+
+	return false;
+}
+
+// レジストリにキーを作成する
+bool MsRegNewKey(UINT root, char *keyname)
+{
+	return MsRegNewKeyEx(root, keyname, false);
+}
+bool MsRegNewKeyEx(UINT root, char *keyname, bool force32bit)
+{
+	return MsRegNewKeyEx2(root, keyname, force32bit, false);
+}
+bool MsRegNewKeyEx2(UINT root, char *keyname, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	// 引数チェック
+	if (keyname == NULL)
+	{
+		return false;
+	}
+
+	// キーが存在するかどうか確認する
+	if (MsRegIsKeyEx2(root, keyname, force32bit, force64bit))
+	{
+		// すでに存在している
+		return true;
+	}
+
+	// キーを作成する
+	if (RegCreateKeyEx(MsGetRootKeyFromInt(root), keyname, 0, NULL, REG_OPTION_NON_VOLATILE,
+		KEY_ALL_ACCESS | MsRegAccessMaskFor64BitEx(force32bit, force64bit), NULL, &h, NULL) != ERROR_SUCCESS)
+	{
+		// 失敗
+		return false;
+	}
+
+	RegCloseKey(h);
+
+	return true;
+}
+
+// 指定されたキーがレジストリに存在するかどうか確認する
+bool MsRegIsKey(UINT root, char *name)
+{
+	return MsRegIsKeyEx(root, name, false);
+}
+bool MsRegIsKeyEx(UINT root, char *name, bool force32bit)
+{
+	return MsRegIsKeyEx2(root, name, force32bit, false);
+}
+bool MsRegIsKeyEx2(UINT root, char *name, bool force32bit, bool force64bit)
+{
+	HKEY h;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (RegOpenKeyEx(MsGetRootKeyFromInt(root), name, 0, KEY_READ | MsRegAccessMaskFor64BitEx(force32bit, force64bit), &h) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	RegCloseKey(h);
+
+	return true;
+}
+
+// ルートキーハンドルの取得
+HKEY MsGetRootKeyFromInt(UINT root)
+{
+	switch (root)
+	{
+	case REG_CLASSES_ROOT:
+		return HKEY_CLASSES_ROOT;
+
+	case REG_LOCAL_MACHINE:
+		return HKEY_LOCAL_MACHINE;
+
+	case REG_CURRENT_USER:
+		return HKEY_CURRENT_USER;
+
+	case REG_USERS:
+		return HKEY_USERS;
+	}
+
+	return NULL;
+}
+
+// コマンドライン文字列から実行ファイル名の部分をカットする (Unicode 版)
+wchar_t *MsCutExeNameFromUniCommandLine(wchar_t *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	if (str[0] != L'\"')
+	{
+		UINT i = UniSearchStrEx(str, L" ", 0, true);
+		if (i == INFINITE)
+		{
+			return str + UniStrLen(str);
+		}
+		else
+		{
+			return str + i + 1;
+		}
+	}
+	else
+	{
+		str++;
+		while (true)
+		{
+			if ((*str) == 0)
+			{
+				return str + UniStrLen(str);
+			}
+			if ((*str) == L'\"')
+			{
+				break;
+			}
+			str++;
+		}
+
+		while (true)
+		{
+			if ((*str) == 0)
+			{
+				return str + UniStrLen(str);
+			}
+			if ((*str) == L' ')
+			{
+				return str + 1;
+			}
+			str++;
+		}
+	}
+}
+
+// コマンドライン文字列から実行ファイル名の部分をカットする
+char *MsCutExeNameFromCommandLine(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	if (str[0] != '\"')
+	{
+		UINT i = SearchStrEx(str, " ", 0, true);
+		if (i == INFINITE)
+		{
+			return str + StrLen(str);
+		}
+		else
+		{
+			return str + i + 1;
+		}
+	}
+	else
+	{
+		str++;
+		while (true)
+		{
+			if ((*str) == 0)
+			{
+				return str + StrLen(str);
+			}
+			if ((*str) == '\"')
+			{
+				break;
+			}
+			str++;
+		}
+
+		while (true)
+		{
+			if ((*str) == 0)
+			{
+				return str + StrLen(str);
+			}
+			if ((*str) == ' ')
+			{
+				return str + 1;
+			}
+			str++;
+		}
+	}
+}
+
+// プロセスハンドルの取得
+void *MsGetCurrentProcess()
+{
+	return ms->hCurrentProcess;
+}
+
+// プロセス ID の取得
+UINT MsGetCurrentProcessId()
+{
+	return ms->CurrentProcessId;
+}
+
+// EXE ファイル名の取得
+char *MsGetExeFileName()
+{
+	return ms == NULL ? "Unknown" : ms->ExeFileName;
+}
+
+// EXE ファイルが置いてあるディレクトリ名の取得
+char *MsGetExeDirName()
+{
+	return ms->ExeFileDir;
+}
+wchar_t *MsGetExeDirNameW()
+{
+	return ms->ExeFileDirW;
+}
+
+// 特殊なディレクトリ名の取得
+char *MsGetSpecialDir(int id)
+{
+	LPITEMIDLIST t = NULL;
+	char tmp[MAX_PATH];
+
+	if (SHGetSpecialFolderLocation(NULL, id, &t) != S_OK)
+	{
+		return CopyStr(ms->ExeFileDir);
+	}
+
+	if (SHGetPathFromIDList(t, tmp) == false)
+	{
+		return CopyStr(ms->ExeFileDir);
+	}
+
+	Win32NukuEn(tmp, sizeof(tmp), tmp);
+
+	return CopyStr(tmp);
+}
+wchar_t *MsGetSpecialDirW(int id)
+{
+	LPITEMIDLIST t = NULL;
+	wchar_t tmp[MAX_PATH];
+
+	if (IsNt() == false)
+	{
+		char *tmp = MsGetSpecialDir(id);
+		wchar_t *ret = CopyStrToUni(tmp);
+
+		Free(tmp);
+
+		return ret;
+	}
+
+	if (SHGetSpecialFolderLocation(NULL, id, &t) != S_OK)
+	{
+		return UniCopyStr(ms->ExeFileDirW);
+	}
+
+	if (SHGetPathFromIDListW(t, tmp) == false)
+	{
+		return UniCopyStr(ms->ExeFileDirW);
+	}
+
+	Win32NukuEnW(tmp, sizeof(tmp), tmp);
+
+	return UniCopyStr(tmp);
+}
+
+// 特殊なディレクトリをすべて取得する
+void MsGetSpecialDirs()
+{
+	char tmp[MAX_PATH];
+
+	// System32
+	GetSystemDirectory(tmp, sizeof(tmp));
+	Win32NukuEn(tmp, sizeof(tmp), tmp);
+	ms->System32Dir = CopyStr(tmp);
+	ms->System32DirW = CopyStrToUni(tmp);
+
+	// Windows ディレクトリは System32 ディレクトリの 1 つ上にある
+	Win32GetDirFromPath(tmp, sizeof(tmp), tmp);
+	Win32NukuEn(tmp, sizeof(tmp), tmp);
+	ms->WindowsDir = CopyStr(tmp);
+	ms->WindowsDirW = CopyStrToUni(tmp);
+
+	// Windows ディレクトリの下の Temp ディレクトリ
+	Format(tmp, sizeof(tmp), "%s\\Temp", ms->WindowsDir);
+	ms->WinTempDir = CopyStr(tmp);
+	ms->WinTempDirW = CopyStrToUni(tmp);
+	MsUniMakeDirEx(ms->WinTempDirW);
+
+	// システムドライブ
+	tmp[2] = 0;
+	ms->WindowsDrive = CopyStr(tmp);
+	ms->WindowsDriveW = CopyStrToUni(tmp);
+
+	// Temp
+	GetTempPath(MAX_PATH, tmp);
+	Win32NukuEn(tmp, sizeof(tmp), tmp);
+	ms->TempDir = CopyStr(tmp);
+
+	// Temp (Unicode) の取得
+	if (IsNt())
+	{
+		wchar_t tmp_w[MAX_PATH];
+
+		GetTempPathW(MAX_PATH, tmp_w);
+		Win32NukuEnW(tmp_w, sizeof(tmp_w), tmp_w);
+
+		ms->TempDirW = CopyUniStr(tmp_w);
+	}
+	else
+	{
+		ms->TempDirW = CopyStrToUni(tmp);
+	}
+	MakeDirExW(ms->TempDirW);
+	MakeDirEx(ms->TempDir);
+
+	// Program Files
+	ms->ProgramFilesDir = MsGetSpecialDir(CSIDL_PROGRAM_FILES);
+	if (StrCmpi(ms->ProgramFilesDir, ms->ExeFileDir) == 0)
+	{
+		char tmp[MAX_PATH];
+		Format(tmp, sizeof(tmp), "%s\\Program Files", ms->WindowsDrive);
+
+		Free(ms->ProgramFilesDir);
+		ms->ProgramFilesDir = CopyStr(tmp);
+	}
+
+	ms->ProgramFilesDirW = MsGetSpecialDirW(CSIDL_PROGRAM_FILES);
+	if (UniStrCmpi(ms->ProgramFilesDirW, ms->ExeFileDirW) == 0)
+	{
+		wchar_t tmp[MAX_PATH];
+		UniFormat(tmp, sizeof(tmp), L"%s\\Program Files", ms->WindowsDriveW);
+
+		Free(ms->ProgramFilesDirW);
+		ms->ProgramFilesDirW = UniCopyStr(tmp);
+	}
+
+	if (MsIsNt())
+	{
+		// 共通のスタートメニュー
+		ms->CommonStartMenuDir = MsGetSpecialDir(CSIDL_COMMON_STARTMENU);
+		ms->CommonStartMenuDirW = MsGetSpecialDirW(CSIDL_COMMON_STARTMENU);
+
+		// 共通のプログラム
+		ms->CommonProgramsDir = MsGetSpecialDir(CSIDL_COMMON_PROGRAMS);
+		ms->CommonProgramsDirW = MsGetSpecialDirW(CSIDL_COMMON_PROGRAMS);
+
+		// 共通のスタートアップ
+		ms->CommonStartupDir = MsGetSpecialDir(CSIDL_COMMON_STARTUP);
+		ms->CommonStartupDirW = MsGetSpecialDirW(CSIDL_COMMON_STARTUP);
+
+		// 共通のアプリケーションデータ
+		ms->CommonAppDataDir = MsGetSpecialDir(CSIDL_COMMON_APPDATA);
+		ms->CommonAppDataDirW = MsGetSpecialDirW(CSIDL_COMMON_APPDATA);
+
+		// 共通のデスクトップ
+		ms->CommonDesktopDir = MsGetSpecialDir(CSIDL_COMMON_DESKTOPDIRECTORY);
+		ms->CommonDesktopDirW = MsGetSpecialDirW(CSIDL_COMMON_DESKTOPDIRECTORY);
+
+		// Local Settings
+		ms->LocalAppDataDir = MsGetSpecialDir(CSIDL_LOCAL_APPDATA);
+		ms->LocalAppDataDirW = MsGetSpecialDirW(CSIDL_LOCAL_APPDATA);
+	}
+	else
+	{
+		// 個別のスタートメニュー
+		ms->PersonalStartMenuDir = MsGetSpecialDir(CSIDL_STARTMENU);
+		ms->CommonStartMenuDir = CopyStr(ms->PersonalStartMenuDir);
+		ms->PersonalStartMenuDirW = MsGetSpecialDirW(CSIDL_STARTMENU);
+		ms->CommonStartMenuDirW = CopyUniStr(ms->PersonalStartMenuDirW);
+
+		// 個別のプログラム
+		ms->PersonalProgramsDir = MsGetSpecialDir(CSIDL_PROGRAMS);
+		ms->CommonProgramsDir = CopyStr(ms->PersonalProgramsDir);
+		ms->PersonalProgramsDirW = MsGetSpecialDirW(CSIDL_PROGRAMS);
+		ms->CommonProgramsDirW = CopyUniStr(ms->PersonalProgramsDirW);
+
+		// 個別のスタートアップ
+		ms->PersonalStartupDir = MsGetSpecialDir(CSIDL_STARTUP);
+		ms->CommonStartupDir = CopyStr(ms->PersonalStartupDir);
+		ms->PersonalStartupDirW = MsGetSpecialDirW(CSIDL_STARTUP);
+		ms->CommonStartupDirW = CopyUniStr(ms->PersonalStartupDirW);
+
+		// 個別のアプリケーションデータ
+		ms->PersonalAppDataDir = MsGetSpecialDir(CSIDL_APPDATA);
+		ms->CommonAppDataDir = CopyStr(ms->PersonalAppDataDir);
+		ms->PersonalAppDataDirW = MsGetSpecialDirW(CSIDL_APPDATA);
+		ms->CommonAppDataDirW = CopyUniStr(ms->PersonalAppDataDirW);
+
+		// 個別のデスクトップ
+		ms->PersonalDesktopDir = MsGetSpecialDir(CSIDL_DESKTOP);
+		ms->CommonDesktopDir = CopyStr(ms->PersonalDesktopDir);
+		ms->PersonalDesktopDirW = MsGetSpecialDirW(CSIDL_DESKTOP);
+		ms->CommonDesktopDirW = CopyUniStr(ms->PersonalDesktopDirW);
+
+		// Local Settings
+		ms->LocalAppDataDir = CopyStr(ms->PersonalAppDataDir);
+		ms->LocalAppDataDirW = CopyUniStr(ms->PersonalAppDataDirW);
+	}
+}
+
+// 現在のユーザーが Administrators かどうかチェックする
+bool MsCheckIsAdmin()
+{
+	UCHAR test_bit[32];
+	UCHAR tmp[32];
+	char *name = "Vpn_Check_Admin_Key";
+	DWORD type;
+	DWORD size;
+	Rand(test_bit, sizeof(test_bit));
+
+	if (RegSetValueEx(HKEY_LOCAL_MACHINE, name, 0, REG_BINARY, test_bit, sizeof(test_bit)) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	size = sizeof(tmp);
+	if (RegQueryValueEx(HKEY_LOCAL_MACHINE, name, 0, &type, tmp, &size) != ERROR_SUCCESS)
+	{
+		return false;
+	}
+
+	RegDeleteValue(HKEY_LOCAL_MACHINE, name);
+
+	if (Cmp(test_bit, tmp, 32) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ライブラリの初期化
+void MsInit()
+{
+	char *str_ansi;
+	wchar_t *str_unicode;
+	OSVERSIONINFO os;
+	char tmp[MAX_SIZE];
+	UINT size;
+	if (ms != NULL)
+	{
+		// すでに初期化されている
+		return;
+	}
+
+	ms = ZeroMalloc(sizeof(MS));
+
+	// インスタンスハンドルの取得
+	ms->hInst = GetModuleHandleA(NULL);
+
+	// KERNEL32.DLL の取得
+	ms->hKernel32 = LoadLibrary("kernel32.dll");
+
+	// OS からコマンドライン文字列を取得する
+	str_ansi = CopyStr(GetCommandLineA());
+	Trim(str_ansi);
+	str_unicode = UniCopyStr(GetCommandLineW());
+	UniTrim(str_unicode);
+
+	SetCommandLineStr(MsCutExeNameFromCommandLine(str_ansi));
+	SetCommandLineUniStr(MsCutExeNameFromUniCommandLine(str_unicode));
+
+	Free(str_unicode);
+	Free(str_ansi);
+
+	// OS のバージョンを取得する
+	Zero(&os, sizeof(os));
+	os.dwOSVersionInfoSize = sizeof(os);
+	GetVersionEx(&os);
+
+	if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
+	{
+		// NT 系
+		ms->IsNt = true;
+
+		ms->nt = MsLoadNtApiFunctions();
+
+		if (ms->nt == NULL)
+		{
+			ms->IsNt = false;
+			ms->IsAdmin = true;
+		}
+		else
+		{
+			// Administrators 判定
+			ms->IsAdmin = MsCheckIsAdmin();
+		}
+	}
+	else
+	{
+		// 9x 系: 常に Administrators を偽装
+		ms->IsAdmin = true;
+	}
+
+	// 現在のプロセスに関する情報を取得する
+	ms->hCurrentProcess = GetCurrentProcess();
+	ms->CurrentProcessId = GetCurrentProcessId();
+
+	// EXE ファイル名を取得
+	GetModuleFileName(NULL, tmp, sizeof(tmp));
+	ms->ExeFileName = CopyStr(tmp);
+	Win32GetDirFromPath(tmp, sizeof(tmp), tmp);
+	ms->ExeFileDir = CopyStr(tmp);
+
+	// EXE ファイル名 (Unicode) を取得
+	if (IsNt())
+	{
+		wchar_t tmp_w[MAX_PATH];
+
+		GetModuleFileNameW(NULL, tmp_w, sizeof(tmp_w));
+		ms->ExeFileNameW = CopyUniStr(tmp_w);
+
+		Win32GetDirFromPathW(tmp_w, sizeof(tmp_w), tmp_w);
+		ms->ExeFileDirW = CopyUniStr(tmp_w);
+	}
+	else
+	{
+		ms->ExeFileNameW = CopyStrToUni(ms->ExeFileName);
+		ms->ExeFileDirW = CopyStrToUni(ms->ExeFileDir);
+	}
+
+	// 特殊なディレクトリを取得
+	MsGetSpecialDirs();
+
+	// 一時ディレクトリの初期化
+	MsInitTempDir();
+
+	// ユーザー名の取得
+	size = sizeof(tmp);
+	GetUserName(tmp, &size);
+	ms->UserName = CopyStr(tmp);
+
+	// ユーザー名の取得 (Unicode)
+	if (IsNt())
+	{
+		wchar_t tmp_w[MAX_PATH];
+
+		size = sizeof(tmp_w);
+
+		GetUserNameW(tmp_w, &size);
+		ms->UserNameW = CopyUniStr(tmp_w);
+	}
+	else
+	{
+		ms->UserNameW = CopyStrToUni(ms->UserName);
+	}
+
+	// フルユーザー名の取得
+	if (ms->nt != NULL && ms->nt->GetUserNameExA != NULL)
+	{
+		wchar_t tmp_w[MAX_PATH];
+
+		size = sizeof(tmp);
+		if (ms->nt->GetUserNameExA(NameSamCompatible, tmp, &size))
+		{
+			ms->UserNameEx = CopyStr(tmp);
+		}
+
+		size = sizeof(tmp_w);
+		if (ms->nt->GetUserNameExW(NameSamCompatible, tmp_w, &size))
+		{
+			ms->UserNameExW = CopyUniStr(tmp_w);
+		}
+	}
+
+	if (ms->UserNameEx == NULL)
+	{
+		ms->UserNameEx = CopyStr(ms->UserName);
+	}
+	if (ms->UserNameExW == NULL)
+	{
+		ms->UserNameExW = CopyUniStr(ms->UserNameW);
+	}
+
+	ms_critical_section = ZeroMalloc(sizeof(CRITICAL_SECTION));
+	InitializeCriticalSection(ms_critical_section);
+
+	// アダプタリストの初期化
+	MsInitAdapterListModule();
+
+	// minidump ベースファイル名の初期化
+	if (true)
+	{
+		wchar_t tmp[MAX_PATH];
+		if (MsIsAdmin())
+		{
+			CombinePathW(tmp, sizeof(tmp), ms->ExeFileDirW, L"vpn_debug\\dump");
+		}
+		else
+		{
+			CombinePathW(tmp, sizeof(tmp), ms->TempDirW, L"vpn_debug\\dump");
+		}
+		ms->MinidumpBaseFileNameW = CopyUniStr(tmp);
+	}
+
+	MsSetEnableMinidump(true);
+
+	if (MsIsNt())
+	{
+		if (ms->nt->MiniDumpWriteDump != NULL)
+		{
+			SetUnhandledExceptionFilter(MsExceptionHandler);
+		}
+	}
+}
+
+// minidump を作成するかどうか選択する
+void MsSetEnableMinidump(bool enabled)
+{
+	ms->MiniDumpEnabled = enabled;
+}
+
+// minidump を出力する
+void MsWriteMinidump(wchar_t *filename, void *ex)
+{
+	wchar_t tmp[MAX_PATH];
+	wchar_t dir[MAX_PATH];
+	HANDLE h;
+	MINIDUMP_EXCEPTION_INFORMATION info;
+	struct _EXCEPTION_POINTERS *exp = (struct _EXCEPTION_POINTERS *)ex;
+
+	if (filename != NULL)
+	{
+		UniStrCpy(tmp, sizeof(tmp), filename);
+	}
+	else
+	{
+		SYSTEMTIME tm;
+
+		Zero(&tm, sizeof(tm));
+		GetLocalTime(&tm);
+
+		UniFormat(tmp, sizeof(tmp), L"%s_%04u%02u%02u_%02u%02u%02u.dmp",
+			ms->MinidumpBaseFileNameW,
+			tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond);
+	}
+
+	GetDirNameFromFilePathW(dir, sizeof(dir), tmp);
+
+	CreateDirectoryW(dir, NULL);
+
+	Zero(&info, sizeof(info));
+
+	if (exp != NULL)
+	{
+		info.ThreadId = GetCurrentThreadId();
+		info.ExceptionPointers = exp;
+		info.ClientPointers = true;
+	}
+
+	h = CreateFileW(tmp, GENERIC_READ | GENERIC_WRITE,
+		FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+		NULL);
+	if (h != INVALID_HANDLE_VALUE)
+	{
+		ms->nt->MiniDumpWriteDump(ms->hCurrentProcess, ms->CurrentProcessId,
+			h,
+			MiniDumpNormal | MiniDumpWithFullMemory | MiniDumpWithDataSegs |
+			MiniDumpWithHandleData
+			,
+			info.ThreadId == 0 ? NULL : &info, NULL, NULL);
+
+		FlushFileBuffers(h);
+		CloseHandle(h);
+	}
+}
+
+// 例外ハンドラ
+LONG CALLBACK MsExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)
+{
+	if (ms->MiniDumpEnabled)
+	{
+		MsWriteMinidump(NULL, ExceptionInfo);
+	}
+
+	return EXCEPTION_CONTINUE_SEARCH;
+}
+
+// ライブラリの解放
+void MsFree()
+{
+	if (ms == NULL)
+	{
+		// 初期化されていない
+		return;
+	}
+
+	// アダプタリストの解放
+	MsFreeAdapterListModule();
+
+	// 一時ディレクトリの解放
+	MsFreeTempDir();
+
+	if (ms->IsNt)
+	{
+		// NT 系 API の解放
+		MsFreeNtApiFunctions(ms->nt);
+	}
+
+	// メモリ解放
+	// ANSI
+	Free(ms->WindowsDir);
+	Free(ms->System32Dir);
+	Free(ms->TempDir);
+	Free(ms->WinTempDir);
+	Free(ms->WindowsDrive);
+	Free(ms->ProgramFilesDir);
+	Free(ms->CommonStartMenuDir);
+	Free(ms->CommonProgramsDir);
+	Free(ms->CommonStartupDir);
+	Free(ms->CommonAppDataDir);
+	Free(ms->CommonDesktopDir);
+	Free(ms->PersonalStartMenuDir);
+	Free(ms->PersonalProgramsDir);
+	Free(ms->PersonalStartupDir);
+	Free(ms->PersonalAppDataDir);
+	Free(ms->PersonalDesktopDir);
+	Free(ms->MyDocumentsDir);
+	Free(ms->ExeFileDir);
+	Free(ms->ExeFileName);
+	Free(ms->UserName);
+	Free(ms->UserNameEx);
+	Free(ms->LocalAppDataDir);
+	// Unicode
+	Free(ms->WindowsDirW);
+	Free(ms->System32DirW);
+	Free(ms->TempDirW);
+	Free(ms->WinTempDirW);
+	Free(ms->WindowsDriveW);
+	Free(ms->ProgramFilesDirW);
+	Free(ms->CommonStartMenuDirW);
+	Free(ms->CommonProgramsDirW);
+	Free(ms->CommonStartupDirW);
+	Free(ms->CommonAppDataDirW);
+	Free(ms->CommonDesktopDirW);
+	Free(ms->PersonalStartMenuDirW);
+	Free(ms->PersonalProgramsDirW);
+	Free(ms->PersonalStartupDirW);
+	Free(ms->PersonalAppDataDirW);
+	Free(ms->PersonalDesktopDirW);
+	Free(ms->MyDocumentsDirW);
+	Free(ms->ExeFileDirW);
+	Free(ms->ExeFileNameW);
+	Free(ms->UserNameW);
+	Free(ms->UserNameExW);
+	Free(ms->LocalAppDataDirW);
+	Free(ms->MinidumpBaseFileNameW);
+	Free(ms);
+	ms = NULL;
+
+	Free(ms_critical_section);
+	ms_critical_section = NULL;
+}
+
+// ディレクトリ取得関係
+char *MsGetCommonAppDataDir()
+{
+	return ms->CommonAppDataDir;
+}
+char *MsGetLocalAppDataDir()
+{
+	return ms->LocalAppDataDir;
+}
+char *MsGetWindowsDir()
+{
+	return ms->WindowsDir;
+}
+wchar_t *MsGetWindowsDirW()
+{
+	return ms->WindowsDirW;
+}
+char *MsGetSystem32Dir()
+{
+	return ms->System32Dir;
+}
+char *MsGetTempDir()
+{
+	return ms->TempDir;
+}
+char *MsGetWindowsDrive()
+{
+	return ms->WindowsDrive;
+}
+char *MsGetProgramFilesDir()
+{
+	return ms->ProgramFilesDir;
+}
+char *MsGetCommonStartMenuDir()
+{
+	return ms->CommonStartMenuDir;
+}
+char *MsGetCommonProgramsDir()
+{
+	return ms->CommonProgramsDir;
+}
+char *MsGetCommonStartupDir()
+{
+	return ms->CommonStartupDir;
+}
+char *MsGetCommonDesktopDir()
+{
+	return ms->CommonDesktopDir;
+}
+char *MsGetPersonalStartMenuDir()
+{
+	if (ms->PersonalStartMenuDir == NULL)
+	{
+		ms->PersonalStartMenuDir = MsGetSpecialDir(CSIDL_STARTMENU);
+	}
+	return ms->PersonalStartMenuDir;
+}
+char *MsGetPersonalProgramsDir()
+{
+	if (ms->PersonalProgramsDir == NULL)
+	{
+		ms->PersonalProgramsDir = MsGetSpecialDir(CSIDL_PROGRAMS);
+	}
+	return ms->PersonalProgramsDir;
+}
+char *MsGetPersonalStartupDir()
+{
+	if (ms->PersonalStartupDir == NULL)
+	{
+		ms->PersonalStartupDir = MsGetSpecialDir(CSIDL_STARTUP);
+	}
+	return ms->PersonalStartupDir;
+}
+char *MsGetPersonalAppDataDir()
+{
+	if (ms->PersonalAppDataDir == NULL)
+	{
+		ms->PersonalAppDataDir = MsGetSpecialDir(CSIDL_APPDATA);
+	}
+	return ms->PersonalAppDataDir;
+}
+char *MsGetPersonalDesktopDir()
+{
+	if (ms->PersonalDesktopDir == NULL)
+	{
+		ms->PersonalDesktopDir = MsGetSpecialDir(CSIDL_DESKTOP);
+	}
+	return ms->PersonalDesktopDir;
+}
+char *MsGetMyDocumentsDir()
+{
+	if (ms->MyDocumentsDir == NULL)
+	{
+		ms->MyDocumentsDir = MsGetSpecialDir(CSIDL_PERSONAL);
+	}
+	return ms->MyDocumentsDir;
+}
+char *MsGetMyTempDir()
+{
+	return ms->MyTempDir;
+}
+char *MsGetUserName()
+{
+	return ms->UserName;
+}
+char *MsGetUserNameEx()
+{
+	return ms->UserNameEx;
+}
+char *MsGetWinTempDir()
+{
+	return ms->WinTempDir;
+}
+
+wchar_t *MsGetExeFileNameW()
+{
+	return ms == NULL ? L"Unknown" : ms->ExeFileNameW;
+}
+wchar_t *MsGetExeFileDirW()
+{
+	return ms->ExeFileDirW;
+}
+wchar_t *MsGetWindowDirW()
+{
+	return ms->WindowsDirW;
+}
+wchar_t *MsGetSystem32DirW()
+{
+	return ms->System32DirW;
+}
+wchar_t *MsGetTempDirW()
+{
+	return ms->TempDirW;
+}
+wchar_t *MsGetWindowsDriveW()
+{
+	return ms->WindowsDriveW;
+}
+wchar_t *MsGetProgramFilesDirW()
+{
+	return ms->ProgramFilesDirW;
+}
+wchar_t *MsGetCommonStartMenuDirW()
+{
+	return ms->CommonStartMenuDirW;
+}
+wchar_t *MsGetCommonProgramsDirW()
+{
+	return ms->CommonProgramsDirW;
+}
+wchar_t *MsGetCommonStartupDirW()
+{
+	return ms->CommonStartupDirW;
+}
+wchar_t *MsGetCommonAppDataDirW()
+{
+	return ms->CommonAppDataDirW;
+}
+wchar_t *MsGetCommonDesktopDirW()
+{
+	return ms->CommonDesktopDirW;
+}
+wchar_t *MsGetPersonalStartMenuDirW()
+{
+	if (ms->PersonalStartMenuDirW == NULL)
+	{
+		ms->PersonalStartMenuDirW = MsGetSpecialDirW(CSIDL_STARTMENU);
+	}
+
+	return ms->PersonalStartMenuDirW;
+}
+wchar_t *MsGetPersonalProgramsDirW()
+{
+	if (ms->PersonalProgramsDirW == NULL)
+	{
+		ms->PersonalProgramsDirW = MsGetSpecialDirW(CSIDL_PROGRAMS);
+	}
+
+	return ms->PersonalProgramsDirW;
+}
+wchar_t *MsGetPersonalStartupDirW()
+{
+	if (ms->PersonalStartupDirW == NULL)
+	{
+		ms->PersonalStartupDirW = MsGetSpecialDirW(CSIDL_STARTUP);
+	}
+
+	return ms->PersonalStartupDirW;
+}
+wchar_t *MsGetPersonalAppDataDirW()
+{
+	if (ms->PersonalAppDataDirW == NULL)
+	{
+		ms->PersonalAppDataDirW = MsGetSpecialDirW(CSIDL_APPDATA);
+	}
+
+	return ms->PersonalAppDataDirW;
+}
+wchar_t *MsGetPersonalDesktopDirW()
+{
+	if (ms->PersonalDesktopDirW == NULL)
+	{
+		ms->PersonalDesktopDirW = MsGetSpecialDirW(CSIDL_DESKTOP);
+	}
+
+	return ms->PersonalDesktopDirW;
+}
+wchar_t *MsGetMyDocumentsDirW()
+{
+	if (ms->MyDocumentsDirW == NULL)
+	{
+		ms->MyDocumentsDirW = MsGetSpecialDirW(CSIDL_PERSONAL);
+	}
+
+	return ms->MyDocumentsDirW;
+}
+wchar_t *MsGetLocalAppDataDirW()
+{
+	return ms->LocalAppDataDirW;
+}
+wchar_t *MsGetMyTempDirW()
+{
+	return ms->MyTempDirW;
+}
+wchar_t *MsGetUserNameW()
+{
+	return ms->UserNameW;
+}
+wchar_t *MsGetUserNameExW()
+{
+	return ms->UserNameExW;
+}
+wchar_t *MsGetWinTempDirW()
+{
+	return ms->WinTempDirW;
+}
+
+
+#endif	// WIN32
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Microsoft.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Microsoft.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Microsoft.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,952 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Microsoft.h
+// Microsoft.c のヘッダ
+
+#ifdef	OS_WIN32
+
+// Windows 用の型が windows.h をインクルードしていなくても使えるようにする
+#ifndef	_WINDEF_
+
+typedef void *HWND;
+
+#endif	// _WINDEF_
+
+#ifndef	MICROSOFT_H
+#define	MICROSOFT_H
+
+
+// イベントログ定数
+#define	MS_EVENTLOG_TYPE_INFORMATION		0
+#define	MS_EVENTLOG_TYPE_WARNING			1
+#define	MS_EVENTLOG_TYPE_ERROR				2
+
+#define	MS_RC_EVENTLOG_TYPE_INFORMATION		0x40000001L
+#define	MS_RC_EVENTLOG_TYPE_WARNING			0x80000002L
+#define	MS_RC_EVENTLOG_TYPE_ERROR			0xC0000003L
+
+
+// TCP/IP レジストリ値
+#define	TCP_MAX_NUM_CONNECTIONS				16777214
+
+#define	DEFAULT_TCP_MAX_WINDOW_SIZE_RECV	5955584
+#define	DEFAULT_TCP_MAX_WINDOW_SIZE_SEND	131072
+#define	DEFAULT_TCP_MAX_NUM_CONNECTIONS		16777214
+
+// 定数
+#define	SVC_ARG_INSTALL				"/install"
+#define	SVC_ARG_UNINSTALL			"/uninstall"
+#define	SVC_ARG_START				"/start"
+#define	SVC_ARG_STOP				"/stop"
+#define	SVC_ARG_TEST				"/test"
+#define	SVC_ARG_USERMODE			"/usermode"
+#define	SVC_ARG_USERMODE_SHOWTRAY	"/usermode_showtray"
+#define	SVC_ARG_USERMODE_HIDETRAY	"/usermode_hidetray"
+#define	SVC_ARG_SERVICE				"/service"
+#define	SVC_ARG_SETUP_INSTALL		"/setup_install"
+#define	SVC_ARG_SETUP_UNINSTALL		"/setup_uninstall"
+#define	SVC_ARG_WIN9X_SERVICE		"/win9x_service"
+#define	SVC_ARG_WIN9X_INSTALL		"/win9x_install"
+#define	SVC_ARG_WIN9X_UNINSTALL		"/win9x_uninstall"
+#define	SVC_ARG_TCP					"/tcp"
+#define	SVC_ARG_TCP_SETUP			"/tcpsetup"
+#define	SVC_ARG_TRAFFIC				"/traffic"
+#define	SVC_ARG_UIHELP				"/uihelp"
+#define	SVC_ARG_UIHELP_W			L"/uihelp"
+#define SVC_ARG_SILENT				"/silent"
+
+// サービスがフリーズした場合の自殺までの時間
+#define	SVC_SELFKILL_TIMEOUT		(5 * 60 * 1000)
+
+// Win32 版仮想 LAN カードのデバイスドライバの名称 (先頭部分)
+#define	VLAN_ADAPTER_NAME			"UT-VPN Client Adapter"
+
+// Win32 版仮想 LAN カードのデバイスドライバの名称 (フルネーム)
+#define	VLAN_ADAPTER_NAME_TAG		"UT-VPN Client Adapter - %s"
+
+// Win32 版仮想 LAN カードの [ネットワーク接続] における表示名 (フルネーム)
+#define	VLAN_CONNECTION_NAME		"%s - UT-VPN Client"
+
+
+// サービス時のコマンドライン書式
+#define	SVC_RUN_COMMANDLINE			L"\"%s\" /service"
+
+// モード値
+#define	SVC_MODE_NONE				0
+#define	SVC_MODE_INSTALL			1
+#define	SVC_MODE_UNINSTALL			2
+#define	SVC_MODE_START				3
+#define	SVC_MODE_STOP				4
+#define	SVC_MODE_TEST				5
+#define	SVC_MODE_USERMODE			6
+#define	SVC_MODE_SERVICE			7
+#define	SVC_MODE_SETUP_INSTALL		8
+#define	SVC_MODE_SETUP_UNINSTALL	9
+#define	SVC_MODE_WIN9X_SERVICE		10
+#define	SVC_MODE_WIN9X_INSTALL		11
+#define	SVC_MODE_WIN9X_UNINSTALL	12
+#define	SVC_MODE_TCP				13
+#define	SVC_MODE_TCPSETUP			14
+#define	SVC_MODE_TRAFFIC			15
+#define	SVC_MODE_UIHELP				16
+
+
+#define	WIN9X_SVC_REGKEY_1			"Software\\Microsoft\\Windows\\CurrentVersion\\RunServices"
+#define	WIN9X_SVC_REGKEY_2			"Software\\Microsoft\\Windows\\CurrentVersion\\Run"
+
+#define	VISTA_MMCSS_KEYNAME			"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Multimedia\\SystemProfile\\Tasks"
+#define	VISTA_MMCSS_FILENAME		"mmcss_backup.dat"
+
+#define	SVC_NAME					"SVC_%s_NAME"
+#define	SVC_TITLE					"SVC_%s_TITLE"
+#define	SVC_DESCRIPT				"SVC_%s_DESCRIPT"
+
+#define	SVC_USERMODE_SETTING_KEY	"Software\\SoftEther Corporation\\UT-VPN\\UserMode Settings"
+#define	SVC_HIDETRAY_REG_VALUE		"HideTray_%S"
+
+#define	SVC_CALLING_SM_PROCESS_ID_KEY	"Software\\SoftEther Corporation\\UT-VPN\\Service Control\\%s"
+#define SVC_CALLING_SM_PROCESS_ID_VALUE	"ProcessId"
+
+#define	MMCSS_PROFILE_KEYNAME		"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Multimedia\\SystemProfile"
+
+// その他の定数
+#define	MS_REG_TCP_SETTING_KEY		"Software\\SoftEther Corporation\\Network Settings"
+
+
+
+// ドライバ関係の定数
+#define	DRIVER_INF_FILE_NAME		L"|vpn_driver.inf"
+#define	DRIVER_INF_FILE_NAME_X64	L"|vpn_driver_x64.inf"
+#define	DRIVER_INF_FILE_NAME_IA64	L"|vpn_driver_ia64.inf"
+#define	DRIVER_INF_FILE_NAME_9X		L"|vpn_driver_9x.inf"
+#define	DRIVER_SYS_FILE_NAME		L"|vpn_driver.sys"
+#define	DRIVER_SYS_FILE_NAME_X64	L"|vpn_driver_x64.sys"
+#define	DRIVER_SYS_FILE_NAME_IA64	L"|vpn_driver_ia64.sys"
+#define	DRIVER_SYS_FILE_NAME_9X		L"|vpn_driver_9x.sys"
+#define	DRIVER_INSTALL_INF_NAME_TAG	"Sen_%s.inf"
+#define	DRIVER_INSTALL_SYS_NAME_TAG	"Sen_%s.sys"
+#define	DRIVER_INSTALL_SYS_NAME_TAG_NEW	"Sen_%04u.sys"
+#define	DRIVER_INSTALL_SYS_NAME_TAG_MAXID	128
+
+// Vista 用ドライバインストーラ関係
+#define	VISTA_DRIVER_INSTALLER_SRC	L"|driver_installer.exe"
+#define	VISTA_DRIVER_INSTALLER_SRC_X64	L"|driver_installer_x64.exe"
+#define	VISTA_DRIVER_INSTALLER_SRC_IA64	L"|driver_installer_ia64.exe"
+#define	VISTA_DRIVER_INSTALLER_DST	L"%s\\driver_installer.exe"
+
+#define	DRIVER_DEVICE_ID_TAG		"SenAdapter_%s"
+
+
+#if		(defined(MICROSOFT_C) || defined(NETWORK_C)) && (defined(OS_WIN32))
+
+typedef enum __TCP_TABLE_CLASS {
+	_TCP_TABLE_BASIC_LISTENER,
+	_TCP_TABLE_BASIC_CONNECTIONS,
+	_TCP_TABLE_BASIC_ALL,
+	_TCP_TABLE_OWNER_PID_LISTENER,
+	_TCP_TABLE_OWNER_PID_CONNECTIONS,
+	_TCP_TABLE_OWNER_PID_ALL,
+	_TCP_TABLE_OWNER_MODULE_LISTENER,
+	_TCP_TABLE_OWNER_MODULE_CONNECTIONS,
+	_TCP_TABLE_OWNER_MODULE_ALL
+} _TCP_TABLE_CLASS, *_PTCP_TABLE_CLASS;
+
+// Win32 ネットワーク関係の API 関数へのポインタ
+typedef struct NETWORK_WIN32_FUNCTIONS
+{
+	HINSTANCE hIpHlpApi32;
+	DWORD (WINAPI *DeleteIpForwardEntry)(PMIB_IPFORWARDROW);
+	DWORD (WINAPI *CreateIpForwardEntry)(PMIB_IPFORWARDROW);
+	DWORD (WINAPI *GetIpForwardTable)(PMIB_IPFORWARDTABLE, PULONG, BOOL);
+	DWORD (WINAPI *GetNetworkParams)(PFIXED_INFO, PULONG);
+	DWORD (WINAPI *GetIfTable)(PMIB_IFTABLE, PULONG, BOOL);
+	DWORD (WINAPI *IpRenewAddress)(PIP_ADAPTER_INDEX_MAP);
+	DWORD (WINAPI *IpReleaseAddress)(PIP_ADAPTER_INDEX_MAP);
+	DWORD (WINAPI *GetInterfaceInfo)(PIP_INTERFACE_INFO, PULONG);
+	DWORD (WINAPI *GetAdaptersInfo)(PIP_ADAPTER_INFO, PULONG);
+	DWORD (WINAPI *GetExtendedTcpTable)(PVOID, PDWORD, BOOL, ULONG, _TCP_TABLE_CLASS, ULONG);
+	DWORD (WINAPI *AllocateAndGetTcpExTableFromStack)(PVOID *, BOOL, HANDLE, DWORD, DWORD);
+	DWORD (WINAPI *GetTcpTable)(PMIB_TCPTABLE, PDWORD, BOOL);
+	DWORD (WINAPI *NotifyRouteChange)(PHANDLE, LPOVERLAPPED);
+	BOOL (WINAPI *CancelIPChangeNotify)(LPOVERLAPPED);
+	DWORD (WINAPI *NhpAllocateAndGetInterfaceInfoFromStack)(IP_INTERFACE_NAME_INFO **,
+		PDWORD, BOOL, HANDLE, DWORD);
+} NETWORK_WIN32_FUNCTIONS;
+#endif
+
+
+#ifdef	MICROSOFT_C
+// 内部用構造体
+typedef struct MS
+{
+	HINSTANCE hInst;
+	HINSTANCE hKernel32;
+	bool IsNt;
+	bool IsAdmin;
+	struct NT_API *nt;
+	HANDLE hCurrentProcess;
+	UINT CurrentProcessId;
+	bool MiniDumpEnabled;
+	char *ExeFileName;
+	char *ExeFileDir;
+	char *WindowsDir;
+	char *System32Dir;
+	char *TempDir;
+	char *WinTempDir;
+	char *WindowsDrive;
+	char *ProgramFilesDir;
+	char *CommonStartMenuDir;
+	char *CommonProgramsDir;
+	char *CommonStartupDir;
+	char *CommonAppDataDir;
+	char *CommonDesktopDir;
+	char *PersonalStartMenuDir;
+	char *PersonalProgramsDir;
+	char *PersonalStartupDir;
+	char *PersonalAppDataDir;
+	char *PersonalDesktopDir;
+	char *MyDocumentsDir;
+	char *LocalAppDataDir;
+	char *MyTempDir;
+	char *UserName;
+	char *UserNameEx;
+	wchar_t *ExeFileNameW;
+	wchar_t *ExeFileDirW;
+	wchar_t *WindowsDirW;
+	wchar_t *System32DirW;
+	wchar_t *TempDirW;
+	wchar_t *WinTempDirW;
+	wchar_t *WindowsDriveW;
+	wchar_t *ProgramFilesDirW;
+	wchar_t *CommonStartMenuDirW;
+	wchar_t *CommonProgramsDirW;
+	wchar_t *CommonStartupDirW;
+	wchar_t *CommonAppDataDirW;
+	wchar_t *CommonDesktopDirW;
+	wchar_t *PersonalStartMenuDirW;
+	wchar_t *PersonalProgramsDirW;
+	wchar_t *PersonalStartupDirW;
+	wchar_t *PersonalAppDataDirW;
+	wchar_t *PersonalDesktopDirW;
+	wchar_t *MyDocumentsDirW;
+	wchar_t *LocalAppDataDirW;
+	wchar_t *MyTempDirW;
+	wchar_t *UserNameW;
+	wchar_t *UserNameExW;
+	wchar_t *MinidumpBaseFileNameW;
+	IO *LockFile;
+} MS;
+
+// Windows NT 用 API
+typedef struct NT_API
+{
+	HINSTANCE hAdvapi32;
+	HINSTANCE hShell32;
+	HINSTANCE hNewDev;
+	HINSTANCE hSetupApi;
+	HINSTANCE hWtsApi32;
+	HINSTANCE hPsApi;
+	HINSTANCE hKernel32;
+	HINSTANCE hSecur32;
+	HINSTANCE hUser32;
+	HINSTANCE hDbgHelp;
+	BOOL (WINAPI *OpenProcessToken)(HANDLE, DWORD, PHANDLE);
+	BOOL (WINAPI *LookupPrivilegeValue)(char *, char *, PLUID);
+	BOOL (WINAPI *AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD);
+	BOOL (WINAPI *InitiateSystemShutdown)(LPTSTR, LPTSTR, DWORD, BOOL, BOOL);
+	BOOL (WINAPI *LogonUserW)(wchar_t *, wchar_t *, wchar_t *, DWORD, DWORD, HANDLE *);
+	BOOL (WINAPI *LogonUserA)(char *, char *, char *, DWORD, DWORD, HANDLE *);
+	BOOL (WINAPI *UpdateDriverForPlugAndPlayDevicesW)(HWND hWnd, wchar_t *hardware_id, wchar_t *inf_path, UINT flag, BOOL *need_reboot);
+	UINT (WINAPI *CM_Get_DevNode_Status_Ex)(UINT *, UINT *, DWORD, UINT, HANDLE);
+	UINT (WINAPI *CM_Get_Device_ID_ExA)(DWORD, char *, UINT, UINT, HANDLE);
+	UINT (WINAPI *WTSQuerySessionInformation)(HANDLE, DWORD, WTS_INFO_CLASS, wchar_t *, DWORD *);
+	void (WINAPI *WTSFreeMemory)(void *);
+	BOOL (WINAPI *WTSDisconnectSession)(HANDLE, DWORD, BOOL);
+	BOOL (WINAPI *WTSEnumerateSessions)(HANDLE, DWORD, DWORD, PWTS_SESSION_INFO *, DWORD *);
+	SC_HANDLE (WINAPI *OpenSCManager)(LPCTSTR, LPCTSTR, DWORD);
+	SC_HANDLE (WINAPI *CreateServiceA)(SC_HANDLE, LPCTSTR, LPCTSTR, DWORD, DWORD, DWORD, DWORD, LPCTSTR, LPCTSTR, LPDWORD, LPCTSTR, LPCTSTR, LPCTSTR);
+	SC_HANDLE (WINAPI *CreateServiceW)(SC_HANDLE, LPCWSTR, LPCWSTR, DWORD, DWORD, DWORD, DWORD, LPCWSTR, LPCWSTR, LPDWORD, LPCWSTR, LPCWSTR, LPCWSTR);
+	BOOL (WINAPI *ChangeServiceConfig2)(SC_HANDLE, DWORD, LPVOID);
+	BOOL (WINAPI *CloseServiceHandle)(SC_HANDLE);
+	SC_HANDLE (WINAPI *OpenService)(SC_HANDLE, LPCTSTR, DWORD);
+	BOOL (WINAPI *QueryServiceStatus)(SC_HANDLE, LPSERVICE_STATUS);
+	BOOL (WINAPI *StartService)(SC_HANDLE, DWORD, LPCTSTR);
+	BOOL (WINAPI *ControlService)(SC_HANDLE, DWORD, LPSERVICE_STATUS);
+	BOOL (WINAPI *SetServiceStatus)(SERVICE_STATUS_HANDLE, LPSERVICE_STATUS);
+	SERVICE_STATUS_HANDLE (WINAPI *RegisterServiceCtrlHandler)(LPCTSTR, LPHANDLER_FUNCTION);
+	BOOL (WINAPI *StartServiceCtrlDispatcher)(CONST LPSERVICE_TABLE_ENTRY);
+	BOOL (WINAPI *DeleteService)(SC_HANDLE);
+	BOOL (WINAPI *EnumProcesses)(DWORD *, DWORD, DWORD *);
+	BOOL (WINAPI *EnumProcessModules)(HANDLE, HMODULE *, DWORD, DWORD *);
+	DWORD (WINAPI *GetModuleFileNameExA)(HANDLE, HMODULE, LPSTR, DWORD);
+	DWORD (WINAPI *GetModuleFileNameExW)(HANDLE, HMODULE, LPWSTR, DWORD);
+	LONG (WINAPI *RegDeleteKeyExA)(HKEY, LPCTSTR, REGSAM, DWORD);
+	BOOL (WINAPI *IsWow64Process)(HANDLE, BOOL *);
+	void (WINAPI *GetNativeSystemInfo)(SYSTEM_INFO *);
+	BOOL (WINAPI *DuplicateTokenEx)(HANDLE, DWORD, SECURITY_ATTRIBUTES *, SECURITY_IMPERSONATION_LEVEL, TOKEN_TYPE, HANDLE *);
+	BOOL (WINAPI *ConvertStringSidToSidA)(LPCSTR, PSID *);
+	BOOL (WINAPI *SetTokenInformation)(HANDLE, TOKEN_INFORMATION_CLASS, void *, DWORD);
+	BOOL (WINAPI *GetTokenInformation)(HANDLE, TOKEN_INFORMATION_CLASS, void *, DWORD, PDWORD);
+	BOOL (WINAPI *CreateProcessAsUserA)(HANDLE, LPCSTR, LPSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, void *, LPCSTR, LPSTARTUPINFOA, LPPROCESS_INFORMATION);
+	BOOL (WINAPI *CreateProcessAsUserW)(HANDLE, LPCWSTR, LPWSTR, LPSECURITY_ATTRIBUTES, LPSECURITY_ATTRIBUTES, BOOL, DWORD, void *, LPCWSTR, LPSTARTUPINFOW, LPPROCESS_INFORMATION);
+	BOOL (WINAPI *LookupAccountSidA)(LPCSTR,PSID,LPSTR,LPDWORD,LPSTR,LPDWORD,PSID_NAME_USE);
+	BOOL (WINAPI *LookupAccountNameA)(LPCSTR,LPCSTR,PSID,LPDWORD,LPSTR,LPDWORD,PSID_NAME_USE);
+	BOOL (WINAPI *GetUserNameExA)(EXTENDED_NAME_FORMAT, LPSTR, PULONG);
+	BOOL (WINAPI *GetUserNameExW)(EXTENDED_NAME_FORMAT, LPWSTR, PULONG);
+	BOOL (WINAPI *SwitchDesktop)(HDESK);
+	HDESK (WINAPI *OpenDesktopA)(LPTSTR, DWORD, BOOL, ACCESS_MASK);
+	BOOL (WINAPI *CloseDesktop)(HDESK);
+	BOOL (WINAPI *SetProcessShutdownParameters)(DWORD, DWORD);
+	HANDLE (WINAPI *RegisterEventSourceW)(LPCWSTR, LPCWSTR);
+	BOOL (WINAPI *ReportEventW)(HANDLE, WORD, WORD, DWORD, PSID, WORD, DWORD, LPCWSTR *, LPVOID);
+	BOOL (WINAPI *DeregisterEventSource)(HANDLE);
+	BOOL (WINAPI *Wow64DisableWow64FsRedirection)(void **);
+	BOOLEAN (WINAPI *Wow64EnableWow64FsRedirection)(BOOLEAN);
+	BOOL (WINAPI *Wow64RevertWow64FsRedirection)(void *);
+	BOOL (WINAPI *GetFileInformationByHandle)(HANDLE, LPBY_HANDLE_FILE_INFORMATION);
+	HANDLE (WINAPI *GetProcessHeap)();
+	BOOL (WINAPI *MiniDumpWriteDump)(HANDLE, DWORD, HANDLE, MINIDUMP_TYPE,
+		PMINIDUMP_EXCEPTION_INFORMATION, PMINIDUMP_USER_STREAM_INFORMATION,
+		PMINIDUMP_CALLBACK_INFORMATION);
+} NT_API;
+
+typedef struct MS_EVENTLOG
+{
+	HANDLE hEventLog;
+} MS_EVENTLOG;
+
+extern NETWORK_WIN32_FUNCTIONS *w32net;
+
+#endif	// MICROSOFT_C
+
+// 警告を出さないようにするための構造体
+typedef struct NO_WARNING
+{
+	DWORD ThreadId;
+	THREAD *NoWarningThread;
+	EVENT *HaltEvent;
+	volatile bool Halt;
+	wchar_t *SoundFileName;
+} NO_WARNING;
+
+// ルートキーの ID
+#define	REG_CLASSES_ROOT		0	// HKEY_CLASSES_ROOT
+#define	REG_LOCAL_MACHINE		1	// HKEY_LOCAL_MACHINE
+#define	REG_CURRENT_USER		2	// HKEY_CURRENT_USER
+#define	REG_USERS				3	// HKEY_USERS
+
+// サービス関数
+typedef void (SERVICE_FUNCTION)();
+
+// プロセスリスト項目
+typedef struct MS_PROCESS
+{
+	char ExeFilename[MAX_PATH];		// EXE ファイル名
+	wchar_t ExeFilenameW[MAX_PATH];	// EXE ファイル名 (Unicode)
+	UINT ProcessId;					// プロセス ID
+} MS_PROCESS;
+
+#define	MAX_MS_ADAPTER_IP_ADDRESS	64
+
+// ネットワークアダプタ
+typedef struct MS_ADAPTER
+{
+	char Title[MAX_PATH];			// 表示名
+	UINT Index;						// インデックス
+	UINT Type;						// 種類
+	UINT Status;					// ステータス
+	UINT Mtu;						// MTU
+	UINT Speed;						// 速度
+	UINT AddressSize;				// アドレスサイズ
+	UCHAR Address[8];				// アドレス
+	UINT64 RecvBytes;				// 受信バイト数
+	UINT64 RecvPacketsBroadcast;	// 受信ブロードキャストパケット数
+	UINT64 RecvPacketsUnicast;		// 受信ユニキャストパケット数
+	UINT64 SendBytes;				// 送信バイト数
+	UINT64 SendPacketsBroadcast;	// 送信ブロードキャストパケット数
+	UINT64 SendPacketsUnicast;		// 送信ユニキャストパケット数
+	bool Info;						// 詳しい情報があるかどうか
+	char Guid[MAX_SIZE];			// GUID
+	UINT NumIpAddress;				// IP アドレス個数
+	IP IpAddresses[MAX_MS_ADAPTER_IP_ADDRESS];	// IP アドレス
+	IP SubnetMasks[MAX_MS_ADAPTER_IP_ADDRESS];	// サブネット マスク
+	UINT NumGateway;				// ゲートウェイ個数
+	IP Gateways[MAX_MS_ADAPTER_IP_ADDRESS];	// ゲートウェイ
+	bool UseDhcp;					// DHCP 使用フラグ
+	IP DhcpServer;					// DHCP サーバー
+	UINT64 DhcpLeaseStart;			// DHCP リース開始日時
+	UINT64 DhcpLeaseExpires;		// DHCP リース期限日時
+	bool UseWins;					// WINS 使用フラグ
+	IP PrimaryWinsServer;			// プライマリ WINS サーバー
+	IP SecondaryWinsServer;			// セカンダリ WINS サーバー
+} MS_ADAPTER;
+
+// ネットワークアダプタリスト
+typedef struct MS_ADAPTER_LIST
+{
+	UINT Num;						// 個数
+	MS_ADAPTER **Adapters;			// 内容
+} MS_ADAPTER_LIST;
+
+// TCP 設定
+typedef struct MS_TCP
+{
+	UINT RecvWindowSize;			// 受信ウインドウサイズ
+	UINT SendWindowSize;			// 送信ウインドウサイズ
+} MS_TCP;
+
+// スリープ防止
+typedef struct MS_NOSLEEP
+{
+	THREAD *Thread;					// スレッド
+	EVENT *HaltEvent;				// 停止イベント
+	volatile bool Halt;				// 停止フラグ
+	bool NoScreenSaver;				// スクリーンセーバーも防止
+
+	// 以下 Windows Vista 用
+	wchar_t ScreenSaveActive[MAX_PATH];
+	wchar_t SCRNSAVE_EXE[MAX_PATH];
+} MS_NOSLEEP;
+
+// 子ウインドウ列挙
+typedef struct ENUM_CHILD_WINDOW_PARAM
+{
+	LIST *o;
+	bool no_recursion;
+	bool include_ipcontrol;
+} ENUM_CHILD_WINDOW_PARAM;
+
+// 関数プロトタイプ
+void MsInit();
+void MsFree();
+char *MsCutExeNameFromCommandLine(char *str);
+wchar_t *MsCutExeNameFromUniCommandLine(wchar_t *str);
+
+DWORD MsRegAccessMaskFor64Bit(bool force32bit);
+DWORD MsRegAccessMaskFor64BitEx(bool force32bit, bool force64bit);
+
+bool MsRegIsKey(UINT root, char *name);
+bool MsRegIsKeyEx(UINT root, char *name, bool force32bit);
+bool MsRegIsKeyEx2(UINT root, char *name, bool force32bit, bool force64bit);
+
+bool MsRegIsValue(UINT root, char *keyname, char *valuename);
+bool MsRegIsValueEx(UINT root, char *keyname, char *valuename, bool force32bit);
+bool MsRegIsValueEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit);
+
+bool MsRegGetValueTypeAndSize(UINT root, char *keyname, char *valuename, UINT *type, UINT *size);
+bool MsRegGetValueTypeAndSizeEx(UINT root, char *keyname, char *valuename, UINT *type, UINT *size, bool force32bit);
+bool MsRegGetValueTypeAndSizeEx2(UINT root, char *keyname, char *valuename, UINT *type, UINT *size, bool force32bit, bool force64bit);
+bool MsRegGetValueTypeAndSizeW(UINT root, char *keyname, char *valuename, UINT *type, UINT *size);
+bool MsRegGetValueTypeAndSizeExW(UINT root, char *keyname, char *valuename, UINT *type, UINT *size, bool force32bit);
+bool MsRegGetValueTypeAndSizeEx2W(UINT root, char *keyname, char *valuename, UINT *type, UINT *size, bool force32bit, bool force64bit);
+
+bool MsRegReadValue(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size);
+bool MsRegReadValueEx(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size, bool force32bit);
+bool MsRegReadValueEx2(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size, bool force32bit, bool force64bit);
+bool MsRegReadValueW(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size);
+bool MsRegReadValueExW(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size, bool force32bit);
+bool MsRegReadValueEx2W(UINT root, char *keyname, char *valuename, void **data, UINT *type, UINT *size, bool force32bit, bool force64bit);
+
+char *MsRegReadStr(UINT root, char *keyname, char *valuename);
+char *MsRegReadStrEx(UINT root, char *keyname, char *valuename, bool force32bit);
+char *MsRegReadStrEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit);
+wchar_t *MsRegReadStrW(UINT root, char *keyname, char *valuename);
+wchar_t *MsRegReadStrExW(UINT root, char *keyname, char *valuename, bool force32bit);
+wchar_t *MsRegReadStrEx2W(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit);
+
+UINT MsRegReadInt(UINT root, char *keyname, char *valuename);
+UINT MsRegReadIntEx(UINT root, char *keyname, char *valuename, bool force32bit);
+UINT MsRegReadIntEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit);
+LIST *MsRegReadStrList(UINT root, char *keyname, char *valuename);
+LIST *MsRegReadStrListEx(UINT root, char *keyname, char *valuename, bool force32bit);
+LIST *MsRegReadStrListEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit);
+
+BUF *MsRegReadBin(UINT root, char *keyname, char *valuename);
+BUF *MsRegReadBinEx(UINT root, char *keyname, char *valuename, bool force32bit);
+BUF *MsRegReadBinEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit);
+
+bool MsRegNewKey(UINT root, char *keyname);
+bool MsRegNewKeyEx(UINT root, char *keyname, bool force32bit);
+bool MsRegNewKeyEx2(UINT root, char *keyname, bool force32bit, bool force64bit);
+
+bool MsRegWriteValue(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size);
+bool MsRegWriteValueEx(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size, bool force32bit);
+bool MsRegWriteValueEx2(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size, bool force32bit, bool force64bit);
+bool MsRegWriteValueW(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size);
+bool MsRegWriteValueExW(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size, bool force32bit);
+bool MsRegWriteValueEx2W(UINT root, char *keyname, char *valuename, UINT type, void *data, UINT size, bool force32bit, bool force64bit);
+
+bool MsRegWriteStr(UINT root, char *keyname, char *valuename, char *str);
+bool MsRegWriteStrEx(UINT root, char *keyname, char *valuename, char *str, bool force32bit);
+bool MsRegWriteStrEx2(UINT root, char *keyname, char *valuename, char *str, bool force32bit, bool force64bit);
+bool MsRegWriteStrExpand(UINT root, char *keyname, char *valuename, char *str);
+bool MsRegWriteStrExpandEx(UINT root, char *keyname, char *valuename, char *str, bool force32bit);
+bool MsRegWriteStrExpandEx2(UINT root, char *keyname, char *valuename, char *str, bool force32bit, bool force64bit);
+bool MsRegWriteStrW(UINT root, char *keyname, char *valuename, wchar_t *str);
+bool MsRegWriteStrExW(UINT root, char *keyname, char *valuename, wchar_t *str, bool force32bit);
+bool MsRegWriteStrEx2W(UINT root, char *keyname, char *valuename, wchar_t *str, bool force32bit, bool force64bit);
+bool MsRegWriteStrExpandW(UINT root, char *keyname, char *valuename, wchar_t *str);
+bool MsRegWriteStrExpandExW(UINT root, char *keyname, char *valuename, wchar_t *str, bool force32bit);
+bool MsRegWriteStrExpandEx2W(UINT root, char *keyname, char *valuename, wchar_t *str, bool force32bit, bool force64bit);
+
+bool MsRegWriteInt(UINT root, char *keyname, char *valuename, UINT value);
+bool MsRegWriteIntEx(UINT root, char *keyname, char *valuename, UINT value, bool force32bit);
+bool MsRegWriteIntEx2(UINT root, char *keyname, char *valuename, UINT value, bool force32bit, bool force64bit);
+bool MsRegWriteBin(UINT root, char *keyname, char *valuename, void *data, UINT size);
+bool MsRegWriteBinEx(UINT root, char *keyname, char *valuename, void *data, UINT size, bool force32bit);
+bool MsRegWriteBinEx2(UINT root, char *keyname, char *valuename, void *data, UINT size, bool force32bit, bool force64bit);
+
+TOKEN_LIST *MsRegEnumKey(UINT root, char *keyname);
+TOKEN_LIST *MsRegEnumKeyEx(UINT root, char *keyname, bool force32bit);
+TOKEN_LIST *MsRegEnumKeyEx2(UINT root, char *keyname, bool force32bit, bool force64bit);
+TOKEN_LIST *MsRegEnumValue(UINT root, char *keyname);
+TOKEN_LIST *MsRegEnumValueEx(UINT root, char *keyname, bool force32bit);
+TOKEN_LIST *MsRegEnumValueEx2(UINT root, char *keyname, bool force32bit, bool force64bit);
+
+bool MsRegDeleteKey(UINT root, char *keyname);
+bool MsRegDeleteKeyEx(UINT root, char *keyname, bool force32bit);
+bool MsRegDeleteKeyEx2(UINT root, char *keyname, bool force32bit, bool force64bit);
+bool MsRegDeleteValue(UINT root, char *keyname, char *valuename);
+bool MsRegDeleteValueEx(UINT root, char *keyname, char *valuename, bool force32bit);
+bool MsRegDeleteValueEx2(UINT root, char *keyname, char *valuename, bool force32bit, bool force64bit);
+
+bool MsIsNt();
+bool MsIsAdmin();
+bool MsEnablePrivilege(char *name, bool enable);
+void *MsGetCurrentProcess();
+UINT MsGetCurrentProcessId();
+char *MsGetExeFileName();
+char *MsGetExeDirName();
+wchar_t *MsGetExeDirNameW();
+
+bool MsShutdown(bool reboot, bool force);
+bool MsShutdownEx(bool reboot, bool force, UINT time_limit, char *message);
+bool MsCheckLogon(wchar_t *username, char *password);
+bool MsIsPasswordEmpty(wchar_t *username);
+TOKEN_LIST *MsEnumNetworkAdapters(char *start_with_name, char *start_with_name_2);
+TOKEN_LIST *MsEnumNetworkAdaptersSen();
+bool MsGetSenDeiverFilename(char *name, UINT size, char *instance_name);
+bool MsMakeNewSenDriverFilename(char *name, UINT size);
+void MsGenerateSenDriverFilenameFromInt(char *name, UINT size, UINT n);
+TOKEN_LIST *MsEnumSenDriverFilenames();
+char *MsGetNetworkAdapterGuid(char *tag_name, char *instance_name);
+wchar_t *MsGetNetworkConnectionName(char *guid);
+char *MsGetNetworkConfigRegKeyNameFromGuid(char *guid);
+char *MsGetNetworkConfigRegKeyNameFromInstanceName(char *tag_name, char *instance_name);
+void MsSetNetworkConfig(char *tag_name, char *instance_name, char *friendly_name, bool show_icon);
+void MsInitNetworkConfig(char *tag_name, char *instance_name, char *connection_tag_name);
+
+char *MsGetSpecialDir(int id);
+wchar_t *MsGetSpecialDirW(int id);
+void MsGetSpecialDirs();
+bool MsCheckIsAdmin();
+void MsInitTempDir();
+void MsFreeTempDir();
+void MsGenLockFile(wchar_t *name, UINT size, wchar_t *temp_dir);
+void MsDeleteTempDir();
+void MsDeleteAllFile(char *dir);
+void MsDeleteAllFileW(wchar_t *dir);
+char *MsCreateTempFileName(char *name);
+char *MsCreateTempFileNameByExt(char *ext);
+IO *MsCreateTempFile(char *name);
+IO *MsCreateTempFileByExt(char *ext);
+
+bool MsShowNetworkConfiguration(HWND hWnd);
+
+bool MsInstallVLan(char *tag_name, char *connection_tag_name, char *instance_name);
+bool MsUpgradeVLan(char *tag_name, char *connection_tag_name, char *instance_name);
+bool MsEnableVLan(char *instance_name);
+bool MsDisableVLan(char *instance_name);
+bool MsUninstallVLan(char *instance_name);
+bool MsIsVLanEnabled(char *instance_name);
+void MsRestartVLan(char *instance_name);
+bool MsIsVLanExists(char *tag_name, char *instance_name);
+bool MsStartDriverInstall(char *instance_name, UCHAR *mac_address, char *sen_sys);
+void MsFinishDriverInstall(char *instance_name, char *sen_sys);
+void MsGetDriverPath(char *instance_name, wchar_t *src_inf, wchar_t *src_sys, wchar_t *dest_inf, wchar_t *dest_sys, char *sen_sys);
+void MsGetDriverPathA(char *instance_name, char *src_inf, char *src_sys, char *dest_inf, char *dest_sys, char *sen_sys);
+void MsGenMacAddress(UCHAR *mac);
+char *MsGetMacAddress(char *tag_name, char *instance_name);
+void MsSetMacAddress(char *tag_name, char *instance_name, char *mac_address);
+char *MsGetDriverVersion(char *tag_name, char *instance_name);
+char *MsGetDriverFileName(char *tag_name, char *instance_name);
+void MsTest();
+void MsInitGlobalNetworkConfig();
+void MsSetThreadPriorityHigh();
+void MsSetThreadPriorityLow();
+void MsSetThreadPriorityIdle();
+void MsSetThreadPriorityRealtime();
+void MsRestoreThreadPriority();
+char *MsGetLocalAppDataDir();
+char *MsGetCommonAppDataDir();
+char *MsGetWindowsDir();
+char *MsGetSystem32Dir();
+char *MsGetTempDir();
+char *MsGetWindowsDrive();
+char *MsGetProgramFilesDir();
+char *MsGetCommonStartMenuDir();
+char *MsGetCommonProgramsDir();
+char *MsGetCommonStartupDir();
+char *MsGetCommonAppDataDir();
+char *MsGetCommonDesktopDir();
+char *MsGetPersonalStartMenuDir();
+char *MsGetPersonalProgramsDir();
+char *MsGetPersonalStartupDir();
+char *MsGetPersonalAppDataDir();
+char *MsGetPersonalDesktopDir();
+char *MsGetMyDocumentsDir();
+char *MsGetMyTempDir();
+char *MsGetUserName();
+char *MsGetUserNameEx();
+char *MsGetWinTempDir();
+wchar_t *MsGetWindowsDirW();
+wchar_t *MsGetExeFileNameW();
+wchar_t *MsGetExeFileDirW();
+wchar_t *MsGetWindowDirW();
+wchar_t *MsGetSystem32DirW();
+wchar_t *MsGetTempDirW();
+wchar_t *MsGetWindowsDriveW();
+wchar_t *MsGetProgramFilesDirW();
+wchar_t *MsGetCommonStartMenuDirW();
+wchar_t *MsGetCommonProgramsDirW();
+wchar_t *MsGetCommonStartupDirW();
+wchar_t *MsGetCommonAppDataDirW();
+wchar_t *MsGetCommonDesktopDirW();
+wchar_t *MsGetPersonalStartMenuDirW();
+wchar_t *MsGetPersonalProgramsDirW();
+wchar_t *MsGetPersonalStartupDirW();
+wchar_t *MsGetPersonalAppDataDirW();
+wchar_t *MsGetPersonalDesktopDirW();
+wchar_t *MsGetMyDocumentsDirW();
+wchar_t *MsGetLocalAppDataDirW();
+wchar_t *MsGetMyTempDirW();
+wchar_t *MsGetUserNameW();
+wchar_t *MsGetUserNameExW();
+wchar_t *MsGetWinTempDirW();
+UINT MsGetProcessId();
+void MsTerminateProcess();
+bool MsIsServiceInstalled(char *name);
+bool MsInstallService(char *name, char *title, wchar_t *description, char *path);
+bool MsInstallServiceExW(char *name, wchar_t *title, wchar_t *description, wchar_t *path, UINT *error_code);
+bool MsInstallServiceW(char *name, wchar_t *title, wchar_t *description, wchar_t *path);
+bool MsUpdateServiceConfig(char *name);
+bool MsUninstallService(char *name);
+bool MsStartService(char *name);
+bool MsStartServiceEx(char *name, UINT *error_code);
+bool MsStopService(char *name);
+bool MsIsServiceRunning(char *name);
+bool MsIsTerminalServiceInstalled();
+bool MsIsUserSwitchingInstalled();
+bool MsIsTerminalServiceMultiUserInstalled();
+UINT MsGetCurrentTerminalSessionId();
+bool MsIsTerminalSessionActive(UINT session_id);
+bool MsIsCurrentTerminalSessionActive();
+bool MsIsCurrentDesktopAvailableForVnc();
+wchar_t *MsGetSessionUserName(UINT session_id);
+UINT MsService(char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop, UINT icon);
+void MsTestModeW(wchar_t *title, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop);
+void MsTestMode(char *title, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop);
+void MsServiceMode(SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop);
+void MsUserModeW(wchar_t *title, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop, UINT icon);
+void MsUserMode(char *title, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop, UINT icon);
+bool MsIsUserMode();
+void MsTestOnly();
+void MsStopUserModeFromService();
+char *MsGetPenCoreDllFileName();
+void MsPlaySound(char *name);
+void MsSetThreadSingleCpu();
+void MsWin9xTest();
+bool MsCheckVLanDeviceIdFromRootEnum(char *name);
+bool MsInstallVLan9x(char *instance_name);
+void MsUpdateCompatibleIDs(char *instance_name);
+LIST *MsGetProcessList();
+LIST *MsGetProcessList9x();
+LIST *MsGetProcessListNt();
+void MsFreeProcessList(LIST *o);
+void MsPrintProcessList(LIST *o);
+int MsCompareProcessList(void *p1, void *p2);
+MS_PROCESS *MsSearchProcessById(LIST *o, UINT id);
+void MsGetCurrentProcessExeName(char *name, UINT size);
+void MsGetCurrentProcessExeNameW(wchar_t *name, UINT size);
+bool MsKillProcess(UINT id);
+void MsKillOtherInstance();
+void MsKillOtherInstanceEx(char *exclude_svcname);
+bool MsGetShortPathNameA(char *long_path, char *short_path, UINT short_path_size);
+bool MsGetShortPathNameW(wchar_t *long_path, wchar_t *short_path, UINT short_path_size);
+void MsWriteCallingServiceManagerProcessId(char *svcname, UINT pid);
+UINT MsReadCallingServiceManagerProcessId(char *svcname, bool current_user);
+
+
+MS_ADAPTER_LIST *MsCreateAdapterListInner();
+MS_ADAPTER_LIST *MsCreateAdapterListInnerEx(bool no_info);
+void MsFreeAdapter(MS_ADAPTER *a);
+void MsFreeAdapterList(MS_ADAPTER_LIST *o);
+wchar_t *MsGetAdapterTypeStr(UINT type);
+wchar_t *MsGetAdapterStatusStr(UINT status);
+MS_ADAPTER *MsCloneAdapter(MS_ADAPTER *a);
+MS_ADAPTER_LIST *MsCloneAdapterList(MS_ADAPTER_LIST *o);
+void MsInitAdapterListModule();
+void MsFreeAdapterListModule();
+MS_ADAPTER_LIST *MsCreateAdapterList();
+MS_ADAPTER_LIST *MsCreateAdapterListEx(bool no_info);
+void MsGetAdapterTcpIpInformation(MS_ADAPTER *a);
+MS_ADAPTER *MsGetAdapter(char *title);
+
+void *MsLoadLibrary(char *name);
+void *MsLoadLibraryW(wchar_t *name);
+void *MsLoadLibraryAsDataFile(char *name);
+void *MsLoadLibraryAsDataFileW(wchar_t *name);
+
+void MsPrintTick();
+bool MsDisableIme();
+
+void MsGetTcpConfig(MS_TCP *tcp);
+void MsSetTcpConfig(MS_TCP *tcp);
+void MsSaveTcpConfigReg(MS_TCP *tcp);
+bool MsLoadTcpConfigReg(MS_TCP *tcp);
+bool MsIsTcpConfigSupported();
+void MsApplyTcpConfig();
+bool MsIsShouldShowTcpConfigApp();
+void MsDeleteTcpConfigReg();
+
+UINT MsGetConsoleWidth();
+UINT MsSetConsoleWidth(UINT size);
+NO_WARNING *MsInitNoWarning();
+void MsFreeNoWarning(NO_WARNING *nw);
+void MsNoWarningThreadProc(THREAD *thread, void *param);
+char *MsNoWarningSoundInit();
+void MsNoWarningSoundFree(char *s);
+bool MsCloseWarningWindow(UINT thread_id);
+LIST *MsEnumChildWindows(LIST *o, HWND hWnd);
+void MsAddWindowToList(LIST *o, HWND hWnd);
+UINT MsGetThreadLocale();
+LIST *NewWindowList();
+int CmpWindowList(void *p1, void *p2);
+void AddWindow(LIST *o, HWND hWnd);
+void FreeWindowList(LIST *o);
+LIST *EnumAllChildWindow(HWND hWnd);
+LIST *EnumAllChildWindowEx(HWND hWnd, bool no_recursion, bool include_ipcontrol, bool no_self);
+LIST *EnumAllWindow();
+LIST *EnumAllWindowEx(bool no_recursion, bool include_ipcontrol);
+LIST *EnumAllTopWindow();
+
+bool MsExecDriverInstaller(char *arg);
+bool MsIsVista();
+bool MsIsWin2000();
+bool MsIsWin2000OrGreater();
+void MsRegistWindowsFirewall(char *title);
+void MsRegistWindowsFirewallEx(char *title, char *exe);
+void MsRegistWindowsFirewallEx2(char *title, char *exe);
+bool MsIs64BitWindows();
+bool MsIsX64();
+bool MsIsIA64();
+void *MsDisableWow64FileSystemRedirection();
+void MsRestoreWow64FileSystemRedirection(void *p);
+void MsSetWow64FileSystemRedirectionEnable(bool enable);
+
+bool MsCheckFileDigitalSignature(HWND hWnd, char *name, bool *danger);
+bool MsCheckFileDigitalSignatureW(HWND hWnd, wchar_t *name, bool *danger);
+
+bool MsGetProcessExeName(char *path, UINT size, UINT id);
+bool MsGetProcessExeNameW(wchar_t *path, UINT size, UINT id);
+bool MsGetWindowOwnerProcessExeName(char *path, UINT size, HWND hWnd);
+bool MsGetWindowOwnerProcessExeNameW(wchar_t *path, UINT size, HWND hWnd);
+
+void *MsRunAsUserEx(char *filename, char *arg, bool hide);
+void *MsRunAsUserExW(wchar_t *filename, wchar_t *arg, bool hide);
+void *MsRunAsUserExInner(char *filename, char *arg, bool hide);
+void *MsRunAsUserExInnerW(wchar_t *filename, wchar_t *arg, bool hide);
+
+UINT MsGetCursorPosHash();
+bool MsIsProcessExists(char *exename);
+bool MsIsProcessExistsW(wchar_t *exename);
+
+void MsGetComputerName(char *name, UINT size);
+void MsNoSleepThread(THREAD *thread, void *param);
+void MsNoSleepThreadVista(THREAD *thread, void *param);
+UINT64 MsGetScreenSaverTimeout();
+void *MsNoSleepStart(bool no_screensaver);
+void MsNoSleepEnd(void *p);
+bool MsIsRemoteDesktopAvailable();
+bool MsIsRemoteDesktopCanEnableByRegistory();
+bool MsIsRemoteDesktopEnabled();
+bool MsEnableRemoteDesktop();
+
+void MsSetFileToHidden(char *name);
+void MsSetFileToHiddenW(wchar_t *name);
+bool MsGetFileVersion(char *name, UINT *v1, UINT *v2, UINT *v3, UINT *v4);
+bool MsGetFileVersionW(wchar_t *name, UINT *v1, UINT *v2, UINT *v3, UINT *v4);
+
+bool MsExtractCabinetFileFromExe(char *exe, char *cab);
+bool MsExtractCabinetFileFromExeW(wchar_t *exe, wchar_t *cab);
+BUF *MsExtractResourceFromExe(char *exe, char *type, char *name);
+BUF *MsExtractResourceFromExeW(wchar_t *exe, char *type, char *name);
+bool MsExtractCab(char *cab_name, char *dest_dir_name);
+bool MsExtractCabW(wchar_t *cab_name, wchar_t *dest_dir_name);
+bool MsGetCabarcExeFilename(char *name, UINT size);
+bool MsGetCabarcExeFilenameW(wchar_t *name, UINT size);
+bool MsExtractCabFromMsi(char *msi, char *cab);
+bool MsExtractCabFromMsiW(wchar_t *msi, wchar_t *cab);
+bool MsIsDirectory(char *name);
+bool MsIsDirectoryW(wchar_t *name);
+bool MsUniIsDirectory(wchar_t *name);
+bool MsUniFileDelete(wchar_t *name);
+bool MsUniDirectoryDelete(wchar_t *name);
+bool MsUniMakeDir(wchar_t *name);
+void MsUniMakeDirEx(wchar_t *name);
+void MsMakeDirEx(char *name);
+bool MsMakeDir(char *name);
+bool MsDirectoryDelete(char *name);
+bool MsFileDelete(char *name);
+bool MsExecute(char *exe, char *arg);
+bool MsExecuteW(wchar_t *exe, wchar_t *arg);
+bool MsExecuteEx(char *exe, char *arg, void **process_handle);
+bool MsExecuteExW(wchar_t *exe, wchar_t *arg, void **process_handle);
+UINT MsWaitProcessExit(void *process_handle);
+bool MsIsFileLocked(char *name);
+bool MsIsFileLockedW(wchar_t *name);
+bool MsIsLocalDrive(char *name);
+bool MsIsLocalDriveW(wchar_t *name);
+void MsUpdateSystem();
+bool MsGetPhysicalMacAddressFromNetbios(void *address);
+bool MsGetPhysicalMacAddressFromApi(void *address);
+bool MsGetPhysicalMacAddress(void *address);
+bool MsIsUseWelcomeLogin();
+UINT64 MsGetHiResCounter();
+double MsGetHiResTimeSpan(UINT64 diff);
+UINT64 MsGetHiResTimeSpanUSec(UINT64 diff);
+BUF *MsRegSubkeysToBuf(UINT root, char *keyname, bool force32bit, bool force64bit);
+void MsBufToRegSubkeys(UINT root, char *keyname, BUF *b, bool overwrite, bool force32bit, bool force64bit);
+void MsRegDeleteSubkeys(UINT root, char *keyname, bool force32bit, bool force64bit);
+void MsRestartMMCSS();
+bool MsIsMMCSSNetworkThrottlingEnabled();
+void MsSetMMCSSNetworkThrottlingEnable(bool enable);
+void MsSetShutdownParameters(UINT level, UINT flag);
+void MsChangeIconOnTrayEx2(void *icon, wchar_t *tooltip, wchar_t *info_title, wchar_t *info, UINT info_flags);
+bool MsIsTrayInited();
+UINT MsGetClipboardOwnerProcessId();
+void MsDeleteClipboard();
+void *MsInitEventLog(wchar_t *src_name);
+void MsFreeEventLog(void *p);
+bool MsWriteEventLog(void *p, UINT type, wchar_t *str);
+bool MsIsWinXPOrWinVista();
+bool MsGetFileInformation(void *h, void *info);
+void MsSetErrorModeToSilent();
+void MsSetEnableMinidump(bool enabled);
+void MsWriteMinidump(wchar_t *filename, void *ex);
+
+// 内部関数
+#ifdef	MICROSOFT_C
+
+LONG CALLBACK MsExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo);
+HKEY MsGetRootKeyFromInt(UINT root);
+NT_API *MsLoadNtApiFunctions();
+void MsFreeNtApiFunctions(NT_API *nt);
+void MsDestroyDevInfo(HDEVINFO info);
+HDEVINFO MsGetDevInfoFromDeviceId(SP_DEVINFO_DATA *dev_info_data, char *device_id);
+bool MsStartDevice(HDEVINFO info, SP_DEVINFO_DATA *dev_info_data);
+bool MsStopDevice(HDEVINFO info, SP_DEVINFO_DATA *dev_info_data);
+bool MsDeleteDevice(HDEVINFO info, SP_DEVINFO_DATA *dev_info_data);
+bool MsIsDeviceRunning(HDEVINFO info, SP_DEVINFO_DATA *dev_info_data);
+void CALLBACK MsServiceDispatcher(DWORD argc, LPTSTR *argv);
+void CALLBACK MsServiceHandler(DWORD opcode);
+void MsServiceStoperThread(THREAD *t, void *p);
+void MsServiceStoperMainThread(THREAD *t, void *p);
+void MsServiceStarterMainThread(THREAD *t, void *p);
+LRESULT CALLBACK MsUserModeWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+void MsShowIconOnTray(HWND hWnd, HICON icon, wchar_t *tooltip, UINT msg);
+void MsRestoreIconOnTray();
+void MsChangeIconOnTray(HICON icon, wchar_t *tooltip);
+void MsChangeIconOnTrayEx(HICON icon, wchar_t *tooltip, wchar_t *info_title, wchar_t *info, UINT info_flags);
+void MsHideIconOnTray();
+void MsUserModeTrayMenu(HWND hWnd);
+bool MsAppendMenu(HMENU hMenu, UINT flags, UINT_PTR id, wchar_t *str);
+bool MsInsertMenu(HMENU hMenu, UINT pos, UINT flags, UINT_PTR id_new_item, wchar_t *lp_new_item);
+bool CALLBACK MsEnumChildWindowProc(HWND hWnd, LPARAM lParam);
+BOOL CALLBACK EnumTopWindowProc(HWND hWnd, LPARAM lParam);
+bool CALLBACK MsEnumThreadWindowProc(HWND hWnd, LPARAM lParam);
+HANDLE MsCreateUserToken();
+SID *MsGetSidFromAccountName(char *name);
+void MsFreeSid(SID *sid);
+
+#endif	// MICROSOFT_C
+
+#endif	// MICROSOFT_H
+
+#endif	// OS_WIN32
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Network.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Network.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Network.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,9389 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Network.c
+// ネットワーク通信モジュール
+
+#define	ENCRYPT_C
+#define	NETWORK_C
+
+#define	__WINCRYPT_H__
+
+#ifdef	WIN32
+// Socket API のために windows.h をインクルード
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#include <Ws2tcpip.h>
+#include <Wspiapi.h>
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <windows.h>
+#include <Iphlpapi.h>
+#endif	// WIN32
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/engine.h>
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include <openssl/pkcs7.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rc4.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <Mayaqua/Mayaqua.h>
+
+#ifdef	OS_WIN32
+NETWORK_WIN32_FUNCTIONS *w32net;
+struct ROUTE_CHANGE_DATA
+{
+	OVERLAPPED Overlapped;
+	HANDLE Handle;
+	UINT NumCalled;
+};
+#endif	// OS_WIN32
+
+// SSL でブロッキングするかどうか
+#if	defined(UNIX_BSD)
+#define	FIX_SSL_BLOCKING
+#endif
+
+// IPV6_V6ONLY 定数
+#ifdef	UNIX_LINUX
+#ifndef	IPV6_V6ONLY
+#define	IPV6_V6ONLY	26
+#endif	// IPV6_V6ONLY
+#endif	// UNIX_LINUX
+
+#ifdef	UNIX_SOLARIS
+#ifndef	IPV6_V6ONLY
+#define	IPV6_V6ONLY	0x27
+#endif	// IPV6_V6ONLY
+#endif	// UNIX_SOLARIS
+
+// SSL_CTX
+static SSL_CTX *ssl_ctx = NULL;
+
+// DNS キャッシュリスト
+static LIST *DnsCache;
+
+// ロック関係
+static LOCK *machine_name_lock = NULL;
+static LOCK *disconnect_function_lock = NULL;
+static LOCK *aho = NULL;
+static LOCK *socket_library_lock = NULL;
+extern LOCK *openssl_lock;
+static LOCK *ssl_accept_lock = NULL;
+static LOCK *ssl_connect_lock = NULL;
+static TOKEN_LIST *cipher_list_token = NULL;
+static COUNTER *num_tcp_connections = NULL;
+static LOCK *dns_lock = NULL;
+static LOCK *unix_dns_server_addr_lock = NULL;
+static IP unix_dns_server;
+static LIST *HostCacheList = NULL;
+static LIST *WaitThreadList = NULL;
+static bool disable_cache = false;
+static bool NetworkReleaseMode = false;			// ネットワークリリースモード
+
+static char *cipher_list = "RC4-MD5 RC4-SHA AES128-SHA AES256-SHA DES-CBC-SHA DES-CBC3-SHA";
+static LIST *ip_clients = NULL;
+
+// ルーティングテーブル変更検出を初期化
+ROUTE_CHANGE *NewRouteChange()
+{
+#ifdef	OS_WIN32
+	return Win32NewRouteChange();
+#else	// OS_WIN32
+	return NULL;
+#endif	// OS_WIN32
+}
+
+// ルーティングテーブル変更検出を解放
+void FreeRouteChange(ROUTE_CHANGE *r)
+{
+#ifdef	OS_WIN32
+	Win32FreeRouteChange(r);
+#endif	// OS_WIN32
+}
+
+// ルーティングテーブルが変更されたかどうか取得
+bool IsRouteChanged(ROUTE_CHANGE *r)
+{
+#ifdef	OS_WIN32
+	return Win32IsRouteChanged(r);
+#else	// OS_WIN32
+	return false;
+#endif	// OS_WIN32
+}
+
+// ルーティングテーブル変更検出機能 (Win32)
+#ifdef	OS_WIN32
+ROUTE_CHANGE *Win32NewRouteChange()
+{
+	ROUTE_CHANGE *r;
+	bool ret;
+
+	if (MsIsNt() == false)
+	{
+		return NULL;
+	}
+
+	if (w32net->CancelIPChangeNotify == NULL ||
+		w32net->NotifyRouteChange == NULL)
+	{
+		return NULL;
+	}
+
+	r = ZeroMalloc(sizeof(ROUTE_CHANGE));
+
+	r->Data = ZeroMalloc(sizeof(ROUTE_CHANGE_DATA));
+
+	r->Data->Overlapped.hEvent = CreateEventA(NULL, false, true, NULL);
+
+	ret = w32net->NotifyRouteChange(&r->Data->Handle, &r->Data->Overlapped);
+	if (!(ret == NO_ERROR || ret == WSA_IO_PENDING || WSAGetLastError() == WSA_IO_PENDING))
+	{
+		Free(r->Data);
+		Free(r);
+
+		return NULL;
+	}
+
+	return r;
+}
+
+void Win32FreeRouteChange(ROUTE_CHANGE *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	w32net->CancelIPChangeNotify(&r->Data->Overlapped);
+	CloseHandle(r->Data->Overlapped.hEvent);
+
+	Free(r->Data);
+	Free(r);
+}
+
+bool Win32IsRouteChanged(ROUTE_CHANGE *r)
+{
+	// 引数チェック
+	if (r == NULL)
+	{
+		return false;
+	}
+
+	if ((r->Data->NumCalled++) == 0)
+	{
+		return true;
+	}
+
+	if (WaitForSingleObject(r->Data->Overlapped.hEvent, 0) == WAIT_OBJECT_0)
+	{
+		w32net->NotifyRouteChange(&r->Data->Handle, &r->Data->Overlapped);
+		return true;
+	}
+
+	return false;
+}
+
+#endif	// OS_WIN32
+
+
+// TCP コネクションのプロセス ID の取得が成功するかどうかを取得
+bool CanGetTcpProcessId()
+{
+	UINT i;
+	bool ret = false;
+	LIST *o = GetTcpTableList();
+
+	if (o == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		TCPTABLE *t = LIST_DATA(o, i);
+
+		if (t->ProcessId != 0)
+		{
+			ret = true;
+			break;
+		}
+	}
+
+	FreeTcpTableList(o);
+
+	return ret;
+}
+
+
+
+
+#define	USE_OLD_GETIP
+
+// Linux における arp_filter を設定する
+void SetLinuxArpFilter()
+{
+	char *filename = "/proc/sys/net/ipv4/conf/all/arp_filter";
+	char *data = "1\n";
+	IO *o;
+
+	o = FileCreate(filename);
+	if (o == NULL)
+	{
+		return;
+	}
+
+	FileWrite(o, data, StrLen(data));
+	FileFlush(o);
+
+	FileClose(o);
+}
+
+// 指定された文字列が IPv6 マスクかどうか判定する
+bool IsIpMask6(char *str)
+{
+	IP mask;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	return StrToMask6(&mask, str);
+}
+
+// 指定された文字列が IPv6 アドレスかどうか判定する
+bool IsStrIPv6Address(char *str)
+{
+	IP ip;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	if (StrToIP6(&ip, str) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// サブネットマスクを整数に変換する
+UINT SubnetMaskToInt6(IP *a)
+{
+	UINT i;
+	// 引数チェック
+	if (IsIP6(a) == false)
+	{
+		return 0;
+	}
+
+	for (i = 0;i <= 128;i++)
+	{
+		IP tmp;
+
+		IntToSubnetMask6(&tmp, i);
+
+		if (CmpIpAddr(a, &tmp) == 0)
+		{
+			return i;
+		}
+	}
+
+	return 0;
+}
+UINT SubnetMaskToInt4(IP *a)
+{
+	UINT i;
+	// 引数チェック
+	if (IsIP4(a) == false)
+	{
+		return 0;
+	}
+
+	for (i = 0;i <= 32;i++)
+	{
+		IP tmp;
+
+		IntToSubnetMask4(&tmp, i);
+
+		if (CmpIpAddr(a, &tmp) == 0)
+		{
+			return i;
+		}
+	}
+
+	return 0;
+}
+UINT SubnetMaskToInt(IP *a)
+{
+	if (IsIP6(a))
+	{
+		return SubnetMaskToInt6(a);
+	}
+	else
+	{
+		return SubnetMaskToInt4(a);
+	}
+}
+
+// 指定した IP アドレスがサブネットマスクかどうか調べる
+bool IsSubnetMask6(IP *a)
+{
+	UINT i;
+	// 引数チェック
+	if (IsIP6(a) == false)
+	{
+		return false;
+	}
+
+	for (i = 0;i <= 128;i++)
+	{
+		IP tmp;
+
+		IntToSubnetMask6(&tmp, i);
+
+		if (CmpIpAddr(a, &tmp) == 0)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// MAC アドレスからグローバルアドレスを生成する
+void GenerateEui64GlobalAddress(IP *ip, IP *prefix, IP *subnet, UCHAR *mac)
+{
+	UCHAR tmp[8];
+	IP a;
+	IP subnet_not;
+	IP or1, or2;
+	// 引数チェック
+	if (ip == NULL || prefix == NULL || subnet == NULL || mac == NULL)
+	{
+		return;
+	}
+
+	GenerateEui64Address6(tmp, mac);
+
+	ZeroIP6(&a);
+
+	Copy(&a.ipv6_addr[8], tmp, 8);
+
+	IPNot6(&subnet_not, subnet);
+	IPAnd6(&or1, &a, &subnet_not);
+	IPAnd6(&or2, prefix, subnet);
+
+	IPOr6(ip, &or1, &or2);
+}
+
+// MAC アドレスからローカルアドレスを生成する
+void GenerateEui64LocalAddress(IP *a, UCHAR *mac)
+{
+	UCHAR tmp[8];
+	// 引数チェック
+	if (a == NULL || mac == NULL)
+	{
+		return;
+	}
+
+	GenerateEui64Address6(tmp, mac);
+
+	ZeroIP6(a);
+	a->ipv6_addr[0] = 0xfe;
+	a->ipv6_addr[1] = 0x80;
+
+	Copy(&a->ipv6_addr[8], tmp, 8);
+}
+
+// MAC アドレスから EUI-64 アドレスを生成する
+void GenerateEui64Address6(UCHAR *dst, UCHAR *mac)
+{
+	// 引数チェック
+	if (dst == NULL || mac == NULL)
+	{
+		return;
+	}
+
+	Copy(dst, mac, 3);
+	Copy(dst + 5, mac, 3);
+
+	dst[3] = 0xff;
+	dst[4] = 0xfe;
+	dst[0] = ((~(dst[0] & 0x02)) & 0x02) | (dst[0] & 0xfd);
+}
+
+// 同一のネットワークかどうか調べる
+bool IsInSameNetwork6(IP *a1, IP *a2, IP *subnet)
+{
+	IP prefix1, prefix2;
+	// 引数チェック
+	if (IsIP6(a1) == false || IsIP6(a2) == false || IsIP6(subnet) == false)
+	{
+		return false;
+	}
+
+	if (a1->ipv6_scope_id != a2->ipv6_scope_id)
+	{
+		return false;
+	}
+
+	GetPrefixAddress6(&prefix1, a1, subnet);
+	GetPrefixAddress6(&prefix2, a2, subnet);
+
+	if (CmpIpAddr(&prefix1, &prefix2) == 0)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// ネットワークプレフィックスアドレスかどうかチェックする
+bool IsNetworkAddress6(IP *ip, IP *subnet)
+{
+	return IsNetworkPrefixAddress6(ip, subnet);
+}
+bool IsNetworkPrefixAddress6(IP *ip, IP *subnet)
+{
+	IP host;
+	// 引数チェック
+	if (ip == NULL || subnet == NULL)
+	{
+		return false;
+	}
+
+	if (IsIP6(ip) == false || IsIP6(subnet) == false)
+	{
+		return false;
+	}
+
+	GetHostAddress6(&host, ip, subnet);
+
+	if (IsZeroIp(&host))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// ユニキャストアドレスが有効かどうかチェックする
+bool CheckUnicastAddress(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	if ((GetIPAddrType6(ip) & IPV6_ADDR_UNICAST) == 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ホストアドレスの取得
+void GetHostAddress6(IP *dst, IP *ip, IP *subnet)
+{
+	IP not;
+	// 引数チェック
+	if (dst == NULL || ip == NULL || subnet == NULL)
+	{
+		return;
+	}
+
+	IPNot6(&not, subnet);
+
+	IPAnd6(dst, ip, &not);
+
+	dst->ipv6_scope_id = ip->ipv6_scope_id;
+}
+
+// プレフィックスアドレスの取得
+void GetPrefixAddress6(IP *dst, IP *ip, IP *subnet)
+{
+	// 引数チェック
+	if (dst == NULL || ip == NULL || subnet == NULL)
+	{
+		return;
+	}
+
+	IPAnd6(dst, ip, subnet);
+
+	dst->ipv6_scope_id = ip->ipv6_scope_id;
+}
+
+// 要請ノードマルチキャストアドレスを取得
+void GetSoliciationMulticastAddr6(IP *dst, IP *src)
+{
+	IP prefix;
+	IP mask104;
+	IP or1, or2;
+
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	ZeroIP6(&prefix);
+	prefix.ipv6_addr[0] = 0xff;
+	prefix.ipv6_addr[1] = 0x02;
+	prefix.ipv6_addr[11] = 0x01;
+	prefix.ipv6_addr[12] = 0xff;
+
+	IntToSubnetMask6(&mask104, 104);
+
+	IPAnd6(&or1, &prefix, &mask104);
+	IPAnd6(&or2, src, &mask104);
+
+	IPOr6(dst, &or1, &or2);
+
+	dst->ipv6_scope_id = src->ipv6_scope_id;
+}
+
+// マルチキャストアドレスに対応した MAC アドレスの生成
+void GenerateMulticastMacAddress6(UCHAR *mac, IP *ip)
+{
+	// 引数チェック
+	if (mac == NULL)
+	{
+		return;
+	}
+
+	mac[0] = 0x33;
+	mac[1] = 0x33;
+	mac[2] = ip->ipv6_addr[12];
+	mac[3] = ip->ipv6_addr[13];
+	mac[4] = ip->ipv6_addr[14];
+	mac[5] = ip->ipv6_addr[15];
+}
+
+// IPv6 アドレスのタイプの取得
+UINT GetIPv6AddrType(IPV6_ADDR *addr)
+{
+	IP ip;
+	// 引数チェック
+	if (addr == NULL)
+	{
+		return 0;
+	}
+
+	IPv6AddrToIP(&ip, addr);
+
+	return GetIPAddrType6(&ip);
+}
+UINT GetIPAddrType6(IP *ip)
+{
+	UINT ret = 0;
+	// 引数チェック
+	if (IsIP6(ip) == false)
+	{
+		return 0;
+	}
+
+	if (ip->ipv6_addr[0] == 0xff)
+	{
+		IP all_node, all_router;
+
+		GetAllNodeMulticaseAddress6(&all_node);
+
+		GetAllRouterMulticastAddress6(&all_router);
+
+		ret |= IPV6_ADDR_MULTICAST;
+
+		if (Cmp(ip->ipv6_addr, all_node.ipv6_addr, 16) == 0)
+		{
+			ret |= IPV6_ADDR_ALL_NODE_MULTICAST;
+		}
+		else if (Cmp(ip->ipv6_addr, all_router.ipv6_addr, 16) == 0)
+		{
+			ret |= IPV6_ADDR_ALL_ROUTER_MULTICAST;
+		}
+		else
+		{
+			if (ip->ipv6_addr[1] == 0x02 && ip->ipv6_addr[2] == 0 && ip->ipv6_addr[3] == 0 &&
+				ip->ipv6_addr[4] == 0 && ip->ipv6_addr[5] == 0 && ip->ipv6_addr[6] == 0 &&
+				ip->ipv6_addr[7] == 0 && ip->ipv6_addr[8] == 0 && ip->ipv6_addr[9] == 0 &&
+				ip->ipv6_addr[10] == 0 && ip->ipv6_addr[11] == 0x01 && ip->ipv6_addr[12] == 0xff)
+			{
+				ret |= IPV6_ADDR_SOLICIATION_MULTICAST;
+			}
+		}
+	}
+	else
+	{
+		ret |= IPV6_ADDR_UNICAST;
+
+		if (ip->ipv6_addr[0] == 0xfe && (ip->ipv6_addr[1] & 0xc0) == 0x80)
+		{
+			ret |= IPV6_ADDR_LOCAL_UNICAST;
+		}
+		else
+		{
+			ret |= IPV6_ADDR_GLOBAL_UNICAST;
+
+			if (IsZero(&ip->ipv6_addr, 16))
+			{
+				ret |= IPV6_ADDR_ZERO;
+			}
+			else
+			{
+				IP loopback;
+
+				GetLoopbackAddress6(&loopback);
+
+				if (Cmp(ip->ipv6_addr, loopback.ipv6_addr, 16) == 0)
+				{
+					ret |= IPV6_ADDR_LOOPBACK;
+				}
+			}
+		}
+	}
+
+	return ret;
+}
+
+// すべてのビットが立っているアドレス
+void GetAllFilledAddress6(IP *ip)
+{
+	UINT i;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	ZeroIP6(ip);
+
+	for (i = 0;i < 15;i++)
+	{
+		ip->ipv6_addr[i] = 0xff;
+	}
+}
+
+// ループバックアドレス
+void GetLoopbackAddress6(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	ZeroIP6(ip);
+
+	ip->ipv6_addr[15] = 0x01;
+}
+
+// 全ノードマルチキャストアドレス
+void GetAllNodeMulticaseAddress6(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	ZeroIP6(ip);
+
+	ip->ipv6_addr[0] = 0xff;
+	ip->ipv6_addr[1] = 0x02;
+	ip->ipv6_addr[15] = 0x01;
+}
+
+// 全ルータマルチキャストアドレス
+void GetAllRouterMulticastAddress6(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	ZeroIP6(ip);
+
+	ip->ipv6_addr[0] = 0xff;
+	ip->ipv6_addr[1] = 0x02;
+	ip->ipv6_addr[15] = 0x02;
+}
+
+// IPv6 アドレスの論理演算
+void IPAnd6(IP *dst, IP *a, IP *b)
+{
+	UINT i;
+	// 引数チェック
+	if (dst == NULL || IsIP6(a) == false || IsIP6(b) == false)
+	{
+		return;
+	}
+
+	ZeroIP6(dst);
+	for (i = 0;i < 16;i++)
+	{
+		dst->ipv6_addr[i] = a->ipv6_addr[i] & b->ipv6_addr[i];
+	}
+}
+void IPOr6(IP *dst, IP *a, IP *b)
+{
+	UINT i;
+	// 引数チェック
+	if (dst == NULL || IsIP6(a) == false || IsIP6(b) == false)
+	{
+		return;
+	}
+
+	ZeroIP6(dst);
+	for (i = 0;i < 16;i++)
+	{
+		dst->ipv6_addr[i] = a->ipv6_addr[i] | b->ipv6_addr[i];
+	}
+}
+void IPNot6(IP *dst, IP *a)
+{
+	UINT i;
+	// 引数チェック
+	if (dst == NULL || IsIP6(a) == false)
+	{
+		return;
+	}
+
+	ZeroIP6(dst);
+	for (i = 0;i < 16;i++)
+	{
+		dst->ipv6_addr[i] = ~(a->ipv6_addr[i]);
+	}
+}
+
+// サブネットマスクの作成
+void IntToSubnetMask6(IP *ip, UINT i)
+{
+	UINT j = i / 8;
+	UINT k = i % 8;
+	UINT z;
+	IP a;
+
+	ZeroIP6(&a);
+
+	for (z = 0;z < 16;z++)
+	{
+		if (z < j)
+		{
+			a.ipv6_addr[z] = 0xff;
+		}
+		else if (z == j)
+		{
+			a.ipv6_addr[z] = ~(0xff >> k);
+		}
+	}
+
+	Copy(ip, &a, sizeof(IP));
+}
+
+// IP アドレスを文字列に変換
+void IP6AddrToStr(char *str, UINT size, IPV6_ADDR *addr)
+{
+	// 引数チェック
+	if (str == NULL || addr == NULL)
+	{
+		return;
+	}
+
+	IPToStr6Array(str, size, addr->Value);
+}
+void IPToStr6Array(char *str, UINT size, UCHAR *bytes)
+{
+	IP ip;
+	// 引数チェック
+	if (str == NULL || bytes == NULL)
+	{
+		return;
+	}
+
+	SetIP6(&ip, bytes);
+
+	IPToStr6(str, size, &ip);
+}
+void IPToStr6(char *str, UINT size, IP *ip)
+{
+	char tmp[MAX_SIZE];
+
+	IPToStr6Inner(tmp, ip);
+
+	StrCpy(str, size, tmp);
+}
+void IPToStr6Inner(char *str, IP *ip)
+{
+	UINT i;
+	USHORT values[8];
+	UINT zero_started_index;
+	UINT max_zero_len;
+	UINT max_zero_start;
+	IP a;
+	// 引数チェック
+	if (str == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	Copy(&a, ip, sizeof(IP));
+
+	for (i = 0;i < 8;i++)
+	{
+		Copy(&values[i], &a.ipv6_addr[i * 2], sizeof(USHORT));
+		values[i] = Endian16(values[i]);
+	}
+
+	// 省略できる場所があるかどうか検索
+	zero_started_index = INFINITE;
+	max_zero_len = 0;
+	max_zero_start = INFINITE;
+	for (i = 0;i < 9;i++)
+	{
+		USHORT v = (i != 8 ? values[i] : 1);
+
+		if (values[i] == 0)
+		{
+			if (zero_started_index == INFINITE)
+			{
+				zero_started_index = i;
+			}
+		}
+		else
+		{
+			UINT zero_len;
+
+			if (zero_started_index != INFINITE)
+			{
+				zero_len = i - zero_started_index;
+				if (zero_len >= 2)
+				{
+					if (max_zero_len < zero_len)
+					{
+						max_zero_start = zero_started_index;
+						max_zero_len = zero_len;
+					}
+				}
+
+				zero_started_index = INFINITE;
+			}
+		}
+	}
+
+	// 文字列を形成
+	StrCpy(str, 0, "");
+	for (i = 0;i < 8;i++)
+	{
+		char tmp[16];
+
+		ToHex(tmp, values[i]);
+		StrLower(tmp);
+
+		if (i == max_zero_start)
+		{
+			if (i == 0)
+			{
+				StrCat(str, 0, "::");
+			}
+			else
+			{
+				StrCat(str, 0, ":");
+			}
+			i += max_zero_len - 1;
+		}
+		else
+		{
+			StrCat(str, 0, tmp);
+			if (i != 7)
+			{
+				StrCat(str, 0, ":");
+			}
+		}
+	}
+
+	// スコープ ID
+	if (ip->ipv6_scope_id != 0)
+	{
+		char tmp[64];
+
+		StrCat(str, 0, "%");
+		ToStr(tmp, ip->ipv6_scope_id);
+
+		StrCat(str, 0, tmp);
+	}
+}
+
+// 文字列を IP アドレスに変換
+bool StrToIP6(IP *ip, char *str)
+{
+	TOKEN_LIST *t;
+	char tmp[MAX_PATH];
+	IP a;
+	UINT i;
+	UINT scope_id = 0;
+	// 引数チェック
+	if (str == NULL || ip == NULL)
+	{
+		return false;
+	}
+
+	ZeroIP6(&a);
+
+	StrCpy(tmp, sizeof(tmp), str);
+	Trim(tmp);
+
+	if (StartWith(tmp, "[") && EndWith(tmp, "]"))
+	{
+		// かぎかっこで囲まれている場合はそれを除去
+		StrCpy(tmp, sizeof(tmp), &tmp[1]);
+
+		if (StrLen(tmp) >= 1)
+		{
+			tmp[StrLen(tmp) - 1] = 0;
+		}
+	}
+
+	// スコープ ID がある場合はそれを解析して除去
+	i = SearchStrEx(tmp, "%", 0, false);
+	if (i != INFINITE)
+	{
+		char ss[MAX_PATH];
+
+		StrCpy(ss, sizeof(ss), &tmp[i + 1]);
+
+		tmp[i] = 0;
+
+		Trim(tmp);
+
+		Trim(ss);
+
+		scope_id = ToInt(ss);
+	}
+
+	// トークン分割
+	t = ParseTokenWithNullStr(tmp, ":");
+	if (t->NumTokens >= 3 && t->NumTokens <= 8)
+	{
+		UINT i, n;
+		bool b = true;
+		UINT k = 0;
+
+		n = 0;
+
+		for (i = 0;i < t->NumTokens;i++)
+		{
+			char *str = t->Token[i];
+
+			if (i != 0 && i != (t->NumTokens - 1) && StrLen(str) == 0)
+			{
+				n++;
+				if (n == 1)
+				{
+					k += 2 * (8 - t->NumTokens + 1);
+				}
+				else
+				{
+					b = false;
+					break;
+				}
+			}
+			else
+			{
+				UCHAR chars[2];
+
+				if (CheckIPItemStr6(str) == false)
+				{
+					b = false;
+					break;
+				}
+
+				IPItemStrToChars6(chars, str);
+
+				a.ipv6_addr[k++] = chars[0];
+				a.ipv6_addr[k++] = chars[1];
+			}
+		}
+
+		if (n != 0 && n != 1)
+		{
+			b = false;
+		}
+		else if (n == 0 && t->NumTokens != 8)
+		{
+			b = false;
+		}
+
+		if (b == false)
+		{
+			FreeToken(t);
+			return false;
+		}
+	}
+	else
+	{
+		FreeToken(t);
+		return false;
+	}
+
+	FreeToken(t);
+
+	Copy(ip, &a, sizeof(IP));
+
+	ip->ipv6_scope_id = scope_id;
+
+	return true;
+}
+bool StrToIP6Addr(IPV6_ADDR *ip, char *str)
+{
+	IP ip2;
+	// 引数チェック
+	if (ip == NULL || str == NULL)
+	{
+		Zero(ip, sizeof(IPV6_ADDR));
+		return false;
+	}
+
+	if (StrToIP6(&ip2, str) == false)
+	{
+		return false;
+	}
+
+	if (IPToIPv6Addr(ip, &ip2) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// IP アドレスの文字から UCHAR 型に変換
+void IPItemStrToChars6(UCHAR *chars, char *str)
+{
+	char tmp[5];
+	BUF *b;
+	UINT len;
+	// 引数チェック
+	if (chars == NULL)
+	{
+		return;
+	}
+
+	Zero(tmp, sizeof(tmp));
+
+	len = StrLen(str);
+	switch (len)
+	{
+	case 0:
+		tmp[0] = tmp[1] = tmp[2] = tmp[3] = '0';
+		break;
+
+	case 1:
+		tmp[0] = tmp[1] = tmp[2] = '0';
+		tmp[3] = str[0];
+		break;
+
+	case 2:
+		tmp[0] = tmp[1] = '0';
+		tmp[2] = str[0];
+		tmp[3] = str[1];
+		break;
+
+	case 3:
+		tmp[0] = '0';
+		tmp[1] = str[0];
+		tmp[2] = str[1];
+		tmp[3] = str[2];
+		break;
+
+	case 4:
+		tmp[0] = str[0];
+		tmp[1] = str[1];
+		tmp[2] = str[2];
+		tmp[3] = str[3];
+		break;
+	}
+
+	b = StrToBin(tmp);
+
+	chars[0] = ((UCHAR *)b->Buf)[0];
+	chars[1] = ((UCHAR *)b->Buf)[1];
+
+	FreeBuf(b);
+}
+
+// IP アドレスの要素文字列の中に不正な文字が含まれていないかどうかチェックする
+bool CheckIPItemStr6(char *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	len = StrLen(str);
+	if (len >= 5)
+	{
+		// 長さ不正
+		return false;
+	}
+
+	for (i = 0;i < len;i++)
+	{
+		char c = str[i];
+
+		if ((c >= 'a' && c <= 'f') ||
+			(c >= 'A' && c <= 'F') ||
+			(c >= '0' && c <= '9'))
+		{
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// ゼロの IPv4 アドレスを作成する
+void ZeroIP4(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	Zero(ip, sizeof(IP));
+}
+
+// ゼロの IPv6 アドレスを作成する
+void ZeroIP6(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	SetIP6(ip, NULL);
+}
+
+// localhost の IP アドレスを取得する
+void GetLocalHostIP6(IP *ip)
+{
+	ZeroIP6(ip);
+
+	ip->ipv6_addr[15] = 1;
+}
+
+// IPV6_ADDR を IP に変換
+void IPv6AddrToIP(IP *ip, IPV6_ADDR *addr)
+{
+	// 引数チェック
+	if (ip == NULL || addr == NULL)
+	{
+		return;
+	}
+
+	SetIP6(ip, addr->Value);
+}
+
+// IP を IPV6_ADDR に変換
+bool IPToIPv6Addr(IPV6_ADDR *addr, IP *ip)
+{
+	UINT i;
+	// 引数チェック
+	if (addr == NULL || ip == NULL)
+	{
+		Zero(addr, sizeof(IPV6_ADDR));
+		return false;
+	}
+
+	if (IsIP6(ip) == false)
+	{
+		Zero(addr, sizeof(IPV6_ADDR));
+		return false;
+	}
+
+	for (i = 0;i < 16;i++)
+	{
+		addr->Value[i] = ip->ipv6_addr[i];
+	}
+
+	return true;
+}
+
+// IPv6 アドレスをセットする
+void SetIP6(IP *ip, UCHAR *value)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	Zero(ip, sizeof(IP));
+
+	ip->addr[0] = 223;
+	ip->addr[1] = 255;
+	ip->addr[2] = 255;
+	ip->addr[3] = 254;
+
+	if (value != NULL)
+	{
+		UINT i;
+
+		for (i = 0;i < 16;i++)
+		{
+			ip->ipv6_addr[i] = value[i];
+		}
+	}
+}
+
+// 指定されたアドレスが IPv6 アドレスかどうかチェックする
+bool IsIP6(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	if (ip->addr[0] == 223 && ip->addr[1] == 255 && ip->addr[2] == 255 && ip->addr[3] == 254)
+	{
+		return true;
+	}
+
+	return false;
+}
+bool IsIP4(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	return (IsIP6(ip) ? false : true);
+}
+
+// IPv6 のサブネット長をチェック
+bool CheckSubnetLength6(UINT i)
+{
+	if (i >= 1 && i <= 127)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// ソケットから対応する TCP コネクションのプロセス ID を取得
+UINT GetTcpProcessIdFromSocket(SOCK *s)
+{
+	LIST *o;
+	TCPTABLE *t;
+	UINT pid = 0;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	o = GetTcpTableList();
+	if (o == NULL)
+	{
+		return 0;
+	}
+
+	t = GetTcpTableFromEndPoint(o, &s->LocalIP, s->LocalPort,
+		&s->RemoteIP, s->RemotePort);
+
+	if (t != NULL)
+	{
+		pid = t->ProcessId;
+	}
+
+	FreeTcpTableList(o);
+
+	return pid;
+}
+UINT GetTcpProcessIdFromSocketReverse(SOCK *s)
+{
+	LIST *o;
+	TCPTABLE *t;
+	UINT pid = 0;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return 0;
+	}
+
+	o = GetTcpTableList();
+	if (o == NULL)
+	{
+		return 0;
+	}
+
+	t = GetTcpTableFromEndPoint(o, &s->RemoteIP, s->RemotePort,
+		&s->LocalIP, s->LocalPort);
+
+	if (t != NULL)
+	{
+		pid = t->ProcessId;
+	}
+
+	FreeTcpTableList(o);
+
+	return pid;
+}
+
+// エンドポイントから TCP テーブルを検索
+TCPTABLE *GetTcpTableFromEndPoint(LIST *o, IP *local_ip, UINT local_port, IP *remote_ip, UINT remote_port)
+{
+	IP local;
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	SetIP(&local, 127, 0, 0, 1);
+
+	if (local_ip == NULL)
+	{
+		local_ip = &local;
+	}
+
+	if (remote_ip == NULL)
+	{
+		remote_ip = &local;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		TCPTABLE *t = LIST_DATA(o, i);
+
+		if (t->Status == TCP_STATE_SYN_SENT || t->Status == TCP_STATE_SYN_RCVD ||
+			t->Status == TCP_STATE_ESTAB)
+		{
+			if (CmpIpAddr(&t->LocalIP, local_ip) == 0)
+			{
+				if (CmpIpAddr(&t->RemoteIP, remote_ip) == 0)
+				{
+					if (t->LocalPort == local_port)
+					{
+						if (t->RemotePort == remote_port)
+						{
+							return t;
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+
+// TCP テーブルリストを取得 (Win32)
+#ifdef	OS_WIN32
+LIST *Win32GetTcpTableList()
+{
+	LIST *o;
+
+	// Windows XP SP2 以降用
+	o = Win32GetTcpTableListByGetExtendedTcpTable();
+	if (o != NULL)
+	{
+		return o;
+	}
+
+	// Windows XP 以降用
+	o = Win32GetTcpTableListByAllocateAndGetTcpExTableFromStack();
+	if (o != NULL)
+	{
+		return o;
+	}
+
+	// 古い Windows 用
+	return Win32GetTcpTableListByGetTcpTable();
+}
+
+// TCP テーブルリストを取得: Windows XP SP2 以降用
+LIST *Win32GetTcpTableListByGetExtendedTcpTable()
+{
+	UINT need_size;
+	UINT i;
+	MIB_TCPTABLE_OWNER_PID *table;
+	bool ok = false;
+	LIST *o;
+	if (w32net->GetExtendedTcpTable == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < 128;i++)
+	{
+		UINT ret;
+		table = MallocFast(sizeof(MIB_TCPTABLE_OWNER_PID));
+		need_size = sizeof(MIB_TCPTABLE_OWNER_PID);
+		ret = w32net->GetExtendedTcpTable(table, &need_size, true, AF_INET, _TCP_TABLE_OWNER_PID_ALL, 0);
+		if (ret == NO_ERROR)
+		{
+			ok = true;
+			break;
+		}
+		else
+		{
+			Free(table);
+			if (ret != ERROR_INSUFFICIENT_BUFFER)
+			{
+				return NULL;
+			}
+		}
+
+		table = MallocFast(need_size);
+
+		ret = w32net->GetExtendedTcpTable(table, &need_size, true, AF_INET, _TCP_TABLE_OWNER_PID_ALL, 0);
+		if (ret == NO_ERROR)
+		{
+			ok = true;
+			break;
+		}
+		else
+		{
+			Free(table);
+
+			if (ret != ERROR_INSUFFICIENT_BUFFER)
+			{
+				return NULL;
+			}
+		}
+	}
+
+	if (ok == false)
+	{
+		return NULL;
+	}
+
+	o = NewListEx(NULL, true);
+
+	for (i = 0;i < table->dwNumEntries;i++)
+	{
+		MIB_TCPROW_OWNER_PID *r = &table->table[i];
+		TCPTABLE *t = ZeroMallocFast(sizeof(TCPTABLE));
+
+		UINTToIP(&t->LocalIP, r->dwLocalAddr);
+		t->LocalPort = Endian16((USHORT)r->dwLocalPort);
+
+		if (r->dwState != TCP_STATE_LISTEN)
+		{
+			UINTToIP(&t->RemoteIP, r->dwRemoteAddr);
+			t->RemotePort = Endian16((USHORT)r->dwRemotePort);
+		}
+
+		t->Status = r->dwState;
+		t->ProcessId = r->dwOwningPid;
+
+		Add(o, t);
+	}
+
+	Free(table);
+
+	return o;
+}
+
+// TCP テーブルリストを取得: Windows XP 以降用
+LIST *Win32GetTcpTableListByAllocateAndGetTcpExTableFromStack()
+{
+	HANDLE heap;
+	UINT i;
+	MIB_TCPTABLE_OWNER_PID *table;
+	bool ok = false;
+	LIST *o;
+	if (w32net->AllocateAndGetTcpExTableFromStack == NULL)
+	{
+		return NULL;
+	}
+
+	heap = GetProcessHeap();
+
+	if (w32net->AllocateAndGetTcpExTableFromStack(&table, true, heap, HEAP_GROWABLE, AF_INET) != ERROR_SUCCESS)
+	{
+		return NULL;
+	}
+
+	o = NewListEx(NULL, true);
+
+	for (i = 0;i < table->dwNumEntries;i++)
+	{
+		MIB_TCPROW_OWNER_PID *r = &table->table[i];
+		TCPTABLE *t = ZeroMallocFast(sizeof(TCPTABLE));
+
+		UINTToIP(&t->LocalIP, r->dwLocalAddr);
+		t->LocalPort = Endian16((USHORT)r->dwLocalPort);
+
+		if (r->dwState != TCP_STATE_LISTEN)
+		{
+			UINTToIP(&t->RemoteIP, r->dwRemoteAddr);
+			t->RemotePort = Endian16((USHORT)r->dwRemotePort);
+		}
+
+		t->ProcessId = r->dwOwningPid;
+		t->Status = r->dwState;
+
+		Add(o, t);
+	}
+
+	HeapFree(heap, 0, table);
+
+	return o;
+}
+
+// TCP テーブルリストを取得: 古い Windows 用
+LIST *Win32GetTcpTableListByGetTcpTable()
+{
+	UINT need_size;
+	UINT i;
+	MIB_TCPTABLE *table;
+	bool ok = false;
+	LIST *o;
+	if (w32net->GetTcpTable == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < 128;i++)
+	{
+		UINT ret;
+		table = MallocFast(sizeof(MIB_TCPTABLE));
+		need_size = sizeof(MIB_TCPTABLE);
+		ret = w32net->GetTcpTable(table, &need_size, true);
+		if (ret == NO_ERROR)
+		{
+			ok = true;
+			break;
+		}
+		else
+		{
+			Free(table);
+			if (ret != ERROR_INSUFFICIENT_BUFFER)
+			{
+				return NULL;
+			}
+		}
+
+		table = MallocFast(need_size);
+
+		ret = w32net->GetTcpTable(table, &need_size, true);
+		if (ret == NO_ERROR)
+		{
+			ok = true;
+			break;
+		}
+		else
+		{
+			Free(table);
+
+			if (ret != ERROR_INSUFFICIENT_BUFFER)
+			{
+				return NULL;
+			}
+		}
+	}
+
+	if (ok == false)
+	{
+		return NULL;
+	}
+
+	o = NewListEx(NULL, true);
+
+	for (i = 0;i < table->dwNumEntries;i++)
+	{
+		MIB_TCPROW *r = &table->table[i];
+		TCPTABLE *t = ZeroMallocFast(sizeof(TCPTABLE));
+
+		UINTToIP(&t->LocalIP, r->dwLocalAddr);
+		t->LocalPort = Endian16((USHORT)r->dwLocalPort);
+
+		if (r->dwState != TCP_STATE_LISTEN)
+		{
+			UINTToIP(&t->RemoteIP, r->dwRemoteAddr);
+			t->RemotePort = Endian16((USHORT)r->dwRemotePort);
+		}
+
+		t->Status = r->dwState;
+
+		Add(o, t);
+	}
+
+	Free(table);
+
+	return o;
+}
+
+#endif	// OS_WIN32
+
+// TCP テーブルの表示
+void PrintTcpTableList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		Print("o == NULL\n\n");
+		return;
+	}
+
+	Print("--- TCPTABLE: %u Entries ---\n", LIST_NUM(o));
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		char tmp1[MAX_PATH], tmp2[MAX_PATH];
+		TCPTABLE *t = LIST_DATA(o, i);
+
+		IPToStr(tmp1, sizeof(tmp1), &t->LocalIP);
+		IPToStr(tmp2, sizeof(tmp2), &t->RemoteIP);
+
+		Print("%s:%u <--> %s:%u  state=%u  pid=%u\n",
+			tmp1, t->LocalPort,
+			tmp2, t->RemotePort,
+			t->Status,
+			t->ProcessId);
+	}
+	Print("------\n\n");
+}
+
+// TCP テーブルの比較
+int CompareTcpTable(void *p1, void *p2)
+{
+	TCPTABLE *t1, *t2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	t1 = *(TCPTABLE **)p1;
+	t2 = *(TCPTABLE **)p2;
+	if (t1 == NULL || t2 == NULL)
+	{
+		return 0;
+	}
+
+	return Cmp(t1, t2, sizeof(TCPTABLE));
+}
+
+// TCP テーブルリストを取得
+LIST *GetTcpTableList()
+{
+#ifdef	OS_WIN32
+	return Win32GetTcpTableList();
+#else	// OS_WIN32
+	return NULL;
+#endif	// OS_WIN32
+}
+
+// TCP テーブルリストを解放
+void FreeTcpTableList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		TCPTABLE *t = LIST_DATA(o, i);
+
+		Free(t);
+	}
+
+	ReleaseList(o);
+}
+
+// 指定された IP アドレスから接続中のクライアント数の取得
+UINT GetNumIpClient(IP *ip)
+{
+	IP_CLIENT *c;
+	UINT ret = 0;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return 0;
+	}
+
+	LockList(ip_clients);
+	{
+		c = SearchIpClient(ip);
+
+		if (c != NULL)
+		{
+			ret = c->NumConnections;
+		}
+	}
+	UnlockList(ip_clients);
+
+	return ret;
+}
+
+// IP クライアントエントリに追加
+void AddIpClient(IP *ip)
+{
+	IP_CLIENT *c;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	LockList(ip_clients);
+	{
+		c = SearchIpClient(ip);
+
+		if (c == NULL)
+		{
+			c = ZeroMallocFast(sizeof(IP_CLIENT));
+			Copy(&c->IpAddress, ip, sizeof(IP));
+			c->NumConnections = 0;
+
+			Add(ip_clients, c);
+		}
+
+		c->NumConnections++;
+	}
+	UnlockList(ip_clients);
+}
+
+// IP クライアントリストから削除
+void DelIpClient(IP *ip)
+{
+	IP_CLIENT *c;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	LockList(ip_clients);
+	{
+		c = SearchIpClient(ip);
+
+		if (c != NULL)
+		{
+			c->NumConnections--;
+
+			if (c->NumConnections == 0)
+			{
+				Delete(ip_clients, c);
+				Free(c);
+			}
+		}
+	}
+	UnlockList(ip_clients);
+}
+
+// IP クライアントエントリの検索
+IP_CLIENT *SearchIpClient(IP *ip)
+{
+	IP_CLIENT t;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return NULL;
+	}
+
+	Zero(&t, sizeof(t));
+	Copy(&t.IpAddress, ip, sizeof(IP));
+
+	return Search(ip_clients, &t);
+}
+
+// クライアントリストの初期化
+void InitIpClientList()
+{
+	ip_clients = NewList(CompareIpClientList);
+}
+
+// クライアントリストの解放
+void FreeIpClientList()
+{
+	UINT i;
+
+	for (i = 0;i < LIST_NUM(ip_clients);i++)
+	{
+		IP_CLIENT *c = LIST_DATA(ip_clients, i);
+
+		Free(c);
+	}
+
+	ReleaseList(ip_clients);
+	ip_clients = NULL;
+}
+
+// クライアントリストエントリの比較
+int CompareIpClientList(void *p1, void *p2)
+{
+	IP_CLIENT *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(IP_CLIENT **)p1;
+	c2 = *(IP_CLIENT **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+
+	return CmpIpAddr(&c1->IpAddress, &c2->IpAddress);
+}
+
+// MAC アドレスの正規化
+bool NormalizeMacAddress(char *dst, UINT size, char *src)
+{
+	BUF *b;
+	bool ret = false;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return false;
+	}
+
+	b = StrToBin(src);
+
+	if (b != NULL && b->Size == 6)
+	{
+		ret = true;
+
+		BinToStr(dst, size, b->Buf, b->Size);
+	}
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// IP アドレスが空かどうか識別する
+bool IsZeroIP(IP *ip)
+{
+	return IsZeroIp(ip);
+}
+bool IsZeroIp(IP *ip)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return true;
+	}
+
+	if (IsIP6(ip) == false)
+	{
+		return IsZero(ip->addr, sizeof(ip->addr));
+	}
+	else
+	{
+		return IsZero(ip->ipv6_addr, sizeof(ip->ipv6_addr));
+	}
+}
+bool IsZeroIP6Addr(IPV6_ADDR *addr)
+{
+	// 引数チェック
+	if (addr == NULL)
+	{
+		return true;
+	}
+
+	return IsZero(addr, sizeof(IPV6_ADDR));
+}
+
+// 指定された IP アドレスがホストとして意味があるかどうかを調べる
+bool IsHostIPAddress4(IP *ip)
+{
+	UINT a;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	a = IPToUINT(ip);
+
+	if (a == 0 || a == 0xffffffff)
+	{
+		return false;
+	}
+
+	return true;
+}
+bool IsHostIPAddress32(UINT ip)
+{
+	IP p;
+
+	UINTToIP(&p, ip);
+
+	return IsHostIPAddress4(&p);
+}
+
+// 指定された IP アドレスとサブネットマスクが正しくネットワークを示すかどうか調べる
+bool IsNetworkAddress(IP *ip, IP *mask)
+{
+	if (IsIP4(ip))
+	{
+		return IsNetworkAddress4(ip, mask);
+	}
+	else
+	{
+		return IsNetworkAddress6(ip, mask);
+	}
+}
+bool IsNetworkAddress4(IP *ip, IP *mask)
+{
+	UINT a, b;
+	// 引数チェック
+	if (ip == NULL || mask == NULL)
+	{
+		return false;
+	}
+
+	if (IsIP4(ip) == false || IsIP4(mask) == false)
+	{
+		return false;
+	}
+
+	if (IsSubnetMask4(mask) == false)
+	{
+		return false;
+	}
+
+	a = IPToUINT(ip);
+	b = IPToUINT(mask);
+
+	if ((a & b) == a)
+	{
+		return true;
+	}
+
+	return false;
+}
+bool IsNetworkAddress32(UINT ip, UINT mask)
+{
+	IP a, b;
+
+	UINTToIP(&a, ip);
+	UINTToIP(&b, mask);
+
+	return IsNetworkAddress4(&a, &b);
+}
+
+// 整数をサブネットマスクに変換する
+UINT IntToSubnetMask32(UINT i)
+{
+	UINT ret = 0xFFFFFFFF;
+
+	// 汚いコード
+	switch (i)
+	{
+	case 0:		ret = 0x00000000;	break;
+	case 1:		ret = 0x80000000;	break;
+	case 2:		ret = 0xC0000000;	break;
+	case 3:		ret = 0xE0000000;	break;
+	case 4:		ret = 0xF0000000;	break;
+	case 5:		ret = 0xF8000000;	break;
+	case 6:		ret = 0xFC000000;	break;
+	case 7:		ret = 0xFE000000;	break;
+	case 8:		ret = 0xFF000000;	break;
+	case 9:		ret = 0xFF800000;	break;
+	case 10:	ret = 0xFFC00000;	break;
+	case 11:	ret = 0xFFE00000;	break;
+	case 12:	ret = 0xFFF00000;	break;
+	case 13:	ret = 0xFFF80000;	break;
+	case 14:	ret = 0xFFFC0000;	break;
+	case 15:	ret = 0xFFFE0000;	break;
+	case 16:	ret = 0xFFFF0000;	break;
+	case 17:	ret = 0xFFFF8000;	break;
+	case 18:	ret = 0xFFFFC000;	break;
+	case 19:	ret = 0xFFFFE000;	break;
+	case 20:	ret = 0xFFFFF000;	break;
+	case 21:	ret = 0xFFFFF800;	break;
+	case 22:	ret = 0xFFFFFC00;	break;
+	case 23:	ret = 0xFFFFFE00;	break;
+	case 24:	ret = 0xFFFFFF00;	break;
+	case 25:	ret = 0xFFFFFF80;	break;
+	case 26:	ret = 0xFFFFFFC0;	break;
+	case 27:	ret = 0xFFFFFFE0;	break;
+	case 28:	ret = 0xFFFFFFF0;	break;
+	case 29:	ret = 0xFFFFFFF8;	break;
+	case 30:	ret = 0xFFFFFFFC;	break;
+	case 31:	ret = 0xFFFFFFFE;	break;
+	case 32:	ret = 0xFFFFFFFF;	break;
+	}
+
+	if (IsLittleEndian())
+	{
+		ret = Swap32(ret);
+	}
+
+	return ret;
+}
+void IntToSubnetMask4(IP *ip, UINT i)
+{
+	UINT m;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	m = IntToSubnetMask32(i);
+
+	UINTToIP(ip, m);
+}
+
+// 指定された IP アドレスがサブネットマスクかどうか調べる
+bool IsSubnetMask(IP *ip)
+{
+	if (IsIP6(ip))
+	{
+		return IsSubnetMask6(ip);
+	}
+	else
+	{
+		return IsSubnetMask4(ip);
+	}
+}
+bool IsSubnetMask4(IP *ip)
+{
+	UINT i;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	if (IsIP6(ip))
+	{
+		return false;
+	}
+
+	i = IPToUINT(ip);
+
+	if (IsLittleEndian())
+	{
+		i = Swap32(i);
+	}
+
+	// 汚いコード
+	switch (i)
+	{
+	case 0x00000000:
+	case 0x80000000:
+	case 0xC0000000:
+	case 0xE0000000:
+	case 0xF0000000:
+	case 0xF8000000:
+	case 0xFC000000:
+	case 0xFE000000:
+	case 0xFF000000:
+	case 0xFF800000:
+	case 0xFFC00000:
+	case 0xFFE00000:
+	case 0xFFF00000:
+	case 0xFFF80000:
+	case 0xFFFC0000:
+	case 0xFFFE0000:
+	case 0xFFFF0000:
+	case 0xFFFF8000:
+	case 0xFFFFC000:
+	case 0xFFFFE000:
+	case 0xFFFFF000:
+	case 0xFFFFF800:
+	case 0xFFFFFC00:
+	case 0xFFFFFE00:
+	case 0xFFFFFF00:
+	case 0xFFFFFF80:
+	case 0xFFFFFFC0:
+	case 0xFFFFFFE0:
+	case 0xFFFFFFF0:
+	case 0xFFFFFFF8:
+	case 0xFFFFFFFC:
+	case 0xFFFFFFFE:
+	case 0xFFFFFFFF:
+		return true;
+	}
+
+	return false;
+}
+bool IsSubnetMask32(UINT ip)
+{
+	IP p;
+
+	UINTToIP(&p, ip);
+
+	return IsSubnetMask4(&p);
+}
+
+// ネットワークリリースモード
+void SetNetworkReleaseMode()
+{
+	NetworkReleaseMode = true;
+}
+
+#ifdef	OS_UNIX			// UNIX 用コード
+
+// ソケットをノンブロッキングモードにしたり解除したりする
+void UnixSetSocketNonBlockingMode(int fd, bool nonblock)
+{
+	UINT flag = 0;
+	// 引数チェック
+	if (fd == INVALID_SOCKET)
+	{
+		return;
+	}
+
+	if (nonblock)
+	{
+		flag = 1;
+	}
+
+#ifdef	FIONBIO
+	ioctl(fd, FIONBIO, &flag);
+#else	// FIONBIO
+	{
+		int flag = fcntl(fd, F_GETFL, 0);
+		if (flag != -1)
+		{
+			if (nonblock)
+			{
+				flag |= O_NONBLOCK;
+			}
+			else
+			{
+				flag = flag & ~O_NONBLOCK;
+
+				fcntl(fd, F_SETFL, flag);
+			}
+		}
+	}
+#endif	// FIONBIO
+}
+
+// 何もしない
+void UnixIpForwardRowToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row)
+{
+}
+
+// 何もしない
+void UnixRouteEntryToIpForwardRow(void *ip_forward_row, ROUTE_ENTRY *entry)
+{
+}
+
+// 何もしない
+int UnixCompareRouteEntryByMetric(void *p1, void *p2)
+{
+	return 1;
+}
+
+// 何もしない
+ROUTE_TABLE *UnixGetRouteTable()
+{
+	ROUTE_TABLE *ret = ZeroMalloc(sizeof(ROUTE_TABLE));
+	ret->NumEntry = 0;
+	ret->Entry = ZeroMalloc(0);
+
+	return ret;
+}
+
+// 何もしない
+bool UnixAddRouteEntry(ROUTE_ENTRY *e, bool *already_exists)
+{
+	return true;
+}
+
+// 何もしない
+void UnixDeleteRouteEntry(ROUTE_ENTRY *e)
+{
+	return;
+}
+
+// 何もしない
+UINT UnixGetVLanInterfaceID(char *instance_name)
+{
+	return 1;
+}
+
+// 何もしない
+char **UnixEnumVLan(char *tag_name)
+{
+	char **list;
+
+	list = ZeroMalloc(sizeof(char *));
+
+	return list;
+}
+
+// 何もしない
+void UnixRenewDhcp()
+{
+}
+
+// デフォルトの DNS サーバーの IP アドレスを取得
+bool UnixGetDefaultDns(IP *ip)
+{
+	BUF *b;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+
+	Lock(unix_dns_server_addr_lock);
+	{
+		if (IsZero(&unix_dns_server, sizeof(IP)) == false)
+		{
+			Copy(ip, &unix_dns_server, sizeof(IP));
+			Unlock(unix_dns_server_addr_lock);
+			return true;
+		}
+
+		ip->addr[0] = 127;
+		ip->addr[1] = 0;
+		ip->addr[2] = 0;
+		ip->addr[3] = 1;
+
+		b = ReadDump("/etc/resolv.conf");
+		if (b != NULL)
+		{
+			char *s;
+			bool f = false;
+			while ((s = CfgReadNextLine(b)) != NULL)
+			{
+				TOKEN_LIST *t = ParseToken(s, "\" \t,");
+				if (t->NumTokens == 2)
+				{
+					if (StrCmpi(t->Token[0], "nameserver") == 0)
+					{
+						StrToIP(ip, t->Token[1]);
+						f = true;
+					}
+				}
+				FreeToken(t);
+
+				Free(s);
+
+				if (f)
+				{
+					break;
+				}
+			}
+			FreeBuf(b);
+		}
+		Copy(&unix_dns_server, ip, sizeof(IP));
+	}
+	Unlock(unix_dns_server_addr_lock);
+
+	return true;
+}
+
+
+// Select 処理
+void UnixSelect(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2)
+{
+	UINT reads[MAXIMUM_WAIT_OBJECTS];
+	UINT writes[MAXIMUM_WAIT_OBJECTS];
+	UINT num_read, num_write, i;
+	UINT p1, p2;
+	SOCK *s;
+	UCHAR tmp[MAX_SIZE];
+	// 引数チェック
+	if (timeout == 0)
+	{
+		return;
+	}
+
+	// 配列の初期化
+	Zero(reads, sizeof(reads));
+	Zero(writes, sizeof(writes));
+	num_read = num_write = 0;
+
+	// イベント配列の設定
+	if (set != NULL)
+	{
+		for (i = 0;i < set->NumSocket;i++)
+		{
+			s = set->Sock[i];
+			if (s != NULL)
+			{
+				UnixInitAsyncSocket(s);
+				reads[num_read++] = s->socket;
+				if (s->WriteBlocked)
+				{
+					writes[num_write++] = s->socket;
+				}
+			}
+		}
+	}
+
+	p1 = p2 = -1;
+
+	if (c1 != NULL)
+	{
+		reads[num_read++] = p1 = c1->pipe_read;
+	}
+	if (c2 != NULL)
+	{
+		reads[num_read++] = p2 = c2->pipe_read;
+	}
+
+	// select を呼び出す
+	UnixSelectInner(num_read, reads, num_write, writes, timeout);
+
+	// pipe から読んでおく
+	if (c1 != NULL && c1->SpecialFlag == false && p1 != -1)
+	{
+		read(p1, tmp, sizeof(tmp));
+	}
+	if (c2 != NULL && c2->SpecialFlag == false && p2 != -1)
+	{
+		read(p2, tmp, sizeof(tmp));
+	}
+}
+
+// キャンセル
+void UnixCancel(CANCEL *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	UnixWritePipe(c->pipe_write);
+}
+
+// キャンセルオブジェクトの解放
+void UnixCleanupCancel(CANCEL *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	if (c->SpecialFlag == false)
+	{
+		UnixDeletePipe(c->pipe_read, c->pipe_write);
+	}
+
+	Free(c);
+}
+
+// 新しいキャンセルオブジェクトの作成
+CANCEL *UnixNewCancel()
+{
+	CANCEL *c = ZeroMallocFast(sizeof(CANCEL));
+
+	c->ref = NewRef();
+	c->SpecialFlag = false;
+
+	UnixNewPipe(&c->pipe_read, &c->pipe_write);
+
+	return c;
+}
+
+// ソケットをソケットイベントに追加する
+void UnixJoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event)
+{
+	// 引数チェック
+	if (sock == NULL || event == NULL || sock->AsyncMode)
+	{
+		return;
+	}
+	if (sock->ListenMode != false || (sock->Type == SOCK_TCP && sock->Connected == false))
+	{
+		return;
+	}
+
+	sock->AsyncMode = true;
+
+	LockList(event->SockList);
+	{
+		Add(event->SockList, sock);
+		AddRef(sock->ref);
+	}
+	UnlockList(event->SockList);
+
+	// ソケットを非同期にする
+	UnixSetSocketNonBlockingMode(sock->socket, true);
+
+	// SOCK_EVENT の参照カウンタを増加
+	AddRef(event->ref);
+	sock->SockEvent = event;
+
+	// ソケットイベントを叩く
+	SetSockEvent(event);
+}
+
+// ソケットイベントを待機する
+bool UnixWaitSockEvent(SOCK_EVENT *event, UINT timeout)
+{
+	UINT num_read, num_write;
+	UINT *reads, *writes;
+	UINT n;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (event == NULL)
+	{
+		return false;
+	}
+
+	LockList(event->SockList);
+	{
+		UINT i;
+		num_read = LIST_NUM(event->SockList) + 1;
+		reads = ZeroMallocFast(sizeof(SOCK *) * num_read);
+
+		num_write = 0;
+
+		for (i = 0;i < (num_read - 1);i++)
+		{
+			SOCK *s = LIST_DATA(event->SockList, i);
+			reads[i] = s->socket;
+			if (s->WriteBlocked)
+			{
+				num_write++;
+			}
+		}
+
+		reads[num_read - 1] = event->pipe_read;
+
+		writes = ZeroMallocFast(sizeof(SOCK *) * num_write);
+
+		n = 0;
+
+		for (i = 0;i < (num_read - 1);i++)
+		{
+			SOCK *s = LIST_DATA(event->SockList, i);
+			if (s->WriteBlocked)
+			{
+				writes[n++] = s->socket;
+			}
+		}
+	}
+	UnlockList(event->SockList);
+
+	if (0)
+	{
+		UINT i;
+		Print("UnixSelectInner: ");
+		for (i = 0;i < num_read;i++)
+		{
+			Print("%u ", reads[i]);
+		}
+		Print("\n");
+	}
+
+	UnixSelectInner(num_read, reads, num_write, writes, timeout);
+
+	read(event->pipe_read, tmp, sizeof(tmp));
+
+	Free(reads);
+	Free(writes);
+
+	return true;
+}
+
+// ソケットイベントをセットする
+void UnixSetSockEvent(SOCK_EVENT *event)
+{
+	// 引数チェック
+	if (event == NULL)
+	{
+		return;
+	}
+
+	UnixWritePipe(event->pipe_write);
+}
+
+// ソケットの select の実行
+void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, UINT timeout)
+{
+	struct pollfd *p;
+	UINT num;
+	UINT i;
+	UINT n;
+	UINT num_read_total, num_write_total;
+
+	if (num_read != 0 && reads == NULL)
+	{
+		num_read = 0;
+	}
+	if (num_write != 0 && writes == NULL)
+	{
+		num_write = 0;
+	}
+
+	if (timeout == 0)
+	{
+		return;
+	}
+
+	num_read_total = num_write_total = 0;
+	for (i = 0;i < num_read;i++)
+	{
+		if (reads[i] != INVALID_SOCKET)
+		{
+			num_read_total++;
+		}
+	}
+	for (i = 0;i < num_write;i++)
+	{
+		if (writes[i] != INVALID_SOCKET)
+		{
+			num_write_total++;
+		}
+	}
+
+	num = num_read_total + num_write_total;
+	p = ZeroMallocFast(sizeof(struct pollfd) * num);
+
+	n = 0;
+
+	for (i = 0;i < num_read;i++)
+	{
+		if (reads[i] != INVALID_SOCKET)
+		{
+			struct pollfd *pfd = &p[n++];
+			pfd->fd = reads[i];
+			pfd->events = POLLIN | POLLPRI | POLLERR | POLLHUP;
+		}
+	}
+
+	for (i = 0;i < num_write;i++)
+	{
+		if (writes[i] != INVALID_SOCKET)
+		{
+			struct pollfd *pfd = &p[n++];
+			pfd->fd = writes[i];
+			pfd->events = POLLIN | POLLPRI | POLLERR | POLLHUP | POLLOUT;
+		}
+	}
+
+	if (num != 0)
+	{
+		poll(p, num, timeout == INFINITE ? -1 : (int)timeout);
+	}
+	else
+	{
+		SleepThread(timeout);
+	}
+
+	Free(p);
+}
+
+// ソケットイベントのクリーンアップ
+void UnixCleanupSockEvent(SOCK_EVENT *event)
+{
+	UINT i;
+	// 引数チェック
+	if (event == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(event->SockList);i++)
+	{
+		SOCK *s = LIST_DATA(event->SockList, i);
+
+		ReleaseSock(s);
+	}
+
+	ReleaseList(event->SockList);
+
+	UnixDeletePipe(event->pipe_read, event->pipe_write);
+
+	Free(event);
+}
+
+// ソケットイベントを作成する
+SOCK_EVENT *UnixNewSockEvent()
+{
+	SOCK_EVENT *e = ZeroMallocFast(sizeof(SOCK_EVENT));
+
+	e->SockList = NewList(NULL);
+	e->ref = NewRef();
+
+	UnixNewPipe(&e->pipe_read, &e->pipe_write);
+
+	return e;
+}
+
+// パイプを閉じる
+void UnixDeletePipe(int p1, int p2)
+{
+	if (p1 != -1)
+	{
+		close(p1);
+	}
+
+	if (p2 != -1)
+	{
+		close(p2);
+	}
+}
+
+// パイプに書き込む
+void UnixWritePipe(int pipe_write)
+{
+	char c = 1;
+	write(pipe_write, &c, 1);
+}
+
+// 新しいパイプを作成する
+void UnixNewPipe(int *pipe_read, int *pipe_write)
+{
+	int fd[2];
+	// 引数チェック
+	if (pipe_read == NULL || pipe_write == NULL)
+	{
+		return;
+	}
+
+	fd[0] = fd[1] = 0;
+
+	pipe(fd);
+
+	*pipe_read = fd[0];
+	*pipe_write = fd[1];
+
+	UnixSetSocketNonBlockingMode(*pipe_write, true);
+	UnixSetSocketNonBlockingMode(*pipe_read, true);
+}
+
+// 非同期ソケットの解放
+void UnixFreeAsyncSocket(SOCK *sock)
+{
+	UINT p;
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return;
+	}
+
+	Lock(sock->lock);
+	{
+		if (sock->AsyncMode == false)
+		{
+			Unlock(sock->lock);
+			return;
+		}
+
+		sock->AsyncMode = false;
+
+		// このソケットが SockEvent に関連付けられているかどうか調べる
+		if (sock->SockEvent != NULL)
+		{
+			SOCK_EVENT *e = sock->SockEvent;
+
+			AddRef(e->ref);
+
+			p = e->pipe_write;
+			LockList(e->SockList);
+			{
+				if (Delete(e->SockList, sock))
+				{
+					ReleaseSock(sock);
+				}
+			}
+			UnlockList(e->SockList);
+
+			// ソケットイベントを解放する
+			ReleaseSockEvent(sock->SockEvent);
+			sock->SockEvent = NULL;
+
+			SetSockEvent(e);
+
+			ReleaseSockEvent(e);
+		}
+	}
+	Unlock(sock->lock);
+}
+
+// ソケットを非同期に設定する
+void UnixInitAsyncSocket(SOCK *sock)
+{
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return;
+	}
+	if (sock->AsyncMode)
+	{
+		// すでに非同期ソケットになっている
+		return;
+	}
+	if (sock->ListenMode != false || (sock->Type == SOCK_TCP && sock->Connected == false))
+	{
+		return;
+	}
+
+	sock->AsyncMode = true;
+
+	UnixSetSocketNonBlockingMode(sock->socket, true);
+}
+
+// ソケットライブラリの初期化
+void UnixInitSocketLibrary()
+{
+	// 特に何もしない
+}
+
+// ソケットライブラリの解放
+void UnixFreeSocketLibrary()
+{
+	// 特に何もしない
+}
+
+#endif	// OS_UNIX
+
+#ifdef	OS_WIN32		// Windows 用コード
+
+NETWORK_WIN32_FUNCTIONS *w32net;
+
+// IP_ADAPTER_INDEX_MAP の比較
+int CompareIpAdapterIndexMap(void *p1, void *p2)
+{
+	IP_ADAPTER_INDEX_MAP *a1, *a2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	a1 = *(IP_ADAPTER_INDEX_MAP **)p1;
+	a2 = *(IP_ADAPTER_INDEX_MAP **)p2;
+	if (a1 == NULL || a2 == NULL)
+	{
+		return 0;
+	}
+
+	if (a1->Index > a2->Index)
+	{
+		return 1;
+	}
+	else if (a1->Index < a2->Index)
+	{
+		return -1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// アダプタの IP アドレスを更新
+bool Win32RenewAddressByGuid(char *guid)
+{
+	IP_ADAPTER_INDEX_MAP a;
+	// 引数チェック
+	if (guid == NULL)
+	{
+		return false;
+	}
+
+	Zero(&a, sizeof(a));
+	if (Win32GetAdapterFromGuid(&a, guid) == false)
+	{
+		return false;
+	}
+
+	return Win32RenewAddress(&a);
+}
+bool Win32RenewAddress(void *a)
+{
+	DWORD ret;
+	// 引数チェック
+	if (a == NULL)
+	{
+		return false;
+	}
+	if (w32net->IpRenewAddress == NULL)
+	{
+		return false;
+	}
+
+	ret = w32net->IpRenewAddress(a);
+
+	if (ret == NO_ERROR)
+	{
+		return true;
+	}
+	else
+	{
+		Debug("IpRenewAddress: Error: %u\n", ret);
+		return false;
+	}
+}
+
+// アダプタの IP アドレスを解放
+bool Win32ReleaseAddress(void *a)
+{
+	DWORD ret;
+	// 引数チェック
+	if (a == NULL)
+	{
+		return false;
+	}
+	if (w32net->IpReleaseAddress == NULL)
+	{
+		return false;
+	}
+
+	ret = w32net->IpReleaseAddress(a);
+
+	if (ret == NO_ERROR)
+	{
+		return true;
+	}
+	else
+	{
+		Debug("IpReleaseAddress: Error: %u\n", ret);
+		return false;
+	}
+}
+bool Win32ReleaseAddressByGuid(char *guid)
+{
+	IP_ADAPTER_INDEX_MAP a;
+	// 引数チェック
+	if (guid == NULL)
+	{
+		return false;
+	}
+
+	Zero(&a, sizeof(a));
+	if (Win32GetAdapterFromGuid(&a, guid) == false)
+	{
+		return false;
+	}
+
+	return Win32ReleaseAddress(&a);
+}
+void Win32ReleaseAddressByGuidExThread(THREAD *t, void *param)
+{
+	WIN32_RELEASEADDRESS_THREAD_PARAM *p;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	p = (WIN32_RELEASEADDRESS_THREAD_PARAM *)param;
+
+	AddRef(p->Ref);
+
+	NoticeThreadInit(t);
+
+	AddWaitThread(t);
+
+	if (p->Renew == false)
+	{
+		p->Ok = Win32ReleaseAddressByGuid(p->Guid);
+	}
+	else
+	{
+		p->Ok = Win32RenewAddressByGuid(p->Guid);
+	}
+
+	ReleaseWin32ReleaseAddressByGuidThreadParam(p);
+
+	DelWaitThread(t);
+}
+bool Win32RenewAddressByGuidEx(char *guid, UINT timeout)
+{
+	return Win32ReleaseOrRenewAddressByGuidEx(guid, timeout, true);
+}
+bool Win32ReleaseAddressByGuidEx(char *guid, UINT timeout)
+{
+	return Win32ReleaseOrRenewAddressByGuidEx(guid, timeout, false);
+}
+bool Win32ReleaseOrRenewAddressByGuidEx(char *guid, UINT timeout, bool renew)
+{
+	THREAD *t;
+	WIN32_RELEASEADDRESS_THREAD_PARAM *p;
+	bool ret = false;
+	UINT64 start_tick = 0;
+	UINT64 end_tick = 0;
+	// 引数チェック
+	if (guid == NULL)
+	{
+		return false;
+	}
+	if (timeout == 0)
+	{
+		timeout = INFINITE;
+	}
+
+	p = ZeroMalloc(sizeof(WIN32_RELEASEADDRESS_THREAD_PARAM));
+	p->Ref = NewRef();
+	StrCpy(p->Guid, sizeof(p->Guid), guid);
+	p->Timeout = timeout;
+	p->Renew = renew;
+
+	t = NewThread(Win32ReleaseAddressByGuidExThread, p);
+	WaitThreadInit(t);
+	start_tick = Tick64();
+	end_tick = start_tick + (UINT64)timeout;
+
+	while (true)
+	{
+		UINT64 now = Tick64();
+		UINT64 remain;
+		UINT remain32;
+
+		if (now >= end_tick)
+		{
+			break;
+		}
+
+		remain = end_tick - now;
+		remain32 = MIN((UINT)remain, 100);
+
+		if (WaitThread(t, remain32))
+		{
+			break;
+		}
+	}
+
+	ReleaseThread(t);
+
+	if (p->Ok)
+	{
+		ret = true;
+	}
+
+	ReleaseWin32ReleaseAddressByGuidThreadParam(p);
+
+	return ret;
+}
+void ReleaseWin32ReleaseAddressByGuidThreadParam(WIN32_RELEASEADDRESS_THREAD_PARAM *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	if (Release(p->Ref) == 0)
+	{
+		Free(p);
+	}
+}
+
+// アダプタを GUID から取得
+bool Win32GetAdapterFromGuid(void *a, char *guid)
+{
+	bool ret = false;
+	IP_INTERFACE_INFO *info;
+	UINT size;
+	int i;
+	LIST *o;
+	wchar_t tmp[MAX_SIZE];
+
+	// 引数チェック
+	if (a == NULL || guid == NULL)
+	{
+		return false;
+	}
+	if (w32net->GetInterfaceInfo == NULL)
+	{
+		return false;
+	}
+
+	UniFormat(tmp, sizeof(tmp), L"\\DEVICE\\TCPIP_%S", guid);
+
+	size = sizeof(IP_INTERFACE_INFO);
+	info = ZeroMallocFast(size);
+
+	if (w32net->GetInterfaceInfo(info, &size) == ERROR_INSUFFICIENT_BUFFER)
+	{
+		Free(info);
+		info = ZeroMallocFast(size);
+	}
+
+	if (w32net->GetInterfaceInfo(info, &size) != NO_ERROR)
+	{
+		Free(info);
+		return false;
+	}
+
+	o = NewListFast(CompareIpAdapterIndexMap);
+
+	for (i = 0;i < info->NumAdapters;i++)
+	{
+		IP_ADAPTER_INDEX_MAP *a = &info->Adapter[i];
+
+		Add(o, a);
+	}
+
+	Sort(o);
+
+	for (i = 0;i < (int)(LIST_NUM(o));i++)
+	{
+		IP_ADAPTER_INDEX_MAP *e = LIST_DATA(o, i);
+
+		if (UniStrCmpi(e->Name, tmp) == 0)
+		{
+			Copy(a, e, sizeof(IP_ADAPTER_INDEX_MAP));
+			ret = true;
+			break;
+		}
+	}
+
+	ReleaseList(o);
+
+	Free(info);
+
+	return ret;
+}
+
+// テスト
+void Win32NetworkTest()
+{
+	IP_INTERFACE_INFO *info;
+	UINT size;
+	int i;
+	LIST *o;
+
+	size = sizeof(IP_INTERFACE_INFO);
+	info = ZeroMallocFast(size);
+
+	if (w32net->GetInterfaceInfo(info, &size) == ERROR_INSUFFICIENT_BUFFER)
+	{
+		Free(info);
+		info = ZeroMallocFast(size);
+	}
+
+	if (w32net->GetInterfaceInfo(info, &size) != NO_ERROR)
+	{
+		Free(info);
+		return;
+	}
+
+	o = NewListFast(CompareIpAdapterIndexMap);
+
+	for (i = 0;i < info->NumAdapters;i++)
+	{
+		IP_ADAPTER_INDEX_MAP *a = &info->Adapter[i];
+
+		Add(o, a);
+	}
+
+	Sort(o);
+
+	for (i = 0;i < (int)(LIST_NUM(o));i++)
+	{
+		IP_ADAPTER_INDEX_MAP *a = LIST_DATA(o, i);
+
+		DoNothing();
+	}
+
+	ReleaseList(o);
+
+	Free(info);
+}
+
+// 指定された LAN カードの DHCP アドレスを更新する
+void Win32RenewDhcp9x(UINT if_id)
+{
+	IP_INTERFACE_INFO *info;
+	UINT size;
+	int i;
+	LIST *o;
+	// 引数チェック
+	if (if_id == 0)
+	{
+		return;
+	}
+
+	size = sizeof(IP_INTERFACE_INFO);
+	info = ZeroMallocFast(size);
+
+	if (w32net->GetInterfaceInfo(info, &size) == ERROR_INSUFFICIENT_BUFFER)
+	{
+		Free(info);
+		info = ZeroMallocFast(size);
+	}
+
+	if (w32net->GetInterfaceInfo(info, &size) != NO_ERROR)
+	{
+		Free(info);
+		return;
+	}
+
+	o = NewListFast(CompareIpAdapterIndexMap);
+
+	for (i = 0;i < info->NumAdapters;i++)
+	{
+		IP_ADAPTER_INDEX_MAP *a = &info->Adapter[i];
+
+		Add(o, a);
+	}
+
+	Sort(o);
+
+	for (i = 0;i < (int)(LIST_NUM(o));i++)
+	{
+		IP_ADAPTER_INDEX_MAP *a = LIST_DATA(o, i);
+
+		if (a->Index == if_id)
+		{
+			char arg[MAX_PATH];
+			Format(arg, sizeof(arg), "/renew %u", i);
+			Run("ipconfig.exe", arg, true, false);
+		}
+	}
+
+	ReleaseList(o);
+
+	Free(info);
+}
+
+// 指定された LAN カードの DHCP アドレスを解放する
+void Win32ReleaseDhcp9x(UINT if_id, bool wait)
+{
+	IP_INTERFACE_INFO *info;
+	UINT size;
+	int i;
+	LIST *o;
+	// 引数チェック
+	if (if_id == 0)
+	{
+		return;
+	}
+
+	size = sizeof(IP_INTERFACE_INFO);
+	info = ZeroMallocFast(size);
+
+	if (w32net->GetInterfaceInfo(info, &size) == ERROR_INSUFFICIENT_BUFFER)
+	{
+		Free(info);
+		info = ZeroMallocFast(size);
+	}
+
+	if (w32net->GetInterfaceInfo(info, &size) != NO_ERROR)
+	{
+		Free(info);
+		return;
+	}
+
+	o = NewListFast(CompareIpAdapterIndexMap);
+
+	for (i = 0;i < info->NumAdapters;i++)
+	{
+		IP_ADAPTER_INDEX_MAP *a = &info->Adapter[i];
+
+		Add(o, a);
+	}
+
+	Sort(o);
+
+	for (i = 0;i < (int)(LIST_NUM(o));i++)
+	{
+		IP_ADAPTER_INDEX_MAP *a = LIST_DATA(o, i);
+
+		if (a->Index == if_id)
+		{
+			char arg[MAX_PATH];
+			Format(arg, sizeof(arg), "/release %u", i);
+			Run("ipconfig.exe", arg, true, wait);
+		}
+	}
+
+	ReleaseList(o);
+
+	Free(info);
+}
+
+// DHCP サーバーから IP アドレスを再取得する
+void Win32RenewDhcp()
+{
+	if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))
+	{
+		Run("ipconfig.exe", "/renew", true, false);
+		if (MsIsVista())
+		{
+			Run("ipconfig.exe", "/renew6", true, false);
+		}
+		else
+		{
+			Run("netsh.exe", "int ipv6 renew", true, false);
+		}
+	}
+	else
+	{
+		Run("ipconfig.exe", "/renew_all", true, false);
+	}
+}
+
+// 指定された文字列を含む仮想 LAN カードの一覧を列挙する
+char **Win32EnumVLan(char *tag_name)
+{
+	MIB_IFTABLE *p;
+	UINT ret;
+	UINT size_needed;
+	UINT num_retry = 0;
+	UINT i;
+	LIST *o;
+	char **ss;
+	// 引数チェック
+	if (tag_name == 0)
+	{
+		return NULL;
+	}
+
+RETRY:
+	p = ZeroMallocFast(sizeof(MIB_IFTABLE));
+	size_needed = 0;
+
+	// 必要なサイズを調べる
+	ret = w32net->GetIfTable(p, &size_needed, 0);
+	if (ret == ERROR_INSUFFICIENT_BUFFER)
+	{
+		// 必要なサイズ分のメモリブロックを再確保
+		Free(p);
+		p = ZeroMallocFast(size_needed);
+	}
+	else if (ret != NO_ERROR)
+	{
+		// 取得失敗
+FAILED:
+		Free(p);
+		return NULL;
+	}
+
+	// 実際に取得する
+	ret = w32net->GetIfTable(p, &size_needed, FALSE);
+	if (ret != NO_ERROR)
+	{
+		// 取得失敗
+		if ((++num_retry) >= 5)
+		{
+			goto FAILED;
+		}
+		Free(p);
+		goto RETRY;
+	}
+
+	// 検索
+	ret = 0;
+	o = NewListFast(CompareStr);
+	for (i = 0;i < p->dwNumEntries;i++)
+	{
+		MIB_IFROW *r = &p->table[i];
+		if (SearchStrEx(r->bDescr, tag_name, 0, false) != INFINITE)
+		{
+			char *s = CopyStr(r->bDescr);
+			Add(o, s);
+		}
+	}
+
+	Free(p);
+
+	// ソート
+	Sort(o);
+
+	// 文字列に変換
+	ss = ZeroMallocFast(sizeof(char *) * (LIST_NUM(o) + 1));
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		ss[i] = LIST_DATA(o, i);
+	}
+	ss[LIST_NUM(o)] = NULL;
+
+	ReleaseList(o);
+
+	return ss;
+}
+
+// 仮想 LAN カードのインスタンス名から仮想 LAN カードの ID を取得する
+UINT Win32GetVLanInterfaceID(char *instance_name)
+{
+	MIB_IFTABLE *p;
+	UINT ret;
+	UINT size_needed;
+	UINT num_retry = 0;
+	UINT i;
+	char ps_miniport_str[MAX_SIZE];
+	char ps_miniport_str2[MAX_SIZE];
+	// 引数チェック
+	if (instance_name == 0)
+	{
+		return 0;
+	}
+
+RETRY:
+	p = ZeroMallocFast(sizeof(MIB_IFTABLE));
+	size_needed = 0;
+
+	// 必要なサイズを調べる
+	ret = w32net->GetIfTable(p, &size_needed, 0);
+	if (ret == ERROR_INSUFFICIENT_BUFFER)
+	{
+		// 必要なサイズ分のメモリブロックを再確保
+		Free(p);
+		p = ZeroMallocFast(size_needed);
+	}
+	else if (ret != NO_ERROR)
+	{
+		// 取得失敗
+FAILED:
+		Free(p);
+		Debug("******** GetIfTable Failed 1. Err = %u\n", ret);
+		return 0;
+	}
+
+	// 実際に取得する
+	ret = w32net->GetIfTable(p, &size_needed, FALSE);
+	if (ret != NO_ERROR)
+	{
+		// 取得失敗
+		if ((++num_retry) >= 5)
+		{
+			goto FAILED;
+		}
+		Free(p);
+		Debug("******** GetIfTable Failed 2. Err = %u\n", ret);
+		goto RETRY;
+	}
+
+	// "%s - パケット スケジューラ ミニポート"
+	Format(ps_miniport_str, sizeof(ps_miniport_str), "%s - ", instance_name);
+	Format(ps_miniport_str2, sizeof(ps_miniport_str2), "%s (Microsoft", instance_name);
+
+	// 検索
+	ret = 0;
+	for (i = 0;i < p->dwNumEntries;i++)
+	{
+		MIB_IFROW *r = &p->table[i];
+		if (instance_name[0] != '@')
+		{
+			if (StrCmpi(r->bDescr, instance_name) == 0 || StartWith(r->bDescr, ps_miniport_str) || StartWith(r->bDescr, ps_miniport_str2))
+			{
+				ret = r->dwIndex;
+			}
+		}
+		else
+		{
+			if (SearchStrEx(r->bDescr, &instance_name[1], 0, false) != INFINITE)
+			{
+				ret = r->dwIndex;
+			}
+		}
+
+		Debug("if[%u] (0x%x): %s\n", i, r->dwIndex, r->bDescr);
+	}
+
+	Free(p);
+
+	return ret;
+}
+
+// デフォルトの DNS サーバーアドレスを取得する
+bool Win32GetDefaultDns(IP *ip, char *domain, UINT size)
+{
+	FIXED_INFO *info;
+	UINT info_size;
+	char *dns_name;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return false;
+	}
+	Zero(ip, sizeof(IP));
+	info_size = 0;
+	info = ZeroMallocFast(sizeof(FIXED_INFO));
+	if (w32net->GetNetworkParams(info, &info_size) == ERROR_BUFFER_OVERFLOW)
+	{
+		Free(info);
+		info = ZeroMallocFast(info_size);
+	}
+	if (w32net->GetNetworkParams(info, &info_size) != NO_ERROR)
+	{
+		Free(info);
+		return false;
+	}
+
+	if (info->DnsServerList.IpAddress.String == NULL)
+	{
+		Free(info);
+		return false;
+	}
+
+	dns_name = info->DnsServerList.IpAddress.String;
+	StrToIP(ip, dns_name);
+
+	if (domain != NULL)
+	{
+		StrCpy(domain, size, info->DomainName);
+		Trim(domain);
+	}
+
+	Free(info);
+
+	return true;
+}
+
+// Win32 用 IP 変換関数
+void Win32UINTToIP(IP *ip, UINT i)
+{
+	UINTToIP(ip, i);
+}
+
+// Win32 用 IP 変換関数
+UINT Win32IPToUINT(IP *ip)
+{
+	return IPToUINT(ip);
+}
+
+// ルーティングテーブルからルーティングエントリを削除
+void Win32DeleteRouteEntry(ROUTE_ENTRY *e)
+{
+	MIB_IPFORWARDROW *p;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	p = ZeroMallocFast(sizeof(MIB_IPFORWARDROW));
+	Win32RouteEntryToIpForwardRow(p, e);
+
+	// 削除
+	w32net->DeleteIpForwardEntry(p);
+
+	Free(p);
+}
+
+// ルーティングテーブルにルーティングエントリを追加
+bool Win32AddRouteEntry(ROUTE_ENTRY *e, bool *already_exists)
+{
+	bool ret = false;
+	bool dummy = false;
+	MIB_IPFORWARDROW *p;
+	UINT err = 0;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return false;
+	}
+	if (already_exists == NULL)
+	{
+		already_exists = &dummy;
+	}
+
+	*already_exists = false;
+
+	p = ZeroMallocFast(sizeof(MIB_IPFORWARDROW));
+	Win32RouteEntryToIpForwardRow(p, e);
+
+	// 追加
+	err = w32net->CreateIpForwardEntry(p);
+	if (err != 0)
+	{
+		if (err == ERROR_OBJECT_ALREADY_EXISTS)
+		{
+			Debug("CreateIpForwardEntry: Already Exists\n");
+			*already_exists = true;
+			ret = true;
+		}
+		else
+		{
+			Debug("CreateIpForwardEntry Error: %u\n", err);
+			ret = false;
+		}
+	}
+	else
+	{
+		ret = true;
+	}
+
+	Free(p);
+
+	return ret;
+}
+
+// ルーティングテーブルの取得
+ROUTE_TABLE *Win32GetRouteTable()
+{
+	ROUTE_TABLE *t = ZeroMallocFast(sizeof(ROUTE_TABLE));
+	MIB_IPFORWARDTABLE *p;
+	UINT ret;
+	UINT size_needed;
+	UINT num_retry = 0;
+	LIST *o;
+	UINT i;
+	ROUTE_ENTRY *e;
+
+RETRY:
+	p = ZeroMallocFast(sizeof(MIB_IFTABLE));
+	size_needed = 0;
+
+	// 必要なサイズを調べる
+	ret = w32net->GetIpForwardTable(p, &size_needed, 0);
+	if (ret == ERROR_INSUFFICIENT_BUFFER)
+	{
+		// 必要なサイズ分のメモリブロックを再確保
+		Free(p);
+		p = ZeroMallocFast(size_needed);
+	}
+	else if (ret != NO_ERROR)
+	{
+		// 取得失敗
+FAILED:
+		Free(p);
+		t->Entry = MallocFast(0);
+		return t;
+	}
+
+	// 実際に取得する
+	ret = w32net->GetIpForwardTable(p, &size_needed, FALSE);
+	if (ret != NO_ERROR)
+	{
+		// 取得失敗
+		if ((++num_retry) >= 5)
+		{
+			goto FAILED;
+		}
+		Free(p);
+		goto RETRY;
+	}
+
+	// リストに追加していく
+	o = NewListFast(Win32CompareRouteEntryByMetric);
+	for (i = 0;i < p->dwNumEntries;i++)
+	{
+		e = ZeroMallocFast(sizeof(ROUTE_ENTRY));
+		Win32IpForwardRowToRouteEntry(e, &p->table[i]);
+		Add(o, e);
+	}
+	Free(p);
+
+	// メトリック順にソート
+	Sort(o);
+
+	// 結果を結合
+	t->NumEntry = LIST_NUM(o);
+	t->Entry = ToArrayEx(o, true);
+	ReleaseList(o);
+
+	return t;
+}
+
+// ルーティングエントリをメトリックによってソートする
+int Win32CompareRouteEntryByMetric(void *p1, void *p2)
+{
+	ROUTE_ENTRY *e1, *e2;
+	// 引数チェック
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+
+	e1 = *(ROUTE_ENTRY **)p1;
+	e2 = *(ROUTE_ENTRY **)p2;
+	if (e1 == NULL || e2 == NULL)
+	{
+		return 0;
+	}
+
+	if (e1->Metric > e2->Metric)
+	{
+		return 1;
+	}
+	else if (e1->Metric == e2->Metric)
+	{
+		return 0;
+	}
+	else
+	{
+		return -1;
+	}
+}
+
+// ROUTE_ENTRY を MIB_IPFORWARDROW に変換
+void Win32RouteEntryToIpForwardRow(void *ip_forward_row, ROUTE_ENTRY *entry)
+{
+	MIB_IPFORWARDROW *r;
+	// 引数チェック
+	if (entry == NULL || ip_forward_row == NULL)
+	{
+		return;
+	}
+
+	r = (MIB_IPFORWARDROW *)ip_forward_row;
+	Zero(r, sizeof(MIB_IPFORWARDROW));
+
+	// IP アドレス
+	r->dwForwardDest = Win32IPToUINT(&entry->DestIP);
+	// サブネットマスク
+	r->dwForwardMask = Win32IPToUINT(&entry->DestMask);
+	// ゲートウェイ IP アドレス
+	r->dwForwardNextHop = Win32IPToUINT(&entry->GatewayIP);
+	// ローカルルーティングフラグ
+	if (entry->LocalRouting)
+	{
+		// ローカル
+		r->dwForwardType = 3;
+	}
+	else
+	{
+		// リモートルータ
+		r->dwForwardType = 4;
+	}
+	// プロトコル
+	r->dwForwardProto = r->dwForwardType - 1;	// 大抵の場合 1 引けば良い
+	if (entry->PPPConnection)
+	{
+		// PPP ちゃうかな？ 危険！
+		r->dwForwardProto++;
+	}
+	// メトリック
+	r->dwForwardMetric1 = entry->Metric;
+
+	if (MsIsVista() == false)
+	{
+		r->dwForwardMetric2 = r->dwForwardMetric3 = r->dwForwardMetric4 = r->dwForwardMetric5 = INFINITE;
+	}
+	else
+	{
+		r->dwForwardMetric2 = r->dwForwardMetric3 = r->dwForwardMetric4 = r->dwForwardMetric5 = 0;
+		r->dwForwardAge = 163240;
+	}
+
+	// インターフェイス ID
+	r->dwForwardIfIndex = entry->InterfaceID;
+
+	Debug("Win32RouteEntryToIpForwardRow()\n");
+	Debug(" r->dwForwardDest=%X\n", r->dwForwardDest);
+	Debug(" r->dwForwardMask=%X\n", r->dwForwardMask);
+	Debug(" r->dwForwardNextHop=%X\n", r->dwForwardNextHop);
+	Debug(" r->dwForwardType=%u\n", r->dwForwardType);
+	Debug(" r->dwForwardProto=%u\n", r->dwForwardProto);
+	Debug(" r->dwForwardMetric1=%u\n", r->dwForwardMetric1);
+	Debug(" r->dwForwardMetric2=%u\n", r->dwForwardMetric2);
+	Debug(" r->dwForwardIfIndex=%u\n", r->dwForwardIfIndex);
+}
+
+// MIB_IPFORWARDROW を ROUTE_ENTRY に変換
+void Win32IpForwardRowToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row)
+{
+	MIB_IPFORWARDROW *r;
+	// 引数チェック
+	if (entry == NULL || ip_forward_row == NULL)
+	{
+		return;
+	}
+
+	r = (MIB_IPFORWARDROW *)ip_forward_row;
+
+	Zero(entry, sizeof(ROUTE_ENTRY));
+	// IP アドレス
+	Win32UINTToIP(&entry->DestIP, r->dwForwardDest);
+	// サブネットマスク
+	Win32UINTToIP(&entry->DestMask, r->dwForwardMask);
+	// ゲートウェイ IP アドレス
+	Win32UINTToIP(&entry->GatewayIP, r->dwForwardNextHop);
+	// ローカルルーティングフラグ
+	if (r->dwForwardType == 3)
+	{
+		entry->LocalRouting = true;
+	}
+	else
+	{
+		entry->LocalRouting = false;
+	}
+	if (entry->LocalRouting && r->dwForwardProto == 3)
+	{
+		// PPP。危険！
+		entry->PPPConnection = true;
+	}
+	// メトリック
+	entry->Metric = r->dwForwardMetric1;
+	// インターフェイス ID
+	entry->InterfaceID = r->dwForwardIfIndex;
+}
+
+// ソケットライブラリの初期化
+void Win32InitSocketLibrary()
+{
+	WSADATA data;
+	Zero(&data, sizeof(data));
+	WSAStartup(MAKEWORD(2, 2), &data);
+
+	// DLL 関数の読み込み
+	w32net = ZeroMalloc(sizeof(NETWORK_WIN32_FUNCTIONS));
+	w32net->hIpHlpApi32 = LoadLibrary("iphlpapi.dll");
+
+	if (w32net->hIpHlpApi32 != NULL)
+	{
+		w32net->CreateIpForwardEntry =
+			(DWORD (__stdcall *)(PMIB_IPFORWARDROW))
+			GetProcAddress(w32net->hIpHlpApi32, "CreateIpForwardEntry");
+
+		w32net->DeleteIpForwardEntry =
+			(DWORD (__stdcall *)(PMIB_IPFORWARDROW))
+			GetProcAddress(w32net->hIpHlpApi32, "DeleteIpForwardEntry");
+
+		w32net->GetIfTable =
+			(DWORD (__stdcall *)(PMIB_IFTABLE, PULONG, BOOL))
+			GetProcAddress(w32net->hIpHlpApi32, "GetIfTable");
+
+		w32net->GetIpForwardTable =
+			(DWORD (__stdcall *)(PMIB_IPFORWARDTABLE, PULONG, BOOL))
+			GetProcAddress(w32net->hIpHlpApi32, "GetIpForwardTable");
+
+		w32net->GetNetworkParams =
+			(DWORD (__stdcall *)(PFIXED_INFO,PULONG))
+			GetProcAddress(w32net->hIpHlpApi32, "GetNetworkParams");
+
+		w32net->IpRenewAddress =
+			(DWORD (__stdcall *)(PIP_ADAPTER_INDEX_MAP))
+			GetProcAddress(w32net->hIpHlpApi32, "IpRenewAddress");
+
+		w32net->IpReleaseAddress =
+			(DWORD (__stdcall *)(PIP_ADAPTER_INDEX_MAP))
+			GetProcAddress(w32net->hIpHlpApi32, "IpReleaseAddress");
+
+		w32net->GetInterfaceInfo =
+			(DWORD (__stdcall *)(PIP_INTERFACE_INFO, PULONG))
+			GetProcAddress(w32net->hIpHlpApi32, "GetInterfaceInfo");
+
+		w32net->GetAdaptersInfo =
+			(DWORD (__stdcall *)(PIP_ADAPTER_INFO, PULONG))
+			GetProcAddress(w32net->hIpHlpApi32, "GetAdaptersInfo");
+
+		w32net->GetExtendedTcpTable =
+			(DWORD (__stdcall *)(PVOID,PDWORD,BOOL,ULONG,_TCP_TABLE_CLASS,ULONG))
+			GetProcAddress(w32net->hIpHlpApi32, "GetExtendedTcpTable");
+
+		w32net->AllocateAndGetTcpExTableFromStack =
+			(DWORD (__stdcall *)(PVOID *,BOOL,HANDLE,DWORD,DWORD))
+			GetProcAddress(w32net->hIpHlpApi32, "AllocateAndGetTcpExTableFromStack");
+
+		w32net->GetTcpTable =
+			(DWORD (__stdcall *)(PMIB_TCPTABLE,PDWORD,BOOL))
+			GetProcAddress(w32net->hIpHlpApi32, "GetTcpTable");
+
+		w32net->NotifyRouteChange =
+			(DWORD (__stdcall *)(PHANDLE,LPOVERLAPPED))
+			GetProcAddress(w32net->hIpHlpApi32, "NotifyRouteChange");
+
+		w32net->CancelIPChangeNotify =
+			(BOOL (__stdcall *)(LPOVERLAPPED))
+			GetProcAddress(w32net->hIpHlpApi32, "CancelIPChangeNotify");
+
+		w32net->NhpAllocateAndGetInterfaceInfoFromStack =
+			(DWORD (__stdcall *)(IP_INTERFACE_NAME_INFO **,PDWORD,BOOL,HANDLE,DWORD))
+			GetProcAddress(w32net->hIpHlpApi32, "NhpAllocateAndGetInterfaceInfoFromStack");
+	}
+}
+
+// ソケットライブラリの解放
+void Win32FreeSocketLibrary()
+{
+	if (w32net != NULL)
+	{
+		FreeLibrary(w32net->hIpHlpApi32);
+
+		Free(w32net);
+		w32net = NULL;
+	}
+
+	WSACleanup();
+}
+
+// キャンセル
+void Win32Cancel(CANCEL *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	SetEvent((HANDLE)c->hEvent);
+}
+
+// キャンセルのクリーンアップ
+void Win32CleanupCancel(CANCEL *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	if (c->SpecialFlag == false)
+	{
+		CloseHandle(c->hEvent);
+	}
+
+	Free(c);
+}
+
+// 新しいキャンセルオブジェクト
+CANCEL *Win32NewCancel()
+{
+	CANCEL *c = ZeroMallocFast(sizeof(CANCEL));
+	c->ref = NewRef();
+	c->SpecialFlag = false;
+	c->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+	return c;
+}
+
+// ソケットイベントの待機
+bool Win32WaitSockEvent(SOCK_EVENT *event, UINT timeout)
+{
+	// 引数チェック
+	if (event == NULL || timeout == 0)
+	{
+		return false;
+	}
+
+	if (WaitForSingleObject((HANDLE)event->hEvent, timeout) == WAIT_OBJECT_0)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// ソケットイベントのクリーンアップ
+void Win32CleanupSockEvent(SOCK_EVENT *event)
+{
+	// 引数チェック
+	if (event == NULL)
+	{
+		return;
+	}
+
+	CloseHandle((HANDLE)event->hEvent);
+
+	Free(event);
+}
+
+// ソケットイベントのセット
+void Win32SetSockEvent(SOCK_EVENT *event)
+{
+	// 引数チェック
+	if (event == NULL)
+	{
+		return;
+	}
+
+	SetEvent((HANDLE)event->hEvent);
+}
+
+// ソケットイベントの作成
+SOCK_EVENT *Win32NewSockEvent()
+{
+	SOCK_EVENT *e = ZeroMallocFast(sizeof(SOCK_EVENT));
+
+	e->ref = NewRef();
+	e->hEvent = (void *)CreateEvent(NULL, FALSE, FALSE, NULL);
+
+	return e;
+}
+
+// ソケットをソケットイベントに関連付けして非同期に設定する
+void Win32JoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event)
+{
+	HANDLE hEvent;
+	// 引数チェック
+	if (sock == NULL || event == NULL || sock->AsyncMode)
+	{
+		return;
+	}
+	if (sock->ListenMode != false || (sock->Type != SOCK_UDP && sock->Connected == false))
+	{
+		return;
+	}
+
+	sock->AsyncMode = true;
+
+	hEvent = event->hEvent;
+
+	// 関連付け
+	WSAEventSelect(sock->socket, hEvent, FD_READ | FD_WRITE | FD_CLOSE);
+
+	// SOCK_EVENT の参照カウンタを増加
+	AddRef(event->ref);
+	sock->SockEvent = event;
+}
+
+// ソケットを非同期に設定する
+void Win32InitAsyncSocket(SOCK *sock)
+{
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return;
+	}
+	if (sock->AsyncMode)
+	{
+		// すでに非同期ソケットになっている
+		return;
+	}
+	if (sock->ListenMode != false || (sock->Type == SOCK_TCP && sock->Connected == false))
+	{
+		return;
+	}
+
+	sock->AsyncMode = true;
+
+	// イベントの作成
+	sock->hEvent = (void *)CreateEvent(NULL, FALSE, FALSE, NULL);
+
+	// 関連付け
+	WSAEventSelect(sock->socket, sock->hEvent, FD_READ | FD_WRITE | FD_CLOSE);
+}
+
+// 非同期ソケットを解放
+void Win32FreeAsyncSocket(SOCK *sock)
+{
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return;
+	}
+
+	// 非同期ソケット
+	if (sock->hEvent != NULL)
+	{
+		CloseHandle((HANDLE)sock->hEvent);
+	}
+	sock->hEvent = NULL;
+	sock->AsyncMode = false;
+
+	// ソケットイベント
+	if (sock->SockEvent != NULL)
+	{
+		ReleaseSockEvent(sock->SockEvent);
+		sock->SockEvent = NULL;
+	}
+}
+
+// Win32 版 Select 関数
+void Win32Select(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2)
+{
+	HANDLE array[MAXIMUM_WAIT_OBJECTS];
+	UINT n, i;
+	SOCK *s;
+	// 引数チェック
+	if (timeout == 0)
+	{
+		return;
+	}
+
+	// 配列の初期化
+	Zero(array, sizeof(array));
+	n = 0;
+
+	// イベント配列の設定
+	if (set != NULL)
+	{
+		for (i = 0;i < set->NumSocket;i++)
+		{
+			s = set->Sock[i];
+			if (s != NULL)
+			{
+				Win32InitAsyncSocket(s);
+				if (s->hEvent != NULL)
+				{
+					array[n++] = (HANDLE)s->hEvent;
+				}
+			}
+		}
+	}
+	if (c1 != NULL && c1->hEvent != NULL)
+	{
+		array[n++] = c1->hEvent;
+	}
+	if (c2 != NULL && c2->hEvent != NULL)
+	{
+		array[n++] = c2->hEvent;
+	}
+
+	if (n == 0)
+	{
+		// 待つイベントが 1 つも登録されていない場合は
+		// 通常の待ち関数を呼ぶ
+		SleepThread(timeout);
+	}
+	else
+	{
+		// イベントが 1 つ以上登録されている場合はイベントを待つ
+		if (n == 1)
+		{
+			// イベントが 1 つの場合は軽量版を呼び出す
+			WaitForSingleObject(array[0], timeout);
+		}
+		else
+		{
+			// イベントが複数の場合
+			WaitForMultipleObjects(n, array, false, timeout);
+		}
+	}
+}
+
+#endif	// OS_WIN32
+
+// IPv6 がサポートされているかどうか調べる
+bool IsIPv6Supported()
+{
+#ifdef	NO_IPV6
+	return false;
+#else	// NO_IPV6
+	SOCKET s;
+
+	s = socket(AF_INET6, SOCK_STREAM, 0);
+	if (s == INVALID_SOCKET)
+	{
+		return false;
+	}
+
+	closesocket(s);
+
+	return true;
+#endif	// NO_IPV6
+}
+
+// ホストキャッシュからホスト名の取得
+bool GetHostCache(char *hostname, UINT size, IP *ip)
+{
+	bool ret;
+	// 引数チェック
+	if (hostname == NULL || ip == NULL)
+	{
+		return false;
+	}
+
+	ret = false;
+
+	LockList(HostCacheList);
+	{
+		HOSTCACHE t, *c;
+		Zero(&t, sizeof(t));
+		Copy(&t.IpAddress, ip, sizeof(IP));
+
+		c = Search(HostCacheList, &t);
+		if (c != NULL)
+		{
+			if (IsEmptyStr(c->HostName) == false)
+			{
+				ret = true;
+				StrCpy(hostname, size, c->HostName);
+			}
+			else
+			{
+				ret = true;
+				StrCpy(hostname, size, "");
+			}
+		}
+	}
+	UnlockList(HostCacheList);
+
+	return ret;
+}
+
+// ホスト名キャッシュへ追加
+void AddHostCache(IP *ip, char *hostname)
+{
+	// 引数チェック
+	if (ip == NULL || hostname == NULL)
+	{
+		return;
+	}
+	if (IsNetworkNameCacheEnabled() == false)
+	{
+		return;
+	}
+
+	LockList(HostCacheList);
+	{
+		HOSTCACHE t, *c;
+		UINT i;
+		LIST *o;
+
+		Zero(&t, sizeof(t));
+		Copy(&t.IpAddress, ip, sizeof(IP));
+
+		c = Search(HostCacheList, &t);
+		if (c == NULL)
+		{
+			c = ZeroMalloc(sizeof(HOSTCACHE));
+			Copy(&c->IpAddress, ip, sizeof(IP));
+			Add(HostCacheList, c);
+		}
+
+		StrCpy(c->HostName, sizeof(c->HostName), hostname);
+		c->Expires = Tick64() + (UINT64)EXPIRES_HOSTNAME;
+
+		o = NewListFast(NULL);
+
+		for (i = 0;i < LIST_NUM(HostCacheList);i++)
+		{
+			HOSTCACHE *c = LIST_DATA(HostCacheList, i);
+
+			if (c->Expires <= Tick64())
+			{
+				Add(o, c);
+			}
+		}
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			HOSTCACHE *c = LIST_DATA(o, i);
+
+			if (Delete(HostCacheList, c))
+			{
+				Free(c);
+			}
+		}
+
+		ReleaseList(o);
+	}
+	UnlockList(HostCacheList);
+}
+
+// ホスト名キャッシュの比較
+int CompareHostCache(void *p1, void *p2)
+{
+	HOSTCACHE *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(HOSTCACHE **)p1;
+	c2 = *(HOSTCACHE **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+
+	return CmpIpAddr(&c1->IpAddress, &c2->IpAddress);
+}
+
+// ホスト名キャッシュの解放
+void FreeHostCache()
+{
+	UINT i;
+
+	for (i = 0;i < LIST_NUM(HostCacheList);i++)
+	{
+		HOSTCACHE *c = LIST_DATA(HostCacheList, i);
+
+		Free(c);
+	}
+
+	ReleaseList(HostCacheList);
+	HostCacheList = NULL;
+}
+
+// ホスト名キャッシュの初期化
+void InitHostCache()
+{
+	HostCacheList = NewList(CompareHostCache);
+}
+
+// スレッドをスレッド待機リストに追加する
+void AddWaitThread(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	AddRef(t->ref);
+
+	LockList(WaitThreadList);
+	{
+		Add(WaitThreadList, t);
+	}
+	UnlockList(WaitThreadList);
+}
+
+// スレッドを待機リストから削除する
+void DelWaitThread(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	LockList(WaitThreadList);
+	{
+		if (Delete(WaitThreadList, t))
+		{
+			ReleaseThread(t);
+		}
+	}
+	UnlockList(WaitThreadList);
+}
+
+// スレッド待機リストの作成
+void InitWaitThread()
+{
+	WaitThreadList = NewList(NULL);
+}
+
+// スレッド待機リストの解放
+void FreeWaitThread()
+{
+	UINT i, num;
+	THREAD **threads;
+
+	LockList(WaitThreadList);
+	{
+		num = LIST_NUM(WaitThreadList);
+		threads = ToArray(WaitThreadList);
+		DeleteAll(WaitThreadList);
+	}
+	UnlockList(WaitThreadList);
+
+	for (i = 0;i < num;i++)
+	{
+		THREAD *t = threads[i];
+		WaitThread(t, INFINITE);
+		ReleaseThread(t);
+	}
+
+	Free(threads);
+
+	ReleaseList(WaitThreadList);
+	WaitThreadList = NULL;
+}
+
+// 暗号リスト名をチェックする
+bool CheckCipherListName(char *name)
+{
+	UINT i;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < cipher_list_token->NumTokens;i++)
+	{
+		if (StrCmpi(cipher_list_token->Token[i], name) == 0)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// DHCP サーバーの IP アドレス更新
+void RenewDhcp()
+{
+#ifdef	OS_WIN32
+	Win32RenewDhcp();
+#else
+	UnixRenewDhcp();
+#endif
+}
+
+// UNIX 用ドメイン名を取得
+bool UnixGetDomainName(char *name, UINT size)
+{
+	bool ret = false;
+	BUF *b = ReadDump("/etc/resolv.conf");
+
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	while (true)
+	{
+		char *s = CfgReadNextLine(b);
+		TOKEN_LIST *t;
+
+		if (s == NULL)
+		{
+			break;
+		}
+
+		Trim(s);
+
+		t = ParseToken(s, " \t");
+		if (t != NULL)
+		{
+			if (t->NumTokens == 2)
+			{
+				if (StrCmpi(t->Token[0], "domain") == 0)
+				{
+					StrCpy(name, size, t->Token[1]);
+					ret = true;
+				}
+			}
+			FreeToken(t);
+		}
+
+		Free(s);
+	}
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// ドメイン名を取得
+bool GetDomainName(char *name, UINT size)
+{
+	bool ret = false;
+	IP ip;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+#ifdef	OS_WIN32
+	ret = Win32GetDefaultDns(&ip, name, size);
+#else	// OS_WIN32
+	ret = UnixGetDomainName(name, size);
+#endif	// OS_WIN32
+
+	return ret;
+}
+
+// デフォルトの DNS サーバーの取得
+bool GetDefaultDns(IP *ip)
+{
+	bool ret = false;
+#ifdef	OS_WIN32
+	ret = Win32GetDefaultDns(ip, NULL, 0);
+#else
+	ret = UnixGetDefaultDns(ip);
+#endif	// OS_WIN32
+	return ret;
+}
+
+// ソケットイベントの作成
+SOCK_EVENT *NewSockEvent()
+{
+	SOCK_EVENT *e = NULL;
+#ifdef	OS_WIN32
+	e = Win32NewSockEvent();
+#else
+	e = UnixNewSockEvent();
+#endif	// OS_WIN32
+	return e;
+}
+
+// ソケットイベントのセット
+void SetSockEvent(SOCK_EVENT *event)
+{
+#ifdef	OS_WIN32
+	Win32SetSockEvent(event);
+#else
+	UnixSetSockEvent(event);
+#endif	// OS_WIN32
+}
+
+// ソケットイベントのクリーンアップ
+void CleanupSockEvent(SOCK_EVENT *event)
+{
+#ifdef	OS_WIN32
+	Win32CleanupSockEvent(event);
+#else
+	UnixCleanupSockEvent(event);
+#endif	// OS_WIN32
+}
+
+// ソケットイベントの待機
+bool WaitSockEvent(SOCK_EVENT *event, UINT timeout)
+{
+	bool ret = false;
+#ifdef	OS_WIN32
+	ret = Win32WaitSockEvent(event, timeout);
+#else
+	ret = UnixWaitSockEvent(event, timeout);
+#endif	// OS_WIN32
+	return ret;
+}
+
+// ソケットイベントの解放
+void ReleaseSockEvent(SOCK_EVENT *event)
+{
+	// 引数チェック
+	if (event == NULL)
+	{
+		return;
+	}
+
+	if (Release(event->ref) == 0)
+	{
+		CleanupSockEvent(event);
+	}
+}
+
+// ソケットをソケットイベントに所属させる
+void JoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event)
+{
+#ifdef	OS_WIN32
+	Win32JoinSockToSockEvent(sock, event);
+#else
+	UnixJoinSockToSockEvent(sock, event);
+#endif	// OS_WIN32
+}
+
+// 新しい特殊キャンセルオブジェクト
+CANCEL *NewCancelSpecial(void *hEvent)
+{
+	CANCEL *c;
+	// 引数チェック
+	if (hEvent == NULL)
+	{
+		return NULL;
+	}
+
+	c = ZeroMalloc(sizeof(CANCEL));
+	c->ref = NewRef();
+	c->SpecialFlag = true;
+
+#ifdef	OS_WIN32
+	c->hEvent = (HANDLE)hEvent;
+#else	// OS_WIN32
+	c->pipe_read = (int)hEvent;
+	c->pipe_write = -1;
+#endif	// OS_WIN32
+
+	return c;
+}
+
+// キャンセルオブジェクトの作成
+CANCEL *NewCancel()
+{
+	CANCEL *c = NULL;
+#ifdef	OS_WIN32
+	c = Win32NewCancel();
+#else
+	c = UnixNewCancel();
+#endif	// OS_WIN32
+	return c;
+}
+
+// キャンセルオブジェクトの解放
+void ReleaseCancel(CANCEL *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	if (Release(c->ref) == 0)
+	{
+		CleanupCancel(c);
+	}
+}
+
+// キャンセルオブジェクトのクリーンアップ
+void CleanupCancel(CANCEL *c)
+{
+#ifdef	OS_WIN32
+	Win32CleanupCancel(c);
+#else
+	UnixCleanupCancel(c);
+#endif
+}
+
+// キャンセル発動
+void Cancel(CANCEL *c)
+{
+#ifdef	OS_WIN32
+	Win32Cancel(c);
+#else
+	UnixCancel(c);
+#endif
+}
+
+// 指定されたルーティングテーブルから最適なルートを計算する
+ROUTE_ENTRY *GetBestRouteEntryFromRouteTable(ROUTE_TABLE *table, IP *ip)
+{
+	return GetBestRouteEntryFromRouteTableEx(table, ip, 0);
+}
+ROUTE_ENTRY *GetBestRouteEntryFromRouteTableEx(ROUTE_TABLE *table, IP *ip, UINT exclude_if_id)
+{
+	UINT i;
+	UINT max_mask = 0;
+	UINT min_metric = INFINITE;
+	ROUTE_ENTRY *ret = NULL;
+	ROUTE_ENTRY *tmp = NULL;
+	// 引数チェック
+	if (ip == NULL || table == NULL)
+	{
+		return NULL;
+	}
+
+	if (IsIP6(ip))
+	{
+		// IPv6 は非サポート
+		return NULL;
+	}
+
+	// 対象となるルーティングテーブルのうち、
+	//  第一条件: サブネットマスクが最も大きい
+	//  第二条件: メトリック値が最も小さい
+	// ものを選択する
+	for (i = 0;i < table->NumEntry;i++)
+	{
+		ROUTE_ENTRY *e = table->Entry[i];
+		UINT dest, net, mask;
+
+		dest = IPToUINT(ip);
+		net = IPToUINT(&e->DestIP);
+		mask = IPToUINT(&e->DestMask);
+
+		if (exclude_if_id != 0)
+		{
+			if (e->InterfaceID == exclude_if_id)
+			{
+				continue;
+			}
+		}
+
+		// マスクテスト
+		if ((dest & mask) == (net & mask))
+		{
+			// これはルーティングの対象となり得る
+			if (mask >= max_mask)
+			{
+				max_mask = mask;
+				if (min_metric >= e->Metric)
+				{
+					min_metric = e->Metric;
+					tmp = e;
+				}
+			}
+		}
+	}
+
+	if (tmp != NULL)
+	{
+		UINT dest, gateway, mask;
+
+		// エントリを生成
+		ret = ZeroMallocFast(sizeof(ROUTE_ENTRY));
+
+		Copy(&ret->DestIP, ip, sizeof(IP));
+		ret->DestMask.addr[0] = 255;
+		ret->DestMask.addr[1] = 255;
+		ret->DestMask.addr[2] = 255;
+		ret->DestMask.addr[3] = 255;
+		Copy(&ret->GatewayIP, &tmp->GatewayIP, sizeof(IP));
+		ret->InterfaceID = tmp->InterfaceID;
+		ret->LocalRouting = tmp->LocalRouting;
+		ret->OldIfMetric = tmp->Metric;
+		ret->Metric = 1;
+		ret->PPPConnection = tmp->PPPConnection;
+
+		// ルーティング制御関係の計算
+		dest = IPToUINT(&tmp->DestIP);
+		gateway = IPToUINT(&tmp->GatewayIP);
+		mask = IPToUINT(&tmp->DestMask);
+		if ((dest & mask) == (gateway & mask))
+		{
+#ifdef	OS_WIN32
+			if (MsIsVista() == false)
+			{
+				// Windows 用調整
+				ret->PPPConnection = true;
+			}
+#endif	// OS_WIN32
+		}
+	}
+
+	return ret;
+}
+
+// ルーティングエントリを解放する
+void FreeRouteEntry(ROUTE_ENTRY *e)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	Free(e);
+}
+
+// 現在のルーティングテーブルを解析して最適なルートエントリを取得する
+ROUTE_ENTRY *GetBestRouteEntry(IP *ip)
+{
+	return GetBestRouteEntryEx(ip, 0);
+}
+ROUTE_ENTRY *GetBestRouteEntryEx(IP *ip, UINT exclude_if_id)
+{
+	ROUTE_TABLE *table;
+	ROUTE_ENTRY *e = NULL;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return NULL;
+	}
+
+	table = GetRouteTable();
+	if (table == NULL)
+	{
+		return NULL;
+	}
+
+	e = GetBestRouteEntryFromRouteTableEx(table, ip, exclude_if_id);
+	FreeRouteTable(table);
+
+	return e;
+}
+
+// 仮想 LAN カードのインターフェース ID の取得
+UINT GetVLanInterfaceID(char *tag_name)
+{
+	UINT ret = 0;
+#ifdef	OS_WIN32
+	ret = Win32GetVLanInterfaceID(tag_name);
+#else	// OS_WIN32
+	ret = UnixGetVLanInterfaceID(tag_name);
+#endif	// OS_WIN32
+	return ret;
+}
+
+// 仮想 LAN カードの列挙変数の解放
+void FreeEnumVLan(char **s)
+{
+	char *a;
+	UINT i;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	i = 0;
+	while (true)
+	{
+		a = s[i++];
+		if (a == NULL)
+		{
+			break;
+		}
+		Free(a);
+	}
+
+	Free(s);
+}
+
+// 仮想 LAN カードの列挙
+char **EnumVLan(char *tag_name)
+{
+	char **ret = NULL;
+#ifdef	OS_WIN32
+	ret = Win32EnumVLan(tag_name);
+#else	// OS_WIN32
+	ret = UnixEnumVLan(tag_name);
+#endif	// OS_WIN32
+	return ret;
+}
+
+// ルーティングテーブルを表示する
+void DebugPrintRouteTable(ROUTE_TABLE *r)
+{
+	UINT i;
+	// 引数チェック
+	if (r == NULL)
+	{
+		return;
+	}
+
+	if (IsDebug() == false)
+	{
+		return;
+	}
+
+	Debug("---- Routing Table (%u Entries) ----\n", r->NumEntry);
+
+	for (i = 0;i < r->NumEntry;i++)
+	{
+		Debug("   ");
+
+		DebugPrintRoute(r->Entry[i]);
+	}
+
+	Debug("------------------------------------\n");
+}
+
+// ルーティングテーブルエントリを表示する
+void DebugPrintRoute(ROUTE_ENTRY *e)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	if (IsDebug() == false)
+	{
+		return;
+	}
+
+	RouteToStr(tmp, sizeof(tmp), e);
+
+	Debug("%s\n", tmp);
+}
+
+// ルーティングテーブルエントリを文字列にする
+void RouteToStr(char *str, UINT str_size, ROUTE_ENTRY *e)
+{
+	char dest_ip[MAX_PATH];
+	char dest_mask[MAX_PATH];
+	char gateway_ip[MAX_PATH];
+	// 引数チェック
+	if (str == NULL || e == NULL)
+	{
+		return;
+	}
+
+	IPToStr(dest_ip, sizeof(dest_ip), &e->DestIP);
+	IPToStr(dest_mask, sizeof(dest_mask), &e->DestMask);
+	IPToStr(gateway_ip, sizeof(gateway_ip), &e->GatewayIP);
+
+	Format(str, str_size, "%s/%s %s m=%u oif=%u if=%u lo=%u p=%u",
+		dest_ip, dest_mask, gateway_ip,
+		e->Metric, e->OldIfMetric, e->InterfaceID,
+		e->LocalRouting, e->PPPConnection);
+}
+
+// ルーティングテーブルの削除
+void DeleteRouteEntry(ROUTE_ENTRY *e)
+{
+	Debug("DeleteRouteEntry();\n");
+#ifdef	OS_WIN32
+	Win32DeleteRouteEntry(e);
+#else	// OS_WIN32
+	UnixDeleteRouteEntry(e);
+#endif
+}
+
+// ルーティングテーブルの追加
+bool AddRouteEntry(ROUTE_ENTRY *e)
+{
+	bool dummy = false;
+	return AddRouteEntryEx(e, &dummy);
+}
+bool AddRouteEntryEx(ROUTE_ENTRY *e, bool *already_exists)
+{
+	bool ret = false;
+	Debug("AddRouteEntryEx();\n");
+#ifdef	OS_WIN32
+	ret = Win32AddRouteEntry(e, already_exists);
+#else	// OS_WIN32
+	ret = UnixAddRouteEntry(e, already_exists);
+#endif
+	return ret;
+}
+
+// ルーティングテーブルの取得
+ROUTE_TABLE *GetRouteTable()
+{
+	ROUTE_TABLE *t = NULL;
+	UINT i;
+	BUF *buf = NewBuf();
+	UCHAR hash[MD5_SIZE];
+
+#ifdef	OS_WIN32
+	t = Win32GetRouteTable();
+#else	//OS_WIN32
+	t = UnixGetRouteTable();
+#endif	// OS_WIN32
+
+	WriteBuf(buf, &t->NumEntry, sizeof(t->NumEntry));
+
+	for (i = 0;i < t->NumEntry;i++)
+	{
+		ROUTE_ENTRY *e = t->Entry[i];
+
+		WriteBuf(buf, e, sizeof(ROUTE_ENTRY));
+	}
+
+	Hash(hash, buf->Buf, buf->Size, false);
+
+	FreeBuf(buf);
+
+	Copy(&t->HashedValue, hash, sizeof(t->HashedValue));
+
+	return t;
+}
+
+// ルーティングテーブルの解放
+void FreeRouteTable(ROUTE_TABLE *t)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < t->NumEntry;i++)
+	{
+		Free(t->Entry[i]);
+	}
+	Free(t->Entry);
+	Free(t);
+}
+
+// UDP 受信
+UINT RecvFrom(SOCK *sock, IP *src_addr, UINT *src_port, void *data, UINT size)
+{
+	SOCKET s;
+	int ret, sz;
+	struct sockaddr_in addr;
+	// 引数チェック
+	if (sock == NULL || src_addr == NULL || src_port == NULL || data == NULL)
+	{
+		return false;
+	}
+	if (sock->Type != SOCK_UDP || sock->socket == INVALID_SOCKET)
+	{
+		return false;
+	}
+	if (size == 0)
+	{
+		return false;
+	}
+
+	if (sock->IPv6)
+	{
+		return RecvFrom6(sock, src_addr, src_port, data, size);
+	}
+
+	s = sock->socket;
+
+	sz = sizeof(addr);
+	ret = recvfrom(s, data, size, 0, (struct sockaddr *)&addr, (int *)&sz);
+	if (ret > 0)
+	{
+		InAddrToIP(src_addr, &addr.sin_addr);
+		*src_port = (UINT)ntohs(addr.sin_port);
+
+		Lock(sock->lock);
+		{
+			sock->RecvNum++;
+			sock->RecvSize += (UINT64)ret;
+		}
+		Unlock(sock->lock);
+
+		// Debug("UDP RecvFrom: %u\n", ret);
+
+		return (UINT)ret;
+	}
+	else
+	{
+		sock->IgnoreRecvErr = false;
+
+#ifdef	OS_WIN32
+		if (WSAGetLastError() == WSAECONNRESET)
+		{
+			sock->IgnoreRecvErr = true;
+		}
+		else if (WSAGetLastError() == WSAEWOULDBLOCK)
+		{
+			return SOCK_LATER;
+		}
+		else
+		{
+			UINT e = WSAGetLastError();
+//			Debug("RecvFrom Error: %u\n", e);
+		}
+#else	// OS_WIN32
+		if (errno == ECONNREFUSED || errno == ECONNRESET)
+		{
+			sock->IgnoreRecvErr = true;
+		}
+		else if (errno == EAGAIN)
+		{
+			return SOCK_LATER;
+		}
+#endif	// OS_WIN32
+		return 0;
+	}
+}
+UINT RecvFrom6(SOCK *sock, IP *src_addr, UINT *src_port, void *data, UINT size)
+{
+	SOCKET s;
+	int ret, sz;
+	struct sockaddr_in6 addr;
+	// 引数チェック
+	if (sock == NULL || src_addr == NULL || src_port == NULL || data == NULL)
+	{
+		return false;
+	}
+	if (sock->Type != SOCK_UDP || sock->socket == INVALID_SOCKET)
+	{
+		return false;
+	}
+	if (size == 0)
+	{
+		return false;
+	}
+
+	s = sock->socket;
+
+	sz = sizeof(addr);
+	ret = recvfrom(s, data, size, 0, (struct sockaddr *)&addr, (int *)&sz);
+	if (ret > 0)
+	{
+		InAddrToIP6(src_addr, &addr.sin6_addr);
+		src_addr->ipv6_scope_id = addr.sin6_scope_id;
+		*src_port = (UINT)ntohs(addr.sin6_port);
+
+		Lock(sock->lock);
+		{
+			sock->RecvNum++;
+			sock->RecvSize += (UINT64)ret;
+		}
+		Unlock(sock->lock);
+
+		// Debug("UDP RecvFrom: %u\n", ret);
+
+		return (UINT)ret;
+	}
+	else
+	{
+		sock->IgnoreRecvErr = false;
+
+#ifdef	OS_WIN32
+		if (WSAGetLastError() == WSAECONNRESET)
+		{
+			sock->IgnoreRecvErr = true;
+		}
+		else if (WSAGetLastError() == WSAEWOULDBLOCK)
+		{
+			return SOCK_LATER;
+		}
+		else
+		{
+			UINT e = WSAGetLastError();
+			//			Debug("RecvFrom Error: %u\n", e);
+		}
+#else	// OS_WIN32
+		if (errno == ECONNREFUSED || errno == ECONNRESET)
+		{
+			sock->IgnoreRecvErr = true;
+		}
+		else if (errno == EAGAIN)
+		{
+			return SOCK_LATER;
+		}
+#endif	// OS_WIN32
+		return 0;
+	}
+}
+
+// OpenSSL のロック
+void LockOpenSSL()
+{
+	Lock(openssl_lock);
+}
+
+// OpenSSL のロック解除
+void UnlockOpenSSL()
+{
+	Unlock(openssl_lock);
+}
+
+
+// UDP 送信
+UINT SendTo(SOCK *sock, IP *dest_addr, UINT dest_port, void *data, UINT size)
+{
+	SOCKET s;
+	int ret;
+	struct sockaddr_in addr;
+	// 引数チェック
+	if (sock == NULL || dest_addr == NULL || dest_port == 0 || data == NULL)
+	{
+		return 0;
+	}
+	if (dest_port >= 65536)
+	{
+		return 0;
+	}
+	if (sock->Type != SOCK_UDP || sock->socket == INVALID_SOCKET)
+	{
+		return 0;
+	}
+	if (size == 0)
+	{
+		return 0;
+	}
+
+	if (sock->IPv6)
+	{
+		return SendTo6(sock, dest_addr, dest_port, data, size);
+	}
+
+	if (IsIP4(dest_addr) == false)
+	{
+		return 0;
+	}
+
+	s = sock->socket;
+	Zero(&addr, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons((USHORT)dest_port);
+	IPToInAddr(&addr.sin_addr, dest_addr);
+
+	if (dest_addr->addr[0] == 255 && dest_addr->addr[1] == 255 && 
+		dest_addr->addr[2] == 255 && dest_addr->addr[3] == 255)
+	{
+		if (sock->UdpBroadcast == false)
+		{
+			bool yes = true;
+
+			sock->UdpBroadcast = true;
+
+			setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&yes, sizeof(yes));
+		}
+	}
+
+	ret = sendto(s, data, size, 0, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret != (int)size)
+	{
+		sock->IgnoreSendErr = false;
+
+#ifdef	OS_WIN32
+		if (WSAGetLastError() == WSAECONNRESET)
+		{
+			sock->IgnoreSendErr = true;
+		}
+		else if (WSAGetLastError() == WSAEWOULDBLOCK)
+		{
+			return SOCK_LATER;
+		}
+		else
+		{
+			UINT e = WSAGetLastError();
+		}
+#else	// OS_WIN32
+		if (errno == ECONNREFUSED || errno == ECONNRESET)
+		{
+			sock->IgnoreRecvErr = true;
+		}
+		else if (errno == EAGAIN)
+		{
+			return SOCK_LATER;
+		}
+#endif	// OS_WIN32
+		return 0;
+	}
+
+	Lock(sock->lock);
+	{
+		sock->SendSize += (UINT64)size;
+		sock->SendNum++;
+	}
+	Unlock(sock->lock);
+
+	return ret;
+}
+UINT SendTo6(SOCK *sock, IP *dest_addr, UINT dest_port, void *data, UINT size)
+{
+	SOCKET s;
+	int ret;
+	struct sockaddr_in6 addr;
+	UINT type;
+	// 引数チェック
+	if (sock == NULL || dest_addr == NULL || dest_port == 0 || data == NULL)
+	{
+		return 0;
+	}
+	if (dest_port >= 65536)
+	{
+		return 0;
+	}
+	if (sock->Type != SOCK_UDP || sock->socket == INVALID_SOCKET)
+	{
+		return 0;
+	}
+	if (size == 0)
+	{
+		return 0;
+	}
+
+	if (IsIP6(dest_addr) == false)
+	{
+		return 0;
+	}
+
+	s = sock->socket;
+	Zero(&addr, sizeof(addr));
+	addr.sin6_family = AF_INET6;
+	addr.sin6_port = htons((USHORT)dest_port);
+	IPToInAddr6(&addr.sin6_addr, dest_addr);
+	addr.sin6_scope_id = dest_addr->ipv6_scope_id;
+
+	type = GetIPAddrType6(dest_addr);
+
+	if (type & IPV6_ADDR_MULTICAST)
+	{
+		if (sock->UdpBroadcast == false)
+		{
+			bool yes = true;
+
+			sock->UdpBroadcast = true;
+
+			setsockopt(s, SOL_SOCKET, SO_BROADCAST, (char *)&yes, sizeof(yes));
+		}
+	}
+
+	ret = sendto(s, data, size, 0, (struct sockaddr *)&addr, sizeof(addr));
+	if (ret != (int)size)
+	{
+		sock->IgnoreSendErr = false;
+
+#ifdef	OS_WIN32
+		if (WSAGetLastError() == WSAECONNRESET)
+		{
+			sock->IgnoreSendErr = true;
+		}
+		else if (WSAGetLastError() == WSAEWOULDBLOCK)
+		{
+			return SOCK_LATER;
+		}
+		else
+		{
+			UINT e = WSAGetLastError();
+		}
+#else	// OS_WIN32
+		if (errno == ECONNREFUSED || errno == ECONNRESET)
+		{
+			sock->IgnoreRecvErr = true;
+		}
+		else if (errno == EAGAIN)
+		{
+			return SOCK_LATER;
+		}
+#endif	// OS_WIN32
+		return 0;
+	}
+
+	Lock(sock->lock);
+	{
+		sock->SendSize += (UINT64)size;
+		sock->SendNum++;
+	}
+	Unlock(sock->lock);
+
+	return ret;
+}
+
+// UDP ソケットの作成と初期化
+// port が 0 の場合は OS がランダムに割り当てる
+SOCK *NewUDP(UINT port)
+{
+	return NewUDPEx(port, false);
+}
+SOCK *NewUDPEx(UINT port, bool ipv6)
+{
+	if (ipv6 == false)
+	{
+		return NewUDP4(port);
+	}
+	else
+	{
+		return NewUDP6(port);
+	}
+}
+SOCK *NewUDP4(UINT port)
+{
+	SOCK *sock;
+	SOCKET s;
+	struct sockaddr_in addr;
+
+	s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+	if (s == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+
+	Zero(&addr, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = htonl(INADDR_ANY);
+	if (port == 0)
+	{
+		addr.sin_port = 0;
+	}
+	else
+	{
+		addr.sin_port = htons((USHORT)port);
+	}
+
+	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) != 0)
+	{
+		// 失敗
+		closesocket(s);
+		return NULL;
+	}
+
+	sock = NewSock();
+
+	sock->Type = SOCK_UDP;
+	sock->Connected = false;
+	sock->AsyncMode = false;
+	sock->ServerMode = false;
+	if (port != 0)
+	{
+		sock->ServerMode = true;
+	}
+
+	sock->socket = s;
+
+	QuerySocketInformation(sock);
+
+	return sock;
+}
+SOCK *NewUDP6(UINT port)
+{
+	SOCK *sock;
+	SOCKET s;
+	struct sockaddr_in6 addr;
+
+	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
+	if (s == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+
+	Zero(&addr, sizeof(addr));
+	addr.sin6_family = AF_INET6;
+	if (port == 0)
+	{
+		addr.sin6_port = 0;
+	}
+	else
+	{
+		addr.sin6_port = htons((USHORT)port);
+	}
+
+	if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) != 0)
+	{
+		// 失敗
+		closesocket(s);
+		return NULL;
+	}
+
+	sock = NewSock();
+
+	sock->Type = SOCK_UDP;
+	sock->Connected = false;
+	sock->AsyncMode = false;
+	sock->ServerMode = false;
+	sock->IPv6 = true;
+	if (port != 0)
+	{
+		sock->ServerMode = true;
+	}
+
+	sock->socket = s;
+
+	QuerySocketInformation(sock);
+
+	return sock;
+}
+
+// Select 関数
+void Select(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2)
+{
+#ifdef	OS_WIN32
+	Win32Select(set, timeout, c1, c2);
+#else
+	UnixSelect(set, timeout, c1, c2);
+#endif	// OS_WIN32
+}
+
+// ソケットセットにソケットを追加
+void AddSockSet(SOCKSET *set, SOCK *sock)
+{
+	// 引数チェック
+	if (set == NULL || sock == NULL)
+	{
+		return;
+	}
+	if (sock->Type == SOCK_TCP && sock->Connected == false)
+	{
+		return;
+	}
+
+	if (set->NumSocket >= MAX_SOCKSET_NUM)
+	{
+		// 上限
+		return;
+	}
+	set->Sock[set->NumSocket++] = sock;
+}
+
+// ソケットセットの初期化
+void InitSockSet(SOCKSET *set)
+{
+	// 引数チェック
+	if (set == NULL)
+	{
+		return;
+	}
+
+	Zero(set, sizeof(SOCKSET));
+}
+
+// TCP すべて受信
+bool RecvAll(SOCK *sock, void *data, UINT size, bool secure)
+{
+	UINT recv_size, sz, ret;
+	// 引数チェック
+	if (sock == NULL || data == NULL)
+	{
+		return false;
+	}
+	if (size == 0)
+	{
+		return true;
+	}
+	if (sock->AsyncMode)
+	{
+		return false;
+	}
+
+	recv_size = 0;
+
+	while (true)
+	{
+		sz = size - recv_size;
+		ret = Recv(sock, (UCHAR *)data + recv_size, sz, secure);
+		if (ret == 0)
+		{
+			return false;
+		}
+		recv_size += ret;
+		if (recv_size >= size)
+		{
+			return true;
+		}
+	}
+}
+
+// TCP 送信バッファを送信する
+bool SendNow(SOCK *sock, int secure)
+{
+	bool ret;
+	// 引数チェック
+	if (sock == NULL || sock->AsyncMode != false)
+	{
+		return false;
+	}
+	if (sock->SendBuf->Size == 0)
+	{
+		return true;
+	}
+
+	ret = SendAll(sock, sock->SendBuf->Buf, sock->SendBuf->Size, secure);
+	ClearBuf(sock->SendBuf);
+
+	return ret;
+}
+
+// TCP 送信バッファ追加
+void SendAdd(SOCK *sock, void *data, UINT size)
+{
+	// 引数チェック
+	if (sock == NULL || data == NULL || size == 0 || sock->AsyncMode != false)
+	{
+		return;
+	}
+
+	WriteBuf(sock->SendBuf, data, size);
+}
+
+// TCP すべて送信
+bool SendAll(SOCK *sock, void *data, UINT size, bool secure)
+{
+	UCHAR *buf;
+	UINT sent_size;
+	UINT ret;
+	// 引数チェック
+	if (sock == NULL || data == NULL)
+	{
+		return false;
+	}
+	if (sock->AsyncMode)
+	{
+		return false;
+	}
+	if (size == 0)
+	{
+		return true;
+	}
+
+	buf = (UCHAR *)data;
+	sent_size = 0;
+
+	while (true)
+	{
+		ret = Send(sock, buf, size - sent_size, secure);
+		if (ret == 0)
+		{
+			return false;
+		}
+		sent_size += ret;
+		buf += ret;
+		if (sent_size >= size)
+		{
+			return true;
+		}
+	}
+}
+
+// 使用したい暗号化アルゴリズム名を設定する
+void SetWantToUseCipher(SOCK *sock, char *name)
+{
+	// 引数チェック
+	if (sock == NULL || name == NULL)
+	{
+		return;
+	}
+
+	if (sock->WaitToUseCipher)
+	{
+		Free(sock->WaitToUseCipher);
+	}
+	sock->WaitToUseCipher = CopyStr(name);
+}
+
+// TCP-SSL 通信を開始する
+bool StartSSL(SOCK *sock, X *x, K *priv)
+{
+	return StartSSLEx(sock, x, priv, false);
+}
+bool StartSSLEx(SOCK *sock, X *x, K *priv, bool client_tls)
+{
+	X509 *x509;
+	EVP_PKEY *key;
+	UINT prev_timeout = 1024;
+
+#ifdef UNIX_SOLARIS
+	SOCKET_TIMEOUT_PARAM *ttparam;
+#endif //UNIX_SOLARIS
+
+	// 引数チェック
+	if (sock == NULL)
+	{
+		Debug("StartSSL Error: #0\n");
+		return false;
+	}
+	if (sock->Connected == false || sock->socket == INVALID_SOCKET ||
+		sock->ListenMode != false)
+	{
+		Debug("StartSSL Error: #1\n");
+		return false;
+	}
+	if (x != NULL && priv == NULL)
+	{
+		Debug("StartSSL Error: #2\n");
+		return false;
+	}
+
+	if (sock->SecureMode)
+	{
+		Debug("StartSSL Error: #3\n");
+		// すでに SSL 通信が開始されている
+		return true;
+	}
+
+	Lock(sock->ssl_lock);
+	if (sock->SecureMode)
+	{
+		Debug("StartSSL Error: #4\n");
+		// すでに SSL 通信が開始されている
+		Unlock(sock->ssl_lock);
+		return true;
+	}
+
+	Lock(openssl_lock);
+	{
+		if (sock->ServerMode)
+		{
+			SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_method());
+		}
+		else
+		{
+			if (client_tls == false)
+			{
+				SSL_CTX_set_ssl_version(ssl_ctx, SSLv3_method());
+			}
+			else
+			{
+				SSL_CTX_set_ssl_version(ssl_ctx, TLSv1_client_method());
+			}
+		}
+		sock->ssl = SSL_new(ssl_ctx);
+		SSL_set_fd(sock->ssl, (int)sock->socket);
+	}
+	Unlock(openssl_lock);
+
+	if (x != NULL)
+	{
+		// 証明書と秘密鍵のチェック
+		if (CheckXandK(x, priv))
+		{
+			// 証明書を使用する
+			x509 = x->x509;
+			key = priv->pkey;
+
+			Lock(openssl_lock);
+			{
+				SSL_use_certificate(sock->ssl, x509);
+				SSL_use_PrivateKey(sock->ssl, key);
+			}
+			Unlock(openssl_lock);
+		}
+	}
+
+	if (sock->WaitToUseCipher != NULL)
+	{
+		// 使用したい暗号化アルゴリズム名を設定する
+		Lock(openssl_lock);
+		{
+			SSL_set_cipher_list(sock->ssl, sock->WaitToUseCipher);
+		}
+		Unlock(openssl_lock);
+	}
+
+	if (sock->ServerMode)
+	{
+//		Lock(ssl_connect_lock);
+
+// SOLARIS用タイムアウトスレッドの起動
+#ifdef UNIX_SOLARIS
+		ttparam = NewSocketTimeout(sock);
+#endif // UNIX_SOLARIS
+
+		// サーバーモード
+		if (SSL_accept(sock->ssl) <= 0)
+		{
+
+// タイムアウトスレッドの停止
+#ifdef UNIX_SOLARIS
+			FreeSocketTimeout(ttparam);
+#endif // UNIX_SOLARIS
+
+			//			Unlock(ssl_connect_lock);
+			// SSL-Accept 失敗
+			Lock(openssl_lock);
+			{
+				SSL_free(sock->ssl);
+			}
+			Unlock(openssl_lock);
+
+			Unlock(sock->ssl_lock);
+			Debug("StartSSL Error: #5\n");
+			return false;
+		}
+
+// タイムアウトスレッドの停止
+#ifdef UNIX_SOLARIS
+		FreeSocketTimeout(ttparam);
+#endif // UNIX_SOLARIS
+
+		//		Unlock(ssl_connect_lock);
+	}
+	else
+	{
+		prev_timeout = GetTimeout(sock);
+		SetTimeout(sock, TIMEOUT_SSL_CONNECT);
+		Lock(ssl_connect_lock);
+		// クライアントモード
+		if (SSL_connect(sock->ssl) <= 0)
+		{
+			Unlock(ssl_connect_lock);
+			// SSL-connect 失敗
+			Lock(openssl_lock);
+			{
+				SSL_free(sock->ssl);
+			}
+			Unlock(openssl_lock);
+
+			Unlock(sock->ssl_lock);
+			Debug("StartSSL Error: #5\n");
+			SetTimeout(sock, prev_timeout);
+			return false;
+		}
+		Unlock(ssl_connect_lock);
+		SetTimeout(sock, prev_timeout);
+	}
+
+	// SSL 通信が開始された
+	sock->SecureMode = true;
+
+	// リモートホストの証明書を取得する
+	Lock(openssl_lock);
+	{
+		x509 = SSL_get_peer_certificate(sock->ssl);
+	}
+	Unlock(openssl_lock);
+
+	if (x509 == NULL)
+	{
+		// リモートホストに証明書は存在しない
+		sock->RemoteX = NULL;
+	}
+	else
+	{
+		// 証明書を取得できた
+		sock->RemoteX = X509ToX(x509);
+	}
+
+	// ローカルホストの証明書を取得する
+	Lock(openssl_lock);
+	{
+		x509 = SSL_get_certificate(sock->ssl);
+	}
+	Unlock(openssl_lock);
+
+	if (x509 == NULL)
+	{
+		// リモートホストに証明書は存在しない
+		sock->LocalX = NULL;
+	}
+	else
+	{
+		X *local_x;
+		// 証明書を取得できた
+		local_x = X509ToX(x509);
+		local_x->do_not_free = true;
+		sock->LocalX = CloneX(local_x);
+		FreeX(local_x);
+	}
+
+	// 自動再試行モード
+	SSL_set_mode(sock->ssl, SSL_MODE_AUTO_RETRY);
+
+	// へんなフラグ
+	SSL_set_mode(sock->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+	// 暗号化に使用しているアルゴリズム名を取得
+	Lock(openssl_lock);
+	{
+		sock->CipherName = CopyStr((char *)SSL_get_cipher(sock->ssl));
+	}
+	Unlock(openssl_lock);
+
+	Unlock(sock->ssl_lock);
+
+	return true;
+}
+
+// TCP-SSL 受信
+UINT SecureRecv(SOCK *sock, void *data, UINT size)
+{
+	SOCKET s;
+	int ret, e = 0;
+	SSL *ssl;
+
+#ifdef UNIX_SOLARIS
+	SOCKET_TIMEOUT_PARAM *ttparam;
+#endif //UNIX_SOLARIS
+
+	s = sock->socket;
+	ssl = sock->ssl;
+
+	if (sock->AsyncMode)
+	{
+		// 非同期モードの場合はデータが 1 バイトでも読み出し可能かどうか確認する。
+		// 読み出し可能なデータが無い場合に read をしてしまうとブロッキングするため
+		// それは避けなければならない。
+		char c;
+		Lock(sock->ssl_lock);
+		{
+			if (sock->Connected == false)
+			{
+				Unlock(sock->ssl_lock);
+				Debug("%s %u SecureRecv() Disconnect\n", __FILE__, __LINE__);
+				return 0;
+			}
+			ret = SSL_peek(ssl, &c, sizeof(c));
+		}
+		Unlock(sock->ssl_lock);
+		if (ret == 0)
+		{
+			// 通信が切れておる
+			Disconnect(sock);
+			Debug("%s %u SecureRecv() Disconnect\n", __FILE__, __LINE__);
+			return 0;
+		}
+		if (ret < 0)
+		{
+			// エラーが発生した
+			e = SSL_get_error(ssl, ret);
+			if (e == SSL_ERROR_WANT_READ || e == SSL_ERROR_WANT_WRITE || e == SSL_ERROR_SSL)
+			{
+				// パケットがまだ届いていない、つまり read してはいけない
+				return SOCK_LATER;
+			}
+		}
+	}
+
+	// 受信する
+	Lock(sock->ssl_lock);
+	{
+		if (sock->Connected == false)
+		{
+			Unlock(sock->ssl_lock);
+			Debug("%s %u SecureRecv() Disconnect\n", __FILE__, __LINE__);
+			return 0;
+		}
+
+#ifdef	OS_UNIX
+		if (sock->AsyncMode == false)
+		{
+			sock->CallingThread = pthread_self();
+		}
+#endif	// OS_UNIX
+
+// SOLARIS用タイムアウトスレッドの起動
+#ifdef UNIX_SOLARIS
+		ttparam = NewSocketTimeout(sock);
+#endif // UNIX_SOLARIS
+
+		ret = SSL_read(ssl, data, size);
+
+// タイムアウトスレッドの停止
+#ifdef UNIX_SOLARIS
+		FreeSocketTimeout(ttparam);
+#endif // UNIX_SOLARIS
+
+
+#ifdef	OS_UNIX
+		if (sock->AsyncMode == false)
+		{
+			sock->CallingThread = 0;
+		}
+#endif	// OS_UNIX
+
+		if (ret < 0)
+		{
+			e = SSL_get_error(ssl, ret);
+		}
+
+	}
+	Unlock(sock->ssl_lock);
+	if (ret > 0)
+	{
+		// 受信成功
+		sock->RecvSize += (UINT64)ret;
+		sock->RecvNum++;
+		return (UINT)ret;
+	}
+	if (ret == 0)
+	{
+		// 通信切断
+		Disconnect(sock);
+		Debug("%s %u SecureRecv() Disconnect\n", __FILE__, __LINE__);
+		return 0;
+	}
+	if (sock->AsyncMode)
+	{
+		if (e == SSL_ERROR_WANT_READ || e == SSL_ERROR_WANT_WRITE || e == SSL_ERROR_SSL)
+		{
+			// パケットがまだ届いていない
+			return SOCK_LATER;
+		}
+	}
+	Disconnect(sock);
+	Debug("%s %u SecureRecv() Disconnect\n", __FILE__, __LINE__);
+	return 0;
+}
+
+// TCP-SSL 送信
+UINT SecureSend(SOCK *sock, void *data, UINT size)
+{
+	SOCKET s;
+	int ret, e;
+	SSL *ssl;
+	s = sock->socket;
+	ssl = sock->ssl;
+
+	if (sock->AsyncMode)
+	{
+		// 非同期モード
+		SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+	}
+
+	// 送信
+	Lock(sock->ssl_lock);
+	{
+		if (sock->Connected == false)
+		{
+			Unlock(sock->ssl_lock);
+			Debug("%s %u SecureRecv() Disconnect\n", __FILE__, __LINE__);
+			return 0;
+		}
+
+		ret = SSL_write(ssl, data, size);
+		if (ret < 0)
+		{
+			e = SSL_get_error(ssl, ret);
+		}
+	}
+	Unlock(sock->ssl_lock);
+
+	if (ret > 0)
+	{
+		// 送信成功
+		sock->SendSize += (UINT64)ret;
+		sock->SendNum++;
+		sock->WriteBlocked = false;
+		return (UINT)ret;
+	}
+	if (ret == 0)
+	{
+		// 切断
+		Debug("%s %u SecureRecv() Disconnect\n", __FILE__, __LINE__);
+		Disconnect(sock);
+		return 0;
+	}
+
+	if (sock->AsyncMode)
+	{
+		// エラー値の確認
+		if (e == SSL_ERROR_WANT_READ || e == SSL_ERROR_WANT_WRITE || e == SSL_ERROR_SSL)
+		{
+			sock->WriteBlocked = true;
+			return SOCK_LATER;
+		}
+		Debug("%s %u e=%u\n", __FILE__, __LINE__, e);
+	}
+	//Debug("%s %u SecureRecv() Disconnect\n", __FILE__, __LINE__);
+	Disconnect(sock);
+	return 0;
+}
+
+// TCP 受信
+UINT Recv(SOCK *sock, void *data, UINT size, bool secure)
+{
+	SOCKET s;
+	int ret;
+
+#ifdef UNIX_SOLARIS
+	SOCKET_TIMEOUT_PARAM *ttparam;
+#endif //UNIX_SOLARIS
+
+	// 引数チェック
+	if (sock == NULL || data == NULL || size == 0)
+	{
+		return 0;
+	}
+	if (sock->Type != SOCK_TCP || sock->Connected == false || sock->ListenMode != false ||
+		sock->socket == INVALID_SOCKET)
+	{
+		return 0;
+	}
+	if (secure != false && sock->SecureMode == false)
+	{
+		return 0;
+	}
+
+	if (secure)
+	{
+		return SecureRecv(sock, data, size);
+	}
+
+	// 受信
+	s = sock->socket;
+
+
+#ifdef	OS_UNIX
+	if (sock->AsyncMode == false)
+	{
+		sock->CallingThread = pthread_self();
+	}
+#endif	// OS_UNIX
+
+// SOLARIS用タイムアウトスレッドの開始
+#ifdef UNIX_SOLARIS
+	ttparam = NewSocketTimeout(sock);
+#endif // UNIX_SOLARIS
+
+	ret = recv(s, data, size, 0);
+
+// タイムアウトスレッドの停止
+#ifdef UNIX_SOLARIS
+	FreeSocketTimeout(ttparam);
+#endif // UNIX_SOLARIS
+
+#ifdef	OS_UNIX
+	if (sock->AsyncMode == false)
+	{
+		sock->CallingThread = 0;
+	}
+#endif	// OS_UNIX
+
+	if (ret > 0)
+	{
+		// 受信成功
+		Lock(sock->lock);
+		{
+			sock->RecvSize += (UINT64)ret;
+			sock->SendNum++;
+		}
+		Unlock(sock->lock);
+		return (UINT)ret;
+	}
+
+	// 送信失敗
+	if (sock->AsyncMode)
+	{
+		// 非同期モードの場合、エラーを調べる
+		if (ret == SOCKET_ERROR)
+		{
+#ifdef	OS_WIN32
+			if (WSAGetLastError() == WSAEWOULDBLOCK)
+			{
+				// ブロッキングしている
+				return SOCK_LATER;
+			}
+			else
+			{
+				Debug("Socket Error: %u\n", WSAGetLastError());
+			}
+#else	// OS_WIN32
+			if (errno == EAGAIN)
+			{
+				// ブロッキングしている
+				return SOCK_LATER;
+			}
+#endif	// OS_WIN32
+		}
+	}
+
+	// 切断された
+	Disconnect(sock);
+	return 0;
+}
+
+// TCP 送信
+UINT Send(SOCK *sock, void *data, UINT size, bool secure)
+{
+	SOCKET s;
+	int ret;
+	// 引数チェック
+	if (sock == NULL || data == NULL || size == 0)
+	{
+		return 0;
+	}
+	size = MIN(size, MAX_SEND_BUF_MEM_SIZE);
+	if (sock->Type != SOCK_TCP || sock->Connected == false || sock->ListenMode != false ||
+		sock->socket == INVALID_SOCKET)
+	{
+		return 0;
+	}
+	if (secure != false && sock->SecureMode == false)
+	{
+		return 0;
+	}
+
+	if (secure)
+	{
+		return SecureSend(sock, data, size);
+	}
+
+	// 送信
+	s = sock->socket;
+	ret = send(s, data, size, 0);
+	if (ret > 0)
+	{
+		// 送信成功
+		Lock(sock->lock);
+		{
+			sock->SendSize += (UINT64)ret;
+			sock->SendNum++;
+		}
+		Unlock(sock->lock);
+		sock->WriteBlocked = false;
+		return (UINT)ret;
+	}
+
+	// 送信失敗
+	if (sock->AsyncMode)
+	{
+		// 非同期モードの場合、エラーを調べる
+		if (ret == SOCKET_ERROR)
+		{
+#ifdef	OS_WIN32
+			if (WSAGetLastError() == WSAEWOULDBLOCK)
+			{
+				// ブロッキングしている
+				sock->WriteBlocked = true;
+				return SOCK_LATER;
+			}
+			else
+			{
+				Debug("Socket Error: %u\n", WSAGetLastError());
+			}
+#else	// OS_WIN32
+			if (errno == EAGAIN)
+			{
+				// ブロッキングしている
+				sock->WriteBlocked = true;
+				return SOCK_LATER;
+			}
+#endif	// OS_WIN32
+		}
+	}
+
+	// 切断された
+	Disconnect(sock);
+	return 0;
+}
+
+// タイムアウトの取得 (ミリ秒)
+UINT GetTimeout(SOCK *sock)
+{
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return INFINITE;
+	}
+	if (sock->Type != SOCK_TCP)
+	{
+		return INFINITE;
+	}
+
+	return sock->TimeOut;
+}
+
+// タイムアウト時間の設定 (ミリ秒)
+void SetTimeout(SOCK *sock, UINT timeout)
+{
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return;
+	}
+	if (sock->Type != SOCK_TCP)
+	{
+		return;
+	}
+
+	if (timeout == INFINITE)
+	{
+		timeout = TIMEOUT_INFINITE;
+	}
+
+	sock->TimeOut = timeout;
+
+//	Debug("SetTimeout(%u)\n",timeout);
+
+#ifdef OS_WIN32
+	setsockopt(sock->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(UINT));
+	setsockopt(sock->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(UINT));
+#endif
+
+#ifdef OS_UNIX
+#ifndef UNIX_SOLARIS
+	{
+		struct timeval tv_timeout;
+
+		tv_timeout.tv_sec = timeout / 1000; // miliseconds to seconds
+		tv_timeout.tv_usec = (timeout % 1000) * 1000; // miliseconds to microseconds
+
+		setsockopt(sock->socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv_timeout, sizeof(tv_timeout));
+		setsockopt(sock->socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv_timeout, sizeof(tv_timeout));
+	}
+#endif // UNIX_SOLARIS
+#endif // OS_UNIX
+}
+
+// 接続受諾初期化
+void AcceptInit(SOCK *s)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Zero(tmp, sizeof(tmp));
+	if (GetHostName(tmp, sizeof(tmp), &s->RemoteIP) == false ||
+		IsEmptyStr(tmp))
+	{
+		IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+	}
+
+	s->RemoteHostname = CopyStr(tmp);
+}
+
+// TCP 接続受諾
+SOCK *Accept(SOCK *sock)
+{
+	SOCK *ret;
+	SOCKET s, new_socket;
+	int size;
+	struct sockaddr_in addr;
+	bool true_flag = true;
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return NULL;
+	}
+	if (sock->ListenMode == false || sock->Type != SOCK_TCP || sock->ServerMode == false)
+	{
+		return NULL;
+	}
+	if (sock->CancelAccept)
+	{
+		return NULL;
+	}
+	if (sock->IPv6)
+	{
+		return Accept6(sock);
+	}
+
+	s = sock->socket;
+	if (s == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+	Zero(&addr, sizeof(addr));
+	size = sizeof(addr);
+
+#ifdef	OS_UNIX
+	sock->CallingThread = pthread_self();
+#endif	// OS_UNIX
+
+	new_socket = accept(s, (struct sockaddr *)&addr,(int *)&size);
+
+#ifdef	OS_UNIX
+	sock->CallingThread = 0;
+#endif	// OS_UNIX
+
+	if (new_socket == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+	if (sock->CancelAccept)
+	{
+		closesocket(new_socket);
+		return NULL;
+	}
+
+	ret = NewSock();
+	ret->socket = new_socket;
+	ret->Connected = true;
+	ret->AsyncMode = false;
+	ret->Type = SOCK_TCP;
+	ret->ServerMode = true;
+	ret->SecureMode = false;
+
+	// TCP オプションの設定
+	setsockopt(ret->socket, IPPROTO_TCP, TCP_NODELAY, (char *)&true_flag, sizeof(bool));
+
+	SetSockPriorityHigh(ret);
+
+	// タイムアウト値の初期化
+	SetTimeout(ret, TIMEOUT_INFINITE);
+
+	// ソケット情報
+	QuerySocketInformation(ret);
+
+	AddIpClient(&ret->RemoteIP);
+
+	return ret;
+}
+SOCK *Accept6(SOCK *sock)
+{
+	SOCK *ret;
+	SOCKET s, new_socket;
+	int size;
+	struct sockaddr_in6 addr;
+	bool true_flag = true;
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return NULL;
+	}
+	if (sock->ListenMode == false || sock->Type != SOCK_TCP || sock->ServerMode == false)
+	{
+		return NULL;
+	}
+	if (sock->CancelAccept)
+	{
+		return NULL;
+	}
+	if (sock->IPv6 == false)
+	{
+		return NULL;
+	}
+
+	s = sock->socket;
+	if (s == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+	Zero(&addr, sizeof(addr));
+	size = sizeof(addr);
+
+#ifdef	OS_UNIX
+	sock->CallingThread = pthread_self();
+#endif	// OS_UNIX
+
+	new_socket = accept(s, (struct sockaddr *)&addr,(int *)&size);
+
+#ifdef	OS_UNIX
+	sock->CallingThread = 0;
+#endif	// OS_UNIX
+
+	if (new_socket == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+	if (sock->CancelAccept)
+	{
+		closesocket(new_socket);
+		return NULL;
+	}
+
+	ret = NewSock();
+	ret->socket = new_socket;
+	ret->Connected = true;
+	ret->AsyncMode = false;
+	ret->Type = SOCK_TCP;
+	ret->ServerMode = true;
+	ret->SecureMode = false;
+
+	// TCP オプションの設定
+	setsockopt(ret->socket, IPPROTO_TCP, TCP_NODELAY, (char *)&true_flag, sizeof(bool));
+
+	SetSockPriorityHigh(ret);
+
+	// タイムアウト値の初期化
+	SetTimeout(ret, TIMEOUT_INFINITE);
+
+	// ソケット情報
+	QuerySocketInformation(ret);
+
+	AddIpClient(&ret->RemoteIP);
+
+	return ret;
+}
+
+// TCP 待ち受け (IPv6)
+SOCK *Listen6(UINT port)
+{
+	return ListenEx6(port, false);
+}
+SOCK *ListenEx6(UINT port, bool local_only)
+{
+	SOCKET s;
+	SOCK *sock;
+	struct sockaddr_in6 addr;
+	struct in6_addr in;
+	bool true_flag = true;
+	IP localhost;
+	// 引数チェック
+	if (port == 0 || port >= 65536)
+	{
+		return NULL;
+	}
+
+	// 初期化
+	Zero(&addr, sizeof(addr));
+	Zero(&in, sizeof(in));
+	GetLocalHostIP6(&localhost);
+
+	addr.sin6_port = htons((UINT)port);
+	addr.sin6_family = AF_INET6;
+
+	if (local_only)
+	{
+		IPToInAddr6(&addr.sin6_addr, &localhost);
+	}
+
+	// ソケットの作成
+	s = socket(AF_INET6, SOCK_STREAM, 0);
+	if (s == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+
+#ifdef	OS_UNIX
+	// UNIX 系では IPv6 Only フラグを立てる必要がある
+	setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &true_flag, sizeof(true_flag));
+#endif	// OS_UNIX
+
+	//SetSocketSendRecvBufferSize(s, SOCKET_BUFFER_SIZE);
+
+#ifdef	OS_UNIX
+	// Windows 系 OS は REUSEADDR の実装にバグがあるっぽいので
+	// UNIX 系のみ有効にした。
+	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&true_flag, sizeof(bool));
+#endif	// OS_UNIX
+
+	if (bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_in6)) != 0)
+	{
+		// bind 失敗
+		closesocket(s);
+		return NULL;
+	}
+	if (listen(s, SOMAXCONN))
+	{
+		// listen 失敗
+		closesocket(s);
+		return NULL;
+	}
+
+	// 成功
+	sock = NewSock();
+	sock->Connected = false;
+	sock->AsyncMode = false;
+	sock->ServerMode = true;
+	sock->Type = SOCK_TCP;
+	sock->socket = s;
+	sock->ListenMode = true;
+	sock->SecureMode = false;
+	sock->LocalPort = port;
+	sock->IPv6 = true;
+
+	return sock;
+}
+
+// TCP 待ち受け
+SOCK *Listen(UINT port)
+{
+	return ListenEx(port, false);
+}
+SOCK *ListenEx(UINT port, bool local_only)
+{
+	SOCKET s;
+	SOCK *sock;
+	struct sockaddr_in addr;
+	struct in_addr in;
+	bool true_flag = true;
+	IP localhost;
+	// 引数チェック
+	if (port == 0 || port >= 65536)
+	{
+		return NULL;
+	}
+
+	// 初期化
+	Zero(&addr, sizeof(addr));
+	Zero(&in, sizeof(in));
+	SetIP(&localhost, 127, 0, 0, 1);
+
+	addr.sin_port = htons((UINT)port);
+	*((UINT *)&addr.sin_addr) = htonl(INADDR_ANY);
+	addr.sin_family = AF_INET;
+
+	if (local_only)
+	{
+		IPToInAddr(&addr.sin_addr, &localhost);
+	}
+
+	// ソケットの作成
+	s = socket(AF_INET, SOCK_STREAM, 0);
+	if (s == INVALID_SOCKET)
+	{
+		return NULL;
+	}
+
+	//SetSocketSendRecvBufferSize(s, SOCKET_BUFFER_SIZE);
+
+#ifdef	OS_UNIX
+	// Windows 系 OS は REUSEADDR の実装にバグがあるっぽいので
+	// UNIX 系のみ有効にした。
+	setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&true_flag, sizeof(bool));
+#endif	// OS_UNIX
+
+	if (bind(s, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0)
+	{
+		// bind 失敗
+		closesocket(s);
+		return NULL;
+	}
+	if (listen(s, SOMAXCONN))
+	{
+		// listen 失敗
+		closesocket(s);
+		return NULL;
+	}
+
+	// 成功
+	sock = NewSock();
+	sock->Connected = false;
+	sock->AsyncMode = false;
+	sock->ServerMode = true;
+	sock->Type = SOCK_TCP;
+	sock->socket = s;
+	sock->ListenMode = true;
+	sock->SecureMode = false;
+	sock->LocalPort = port;
+
+	return sock;
+}
+
+// TCP 切断
+void Disconnect(SOCK *sock)
+{
+	SOCKET s;
+	bool true_flag = true;
+	bool false_flag = false;
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return;
+	}
+
+	sock->Disconnecting = true;
+
+#ifdef	OS_UNIX
+	UnixFreeAsyncSocket(sock);
+#endif	// UnixFreeAsyncSocket
+
+	if (sock->Type == SOCK_TCP && sock->ListenMode)
+	{
+		// Listen 中のソケットの場合は localhost に対して接続する
+		sock->CancelAccept = true;
+
+		if (sock->IPv6 == false)
+		{
+			CheckTCPPort("127.0.0.1", sock->LocalPort);
+		}
+		else
+		{
+			CheckTCPPort("::1", sock->LocalPort);
+		}
+	}
+
+	Lock(disconnect_function_lock);
+
+	Lock(sock->disconnect_lock);
+
+	if (sock->Type == SOCK_TCP)
+	{
+		if (sock->socket != INVALID_SOCKET)
+		{
+			// 強制切断フラグ
+			#ifdef	SO_DONTLINGER
+				setsockopt(sock->socket, SOL_SOCKET, SO_DONTLINGER, (char *)&true_flag, sizeof(bool));
+			#else	// SO_DONTLINGER
+				setsockopt(sock->socket, SOL_SOCKET, SO_LINGER, (char *)&false_flag, sizeof(bool));
+			#endif	// SO_DONTLINGER
+//			setsockopt(sock->socket, SOL_SOCKET, SO_REUSEADDR, (char *)&true_flag, sizeof(bool));
+		}
+
+		// TCP ソケット
+		Lock(sock->lock);
+		{
+			if (sock->socket == INVALID_SOCKET)
+			{
+				Unlock(sock->lock);
+				Unlock(sock->disconnect_lock);
+				Unlock(disconnect_function_lock);
+				return;
+			}
+			s = sock->socket;
+
+			if (sock->Connected)
+			{
+				struct linger ling;
+				Zero(&ling, sizeof(ling));
+
+
+#if	0
+				// SSL 切断
+				Lock(sock->ssl_lock);
+				{
+					if (sock->SecureMode)
+					{
+						SSL_shutdown(sock->ssl);
+					}
+				}
+				Unlock(sock->ssl_lock);
+#endif
+				// 切断
+				shutdown(s, 2);
+			}
+
+			// ソケットを閉じる
+			closesocket(s);
+
+#ifdef	OS_UNIX
+#ifdef	FIX_SSL_BLOCKING
+			if (sock->CallingThread != NULL)
+			{
+				pthread_kill(sock->CallingThread, 64);
+			}
+#endif	// FIX_SSL_BLOCKING
+#endif	// OS_UNIX
+
+			// SSL を解放
+			Lock(sock->ssl_lock);
+			{
+				if (sock->SecureMode)
+				{
+					if (sock->ssl != NULL)
+					{
+						Lock(openssl_lock);
+						{
+							SSL_free(sock->ssl);
+						}
+						Unlock(openssl_lock);
+						sock->ssl = NULL;
+					}
+					sock->Connected = false;
+					// 証明書を解放
+					if (sock->RemoteX != NULL)
+					{
+						FreeX(sock->RemoteX);
+						sock->RemoteX = NULL;
+					}
+					if (sock->LocalX != NULL)
+					{
+						FreeX(sock->LocalX);
+						sock->LocalX = NULL;
+					}
+
+					// 暗号化アルゴリズム名
+					if (sock->CipherName != NULL)
+					{
+						Free(sock->CipherName);
+						sock->CipherName = NULL;
+					}
+					sock->SecureMode = false;
+				}
+			}
+			Unlock(sock->ssl_lock);
+
+			// 初期化
+			sock->socket = INVALID_SOCKET;
+			sock->Type = 0;
+			sock->AsyncMode = false;
+			sock->Connected = false;
+			sock->ListenMode = false;
+			sock->SecureMode = false;
+
+			if (sock->ServerMode && sock->ListenMode == false)
+			{
+				DelIpClient(&sock->RemoteIP);
+			}
+		}
+		Unlock(sock->lock);
+	}
+	else if (sock->Type == SOCK_UDP)
+	{
+		// UDP ソケット
+		Lock(sock->lock);
+		{
+			if (sock->socket == INVALID_SOCKET)
+			{
+				Unlock(sock->lock);
+				Unlock(sock->disconnect_lock);
+				Unlock(disconnect_function_lock);
+				return;
+			}
+
+			s = sock->socket;
+
+			// ソケットを閉じる
+			closesocket(s);
+
+			// 初期化
+			sock->socket = INVALID_SOCKET;
+			sock->Type = 0;
+			sock->AsyncMode = false;
+			sock->Connected = false;
+			sock->ListenMode = false;
+			sock->SecureMode = false;
+		}
+		Unlock(sock->lock);
+	}
+	Unlock(sock->disconnect_lock);
+
+	Unlock(disconnect_function_lock);
+}
+
+typedef struct TCP_PORT_CHECK
+{
+	REF *ref;
+	char hostname[MAX_SIZE];
+	UINT port;
+	bool ok;
+} TCP_PORT_CHECK;
+
+// TCP ポートチェック用スレッド
+void CheckTCPPortThread(THREAD *thread, void *param)
+{
+	TCP_PORT_CHECK *c;
+	SOCK *s;
+	// 引数チェック
+	if (thread == NULL || param == NULL)
+	{
+		return;
+	}
+
+	c = (TCP_PORT_CHECK *)param;
+	AddRef(c->ref);
+	NoticeThreadInit(thread);
+
+	AddWaitThread(thread);
+
+	s = Connect(c->hostname, c->port);
+	if (s != NULL)
+	{
+		c->ok = true;
+		Disconnect(s);
+		ReleaseSock(s);
+	}
+
+	if (Release(c->ref) == 0)
+	{
+		Free(c);
+	}
+
+	DelWaitThread(thread);
+}
+
+// TCP ポートに接続可能かどうかチェックする
+bool CheckTCPPortEx(char *hostname, UINT port, UINT timeout)
+{
+	SOCK *s;
+	// 引数チェック
+	if (hostname == NULL || port == 0 || port >= 65536)
+	{
+		return false;
+	}
+
+	if (timeout == 0)
+	{
+		timeout = TIMEOUT_TCP_PORT_CHECK;
+	}
+
+	s = ConnectEx(hostname, port, timeout);
+	if (s == NULL)
+	{
+		return false;
+	}
+	else
+	{
+		Disconnect(s);
+		ReleaseSock(s);
+		return true;
+	}
+}
+bool CheckTCPPort(char *hostname, UINT port)
+{
+	return CheckTCPPortEx(hostname, port, TIMEOUT_TCP_PORT_CHECK);
+}
+
+#ifdef	OS_UNIX
+// タイムアウト付き接続 (UNIX 版)
+int connect_timeout(SOCKET s, struct sockaddr *addr, int size, int timeout, bool *cancel_flag)
+{
+	SOCKSET set;
+	bool ok = false;
+	UINT64 start_time;
+	// 引数チェック
+	if (s == INVALID_SOCKET || addr == NULL)
+	{
+		return -1;
+	}
+	if (timeout == 0)
+	{
+		timeout = TIMEOUT_TCP_PORT_CHECK;
+	}
+
+	UnixSetSocketNonBlockingMode(s, true);
+
+	start_time = Tick64();
+
+	while (true)
+	{
+		int ret;
+		ret = connect(s, addr, size);
+		if (ret == 0 || errno == EISCONN)
+		{
+			ok = true;
+			break;
+		}
+		else
+		{
+			if (((start_time + (UINT64)timeout) <= Tick64()) || (errno != EAGAIN && errno != EINPROGRESS && errno != EALREADY))
+			{
+				// 失敗
+				break;
+			}
+			else if (*cancel_flag)
+			{
+				// キャンセル
+				break;
+			}
+			else
+			{
+				// 接続中
+				SleepThread(50);
+				UnixSelectInner(1, (UINT *)&s, 1, (UINT *)&s, 100);
+			}
+		}
+	}
+
+	UnixSetSocketNonBlockingMode(s, false);
+
+	if (ok)
+	{
+		return 0;
+	}
+	else
+	{
+		return -1;
+	}
+}
+#else
+// タイムアウト付き接続 (Win32 版)
+int connect_timeout(SOCKET s, struct sockaddr *addr, int size, int timeout, bool *cancel_flag)
+{
+	UINT64 start_time;
+	bool ok = false;
+	bool timeouted = false;
+	WSAEVENT hEvent;
+	UINT zero = 0;
+	UINT tmp = 0;
+	UINT ret_size = 0;
+	bool is_nt = false;
+	// 引数チェック
+	if (s == INVALID_SOCKET || addr == NULL)
+	{
+		return -1;
+	}
+	if (timeout == 0)
+	{
+		timeout = TIMEOUT_TCP_PORT_CHECK;
+	}
+
+	is_nt = OS_IS_WINDOWS_NT(GetOsInfo()->OsType);
+
+	// イベントを作成
+	hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+	// ソケットをイベントに関連付ける
+	WSAEventSelect(s, hEvent, FD_CONNECT);
+
+	start_time = Tick64();
+
+	while (true)
+	{
+		int ret;
+		
+		ret = connect(s, addr, size);
+
+		if (ret == 0)
+		{
+			ok = true;
+			break;
+		}
+		else
+		{
+			int err = WSAGetLastError();
+			//Debug("err=%u\n", err);
+			//Debug("cancel_flag=%u\n", *cancel_flag);
+			if (timeouted && ((err == WSAEALREADY) || (err == WSAEWOULDBLOCK && !is_nt)))
+			{
+				// タイムアウト
+				ok = false;
+				break;
+			}
+			if (*cancel_flag)
+			{
+				// キャンセル
+				ok = false;
+				break;
+			}
+			if (err == WSAEISCONN || (err == WSAEINVAL && is_nt))
+			{
+				ok = true;
+				break;
+			}
+			if (((start_time + (UINT64)timeout) <= Tick64()) || (err != WSAEWOULDBLOCK && err != WSAEALREADY && (is_nt || err != WSAEINVAL)))
+			{
+				// 失敗 (タイムアウト)
+				break;
+			}
+			else
+			{
+				SleepThread(10);
+				// 接続中
+				if (WaitForSingleObject(hEvent, 100) == WAIT_OBJECT_0)
+				{
+					timeouted = true;
+				}
+			}
+		}
+	}
+
+	// ソケットをイベントから外す
+	WSAEventSelect(s, hEvent, 0);
+
+	// 同期ソケットに戻す
+	WSAIoctl(s, FIONBIO, &zero, sizeof(zero), &tmp, sizeof(tmp), &ret_size, NULL, NULL);
+
+	// イベントを閉じる
+	CloseHandle(hEvent);
+
+	if (ok)
+	{
+		return 0;
+	}
+	else
+	{
+		return -1;
+	}
+}
+#endif	// OS_UNIX
+
+// ソケットのパケットの優先順位を向上させる (未使用)
+void SetSockPriorityHigh(SOCK *s)
+{
+	int value;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	value = 16;
+
+#ifdef	IP_TOS
+	//setsockopt(s->socket, IPPROTO_IP, IP_TOS, (char *)&value, sizeof(int));
+#endif	// IP_TOS
+}
+
+// TCP 接続
+SOCK *Connect(char *hostname, UINT port)
+{
+	return ConnectEx(hostname, port, 0);
+}
+SOCK *ConnectEx(char *hostname, UINT port, UINT timeout)
+{
+	return ConnectEx2(hostname, port, timeout, NULL);
+}
+SOCK *ConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag)
+{
+	SOCK *sock;
+	SOCKET s;
+	struct linger ling;
+	struct sockaddr_in sockaddr4;
+	struct in_addr addr4;
+	IP ip4;
+	struct sockaddr_in6 sockaddr6;
+	struct in6_addr addr6;
+	IP ip6;
+	bool true_flag = true;
+	bool false_flag = false;
+	char tmp[MAX_SIZE];
+	IP current_ip;
+	bool is_ipv6 = false;
+	bool dummy = false;
+	// 引数チェック
+	if (hostname == NULL || port == 0 || port >= 65536)
+	{
+		return NULL;
+	}
+	if (timeout == 0)
+	{
+		timeout = TIMEOUT_TCP_PORT_CHECK;
+	}
+	if (cancel_flag == NULL)
+	{
+		cancel_flag = &dummy;
+	}
+
+	Zero(&current_ip, sizeof(current_ip));
+
+	Zero(&sockaddr4, sizeof(sockaddr4));
+	Zero(&addr4, sizeof(addr4));
+	Zero(&ip4, sizeof(ip4));
+
+	Zero(&sockaddr6, sizeof(sockaddr6));
+	Zero(&addr6, sizeof(addr6));
+	Zero(&ip6, sizeof(ip6));
+
+	// 正引き
+	if (GetIP46Ex(&ip4, &ip6, hostname, 0, cancel_flag) == false)
+	{
+		return NULL;
+	}
+
+	s = INVALID_SOCKET;
+
+	// IPv4 で接続を試行する
+	if (IsZeroIp(&ip4) == false)
+	{
+		// sockaddr_in の生成
+		IPToInAddr(&addr4, &ip4);
+		sockaddr4.sin_port = htons((USHORT)port);
+		sockaddr4.sin_family = AF_INET;
+		sockaddr4.sin_addr.s_addr = addr4.s_addr;
+
+		// ソケット作成
+		s = socket(AF_INET, SOCK_STREAM, 0);
+		if (s != INVALID_SOCKET)
+		{
+			// 接続
+			if (connect_timeout(s, (struct sockaddr *)&sockaddr4, sizeof(struct sockaddr_in), timeout, cancel_flag) != 0)
+			{
+				// 接続失敗
+				closesocket(s);
+				s = INVALID_SOCKET;
+			}
+			else
+			{
+				Copy(&current_ip, &ip4, sizeof(IP));
+			}
+		}
+	}
+
+	// IPv6 で接続を試行する
+	if (s == INVALID_SOCKET && IsZeroIp(&ip6) == false)
+	{
+		// sockaddr_in6 の生成
+		IPToInAddr6(&addr6, &ip6);
+		sockaddr6.sin6_port = htons((USHORT)port);
+		sockaddr6.sin6_family = AF_INET6;
+		sockaddr6.sin6_scope_id = ip6.ipv6_scope_id;
+		Copy(&sockaddr6.sin6_addr, &addr6, sizeof(addr6));
+
+		// ソケット作成
+		s = socket(AF_INET6, SOCK_STREAM, 0);
+		if (s != INVALID_SOCKET)
+		{
+			// 接続
+			if (connect_timeout(s, (struct sockaddr *)&sockaddr6, sizeof(struct sockaddr_in6), timeout, cancel_flag) != 0)
+			{
+				// 接続失敗
+				closesocket(s);
+				s = INVALID_SOCKET;
+			}
+			else
+			{
+				Copy(&current_ip, &ip6, sizeof(IP));
+
+				is_ipv6 = true;
+			}
+		}
+	}
+
+	if (s == INVALID_SOCKET)
+	{
+		// IPv4, IPv6 の両方で接続失敗
+		return NULL;
+	}
+
+	// SOCK の作成
+	sock = NewSock();
+	sock->socket = s;
+	sock->Type = SOCK_TCP;
+	sock->ServerMode = false;
+
+	SetSockPriorityHigh(sock);
+
+	// ホスト名解決
+	if (GetHostName(tmp, sizeof(tmp), &current_ip) == false)
+	{
+		StrCpy(tmp, sizeof(tmp), hostname);
+	}
+
+	//Debug("PTR: %s\n", tmp);
+
+	sock->RemoteHostname = CopyStr(tmp);
+
+//	Debug("new socket: %u\n", s);
+
+	Zero(&ling, sizeof(ling));
+	// 強制切断フラグ
+#ifdef	SO_DONTLINGER
+	setsockopt(sock->socket, SOL_SOCKET, SO_DONTLINGER, (char *)&true_flag, sizeof(bool));
+#else	// SO_DONTLINGER
+	setsockopt(sock->socket, SOL_SOCKET, SO_LINGER, (char *)&false_flag, sizeof(bool));
+#endif	// SO_DONTLINGER
+//	setsockopt(sock->socket, SOL_SOCKET, SO_REUSEADDR, (char *)&true_flag, sizeof(bool));
+
+	// TCP オプションの設定
+	setsockopt(sock->socket, IPPROTO_TCP, TCP_NODELAY, (char *)&true_flag, sizeof(bool));
+
+	// タイムアウト値の初期化
+	SetTimeout(sock, TIMEOUT_INFINITE);
+
+	// ソケット情報の取得
+	QuerySocketInformation(sock);
+
+	sock->Connected = true;
+	sock->AsyncMode = false;
+	sock->SecureMode = false;
+	sock->IPv6 = is_ipv6;
+
+	return sock;
+}
+
+// ソケットの送受信バッファサイズを最大にする
+void SetSocketSendRecvBufferSize(int s, UINT size)
+{
+	int value = (int)size;
+	// 引数チェック
+	if (s == INVALID_SOCKET)
+	{
+		return;
+	}
+
+	setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&value, sizeof(int));
+	setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&value, sizeof(int));
+}
+
+// ソケット情報の取得
+void QuerySocketInformation(SOCK *sock)
+{
+	// 引数チェック
+	if (sock == NULL)
+	{
+		return;
+	}
+
+	Lock(sock->lock);
+	{
+		struct sockaddr_in6 sockaddr6;
+		struct in6_addr *addr6;
+		int size;
+
+		if (sock->Type == SOCK_TCP)
+		{
+			// リモートホストの情報を取得
+			size = sizeof(sockaddr6);
+			if (getpeername(sock->socket, (struct sockaddr *)&sockaddr6, (int *)&size) == 0)
+			{
+				if (size >= sizeof(struct sockaddr_in6))
+				{
+					sock->RemotePort = (UINT)ntohs(sockaddr6.sin6_port);
+					addr6 = &sockaddr6.sin6_addr;
+					InAddrToIP6(&sock->RemoteIP, addr6);
+					sock->RemoteIP.ipv6_scope_id = sockaddr6.sin6_scope_id;
+				}
+				else
+				{
+					struct sockaddr_in *sockaddr;
+					struct in_addr *addr;
+
+					sockaddr = (struct sockaddr_in *)&sockaddr6;
+					sock->RemotePort = (UINT)ntohs(sockaddr->sin_port);
+					addr = &sockaddr->sin_addr;
+					InAddrToIP(&sock->RemoteIP, addr);
+				}
+			}
+		}
+
+		// ローカルホストの情報を取得
+		size = sizeof(sockaddr6);
+		if (getsockname(sock->socket, (struct sockaddr *)&sockaddr6, (int *)&size) == 0)
+		{
+			if (size >= sizeof(struct sockaddr_in6))
+			{
+				sock->LocalPort = (UINT)ntohs(sockaddr6.sin6_port);
+				addr6 = &sockaddr6.sin6_addr;
+				InAddrToIP6(&sock->LocalIP, addr6);
+				sock->LocalIP.ipv6_scope_id = sockaddr6.sin6_scope_id;
+			}
+			else
+			{
+				struct sockaddr_in *sockaddr;
+				struct in_addr *addr;
+
+				sockaddr = (struct sockaddr_in *)&sockaddr6;
+				sock->LocalPort = (UINT)ntohs(sockaddr->sin_port);
+				addr = &sockaddr->sin_addr;
+				InAddrToIP(&sock->LocalIP, addr);
+			}
+		}
+	}
+	Unlock(sock->lock);
+}
+
+// ソケットの解放
+void ReleaseSock(SOCK *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	if (Release(s->ref) == 0)
+	{
+		if (s->ListenMode == false && s->ServerMode)
+		{
+			Print("");
+		}
+		CleanupSock(s);
+	}
+}
+
+// ソケットのクリーンアップ
+void CleanupSock(SOCK *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+//	{Debug("CleanupSock: Disconnect() Called: %s %u\n", __FILE__, __LINE__);Disconnect(s);}
+	Disconnect(s);
+
+#ifdef	OS_WIN32
+	Win32FreeAsyncSocket(s);
+#else	// OS_WIN32
+	UnixFreeAsyncSocket(s);
+#endif	// OS_WIN32
+
+	FreeBuf(s->SendBuf);
+	if (s->socket != INVALID_SOCKET)
+	{
+#ifdef	OS_WIN32
+		closesocket(s->socket);
+#else	// OS_WIN32
+		close(s->socket);
+#endif	// OS_WIN32
+	}
+	Free(s->RemoteHostname);
+
+	Free(s->WaitToUseCipher);
+	DeleteLock(s->lock);
+	DeleteLock(s->ssl_lock);
+	DeleteLock(s->disconnect_lock);
+
+	Dec(num_tcp_connections);
+
+	Free(s);
+}
+
+// 新しいソケットの作成
+SOCK *NewSock()
+{
+	SOCK *s = ZeroMallocFast(sizeof(SOCK));
+
+	s->ref = NewRef();
+	s->lock = NewLock();
+	s->SendBuf = NewBuf();
+	s->socket = INVALID_SOCKET;
+	s->ssl_lock = NewLock();
+	s->disconnect_lock = NewLock();
+
+	Inc(num_tcp_connections);
+
+	return s;
+}
+
+// IP を UINT に変換する
+UINT IPToUINT(IP *ip)
+{
+	UCHAR *b;
+	UINT i, value = 0;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return 0;
+	}
+
+	b = (UCHAR *)&value;
+	for (i = 0;i < 4;i++)
+	{
+		b[i] = ip->addr[i];
+	}
+
+	return value;
+}
+
+// UNIT を IP に変換する
+void UINTToIP(IP *ip, UINT value)
+{
+	UCHAR *b;
+	UINT i;
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	ZeroIP4(ip);
+
+	b = (UCHAR *)&value;
+	for (i = 0;i < 4;i++)
+	{
+		ip->addr[i] = b[i];
+	}
+}
+
+// コンピュータのホスト名を取得
+void GetMachineHostName(char *name, UINT size)
+{
+	char tmp[MAX_SIZE];
+	UINT i, len;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	GetMachineName(tmp, sizeof(tmp));
+
+	len = StrLen(tmp);
+	for (i = 0;i < len;i++)
+	{
+		if (tmp[i] == '.')
+		{
+			tmp[i] = 0;
+		}
+	}
+
+	ConvertSafeFileName(name, size, tmp);
+}
+
+// このコンピュータの IP アドレスを取得
+void GetMachineIp(IP *ip)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	Zero(ip, sizeof(IP));
+	SetIP(ip, 127, 0, 0, 1);
+
+	GetMachineName(tmp, sizeof(tmp));
+	GetIP(ip, tmp);
+}
+
+// コンピュータ名を hosts から取得
+bool GetMachineNameFromHosts(char *name, UINT size)
+{
+	bool ret = false;
+	char *s;
+	BUF *b;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	b = ReadDump("/etc/hosts");
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	while (true)
+	{
+		s = CfgReadNextLine(b);
+		if (s == NULL)
+		{
+			break;
+		}
+		else
+		{
+			TOKEN_LIST *t = ParseToken(s, " \t");
+
+			if (t != NULL)
+			{
+				if (t->NumTokens >= 2)
+				{
+					if (StrCmpi(t->Token[0], "127.0.0.1") == 0)
+					{
+						UINT i;
+
+						for (i = 1;i < t->NumTokens;i++)
+						{
+							if (StartWith(t->Token[i], "localhost") == false)
+							{
+								StrCpy(name, size, t->Token[i]);
+								ret = true;
+							}
+						}
+					}
+				}
+			}
+			FreeToken(t);
+		}
+
+		Free(s);
+	}
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// このコンピュータのコンピュータ名を取得
+void GetMachineName(char *name, UINT size)
+{
+	GetMachineNameEx(name, size, false);
+}
+void GetMachineNameEx(char *name, UINT size, bool no_load_hosts)
+{
+	static char name_cache[MAX_SIZE];
+	static bool name_cached = false;
+	char tmp[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	IP ip;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	Lock(machine_name_lock);
+	{
+		if (name_cached != false)
+		{
+			StrCpy(name, size, name_cache);
+			Unlock(machine_name_lock);
+			return;
+		}
+		if (gethostname(tmp, MAX_SIZE) != 0)
+		{
+			StrCpy(name, size, "Unknown");
+			Unlock(machine_name_lock);
+			return;
+		}
+		if (GetIP(&ip, tmp) == false)
+		{
+			StrCpy(name, size, tmp);
+			Unlock(machine_name_lock);
+			return;
+		}
+		if (GetHostNameInner(name, size, &ip) == false || StartWith(name, "localhost"))
+		{
+			StrCpy(name, size, tmp);
+		}
+		if (StartWith(name, "localhost"))
+		{
+			if (no_load_hosts == false && OS_IS_UNIX(GetOsInfo()->OsType))
+			{
+				if (GetMachineNameFromHosts(tmp2, sizeof(tmp2)))
+				{
+					StrCpy(name, sizeof(name), tmp2);
+				}
+			}
+		}
+
+		StrCpy(name_cache, sizeof(name_cache), name);
+		name_cached = true;
+	}
+	Unlock(machine_name_lock);
+}
+
+// ホスト名取得スレッド
+void GetHostNameThread(THREAD *t, void *p)
+{
+	IP *ip;
+	char hostname[256];
+	// 引数チェック
+	if (t == NULL || p == NULL)
+	{
+		return;
+	}
+
+	ip = (IP *)p;
+
+	AddWaitThread(t);
+
+	NoticeThreadInit(t);
+
+	if (GetHostNameInner(hostname, sizeof(hostname), ip))
+	{
+		AddHostCache(ip, hostname);
+	}
+
+	Free(ip);
+
+	DelWaitThread(t);
+}
+
+// ホスト名の取得
+bool GetHostName(char *hostname, UINT size, IP *ip)
+{
+	THREAD *t;
+	IP *p_ip;
+	bool ret;
+	// 引数チェック
+	if (hostname == NULL || ip == NULL)
+	{
+		return false;
+	}
+
+	if (GetHostCache(hostname, size, ip))
+	{
+		if (IsEmptyStr(hostname) == false)
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	p_ip = ZeroMalloc(sizeof(IP));
+	Copy(p_ip, ip, sizeof(IP));
+
+	t = NewThread(GetHostNameThread, p_ip);
+
+	WaitThreadInit(t);
+
+	WaitThread(t, TIMEOUT_HOSTNAME);
+
+	ReleaseThread(t);
+
+	ret = GetHostCache(hostname, size, ip);
+	if (ret == false)
+	{
+		if (IsIP4(ip))
+		{
+			ret = GetNetBiosName(hostname, size, ip);
+			if (ret)
+			{
+				AddHostCache(ip, hostname);
+			}
+		}
+	}
+	else
+	{
+		if (IsEmptyStr(hostname))
+		{
+			ret = false;
+		}
+	}
+	if (ret == false)
+	{
+		AddHostCache(ip, "");
+		StrCpy(hostname, size, "");
+	}
+
+	return ret;
+}
+
+// DNS 逆引きクエリを行う
+bool GetHostNameInner(char *hostname, UINT size, IP *ip)
+{
+	struct in_addr addr;
+	struct sockaddr_in sa;
+	char tmp[MAX_SIZE];
+	char ip_str[64];
+	// 引数チェック
+	if (hostname == NULL || ip == NULL)
+	{
+		return false;
+	}
+
+	if (IsIP6(ip))
+	{
+		return GetHostNameInner6(hostname, size, ip);
+	}
+
+	// 逆引き
+	IPToInAddr(&addr, ip);
+	Zero(&sa, sizeof(sa));
+	sa.sin_family = AF_INET;
+
+#if	defined(UNIX_BSD) || defined(UNIX_MACOS)
+	sa.sin_len = INET_ADDRSTRLEN;
+#endif	// UNIX_BSD || UNIX_MACOS
+
+	Copy(&sa.sin_addr, &addr, sizeof(struct in_addr));
+	sa.sin_port = 0;
+
+	if (getnameinfo((struct sockaddr *)&sa, sizeof(sa), tmp, sizeof(tmp), NULL, 0, 0) != 0)
+	{
+		return false;
+	}
+
+	IPToStr(ip_str, sizeof(ip_str), ip);
+
+	if (StrCmpi(tmp, ip_str) == 0)
+	{
+		return false;
+	}
+
+	if (IsEmptyStr(tmp))
+	{
+		return false;
+	}
+
+	StrCpy(hostname, size, tmp);
+
+	return true;
+}
+bool GetHostNameInner6(char *hostname, UINT size, IP *ip)
+{
+	struct in6_addr addr;
+	struct sockaddr_in6 sa;
+	char tmp[MAX_SIZE];
+	char ip_str[256];
+	// 引数チェック
+	if (hostname == NULL || ip == NULL)
+	{
+		return false;
+	}
+
+	// 逆引き
+	IPToInAddr6(&addr, ip);
+	Zero(&sa, sizeof(sa));
+	sa.sin6_family = AF_INET6;
+
+#if	defined(UNIX_BSD) || defined(UNIX_MACOS)
+	sa.sin6_len = INET6_ADDRSTRLEN;
+#endif	// UNIX_BSD || UNIX_MACOS
+
+	Copy(&sa.sin6_addr, &addr, sizeof(struct in6_addr));
+	sa.sin6_port = 0;
+
+	if (getnameinfo((struct sockaddr *)&sa, sizeof(sa), tmp, sizeof(tmp), NULL, 0, 0) != 0)
+	{
+		return false;
+	}
+
+	IPToStr(ip_str, sizeof(ip_str), ip);
+
+	if (StrCmpi(tmp, ip_str) == 0)
+	{
+		return false;
+	}
+
+	if (IsEmptyStr(tmp))
+	{
+		return false;
+	}
+
+	StrCpy(hostname, size, tmp);
+
+	return true;
+}
+
+#define	NUM_NBT_QUERYS_SEND			3
+
+// IP アドレスからそのマシンの NetBIOS 名を取得する
+bool GetNetBiosName(char *name, UINT size, IP *ip)
+{
+	SOCK *s;
+	UINT i, j;
+	bool flag = false;
+	bool ok = false;
+	NBTREQUEST req;
+	UCHAR buf[1024];
+	USHORT tran_id[NUM_NBT_QUERYS_SEND];
+	UINT64 timeout_tick;
+	// 引数チェック
+	if (name == NULL || ip == NULL)
+	{
+		return false;
+	}
+
+	IPToStr(name, size, ip);
+
+	for (i = 0;i < NUM_NBT_QUERYS_SEND;i++)
+	{
+		tran_id[i] = Rand16();
+	}
+
+	s = NewUDP(0);
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	for (j = 0;j < NUM_NBT_QUERYS_SEND;j++)
+	{
+		Zero(&req, sizeof(req));
+		req.TransactionId = Endian16(tran_id[j]);
+		req.NumQuestions = Endian16(1);
+		req.Query[0] = 0x20;
+		req.Query[1] = 0x43;
+		req.Query[2] = 0x4b;
+		for (i = 3;i <= 32;i++)
+		{
+			req.Query[i] = 0x41;
+		}
+		req.Query[35] = 0x21;
+		req.Query[37] = 0x01;
+
+		if (SendTo(s, ip, 137, &req, sizeof(req)) == 0)
+		{
+			ReleaseSock(s);
+			return false;
+		}
+	}
+
+	timeout_tick = Tick() + (UINT64)TIMEOUT_NETBIOS_HOSTNAME;
+
+	while (1)
+	{
+		UINT ret;
+		IP src_ip;
+		UINT src_port;
+		SOCKSET set;
+		if (Tick() >= timeout_tick)
+		{
+			break;
+		}
+		InitSockSet(&set);
+		AddSockSet(&set, s);
+		Select(&set, 100, NULL, NULL);
+
+		if (flag == false)
+		{
+			flag = true;
+		}
+		else
+		{
+			SleepThread(10);
+		}
+
+		ret = RecvFrom(s, &src_ip, &src_port, buf, sizeof(buf));
+
+		if (ret == SOCK_LATER)
+		{
+			continue;
+		}
+		else if (ret == 0)
+		{
+			break;
+		}
+		else
+		{
+			if (ret >= sizeof(NBTRESPONSE))
+			{
+				NBTRESPONSE *r = (NBTRESPONSE *)buf;
+				bool b = false;
+				UINT i;
+				USHORT id = Endian16(r->TransactionId);
+				for (i = 0;i < NUM_NBT_QUERYS_SEND;i++)
+				{
+					if (id == tran_id[i])
+					{
+						b = true;
+						break;
+					}
+				}
+				if (b)
+				{
+					if (r->Flags != 0 && r->NumQuestions == 0 && r->AnswerRRs >= 1)
+					{
+						if (r->Response[0] == 0x20 && r->Response[1] == 0x43 &&
+							r->Response[2] == 0x4b)
+						{
+							if (r->Response[34] == 0x00 && r->Response[35] == 0x21 &&
+								r->Response[36] == 0x00 && r->Response[37] == 0x01)
+							{
+								char *a = (char *)(&r->Response[45]);
+								if (StrCheckLen(a, 15))
+								{
+									if (IsEmptyStr(a) == false)
+									{
+										StrCpy(name, size, a);
+										Trim(name);
+										ok = true;
+									}
+									else
+									{
+										ok = false;
+										break;
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	ReleaseSock(s);
+	return ok;
+}
+
+// IP アドレスを設定する
+void SetIP(IP *ip, UCHAR a1, UCHAR a2, UCHAR a3, UCHAR a4)
+{
+	// 引数チェック
+	if (ip == NULL)
+	{
+		return;
+	}
+
+	Zero(ip, sizeof(IP));
+	ip->addr[0] = a1;
+	ip->addr[1] = a2;
+	ip->addr[2] = a3;
+	ip->addr[3] = a4;
+}
+
+// DNS 正引きを行って結果を v4 と v6 のどちらかで得る (両方の場合は IPv4 優先)
+bool GetIP46Any4(IP *ip, char *hostname)
+{
+	IP ip4, ip6;
+	bool b = false;
+	// 引数チェック
+	if (ip == NULL || hostname == NULL)
+	{
+		return false;
+	}
+
+	if (GetIP46(&ip4, &ip6, hostname) == false)
+	{
+		return false;
+	}
+
+	if (IsZeroIp(&ip6) == false)
+	{
+		Copy(ip, &ip6, sizeof(IP));
+
+		b = true;
+	}
+
+	if (IsZeroIp(&ip4) == false)
+	{
+		Copy(ip, &ip4, sizeof(IP));
+
+		b = true;
+	}
+
+	return b;
+}
+
+// DNS 正引きを行って結果を v4 と v6 のどちらかで得る (両方の場合は IPv6 優先)
+bool GetIP46Any6(IP *ip, char *hostname)
+{
+	IP ip4, ip6;
+	bool b = false;
+	// 引数チェック
+	if (ip == NULL || hostname == NULL)
+	{
+		return false;
+	}
+
+	if (GetIP46(&ip4, &ip6, hostname) == false)
+	{
+		return false;
+	}
+
+	if (IsZeroIp(&ip4) == false)
+	{
+		Copy(ip, &ip4, sizeof(IP));
+
+		b = true;
+	}
+
+	if (IsZeroIp(&ip6) == false)
+	{
+		Copy(ip, &ip6, sizeof(IP));
+
+		b = true;
+	}
+
+	return b;
+}
+
+// DNS 正引きを行って結果を v4 と v6 の両方で得る
+bool GetIP46(IP *ip4, IP *ip6, char *hostname)
+{
+	return GetIP46Ex(ip4, ip6, hostname, 0, NULL);
+}
+bool GetIP46Ex(IP *ip4, IP *ip6, char *hostname, UINT timeout, bool *cancel)
+{
+	IP a, b;
+	bool ok_a, ok_b;
+	// 引数チェック
+	if (ip4 == NULL || ip6 == NULL || hostname == NULL)
+	{
+		return false;
+	}
+
+	ZeroIP4(ip4);
+	ZeroIP6(ip6);
+
+	ok_a = ok_b = false;
+
+	if (GetIP6Ex(&a, hostname, timeout, cancel))
+	{
+		ok_a = true;
+	}
+
+	if (GetIP4Ex(&b, hostname, timeout, cancel))
+	{
+		ok_b = true;
+	}
+
+	if (ok_a)
+	{
+		if (IsIP4(&a))
+		{
+			Copy(ip4, &a, sizeof(IP));
+		}
+	}
+	if (ok_b)
+	{
+		if (IsIP4(&b))
+		{
+			Copy(ip4, &b, sizeof(IP));
+		}
+
+		if (IsIP6(&b))
+		{
+			Copy(ip6, &b, sizeof(IP));
+		}
+	}
+	if (ok_a)
+	{
+		if (IsIP6(&a))
+		{
+			Copy(ip6, &a, sizeof(IP));
+		}
+	}
+
+	if (IsZeroIp(ip4) && IsZeroIp(ip6))
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// GetIP 用スレッドのパラメータのクリーンアップ
+void CleanupGetIPThreadParam(GETIP_THREAD_PARAM *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	Free(p);
+}
+
+// GetIP 用スレッドのパラメータの解放
+void ReleaseGetIPThreadParam(GETIP_THREAD_PARAM *p)
+{
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	if (Release(p->Ref) == 0)
+	{
+		CleanupGetIPThreadParam(p);
+	}
+}
+
+// DNS 正引きクエリ (タイムアウト付き) を行うスレッド
+void GetIP4Ex6ExThread(THREAD *t, void *param)
+{
+	GETIP_THREAD_PARAM *p;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	p = (GETIP_THREAD_PARAM *)param;
+
+	AddRef(p->Ref);
+
+	NoticeThreadInit(t);
+
+	AddWaitThread(t);
+
+	// 解決の実行
+	if (p->IPv6 == false)
+	{
+		// IPv4
+		p->Ok = GetIP4Inner(&p->Ip, p->HostName);
+	}
+	else
+	{
+		// IPv6
+		p->Ok = GetIP6Inner(&p->Ip, p->HostName);
+	}
+
+	ReleaseGetIPThreadParam(p);
+
+	DelWaitThread(t);
+}
+
+// DNS 正引きクエリ (タイムアウト付き) を行う
+bool GetIP4Ex6Ex(IP *ip, char *hostname, UINT timeout, bool ipv6, bool *cancel)
+{
+	GETIP_THREAD_PARAM *p;
+	THREAD *t;
+	bool ret = false;
+	UINT64 start_tick = 0;
+	UINT64 end_tick = 0;
+	// 引数チェック
+	if (ip == NULL || hostname == NULL)
+	{
+		return false;
+	}
+	if (timeout == 0)
+	{
+		timeout = TIMEOUT_GETIP;
+	}
+
+	p = ZeroMalloc(sizeof(GETIP_THREAD_PARAM));
+	p->Ref = NewRef();
+	StrCpy(p->HostName, sizeof(p->HostName), hostname);
+	p->IPv6 = ipv6;
+	p->Timeout = timeout;
+	p->Ok = false;
+
+	t = NewThread(GetIP4Ex6ExThread, p);
+	WaitThreadInit(t);
+
+	if (cancel == NULL)
+	{
+		WaitThread(t, timeout);
+	}
+	else
+	{
+		start_tick = Tick64();
+		end_tick = start_tick + (UINT64)timeout;
+
+		while (true)
+		{
+			UINT64 now = Tick64();
+			UINT64 remain;
+			UINT remain32;
+
+			if (*cancel)
+			{
+				break;
+			}
+
+			if (now >= end_tick)
+			{
+				break;
+			}
+
+			remain = end_tick - now;
+			remain32 = MIN((UINT)remain, 100);
+
+			if (WaitThread(t, remain32))
+			{
+				break;
+			}
+		}
+	}
+
+	ReleaseThread(t);
+
+	if (p->Ok)
+	{
+		ret = true;
+		Copy(ip, &p->Ip, sizeof(IP));
+	}
+
+	ReleaseGetIPThreadParam(p);
+
+	return ret;
+}
+bool GetIP4Ex(IP *ip, char *hostname, UINT timeout, bool *cancel)
+{
+	return GetIP4Ex6Ex(ip, hostname, timeout, false, cancel);
+}
+bool GetIP6Ex(IP *ip, char *hostname, UINT timeout, bool *cancel)
+{
+	return GetIP4Ex6Ex(ip, hostname, timeout, true, cancel);
+}
+bool GetIP4(IP *ip, char *hostname)
+{
+	return GetIP4Ex(ip, hostname, 0, NULL);
+}
+bool GetIP6(IP *ip, char *hostname)
+{
+	return GetIP6Ex(ip, hostname, 0, NULL);
+}
+
+// DNS 正引きクエリを行う
+bool GetIP(IP *ip, char *hostname)
+{
+	return GetIPEx(ip, hostname, false);
+}
+bool GetIPEx(IP *ip, char *hostname, bool ipv6)
+{
+	if (ipv6 == false)
+	{
+		return GetIP4(ip, hostname);
+	}
+	else
+	{
+		return GetIP6(ip, hostname);
+	}
+}
+bool GetIP6Inner(IP *ip, char *hostname)
+{
+	struct sockaddr_in6 in;
+	struct in6_addr addr;
+	struct addrinfo hint;
+	struct addrinfo *info;
+	// 引数チェック
+	if (ip == NULL || hostname == NULL)
+	{
+		return false;
+	}
+
+	if (IsEmptyStr(hostname))
+	{
+		return false;
+	}
+
+	if (StrCmpi(hostname, "localhost") == 0)
+	{
+		GetLocalHostIP6(ip);
+		return true;
+	}
+
+	if (StrToIP6(ip, hostname) == false && StrToIP(ip, hostname) == false)
+	{
+		// 正引き
+		Zero(&hint, sizeof(hint));
+		hint.ai_family = AF_INET6;
+		hint.ai_socktype = SOCK_STREAM;
+		hint.ai_protocol = IPPROTO_TCP;
+		info = NULL;
+
+		if (getaddrinfo(hostname, NULL, &hint, &info) != 0 ||
+			info->ai_family != AF_INET6)
+		{
+			if (info)
+			{
+				freeaddrinfo(info);
+			}
+			return QueryDnsCacheEx(ip, hostname, true);
+		}
+		// 正引き成功
+		Copy(&in, info->ai_addr, sizeof(struct sockaddr_in6));
+		freeaddrinfo(info);
+
+		Copy(&addr, &in.sin6_addr, sizeof(addr));
+		InAddrToIP6(ip, &addr);
+	}
+
+	// キャッシュ保存
+	NewDnsCache(hostname, ip);
+
+	return true;
+}
+bool GetIP4Inner(IP *ip, char *hostname)
+{
+	struct sockaddr_in in;
+	struct in_addr addr;
+	struct addrinfo hint;
+	struct addrinfo *info;
+	// 引数チェック
+	if (ip == NULL || hostname == NULL)
+	{
+		return false;
+	}
+
+	if (IsEmptyStr(hostname))
+	{
+		return false;
+	}
+
+	if (StrCmpi(hostname, "localhost") == 0)
+	{
+		SetIP(ip, 127, 0, 0, 1);
+		return true;
+	}
+
+	if (StrToIP6(ip, hostname) == false && StrToIP(ip, hostname) == false)
+	{
+		// 正引き
+		Zero(&hint, sizeof(hint));
+		hint.ai_family = AF_INET;
+		hint.ai_socktype = SOCK_STREAM;
+		hint.ai_protocol = IPPROTO_TCP;
+		info = NULL;
+
+		if (getaddrinfo(hostname, NULL, &hint, &info) != 0 ||
+			info->ai_family != AF_INET)
+		{
+			if (info)
+			{
+				freeaddrinfo(info);
+			}
+			return QueryDnsCache(ip, hostname);
+		}
+		// 正引き成功
+		Copy(&in, info->ai_addr, sizeof(struct sockaddr_in));
+		freeaddrinfo(info);
+		Copy(&addr, &in.sin_addr, sizeof(addr));
+		InAddrToIP(ip, &addr);
+	}
+
+	// キャッシュ保存
+	NewDnsCache(hostname, ip);
+
+	return true;
+}
+
+// DNS キャッシュを検索する
+bool QueryDnsCache(IP *ip, char *hostname)
+{
+	return QueryDnsCacheEx(ip, hostname, false);
+}
+bool QueryDnsCacheEx(IP *ip, char *hostname, bool ipv6)
+{
+	DNSCACHE *c;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (ip == NULL || hostname == NULL)
+	{
+		return false;
+	}
+
+	GenDnsCacheKeyName(tmp, sizeof(tmp), hostname, ipv6);
+
+	c = FindDnsCache(tmp);
+	if (c == NULL)
+	{
+		return false;
+	}
+
+	Copy(ip, &c->IpAddress, sizeof(IP));
+
+	return true;
+}
+
+// IP を文字列に変換
+void IPToUniStr(wchar_t *str, UINT size, IP *ip)
+{
+	char tmp[128];
+
+	IPToStr(tmp, sizeof(tmp), ip);
+	StrToUni(str, size, tmp);
+}
+
+// IP を文字列に変換 (32bit UINT)
+void IPToUniStr32(wchar_t *str, UINT size, UINT ip)
+{
+	char tmp[128];
+
+	IPToStr32(tmp, sizeof(tmp), ip);
+	StrToUni(str, size, tmp);
+}
+
+// IP を文字列に変換 (128bit byte array)
+void IPToStr128(char *str, UINT size, UCHAR *ip_bytes)
+{
+	IP ip_st;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	SetIP6(&ip_st, ip_bytes);
+	IPToStr(str, size, &ip_st);
+}
+
+// IP を文字列に変換 (32bit UINT)
+void IPToStr32(char *str, UINT size, UINT ip)
+{
+	IP ip_st;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	UINTToIP(&ip_st, ip);
+	IPToStr(str, size, &ip_st);
+}
+
+// IPv4 または IPv6 を文字列に変換
+void IPToStr4or6(char *str, UINT size, UINT ip_4_uint, UCHAR *ip_6_bytes)
+{
+	IP ip4;
+	IP ip6;
+	IP ip;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	Zero(&ip, sizeof(ip));
+
+	UINTToIP(&ip4, ip_4_uint);
+	SetIP6(&ip6, ip_6_bytes);
+
+	if (IsIP6(&ip4) || (IsZeroIp(&ip4) && (IsZeroIp(&ip6) == false)))
+	{
+		Copy(&ip, &ip6, sizeof(IP));
+	}
+	else
+	{
+		Copy(&ip, &ip4, sizeof(IP));
+	}
+
+	IPToStr(str, size, &ip);
+}
+
+// IP を文字列に変換
+void IPToStr(char *str, UINT size, IP *ip)
+{
+	// 引数チェック
+	if (str == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	if (IsIP6(ip))
+	{
+		IPToStr6(str, size, ip);
+	}
+	else
+	{
+		IPToStr4(str, size, ip);
+	}
+}
+
+// IPv4 を文字列に変換
+void IPToStr4(char *str, UINT size, IP *ip)
+{
+	// 引数チェック
+	if (str == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	// 変換
+	snprintf(str, size != 0 ? size : 64, "%u.%u.%u.%u", ip->addr[0], ip->addr[1], ip->addr[2], ip->addr[3]);
+}
+
+// 文字列を IP に変換
+bool StrToIP(IP *ip, char *str)
+{
+	TOKEN_LIST *token;
+	char *tmp;
+	UINT i;
+	// 引数チェック
+	if (ip == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	if (StrToIP6(ip, str))
+	{
+		return true;
+	}
+
+	Zero(ip, sizeof(IP));
+
+	tmp = CopyStr(str);
+	Trim(tmp);
+	token = ParseToken(tmp, ".");
+	Free(tmp);
+
+	if (token->NumTokens != 4)
+	{
+		FreeToken(token);
+		return false;
+	}
+	for (i = 0;i < 4;i++)
+	{
+		char *s = token->Token[i];
+		if (s[0] < '0' || s[0] > '9' ||
+			(ToInt(s) >= 256))
+		{
+			FreeToken(token);
+			return false;
+		}
+	}
+	Zero(ip, sizeof(IP));
+	for (i = 0;i < 4;i++)
+	{
+		ip->addr[i] = (UCHAR)ToInt(token->Token[i]);
+	}
+
+	FreeToken(token);
+
+	return true;
+}
+UINT StrToIP32(char *str)
+{
+	IP ip;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	if (StrToIP(&ip, str) == false)
+	{
+		return 0;
+	}
+
+	return IPToUINT(&ip);
+}
+bool UniStrToIP(IP *ip, wchar_t *str)
+{
+	char *tmp;
+	bool ret;
+
+	tmp = CopyUniToStr(str);
+	ret = StrToIP(ip, tmp);
+	Free(tmp);
+
+	return ret;
+}
+UINT UniStrToIP32(wchar_t *str)
+{
+	UINT ret;
+	char *tmp;
+
+	tmp = CopyUniToStr(str);
+	ret = StrToIP32(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// IP を in_addr に変換
+void IPToInAddr(struct in_addr *addr, IP *ip)
+{
+	UINT i;
+	// 引数チェック
+	if (addr == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	Zero(addr, sizeof(struct in_addr));
+
+	if (IsIP6(ip) == false)
+	{
+		for (i = 0;i < 4;i++)
+		{
+			((UCHAR *)addr)[i] = ip->addr[i];
+		}
+	}
+}
+
+// IP を in6_addr に変換
+void IPToInAddr6(struct in6_addr *addr, IP *ip)
+{
+	UINT i;
+	// 引数チェック
+	if (addr == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	Zero(addr, sizeof(struct in_addr));
+
+	if (IsIP6(ip))
+	{
+		for (i = 0;i < 16;i++)
+		{
+			((UCHAR *)addr)[i] = ip->ipv6_addr[i];
+		}
+	}
+}
+
+// in_addr を IP に変換
+void InAddrToIP(IP *ip, struct in_addr *addr)
+{
+	UINT i;
+	// 引数チェック
+	if (ip == NULL || addr == NULL)
+	{
+		return;
+	}
+
+	Zero(ip, sizeof(IP));
+
+	for (i = 0;i < 4;i++)
+	{
+		ip->addr[i] = ((UCHAR *)addr)[i];
+	}
+}
+
+// in6_addr を IP に変換
+void InAddrToIP6(IP *ip, struct in6_addr *addr)
+{
+	UINT i;
+	// 引数チェック
+	if (ip == NULL || addr == NULL)
+	{
+		return;
+	}
+
+	ZeroIP6(ip);
+	for (i = 0;i < 16;i++)
+	{
+		ip->ipv6_addr[i] = ((UCHAR *)addr)[i];
+	}
+}
+
+// DNS キャッシュの検索
+DNSCACHE *FindDnsCache(char *hostname)
+{
+	return FindDnsCacheEx(hostname, false);
+}
+DNSCACHE *FindDnsCacheEx(char *hostname, bool ipv6)
+{
+	DNSCACHE *c;
+	char tmp[MAX_SIZE];
+	if (hostname == NULL)
+	{
+		return NULL;
+	}
+
+	GenDnsCacheKeyName(tmp, sizeof(tmp), hostname, ipv6);
+
+	LockDnsCache();
+	{
+		DNSCACHE t;
+		t.HostName = tmp;
+		c = Search(DnsCache, &t);
+	}
+	UnlockDnsCache();
+
+	return c;
+}
+
+// DNS キャッシュ用の IPv4 / IPv6 キー名を生成
+void GenDnsCacheKeyName(char *dst, UINT size, char *src, bool ipv6)
+{
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return;
+	}
+
+	if (ipv6 == false)
+	{
+		StrCpy(dst, size, src);
+	}
+	else
+	{
+		Format(dst, size, "%s@ipv6", src);
+	}
+}
+
+// 新しい DNS キャッシュの登録
+void NewDnsCache(char *hostname, IP *ip)
+{
+	NewDnsCacheEx(hostname, ip, IsIP6(ip));
+}
+void NewDnsCacheEx(char *hostname, IP *ip, bool ipv6)
+{
+	DNSCACHE *c;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (hostname == NULL || ip == NULL)
+	{
+		return;
+	}
+
+	if (IsNetworkNameCacheEnabled() == false)
+	{
+		return;
+	}
+
+	GenDnsCacheKeyName(tmp, sizeof(tmp), hostname, ipv6);
+
+	LockDnsCache();
+	{
+		DNSCACHE t;
+
+		// まず hostname に該当するものがあるかどうか検索してみる
+		t.HostName = tmp;
+		c = Search(DnsCache, &t);
+
+		if (c == NULL)
+		{
+			// 新規登録
+			c = ZeroMalloc(sizeof(DNSCACHE));
+			c->HostName = CopyStr(tmp);
+
+			Copy(&c->IpAddress, ip, sizeof(IP));
+
+			Add(DnsCache, c);
+		}
+		else
+		{
+			// 更新
+			Copy(&c->IpAddress, ip, sizeof(IP));
+		}
+	}
+	UnlockDnsCache();
+}
+
+// DNS キャッシュの名前比較
+int CompareDnsCache(void *p1, void *p2)
+{
+	DNSCACHE *c1, *c2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	c1 = *(DNSCACHE **)p1;
+	c2 = *(DNSCACHE **)p2;
+	if (c1 == NULL || c2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(c1->HostName, c2->HostName);
+}
+
+// DNS キャッシュの初期化
+void InitDnsCache()
+{
+	// リスト作成
+	DnsCache = NewList(CompareDnsCache);
+}
+
+// DNS キャッシュの解放
+void FreeDnsCache()
+{
+	LockDnsCache();
+	{
+		DNSCACHE *c;
+		UINT i;
+		for (i = 0;i < LIST_NUM(DnsCache);i++)
+		{
+			// エントリのメモリ解放
+			c = LIST_DATA(DnsCache, i);
+			Free(c->HostName);
+			Free(c);
+		}
+	}
+	UnlockDnsCache();
+
+	// リスト解放
+	ReleaseList(DnsCache);
+	DnsCache = NULL;
+}
+
+// DNS キャッシュのロック
+void LockDnsCache()
+{
+	LockList(DnsCache);
+}
+
+// DNS キャッシュのロック解除
+void UnlockDnsCache()
+{
+	UnlockList(DnsCache);
+}
+
+// ネットワーク通信モジュールの初期化
+void InitNetwork()
+{
+	num_tcp_connections = NewCounter();
+
+	// クライアントリストの初期化
+	InitIpClientList();
+
+	// スレッド関係の初期化
+	InitWaitThread();
+
+	// ホスト名キャッシュの初期化
+	InitHostCache();
+
+#ifdef	OS_WIN32
+	// ソケットライブラリの初期化
+	Win32InitSocketLibrary();
+#else
+	UnixInitSocketLibrary();
+#endif	// OS_WIN32
+
+	// DNS キャッシュの初期化
+	InitDnsCache();
+
+	// OpenSSL の初期化
+	ssl_ctx = SSL_CTX_new(SSLv23_method());
+
+	// ロック初期化
+	machine_name_lock = NewLock();
+	disconnect_function_lock = NewLock();
+	aho = NewLock();
+	socket_library_lock = NewLock();
+	ssl_connect_lock = NewLock();
+//	ssl_accept_lock = NewLock();
+	dns_lock = NewLock();
+	unix_dns_server_addr_lock = NewLock();
+	Zero(&unix_dns_server, sizeof(unix_dns_server));
+
+	cipher_list_token = ParseToken(cipher_list, " ");
+
+	disable_cache = false;
+}
+
+// ネットワーク名キャッシュの有効化
+void EnableNetworkNameCache()
+{
+	disable_cache = false;
+}
+
+// ネットワーク名キャッシュの無効化
+void DisableNetworkNameCache()
+{
+	disable_cache = true;
+}
+
+// ネットワーク名キャッシュが有効かどうか取得
+bool IsNetworkNameCacheEnabled()
+{
+	return !disable_cache;
+}
+
+// 暗号化アルゴリズムリストを取得
+TOKEN_LIST *GetCipherList()
+{
+	return cipher_list_token;
+}
+
+// TCP コネクション数カウンタを取得
+COUNTER *GetNumTcpConnectionsCounter()
+{
+	return num_tcp_connections;
+}
+
+// ネットワーク通信モジュールの解放
+void FreeNetwork()
+{
+	FreeToken(cipher_list_token);
+	cipher_list_token = NULL;
+
+	Zero(&unix_dns_server, sizeof(unix_dns_server));
+
+	// ロック解放
+	DeleteLock(unix_dns_server_addr_lock);
+	DeleteLock(dns_lock);
+	DeleteLock(ssl_accept_lock);
+	DeleteLock(machine_name_lock);
+	DeleteLock(disconnect_function_lock);
+	DeleteLock(aho);
+	DeleteLock(socket_library_lock);
+	DeleteLock(ssl_connect_lock);
+	machine_name_lock = NULL;
+	ssl_accept_lock = machine_name_lock = disconnect_function_lock =
+		aho = socket_library_lock = ssl_connect_lock = NULL;
+
+	// OpenSSL の解放
+	SSL_CTX_free(ssl_ctx);
+	ssl_ctx = NULL;
+
+	// スレッド関係の解放
+	FreeWaitThread();
+
+	// DNS キャッシュの解放
+	FreeDnsCache();
+
+	// ホスト名キャッシュの解放
+	FreeHostCache();
+
+#ifdef	OS_WIN32
+	// ソケットライブラリの解放
+	Win32FreeSocketLibrary();
+#else
+	UnixFreeSocketLibrary();
+#endif	// OS_WIN32
+
+	DeleteCounter(num_tcp_connections);
+	num_tcp_connections = NULL;
+
+	// クライアントリストの解放
+	FreeIpClientList();
+}
+
+// ソケットリストにソケットを追加する
+void AddSockList(SOCKLIST *sl, SOCK *s)
+{
+	// 引数チェック
+	if (sl == NULL || s == NULL)
+	{
+		return;
+	}
+
+	LockList(sl->SockList);
+	{
+		if (IsInList(sl->SockList, s) == false)
+		{
+			AddRef(s->ref);
+
+			Insert(sl->SockList, s);
+		}
+	}
+	UnlockList(sl->SockList);
+}
+
+// ソケットリストからソケットを削除する
+void DelSockList(SOCKLIST *sl, SOCK *s)
+{
+	// 引数チェック
+	if (sl == NULL || s == NULL)
+	{
+		return;
+	}
+
+	LockList(sl->SockList);
+	{
+		if (Delete(sl->SockList, s))
+		{
+			ReleaseSock(s);
+		}
+	}
+	UnlockList(sl->SockList);
+}
+
+// ソケットリストのソケットをすべて停止させて削除する
+void StopSockList(SOCKLIST *sl)
+{
+	SOCK **ss;
+	UINT num, i;
+	// 引数チェック
+	if (sl == NULL)
+	{
+		return;
+	}
+
+	LockList(sl->SockList);
+	{
+		num = LIST_NUM(sl->SockList);
+		ss = ToArray(sl->SockList);
+
+		DeleteAll(sl->SockList);
+	}
+	UnlockList(sl->SockList);
+
+	for (i = 0;i < num;i++)
+	{
+		SOCK *s = ss[i];
+
+		Disconnect(s);
+		ReleaseSock(s);
+	}
+
+	Free(ss);
+}
+
+// ソケットリストの削除
+void FreeSockList(SOCKLIST *sl)
+{
+	// 引数チェック
+	if (sl == NULL)
+	{
+		return;
+	}
+
+	StopSockList(sl);
+
+	ReleaseList(sl->SockList);
+
+	Free(sl);
+}
+
+// ソケットリストの作成
+SOCKLIST *NewSockList()
+{
+	SOCKLIST *sl = ZeroMallocFast(sizeof(SOCKLIST));
+
+	sl->SockList = NewList(NULL);
+
+	return sl;
+}
+
+// Solarisでのソケットのタイムアウト用スレッド
+void SocketTimeoutThread(THREAD *t, void *param)
+{
+	SOCKET_TIMEOUT_PARAM *ttparam;
+	ttparam = (SOCKET_TIMEOUT_PARAM *)param;
+
+	// タイムアウト時間だけ待つ
+	Select(NULL, ttparam->sock->TimeOut, ttparam->cancel, NULL);
+
+	// ブロック中ならディスコネクトする
+	if(! ttparam->unblocked)
+	{
+//		Debug("Socket timeouted\n");
+		closesocket(ttparam->sock->socket);
+	}
+	else
+	{
+//		Debug("Socket timeout cancelled\n");
+	}
+}
+
+// タイムアウト用スレッドの初期化と開始
+SOCKET_TIMEOUT_PARAM *NewSocketTimeout(SOCK *sock)
+{
+	SOCKET_TIMEOUT_PARAM *ttp;
+	if(! sock->AsyncMode && sock->TimeOut != TIMEOUT_INFINITE)
+	{
+//		Debug("NewSockTimeout(%u)\n",sock->TimeOut);
+
+		ttp = (SOCKET_TIMEOUT_PARAM*)Malloc(sizeof(SOCKET_TIMEOUT_PARAM));
+
+		// タイムアウトスレッド用のパラメータをセット
+		ttp->cancel = NewCancel();
+		ttp->sock = sock;
+		ttp->unblocked = false;
+		ttp->thread = NewThread(SocketTimeoutThread, ttp);
+		return ttp;
+	}
+	return NULL;
+}
+
+// タイムアウト用スレッドの停止と開放
+void FreeSocketTimeout(SOCKET_TIMEOUT_PARAM *ttp)
+{
+	if(ttp == NULL)
+	{
+		return;
+	}
+
+	ttp->unblocked = true;
+	Cancel(ttp->cancel);
+	WaitThread(ttp->thread, INFINITE);
+	ReleaseCancel(ttp->cancel);
+	ReleaseThread(ttp->thread);
+	Free(ttp);
+//	Debug("FreeSocketTimeout succeed\n");
+	return;
+}
+
+// IP アドレスとサブネット マスクのパース
+bool ParseIpAndSubnetMask46(char *src, IP *ip, IP *mask)
+{
+	// 引数チェック
+	if (src == NULL || ip == NULL || mask == NULL)
+	{
+		return false;
+	}
+
+	if (ParseIpAndMask46(src, ip, mask) == false)
+	{
+		return false;
+	}
+
+	if (IsIP4(ip))
+	{
+		return IsSubnetMask4(mask);
+	}
+	else
+	{
+		return IsSubnetMask6(mask);
+	}
+}
+bool ParseIpAndSubnetMask6(char *src, IP *ip, IP *mask)
+{
+	if (ParseIpAndSubnetMask46(src, ip, mask) == false)
+	{
+		return false;
+	}
+
+	if (IsIP6(ip) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+bool ParseIpAndSubnetMask4(char *src, UINT *ip, UINT *mask)
+{
+	IP ip2, mask2;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return false;
+	}
+
+	if (ParseIpAndSubnetMask46(src, &ip2, &mask2) == false)
+	{
+		return false;
+	}
+
+	if (IsIP4(&ip2) == false)
+	{
+		return false;
+	}
+
+	if (ip != NULL)
+	{
+		*ip = IPToUINT(&ip2);
+	}
+
+	if (mask != NULL)
+	{
+		*mask = IPToUINT(&mask2);
+	}
+
+	return true;
+}
+
+
+// IP アドレスとマスクのパース
+bool ParseIpAndMask46(char *src, IP *ip, IP *mask)
+{
+	TOKEN_LIST *t;
+	char *ipstr;
+	char *subnetstr;
+	bool ret = false;
+	IP ip2;
+	IP mask2;
+	// 引数チェック
+	if (src == NULL || ip == NULL || mask == NULL)
+	{
+		return false;
+	}
+
+	Zero(&ip2, sizeof(IP));
+	Zero(&mask2, sizeof(IP));
+
+	t = ParseToken(src, "/");
+	if (t->NumTokens != 2)
+	{
+		FreeToken(t);
+		return false;
+	}
+
+	ipstr = t->Token[0];
+	subnetstr = t->Token[1];
+	Trim(ipstr);
+	Trim(subnetstr);
+
+	if (StrToIP(&ip2, ipstr))
+	{
+		if (StrToIP(&mask2, subnetstr))
+		{
+			// IP アドレス部とマスク部が同一の種類かどうか比較する
+			if (IsIP6(&ip2) && IsIP6(&mask2))
+			{
+				// 両方とも IPv6
+				ret = true;
+				Copy(ip, &ip2, sizeof(IP));
+				Copy(mask, &mask2, sizeof(IP));
+			}
+			else if (IsIP4(&ip2) && IsIP4(&mask2))
+			{
+				// 両方とも IPv4
+				ret = true;
+				Copy(ip, &ip2, sizeof(IP));
+				Copy(mask, &mask2, sizeof(IP));
+			}
+		}
+		else
+		{
+			if (IsNum(subnetstr))
+			{
+				UINT i = ToInt(subnetstr);
+				// マスク部が数値
+				if (IsIP6(&ip2) && i <= 128)
+				{
+					ret = true;
+					Copy(ip, &ip2, sizeof(IP));
+					IntToSubnetMask6(mask, i);
+				}
+				else if (i <= 32)
+				{
+					ret = true;
+					Copy(ip, &ip2, sizeof(IP));
+					IntToSubnetMask4(mask, i);
+				}
+			}
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+bool ParseIpAndMask4(char *src, UINT *ip, UINT *mask)
+{
+	IP ip_ip, ip_mask;
+	if (ParseIpAndMask46(src, &ip_ip, &ip_mask) == false)
+	{
+		return false;
+	}
+
+	if (IsIP4(&ip_ip) == false)
+	{
+		return false;
+	}
+
+	if (ip != NULL)
+	{
+		*ip = IPToUINT(&ip_ip);
+	}
+
+	if (mask != NULL)
+	{
+		*mask = IPToUINT(&ip_mask);
+	}
+
+	return true;
+}
+bool ParseIpAndMask6(char *src, IP *ip, IP *mask)
+{
+	if (ParseIpAndMask46(src, ip, mask) == false)
+	{
+		return false;
+	}
+
+	if (IsIP6(ip) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+
+// IPv4 アドレスの指定が正しいかどうかチェックする
+bool IsIpStr4(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	if (StrToIP32(str) == 0 && StrCmpi(str, "0.0.0.0") != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// IPv6 アドレスの指定が正しいかどうかチェックする
+bool IsIpStr6(char *str)
+{
+	IP ip;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	if (StrToIP6(&ip, str) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// IP アドレスの指定が正しいかどうかチェックする
+bool IsIpStr46(char *str)
+{
+	if (IsIpStr4(str) || IsIpStr6(str))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+
+// 文字列を IPv4 マスクに変換
+bool StrToMask4(IP *mask, char *str)
+{
+	// 引数チェック
+	if (mask == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	if (str[0] == '/')
+	{
+		str++;
+	}
+
+	if (IsNum(str))
+	{
+		UINT n = ToInt(str);
+
+		if (n <= 32)
+		{
+			IntToSubnetMask4(mask, n);
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if (StrToIP(mask, str) == false)
+		{
+			return false;
+		}
+		else
+		{
+			return IsIP4(mask);
+		}
+	}
+}
+
+// 文字列を IPv6 マスクに変換
+bool StrToMask6(IP *mask, char *str)
+{
+	// 引数チェック
+	if (mask == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	if (str[0] == '/')
+	{
+		str++;
+	}
+
+	if (IsNum(str))
+	{
+		UINT n = ToInt(str);
+
+		if (n <= 128)
+		{
+			IntToSubnetMask6(mask, n);
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+	else
+	{
+		if (StrToIP(mask, str) == false)
+		{
+			return false;
+		}
+		else
+		{
+			return IsIP6(mask);
+		}
+	}
+}
+bool StrToMask6Addr(IPV6_ADDR *mask, char *str)
+{
+	IP ip;
+
+	if (StrToMask6(&ip, str) == false)
+	{
+		return false;
+	}
+
+	if (IPToIPv6Addr(mask, &ip) == false)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 文字列を IPv4 / IPv6 マスクに変換
+bool StrToMask46(IP *mask, char *str, bool ipv6)
+{
+	if (ipv6)
+	{
+		return StrToMask6(mask, str);
+	}
+	else
+	{
+		return StrToMask4(mask, str);
+	}
+}
+
+
+// IPv4 / IPv6 マスクを文字列に変換
+void MaskToStr(char *str, UINT size, IP *mask)
+{
+	MaskToStrEx(str, size, mask, false);
+}
+void MaskToStrEx(char *str, UINT size, IP *mask, bool always_full_address)
+{
+	// 引数チェック
+	if (str == NULL || mask == NULL)
+	{
+		return;
+	}
+
+	if (always_full_address == false && IsSubnetMask(mask))
+	{
+		ToStr(str, SubnetMaskToInt(mask));
+	}
+	else
+	{
+		IPToStr(str, size, mask);
+	}
+}
+void MaskToStr32(char *str, UINT size, UINT mask)
+{
+	MaskToStr32Ex(str, size, mask, false);
+}
+void MaskToStr32Ex(char *str, UINT size, UINT mask, bool always_full_address)
+{
+	IP ip;
+
+	UINTToIP(&ip, mask);
+
+	MaskToStrEx(str, size, &ip, always_full_address);
+}
+void Mask6AddrToStrEx(char *str, UINT size, IPV6_ADDR *mask, bool always_full_address)
+{
+	IP ip;
+
+	// 引数チェック
+	if (str == NULL || mask == NULL)
+	{
+		StrCpy(str, size, "");
+		return;
+	}
+
+	IPv6AddrToIP(&ip, mask);
+
+	MaskToStrEx(str, size, &ip, always_full_address);
+}
+void Mask6AddrToStr(char *str, UINT size, IPV6_ADDR *mask)
+{
+	Mask6AddrToStrEx(str, size, mask, false);
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Network.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Network.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Network.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,703 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Network.h
+// Network.c のヘッダ
+
+#ifndef	NETWORK_H
+#define	NETWORK_H
+
+#define	TIMEOUT_GETIP				2300
+
+#define	TIMEOUT_INFINITE			(0x7fffffff)
+#define	TIMEOUT_TCP_PORT_CHECK		(10 * 1000)
+#define	TIMEOUT_SSL_CONNECT			(15 * 1000)
+
+#define	TIMEOUT_HOSTNAME			(500)
+#define	TIMEOUT_NETBIOS_HOSTNAME	(100)
+#define	EXPIRES_HOSTNAME			(10 * 60 * 1000)
+
+#define	SOCKET_BUFFER_SIZE			0x10000000
+
+#define	IPV6_DUMMY_FOR_IPV4			0xFEFFFFDF
+
+
+// IP アドレス
+struct IP
+{
+	UCHAR addr[4];					// IPv4 アドレス, ※ 223.255.255.254 = IPv6 を意味する
+	UCHAR ipv6_addr[16];			// IPv6 アドレス
+	UINT ipv6_scope_id;				// IPv6 スコープ ID
+};
+
+// IP 構造体をアドレス部分のみで比較する際のサイズ
+#define	SIZE_OF_IP_FOR_ADDR			(sizeof(UCHAR) * 20)
+
+// IP アドレス部を比較
+#define	CmpIpAddr(ip1, ip2)			(Cmp((ip1), (ip2), SIZE_OF_IP_FOR_ADDR))
+
+// IPv6 アドレス (異形式)
+struct IPV6_ADDR
+{
+	UCHAR Value[16];				// 値
+} GCC_PACKED;
+
+// IPv6アドレスの種類
+#define IPV6_ADDR_UNICAST						1	// ユニキャスト
+#define IPV6_ADDR_LOCAL_UNICAST					2	// ローカルユニキャスト
+#define IPV6_ADDR_GLOBAL_UNICAST				4	// グローバルユニキャスト
+#define IPV6_ADDR_MULTICAST						8	// マルチキャスト
+#define IPV6_ADDR_ALL_NODE_MULTICAST			16	// 全ノードマルチキャスト
+#define IPV6_ADDR_ALL_ROUTER_MULTICAST			32	// 全ルータマルチキャスト
+#define IPV6_ADDR_SOLICIATION_MULTICAST			64	// 要請ノードマルチキャスト
+#define	IPV6_ADDR_ZERO							128	// オールゼロ
+#define	IPV6_ADDR_LOOPBACK						256	// ループバック
+
+
+// DNS キャッシュリスト
+struct DNSCACHE
+{
+	char *HostName;
+	IP IpAddress;
+};
+
+// クライアントリスト
+struct IP_CLIENT
+{
+	IP IpAddress;					// IP アドレス
+	UINT NumConnections;			// 接続個数
+};
+
+// ソケットイベント
+struct SOCK_EVENT
+{
+	REF *ref;						// 参照カウンタ
+#ifdef	OS_WIN32
+	void *hEvent;					// Win32 イベントハンドルへのポインタ
+#else	// OS_WIN32
+	LIST *SockList;					// ソケットリスト
+	int pipe_read, pipe_write;		// パイプ
+#endif	// OS_WIN32
+};
+
+// ソケットの種類
+#define	SOCK_TCP				1
+#define	SOCK_UDP				2
+
+// ソケット
+struct SOCK
+{
+	REF *ref;					// 参照カウンタ
+	LOCK *lock;					// ロック
+	LOCK *ssl_lock;				// SSL 関係のロック
+	LOCK *disconnect_lock;		// 切断用ロック
+	SOCKET socket;				// ソケット番号
+	SSL *ssl;					// SSL オブジェクト
+	UINT Type;					// ソケットの種類
+	bool Connected;				// 接続中フラグ
+	bool ServerMode;			// サーバーモード
+	bool AsyncMode;				// 非同期モード
+	bool SecureMode;			// SSL 通信モード
+	bool ListenMode;			// Listen 中
+	BUF *SendBuf;				// 送信バッファ
+	IP RemoteIP;				// リモートホストの IP アドレス
+	IP LocalIP;					// ローカルホストの IP アドレス
+	char *RemoteHostname;		// リモートホスト名
+	UINT RemotePort;			// リモート側のポート番号
+	UINT LocalPort;				// ローカル側のポート番号
+	UINT64 SendSize;			// 送信したデータサイズの合計
+	UINT64 RecvSize;			// 受信したデータサイズの合計
+	UINT64 SendNum;				// 送信したデータブロック数
+	UINT64 RecvNum;				// 受信したデータブロック数
+	X *RemoteX;					// リモートホストの証明書
+	X *LocalX;					// ローカルホストの証明書
+	char *CipherName;			// 暗号化アルゴリズム名
+	char *WaitToUseCipher;		// 使用したいアルゴリズム名を設定する
+	bool IgnoreRecvErr;			// RecvFrom エラーを無視できるかどうか
+	bool IgnoreSendErr;			// SendTo エラーを無視できるかどうか
+	UINT TimeOut;				// タイムアウト値
+	SOCK_EVENT *SockEvent;		// 関連付けられているソケットイベント
+	bool CancelAccept;			// Accept のキャンセルフラグ
+	bool WriteBlocked;			// 前回の書き込みがブロックされた
+	bool Disconnecting;			// 切断しようとしている
+	bool UdpBroadcast;			// UDP ブロードキャストモード
+	void *Param;				// 任意のパラメータ
+	bool IPv6;					// IPv6
+
+#ifdef	OS_UNIX
+	pthread_t CallingThread;	// システムコールを呼び出しているスレッド
+#endif	// OS_UNIX
+
+#ifdef	OS_WIN32
+	void *hEvent;				// 非同期モードの場合のイベント
+#endif	// OS_WIN32
+};
+
+// 戻り値の定数
+#define	SOCK_LATER	(0xffffffff)	// ブロッキング中
+
+// ソケットセット
+#define	MAX_SOCKSET_NUM		60		// ソケットセットに格納できるソケット数
+struct SOCKSET
+{
+	UINT NumSocket;					// ソケット数
+	SOCK *Sock[MAX_SOCKSET_NUM];	// ソケットへのポインタの配列
+};
+
+// キャンセルオブジェクト
+struct CANCEL
+{
+	REF *ref;						// 参照カウンタ
+	bool SpecialFlag;				// 特殊フラグ (Win32 ドライバが生成したイベントを関連付ける)
+#ifdef	OS_WIN32
+	void *hEvent;					// Win32 イベントハンドルへのポインタ
+#else	// OS_WIN32
+	int pipe_read, pipe_write;		// パイプ
+#endif	// OS_WIN32
+};
+
+// ルーティングテーブルエントリ
+struct ROUTE_ENTRY
+{
+	IP DestIP;
+	IP DestMask;
+	IP GatewayIP;
+	bool LocalRouting;
+	bool PPPConnection;
+	UINT Metric;
+	UINT OldIfMetric;
+	UINT InterfaceID;
+};
+
+// ルーティングテーブル
+struct ROUTE_TABLE
+{
+	UINT NumEntry;
+	UINT HashedValue;
+	ROUTE_ENTRY **Entry;
+};
+
+// ホスト名キャッシュリスト
+typedef struct HOSTCACHE
+{
+	UINT64 Expires;							// 有効期限
+	IP IpAddress;							// IP アドレス
+	char HostName[256];						// ホスト名
+} HOSTCACHE;
+
+// NETBIOS 名前要求
+typedef struct NBTREQUEST
+{
+	USHORT TransactionId;
+	USHORT Flags;
+	USHORT NumQuestions;
+	USHORT AnswerRRs;
+	USHORT AuthorityRRs;
+	USHORT AdditionalRRs;
+	UCHAR Query[38];
+} NBTREQUEST;
+
+// NETBIOS 名前応答
+typedef struct NBTRESPONSE
+{
+	USHORT TransactionId;
+	USHORT Flags;
+	USHORT NumQuestions;
+	USHORT AnswerRRs;
+	USHORT AuthorityRRs;
+	USHORT AdditionalRRs;
+	UCHAR Response[61];
+} NBTRESPONSE;
+
+// ソケットリスト
+typedef struct SOCKLIST
+{
+	LIST *SockList;
+} SOCKLIST;
+
+
+// Solaris 用タイムアウトスレッドのパラメータ
+typedef struct SOCKET_TIMEOUT_PARAM{
+	SOCK *sock;
+	CANCEL *cancel;
+	THREAD *thread;
+	bool unblocked;
+} SOCKET_TIMEOUT_PARAM;
+
+// GetIP 用スレッドのパラメータ
+struct GETIP_THREAD_PARAM
+{
+	REF *Ref;
+	char HostName[MAX_PATH];
+	bool IPv6;
+	UINT Timeout;
+	IP Ip;
+	bool Ok;
+};
+
+// IP アドレスリリース用スレッドのパラメータ
+struct WIN32_RELEASEADDRESS_THREAD_PARAM
+{
+	REF *Ref;
+	char Guid[MAX_SIZE];
+	UINT Timeout;
+	bool Ok;
+	bool Renew;
+};
+
+// TCP テーブルエントリ
+typedef struct TCPTABLE
+{
+	UINT Status;
+	IP LocalIP;
+	UINT LocalPort;
+	IP RemoteIP;
+	UINT RemotePort;
+	UINT ProcessId;
+} TCPTABLE;
+
+// TCP の状態
+#define	TCP_STATE_CLOSED				1
+#define	TCP_STATE_LISTEN				2
+#define	TCP_STATE_SYN_SENT				3
+#define	TCP_STATE_SYN_RCVD				4
+#define	TCP_STATE_ESTAB					5
+#define	TCP_STATE_FIN_WAIT1				6
+#define	TCP_STATE_FIN_WAIT2				7
+#define	TCP_STATE_CLOSE_WAIT			8
+#define	TCP_STATE_CLOSING				9
+#define	TCP_STATE_LAST_ACK				10
+#define	TCP_STATE_TIME_WAIT				11
+#define	TCP_STATE_DELETE_TCB			12
+
+// ルーティングテーブル変化通知
+struct ROUTE_CHANGE
+{
+	ROUTE_CHANGE_DATA *Data;
+};
+
+
+#ifdef	OS_WIN32
+
+// Win32 用関数プロトタイプ
+void Win32InitSocketLibrary();
+void Win32FreeSocketLibrary();
+void Win32Select(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2);
+void Win32InitAsyncSocket(SOCK *sock);
+void Win32JoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event);
+void Win32FreeAsyncSocket(SOCK *sock);
+void Win32IpForwardRowToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row);
+void Win32RouteEntryToIpForwardRow(void *ip_forward_row, ROUTE_ENTRY *entry);
+int Win32CompareRouteEntryByMetric(void *p1, void *p2);
+ROUTE_TABLE *Win32GetRouteTable();
+bool Win32AddRouteEntry(ROUTE_ENTRY *e, bool *already_exists);
+void Win32DeleteRouteEntry(ROUTE_ENTRY *e);
+void Win32UINTToIP(IP *ip, UINT i);
+UINT Win32IPToUINT(IP *ip);
+UINT Win32GetVLanInterfaceID(char *instance_name);
+char **Win32EnumVLan(char *tag_name);
+void Win32Cancel(CANCEL *c);
+void Win32CleanupCancel(CANCEL *c);
+CANCEL *Win32NewCancel();
+SOCK_EVENT *Win32NewSockEvent();
+void Win32SetSockEvent(SOCK_EVENT *event);
+void Win32CleanupSockEvent(SOCK_EVENT *event);
+bool Win32WaitSockEvent(SOCK_EVENT *event, UINT timeout);
+bool Win32GetDefaultDns(IP *ip, char *domain, UINT size);
+void Win32RenewDhcp();
+void Win32RenewDhcp9x(UINT if_id);
+void Win32ReleaseDhcp9x(UINT if_id, bool wait);
+int CompareIpAdapterIndexMap(void *p1, void *p2);
+LIST *Win32GetTcpTableList();
+LIST *Win32GetTcpTableListByGetExtendedTcpTable();
+LIST *Win32GetTcpTableListByAllocateAndGetTcpExTableFromStack();
+LIST *Win32GetTcpTableListByGetTcpTable();
+ROUTE_CHANGE *Win32NewRouteChange();
+void Win32FreeRouteChange(ROUTE_CHANGE *r);
+bool Win32IsRouteChanged(ROUTE_CHANGE *r);
+bool Win32GetAdapterFromGuid(void *a, char *guid);
+
+bool Win32ReleaseAddress(void *a);
+bool Win32ReleaseAddressByGuid(char *guid);
+bool Win32ReleaseAddressByGuidEx(char *guid, UINT timeout);
+void Win32ReleaseAddressByGuidExThread(THREAD *t, void *param);
+void ReleaseWin32ReleaseAddressByGuidThreadParam(WIN32_RELEASEADDRESS_THREAD_PARAM *p);
+bool Win32ReleaseOrRenewAddressByGuidEx(char *guid, UINT timeout, bool renew);
+bool Win32RenewAddress(void *a);
+bool Win32RenewAddressByGuid(char *guid);
+bool Win32RenewAddressByGuidEx(char *guid, UINT timeout);
+
+
+#else	// OS_WIN32
+
+// UNIX 用関数プロトタイプ
+void UnixInitSocketLibrary();
+void UnixFreeSocketLibrary();
+void UnixSelect(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2);
+void UnixInitAsyncSocket(SOCK *sock);
+void UnixJoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event);
+void UnixFreeAsyncSocket(SOCK *sock);
+void UnixIpForwardRowToRouteEntry(ROUTE_ENTRY *entry, void *ip_forward_row);
+void UnixRouteEntryToIpForwardRow(void *ip_forward_row, ROUTE_ENTRY *entry);
+int UnixCompareRouteEntryByMetric(void *p1, void *p2);
+ROUTE_TABLE *UnixGetRouteTable();
+bool UnixAddRouteEntry(ROUTE_ENTRY *e, bool *already_exists);
+void UnixDeleteRouteEntry(ROUTE_ENTRY *e);
+UINT UnixGetVLanInterfaceID(char *instance_name);
+char **UnixEnumVLan(char *tag_name);
+void UnixCancel(CANCEL *c);
+void UnixCleanupCancel(CANCEL *c);
+CANCEL *UnixNewCancel();
+SOCK_EVENT *UnixNewSockEvent();
+void UnixSetSockEvent(SOCK_EVENT *event);
+void UnixCleanupSockEvent(SOCK_EVENT *event);
+bool UnixWaitSockEvent(SOCK_EVENT *event, UINT timeout);
+bool UnixGetDefaultDns(IP *ip);
+void UnixRenewDhcp();
+void UnixNewPipe(int *pipe_read, int *pipe_write);
+void UnixWritePipe(int pipe_write);
+void UnixDeletePipe(int p1, int p2);
+void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, UINT timeout);
+void UnixSetSocketNonBlockingMode(int fd, bool nonblock);
+
+#endif	// OS_WIN32
+
+// 関数プロトタイプ
+void InitNetwork();
+void FreeNetwork();
+void InitDnsCache();
+void FreeDnsCache();
+void LockDnsCache();
+void UnlockDnsCache();
+int CompareDnsCache(void *p1, void *p2);
+void GenDnsCacheKeyName(char *dst, UINT size, char *src, bool ipv6);
+void NewDnsCacheEx(char *hostname, IP *ip, bool ipv6);
+DNSCACHE *FindDnsCacheEx(char *hostname, bool ipv6);
+bool QueryDnsCacheEx(IP *ip, char *hostname, bool ipv6);
+void NewDnsCache(char *hostname, IP *ip);
+DNSCACHE *FindDnsCache(char *hostname);
+bool QueryDnsCache(IP *ip, char *hostname);
+void InAddrToIP(IP *ip, struct in_addr *addr);
+void InAddrToIP6(IP *ip, struct in6_addr *addr);
+void IPToInAddr(struct in_addr *addr, IP *ip);
+void IPToInAddr6(struct in6_addr *addr, IP *ip);
+bool StrToIP(IP *ip, char *str);
+UINT StrToIP32(char *str);
+bool UniStrToIP(IP *ip, wchar_t *str);
+UINT UniStrToIP32(wchar_t *str);
+void IPToStr(char *str, UINT size, IP *ip);
+void IPToStr4(char *str, UINT size, IP *ip);
+void IPToStr32(char *str, UINT size, UINT ip);
+void IPToStr128(char *str, UINT size, UCHAR *ip_bytes);
+void IPToStr4or6(char *str, UINT size, UINT ip_4_uint, UCHAR *ip_6_bytes);
+void IPToUniStr(wchar_t *str, UINT size, IP *ip);
+void IPToUniStr32(wchar_t *str, UINT size, UINT ip);
+bool GetIPEx(IP *ip, char *hostname, bool ipv6);
+bool GetIP46(IP *ip4, IP *ip6, char *hostname);
+bool GetIP46Ex(IP *ip4, IP *ip6, char *hostname, UINT timeout, bool *cancel);
+bool GetIP46Any4(IP *ip, char *hostname);
+bool GetIP46Any6(IP *ip, char *hostname);
+bool GetIP(IP *ip, char *hostname);
+bool GetIP4(IP *ip, char *hostname);
+bool GetIP6(IP *ip, char *hostname);
+bool GetIP4Ex(IP *ip, char *hostname, UINT timeout, bool *cancel);
+bool GetIP6Ex(IP *ip, char *hostname, UINT timeout, bool *cancel);
+bool GetIP4Ex6Ex(IP *ip, char *hostname, UINT timeout, bool ipv6, bool *cancel);
+void GetIP4Ex6ExThread(THREAD *t, void *param);
+void ReleaseGetIPThreadParam(GETIP_THREAD_PARAM *p);
+void CleanupGetIPThreadParam(GETIP_THREAD_PARAM *p);
+bool GetIP4Inner(IP *ip, char *hostname);
+bool GetIP6Inner(IP *ip, char *hostname);
+bool GetHostNameInner(char *hostname, UINT size, IP *ip);
+bool GetHostNameInner6(char *hostname, UINT size, IP *ip);
+bool GetHostName(char *hostname, UINT size, IP *ip);
+void GetHostNameThread(THREAD *t, void *p);
+void GetMachineName(char *name, UINT size);
+void GetMachineNameEx(char *name, UINT size, bool no_load_hosts);
+bool GetMachineNameFromHosts(char *name, UINT size);
+void GetMachineIp(IP *ip);
+void GetMachineHostName(char *name, UINT size);
+void UINTToIP(IP *ip, UINT value);
+UINT IPToUINT(IP *ip);
+SOCK *NewSock();
+void ReleaseSock(SOCK *s);
+void CleanupSock(SOCK *s);
+SOCK *Connect(char *hostname, UINT port);
+SOCK *ConnectEx(char *hostname, UINT port, UINT timeout);
+SOCK *ConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag);
+void SetSocketSendRecvBufferSize(int s, UINT size);
+void QuerySocketInformation(SOCK *sock);
+void Disconnect(SOCK *sock);
+SOCK *Listen(UINT port);
+SOCK *ListenEx(UINT port, bool local_only);
+SOCK *Listen6(UINT port);
+SOCK *ListenEx6(UINT port, bool local_only);
+SOCK *Accept(SOCK *sock);
+SOCK *Accept6(SOCK *sock);
+UINT Send(SOCK *sock, void *data, UINT size, bool secure);
+UINT Recv(SOCK *sock, void *data, UINT size, bool secure);
+UINT SecureSend(SOCK *sock, void *data, UINT size);
+UINT SecureRecv(SOCK *sock, void *data, UINT size);
+bool StartSSL(SOCK *sock, X *x, K *priv);
+bool StartSSLEx(SOCK *sock, X *x, K *priv, bool client_tls);
+bool SendAll(SOCK *sock, void *data, UINT size, bool secure);
+void SendAdd(SOCK *sock, void *data, UINT size);
+bool SendNow(SOCK *sock, int secure);
+bool RecvAll(SOCK *sock, void *data, UINT size, bool secure);
+void InitSockSet(SOCKSET *set);
+void AddSockSet(SOCKSET *set, SOCK *sock);
+CANCEL *NewCancel();
+CANCEL *NewCancelSpecial(void *hEvent);
+void ReleaseCancel(CANCEL *c);
+void CleanupCancel(CANCEL *c);
+void Cancel(CANCEL *c);
+void Select(SOCKSET *set, UINT timeout, CANCEL *c1, CANCEL *c2);
+void SetWantToUseCipher(SOCK *sock, char *name);
+SOCK *NewUDP(UINT port);
+SOCK *NewUDPEx(UINT port, bool ipv6);
+SOCK *NewUDP4(UINT port);
+SOCK *NewUDP6(UINT port);
+UINT SendTo(SOCK *sock, IP *dest_addr, UINT dest_port, void *data, UINT size);
+UINT SendTo6(SOCK *sock, IP *dest_addr, UINT dest_port, void *data, UINT size);
+UINT RecvFrom(SOCK *sock, IP *src_addr, UINT *src_port, void *data, UINT size);
+UINT RecvFrom6(SOCK *sock, IP *src_addr, UINT *src_port, void *data, UINT size);
+void SetTimeout(SOCK *sock, UINT timeout);
+UINT GetTimeout(SOCK *sock);
+void LockOpenSSL();
+void UnlockOpenSSL();
+bool CheckTCPPort(char *hostname, UINT port);
+bool CheckTCPPortEx(char *hostname, UINT port, UINT timeout);
+void CheckTCPPortThread(THREAD *thread, void *param);
+ROUTE_TABLE *GetRouteTable();
+void FreeRouteTable(ROUTE_TABLE *t);
+bool AddRouteEntryEx(ROUTE_ENTRY *e, bool *already_exists);
+bool AddRouteEntry(ROUTE_ENTRY *e);
+void DeleteRouteEntry(ROUTE_ENTRY *e);
+char **EnumVLan(char *tag_name);
+void FreeEnumVLan(char **s);
+UINT GetVLanInterfaceID(char *tag_name);
+ROUTE_ENTRY *GetBestRouteEntry(IP *ip);
+ROUTE_ENTRY *GetBestRouteEntryEx(IP *ip, UINT exclude_if_id);
+ROUTE_ENTRY *GetBestRouteEntryFromRouteTable(ROUTE_TABLE *table, IP *ip);
+ROUTE_ENTRY *GetBestRouteEntryFromRouteTableEx(ROUTE_TABLE *table, IP *ip, UINT exclude_if_id);
+void FreeRouteEntry(ROUTE_ENTRY *e);
+void JoinSockToSockEvent(SOCK *sock, SOCK_EVENT *event);
+SOCK_EVENT *NewSockEvent();
+void SetSockEvent(SOCK_EVENT *event);
+void CleanupSockEvent(SOCK_EVENT *event);
+bool WaitSockEvent(SOCK_EVENT *event, UINT timeout);
+void ReleaseSockEvent(SOCK_EVENT *event);
+void SetIP(IP *ip, UCHAR a1, UCHAR a2, UCHAR a3, UCHAR a4);
+bool GetDefaultDns(IP *ip);
+bool GetDomainName(char *name, UINT size);
+bool UnixGetDomainName(char *name, UINT size);
+void RenewDhcp();
+void AcceptInit(SOCK *s);
+bool CheckCipherListName(char *name);
+TOKEN_LIST *GetCipherList();
+COUNTER *GetNumTcpConnectionsCounter();
+void InitWaitThread();
+void FreeWaitThread();
+void AddWaitThread(THREAD *t);
+void DelWaitThread(THREAD *t);
+void InitHostCache();
+void FreeHostCache();
+int CompareHostCache(void *p1, void *p2);
+void AddHostCache(IP *ip, char *hostname);
+bool GetHostCache(char *hostname, UINT size, IP *ip);
+bool IsSubnetMask(IP *ip);
+bool IsSubnetMask4(IP *ip);
+bool IsSubnetMask32(UINT ip);
+bool IsNetworkAddress(IP *ip, IP *mask);
+bool IsNetworkAddress4(IP *ip, IP *mask);
+bool IsNetworkAddress32(UINT ip, UINT mask);
+bool IsHostIPAddress4(IP *ip);
+bool IsHostIPAddress32(UINT ip);
+bool IsZeroIp(IP *ip);
+bool IsZeroIP(IP *ip);
+bool IsZeroIP6Addr(IPV6_ADDR *addr);
+UINT IntToSubnetMask32(UINT i);
+void IntToSubnetMask4(IP *ip, UINT i);
+bool GetNetBiosName(char *name, UINT size, IP *ip);
+bool NormalizeMacAddress(char *dst, UINT size, char *src);
+SOCKLIST *NewSockList();
+void AddSockList(SOCKLIST *sl, SOCK *s);
+void DelSockList(SOCKLIST *sl, SOCK *s);
+void StopSockList(SOCKLIST *sl);
+void FreeSockList(SOCKLIST *sl);
+bool IsIPv6Supported();
+void SetSockPriorityHigh(SOCK *s);
+void InitIpClientList();
+void FreeIpClientList();
+int CompareIpClientList(void *p1, void *p2);
+void AddIpClient(IP *ip);
+void DelIpClient(IP *ip);
+IP_CLIENT *SearchIpClient(IP *ip);
+UINT GetNumIpClient(IP *ip);
+void SetLinuxArpFilter();
+LIST *GetTcpTableList();
+void FreeTcpTableList(LIST *o);
+int CompareTcpTable(void *p1, void *p2);
+void PrintTcpTableList(LIST *o);
+TCPTABLE *GetTcpTableFromEndPoint(LIST *o, IP *local_ip, UINT local_port, IP *remote_ip, UINT remote_port);
+UINT GetTcpProcessIdFromSocket(SOCK *s);
+UINT GetTcpProcessIdFromSocketReverse(SOCK *s);
+bool CanGetTcpProcessId();
+int connect_timeout(SOCKET s, struct sockaddr *addr, int size, int timeout, bool *cancel_flag);
+void EnableNetworkNameCache();
+void DisableNetworkNameCache();
+bool IsNetworkNameCacheEnabled();
+ROUTE_CHANGE *NewRouteChange();
+void FreeRouteChange(ROUTE_CHANGE *r);
+bool IsRouteChanged(ROUTE_CHANGE *r);
+void RouteToStr(char *str, UINT str_size, ROUTE_ENTRY *e);
+void DebugPrintRoute(ROUTE_ENTRY *e);
+void DebugPrintRouteTable(ROUTE_TABLE *r);
+
+void SocketTimeoutThread(THREAD *t, void *param);
+SOCKET_TIMEOUT_PARAM *NewSocketTimeout(SOCK *sock);
+void FreeSocketTimeout(SOCKET_TIMEOUT_PARAM *ttp);
+
+bool CheckSubnetLength6(UINT i);
+bool IsIP6(IP *ip);
+bool IsIP4(IP *ip);
+void IPv6AddrToIP(IP *ip, IPV6_ADDR *addr);
+bool IPToIPv6Addr(IPV6_ADDR *addr, IP *ip);
+void SetIP6(IP *ip, UCHAR *value);
+void GetLocalHostIP6(IP *ip);
+void ZeroIP6(IP *ip);
+void ZeroIP4(IP *ip);
+bool CheckIPItemStr6(char *str);
+void IPItemStrToChars6(UCHAR *chars, char *str);
+bool StrToIP6(IP *ip, char *str);
+bool StrToIP6Addr(IPV6_ADDR *ip, char *str);
+void IPToStr6(char *str, UINT size, IP *ip);
+void IP6AddrToStr(char *str, UINT size, IPV6_ADDR *addr);
+void IPToStr6Array(char *str, UINT size, UCHAR *bytes);
+void IPToStr6Inner(char *str, IP *ip);
+void IntToSubnetMask6(IP *ip, UINT i);
+void IPNot6(IP *dst, IP *a);
+void IPOr6(IP *dst, IP *a, IP *b);
+void IPAnd6(IP *dst, IP *a, IP *b);
+void GetAllRouterMulticastAddress6(IP *ip);
+void GetAllNodeMulticaseAddress6(IP *ip);
+void GetLoopbackAddress6(IP *ip);
+void GetAllFilledAddress6(IP *ip);
+UINT GetIPAddrType6(IP *ip);
+UINT GetIPv6AddrType(IPV6_ADDR *addr);
+void GenerateMulticastMacAddress6(UCHAR *mac, IP *ip);
+void GetSoliciationMulticastAddr6(IP *dst, IP *src);
+bool CheckUnicastAddress(IP *ip);
+bool IsNetworkPrefixAddress6(IP *ip, IP *subnet);
+bool IsNetworkAddress6(IP *ip, IP *subnet);
+void GetHostAddress6(IP *dst, IP *ip, IP *subnet);
+void GetPrefixAddress6(IP *dst, IP *ip, IP *subnet);
+bool IsNetworkPrefixAddress6(IP *ip, IP *subnet);
+bool IsInSameNetwork6(IP *a1, IP *a2, IP *subnet);
+void GenerateEui64Address6(UCHAR *dst, UCHAR *mac);
+void GenerateEui64LocalAddress(IP *a, UCHAR *mac);
+void GenerateEui64GlobalAddress(IP *ip, IP *prefix, IP *subnet, UCHAR *mac);
+bool IsSubnetMask6(IP *a);
+UINT SubnetMaskToInt(IP *a);
+UINT SubnetMaskToInt6(IP *a);
+UINT SubnetMaskToInt4(IP *a);
+bool IsStrIPv6Address(char *str);
+
+bool ParseIpAndSubnetMask4(char *src, UINT *ip, UINT *mask);
+bool ParseIpAndSubnetMask6(char *src, IP *ip, IP *mask);
+bool ParseIpAndSubnetMask46(char *src, IP *ip, IP *mask);
+bool ParseIpAndMask4(char *src, UINT *ip, UINT *mask);
+bool ParseIpAndMask6(char *src, IP *ip, IP *mask);
+bool ParseIpAndMask46(char *src, IP *ip, IP *mask);
+bool IsIpStr4(char *str);
+bool IsIpStr6(char *str);
+bool IsIpMask6(char *str);
+bool IsIpStr46(char *str);
+bool StrToMask4(IP *mask, char *str);
+bool StrToMask6(IP *mask, char *str);
+bool StrToMask6Addr(IPV6_ADDR *mask, char *str);
+bool StrToMask46(IP *mask, char *str, bool ipv6);
+void MaskToStr(char *str, UINT size, IP *mask);
+void Mask6AddrToStrEx(char *str, UINT size, IPV6_ADDR *mask, bool always_full_address);
+void Mask6AddrToStr(char *str, UINT size, IPV6_ADDR *mask);
+void MaskToStr32(char *str, UINT size, UINT mask);
+void MaskToStr32Ex(char *str, UINT size, UINT mask, bool always_full_address);
+void MaskToStrEx(char *str, UINT size, IP *mask, bool always_full_address);
+
+
+#endif	// NETWORK_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/OS.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/OS.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/OS.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,510 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// OS.c
+// オペレーティングシステム依存コード
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+#undef	Lock
+#undef	Unlock
+
+// ディスパッチテーブル
+static OS_DISPATCH_TABLE *os = NULL;
+
+// OS 種類を文字列に変換
+char *OsTypeToStr(UINT type)
+{
+	switch (type)
+	{
+	case 0:
+		return "Unsupported OS by SoftEther Corporation\0\n";
+	case OSTYPE_WINDOWS_95:
+		return "Windows 95\0\n";
+	case OSTYPE_WINDOWS_98:
+		return "Windows 98\0\n";
+	case OSTYPE_WINDOWS_ME:
+		return "Windows Millennium Edition\0\n";
+	case OSTYPE_WINDOWS_UNKNOWN:
+		return "Windows 9x Unknown Version\0\n";
+	case OSTYPE_WINDOWS_NT_4_WORKSTATION:
+		return "Windows NT 4.0 Workstation\0\n";
+	case OSTYPE_WINDOWS_NT_4_SERVER:
+		return "Windows NT 4.0 Server\0\n";
+	case OSTYPE_WINDOWS_NT_4_SERVER_ENTERPRISE:
+		return "Windows NT 4.0 Server, Enterprise Edition\0\n";
+	case OSTYPE_WINDOWS_NT_4_BACKOFFICE:
+		return "BackOffice Server 4.5\0\n";
+	case OSTYPE_WINDOWS_NT_4_SMS:
+		return "Small Business Server 4.5\0\n";
+	case OSTYPE_WINDOWS_2000_PROFESSIONAL:
+		return "Windows 2000 Professional\0\n";
+	case OSTYPE_WINDOWS_2000_SERVER:
+		return "Windows 2000 Server\0\n";
+	case OSTYPE_WINDOWS_2000_ADVANCED_SERVER:
+		return "Windows 2000 Advanced Server\0\n";
+	case OSTYPE_WINDOWS_2000_DATACENTER_SERVER:
+		return "Windows 2000 Datacenter Server\0\n";
+	case OSTYPE_WINDOWS_2000_BACKOFFICE:
+		return "BackOffice Server 2000\0\n";
+	case OSTYPE_WINDOWS_2000_SBS:
+		return "Small Business Server 2000\0\n";
+	case OSTYPE_WINDOWS_XP_HOME:
+		return "Windows XP Home Edition\0\n";
+	case OSTYPE_WINDOWS_XP_PROFESSIONAL:
+		return "Windows XP Professional\0\n";
+	case OSTYPE_WINDOWS_2003_WEB:
+		return "Windows Server 2003 Web Edition\0\n";
+	case OSTYPE_WINDOWS_2003_STANDARD:
+		return "Windows Server 2003 Standard Edition\0\n";
+	case OSTYPE_WINDOWS_2003_ENTERPRISE:
+		return "Windows Server 2003 Enterprise Edition\0\n";
+	case OSTYPE_WINDOWS_2003_DATACENTER:
+		return "Windows Server 2003 Datacenter Edition\0\n";
+	case OSTYPE_WINDOWS_2003_BACKOFFICE:
+		return "BackOffice Server 2003\0\n";
+	case OSTYPE_WINDOWS_2003_SBS:
+		return "Small Business Server 2003\0\n";
+	case OSTYPE_WINDOWS_LONGHORN_PROFESSIONAL:
+		return "Windows Vista\0\n";
+	case OSTYPE_WINDOWS_LONGHORN_SERVER:
+		return "Windows Server 2008\0\n";
+	case OSTYPE_WINDOWS_7:
+		return "Windows 7\0\n";
+	case OSTYPE_WINDOWS_SERVER_2008_R2:
+		return "Windows Server 2008 R2\0\n";
+	case OSTYPE_WINDOWS_8:
+		return "Windows 8 or greater\0\n";
+	case OSTYPE_WINDOWS_SERVER_8:
+		return "Windows Server 8 or greater\0\n";
+	case OSTYPE_UNIX_UNKNOWN:
+		return "UNIX System\0\n";
+	case OSTYPE_LINUX:
+		return "Linux\0\n";
+	case OSTYPE_SOLARIS:
+		return "Sun Solaris\0\n";
+	case OSTYPE_CYGWIN:
+		return "Gnu Sygwin\0\n";
+	case OSTYPE_BSD:
+		return "BSD System\0\n";
+	case OSTYPE_MACOS_X:
+		return "Mac OS X\0\n";
+	}
+
+	return "Unknown OS";
+}
+
+// 初期化
+void OSInit()
+{
+	// ディスパッチテーブルの取得
+#ifdef	OS_WIN32
+	os = Win32GetDispatchTable();
+#else	// OS_WIN32
+	os = UnixGetDispatchTable();
+#endif	// OS_WIN32
+
+	// OS 固有の初期化関数の呼び出し
+	os->Init();
+}
+
+// 解放
+void OSFree()
+{
+	os->Free();
+}
+
+// メモリ情報取得
+void OSGetMemInfo(MEMINFO *info)
+{
+	// 引数チェック
+	if (info == NULL)
+	{
+		return;
+	}
+
+	os->GetMemInfo(info);
+}
+
+// イールド
+void OSYield()
+{
+	os->Yield();
+}
+
+// シングルインスタンス開始
+void *OSNewSingleInstance(char *instance_name)
+{
+	return os->NewSingleInstance(instance_name);
+}
+
+void OSFreeSingleInstance(void *data)
+{
+	os->FreeSingleInstance(data);
+}
+
+// 優先順位を上げる
+void OSSetHighPriority()
+{
+	os->SetHighPriority();
+}
+
+// 優先順位を戻す
+void OSRestorePriority()
+{
+	os->RestorePriority();
+}
+
+// プロダクト ID の取得
+char* OSGetProductId()
+{
+	return os->GetProductId();
+}
+
+// OS がサポートされているかどうかチェックする
+bool OSIsSupportedOs()
+{
+	return os->IsSupportedOs();
+}
+
+// OS 情報の取得
+void OSGetOsInfo(OS_INFO *info)
+{
+	os->GetOsInfo(info);
+}
+
+// アラートの表示
+void OSAlert(char *msg, char *caption)
+{
+	os->Alert(msg, caption);
+}
+void OSAlertW(wchar_t *msg, wchar_t *caption)
+{
+	os->AlertW(msg, caption);
+}
+
+// プロセス起動
+bool OSRun(char *filename, char *arg, bool hide, bool wait)
+{
+	return os->Run(filename, arg, hide, wait);
+}
+bool OSRunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)
+{
+	return os->RunW(filename, arg, hide, wait);
+}
+
+// スレッド ID の取得
+UINT OSThreadId()
+{
+	return os->ThreadId();
+}
+
+// リネーム
+bool OSFileRename(char *old_name, char *new_name)
+{
+	return os->FileRename(old_name, new_name);
+}
+bool OSFileRenameW(wchar_t *old_name, wchar_t *new_name)
+{
+	return os->FileRenameW(old_name, new_name);
+}
+
+// ファイルサイズを取得する
+UINT64 OSFileSize(void *pData)
+{
+	return os->FileSize(pData);
+}
+
+// ファイルをシークする
+bool OSFileSeek(void *pData, UINT mode, int offset)
+{
+	return os->FileSeek(pData, mode, offset);
+}
+
+// ファイルを削除する
+bool OSFileDelete(char *name)
+{
+	return os->FileDelete(name);
+}
+bool OSFileDeleteW(wchar_t *name)
+{
+	return os->FileDeleteW(name);
+}
+
+// ディレクトリを作成する
+bool OSMakeDir(char *name)
+{
+	return os->MakeDir(name);
+}
+bool OSMakeDirW(wchar_t *name)
+{
+	return os->MakeDirW(name);
+}
+
+// ディレクトリを削除する
+bool OSDeleteDir(char *name)
+{
+	return os->DeleteDir(name);
+}
+bool OSDeleteDirW(wchar_t *name)
+{
+	return os->DeleteDirW(name);
+}
+
+// ファイルを開く
+void *OSFileOpen(char *name, bool write_mode, bool read_lock)
+{
+	return os->FileOpen(name, write_mode, read_lock);
+}
+void *OSFileOpenW(wchar_t *name, bool write_mode, bool read_lock)
+{
+	return os->FileOpenW(name, write_mode, read_lock);
+}
+
+// ファイルを作成する
+void *OSFileCreate(char *name)
+{
+	return os->FileCreate(name);
+}
+void *OSFileCreateW(wchar_t *name)
+{
+	return os->FileCreateW(name);
+}
+
+// ファイルに書き込む
+bool OSFileWrite(void *pData, void *buf, UINT size)
+{
+	return os->FileWrite(pData, buf, size);
+}
+
+// ファイルから読み込む
+bool OSFileRead(void *pData, void *buf, UINT size)
+{
+	return os->FileRead(pData, buf, size);
+}
+
+// ファイルを閉じる
+void OSFileClose(void *pData, bool no_flush)
+{
+	os->FileClose(pData, no_flush);
+}
+
+// ファイルのフラッシュ
+void OSFileFlush(void *pData)
+{
+	os->FileFlush(pData);
+}
+
+// コールスタックの取得
+CALLSTACK_DATA *OSGetCallStack()
+{
+	return os->GetCallStack();
+}
+
+// シンボル情報の取得
+bool OSGetCallStackSymbolInfo(CALLSTACK_DATA *s)
+{
+	return os->GetCallStackSymbolInfo(s);
+}
+
+// スレッドの終了を待機
+bool OSWaitThread(THREAD *t)
+{
+	return os->WaitThread(t);
+}
+
+// スレッドの解放
+void OSFreeThread(THREAD *t)
+{
+	os->FreeThread(t);
+}
+
+// スレッドの初期化
+bool OSInitThread(THREAD *t)
+{
+	return os->InitThread(t);
+}
+
+// メモリ確保
+void *OSMemoryAlloc(UINT size)
+{
+	return os->MemoryAlloc(size);
+}
+
+// メモリ再確保
+void *OSMemoryReAlloc(void *addr, UINT size)
+{
+	return os->MemoryReAlloc(addr, size);
+}
+
+// メモリ解放
+void OSMemoryFree(void *addr)
+{
+	os->MemoryFree(addr);
+}
+
+// システムタイマの取得
+UINT OSGetTick()
+{
+	return os->GetTick();
+}
+
+// システム時刻の取得
+void OSGetSystemTime(SYSTEMTIME *system_time)
+{
+	os->GetSystemTime(system_time);
+}
+
+// 32bit インクリメント
+void OSInc32(UINT *value)
+{
+	os->Inc32(value);
+}
+
+// 32bit デクリメント
+void OSDec32(UINT *value)
+{
+	os->Dec32(value);
+}
+
+// スレッドの休止
+void OSSleep(UINT time)
+{
+	os->Sleep(time);
+}
+
+// ロック作成
+LOCK *OSNewLock()
+{
+	return os->NewLock();
+}
+
+// ロック
+bool OSLock(LOCK *lock)
+{
+	return os->Lock(lock);
+}
+
+// ロック解除
+void OSUnlock(LOCK *lock)
+{
+	os->Unlock(lock);
+}
+
+// ロック削除
+void OSDeleteLock(LOCK *lock)
+{
+	os->DeleteLock(lock);
+}
+
+// イベント初期化
+void OSInitEvent(EVENT *event)
+{
+	os->InitEvent(event);
+}
+
+// イベントのセット
+void OSSetEvent(EVENT *event)
+{
+	os->SetEvent(event);
+}
+
+// イベントのリセット
+void OSResetEvent(EVENT *event)
+{
+	os->ResetEvent(event);
+}
+
+// イベントの待機
+bool OSWaitEvent(EVENT *event, UINT timeout)
+{
+	return os->WaitEvent(event, timeout);
+}
+
+// イベントの解放
+void OSFreeEvent(EVENT *event)
+{
+	os->FreeEvent(event);
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/OS.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/OS.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/OS.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,213 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// OS.h
+// OS.c のヘッダ
+
+#ifndef	OS_H
+#define	OS_H
+
+// 関数プロトタイプ
+char *OsTypeToStr(UINT type);
+
+void OSInit();
+void OSFree();
+void *OSMemoryAlloc(UINT size);
+void *OSMemoryReAlloc(void *addr, UINT size);
+void OSMemoryFree(void *addr);
+UINT OSGetTick();
+void OSGetSystemTime(SYSTEMTIME *system_time);
+void OSInc32(UINT *value);
+void OSDec32(UINT *value);
+void OSSleep(UINT time);
+LOCK *OSNewLock();
+bool OSLock(LOCK *lock);
+void OSUnlock(LOCK *lock);
+void OSDeleteLock(LOCK *lock);
+void OSInitEvent(EVENT *event);
+void OSSetEvent(EVENT *event);
+void OSResetEvent(EVENT *event);
+bool OSWaitEvent(EVENT *event, UINT timeout);
+void OSFreeEvent(EVENT *event);
+bool OSWaitThread(THREAD *t);
+void OSFreeThread(THREAD *t);
+bool OSInitThread(THREAD *t);
+void *OSFileOpen(char *name, bool write_mode, bool read_lock);
+void *OSFileOpenW(wchar_t *name, bool write_mode, bool read_lock);
+void *OSFileCreate(char *name);
+void *OSFileCreateW(wchar_t *name);
+bool OSFileWrite(void *pData, void *buf, UINT size);
+bool OSFileRead(void *pData, void *buf, UINT size);
+void OSFileClose(void *pData, bool no_flush);
+void OSFileFlush(void *pData);
+UINT64 OSFileSize(void *pData);
+bool OSFileSeek(void *pData, UINT mode, int offset);
+bool OSFileDelete(char *name);
+bool OSFileDeleteW(wchar_t *name);
+bool OSMakeDir(char *name);
+bool OSMakeDirW(wchar_t *name);
+bool OSDeleteDir(char *name);
+bool OSDeleteDirW(wchar_t *name);
+CALLSTACK_DATA *OSGetCallStack();
+bool OSGetCallStackSymbolInfo(CALLSTACK_DATA *s);
+bool OSFileRename(char *old_name, char *new_name);
+bool OSFileRenameW(wchar_t *old_name, wchar_t *new_name);
+UINT OSThreadId();
+bool OSRun(char *filename, char *arg, bool hide, bool wait);
+bool OSRunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait);
+bool OSIsSupportedOs();
+void OSGetOsInfo(OS_INFO *info);
+void OSAlert(char *msg, char *caption);
+void OSAlertW(wchar_t *msg, wchar_t *caption);
+char* OSGetProductId();
+void OSSetHighPriority();
+void OSRestorePriority();
+void *OSNewSingleInstance(char *instance_name);
+void OSFreeSingleInstance(void *data);
+void OSGetMemInfo(MEMINFO *info);
+void OSYield();
+
+// ディスパッチテーブル
+typedef struct OS_DISPATCH_TABLE
+{
+	void (*Init)();
+	void (*Free)();
+	void *(*MemoryAlloc)(UINT size);
+	void *(*MemoryReAlloc)(void *addr, UINT size);
+	void (*MemoryFree)(void *addr);
+	UINT (*GetTick)();
+	void (*GetSystemTime)(SYSTEMTIME *system_time);
+	void (*Inc32)(UINT *value);
+	void (*Dec32)(UINT *value);
+	void (*Sleep)(UINT time);
+	LOCK *(*NewLock)();
+	bool (*Lock)(LOCK *lock);
+	void (*Unlock)(LOCK *lock);
+	void (*DeleteLock)(LOCK *lock);
+	void (*InitEvent)(EVENT *event);
+	void (*SetEvent)(EVENT *event);
+	void (*ResetEvent)(EVENT *event);
+	bool (*WaitEvent)(EVENT *event, UINT timeout);
+	void (*FreeEvent)(EVENT *event);
+	bool (*WaitThread)(THREAD *t);
+	void (*FreeThread)(THREAD *t);
+	bool (*InitThread)(THREAD *t);
+	UINT (*ThreadId)();
+	void *(*FileOpen)(char *name, bool write_mode, bool read_lock);
+	void *(*FileOpenW)(wchar_t *name, bool write_mode, bool read_lock);
+	void *(*FileCreate)(char *name);
+	void *(*FileCreateW)(wchar_t *name);
+	bool (*FileWrite)(void *pData, void *buf, UINT size);
+	bool (*FileRead)(void *pData, void *buf, UINT size);
+	void (*FileClose)(void *pData, bool no_flush);
+	void (*FileFlush)(void *pData);
+	UINT64 (*FileSize)(void *pData);
+	bool (*FileSeek)(void *pData, UINT mode, int offset);
+	bool (*FileDelete)(char *name);
+	bool (*FileDeleteW)(wchar_t *name);
+	bool (*MakeDir)(char *name);
+	bool (*MakeDirW)(wchar_t *name);
+	bool (*DeleteDir)(char *name);
+	bool (*DeleteDirW)(wchar_t *name);
+	CALLSTACK_DATA *(*GetCallStack)();
+	bool (*GetCallStackSymbolInfo)(CALLSTACK_DATA *s);
+	bool (*FileRename)(char *old_name, char *new_name);
+	bool (*FileRenameW)(wchar_t *old_name, wchar_t *new_name);
+	bool (*Run)(char *filename, char *arg, bool hide, bool wait);
+	bool (*RunW)(wchar_t *filename, wchar_t *arg, bool hide, bool wait);
+	bool (*IsSupportedOs)();
+	void (*GetOsInfo)(OS_INFO *info);
+	void (*Alert)(char *msg, char *caption);
+	void (*AlertW)(wchar_t *msg, wchar_t *caption);
+	char *(*GetProductId)();
+	void (*SetHighPriority)();
+	void (*RestorePriority)();
+	void *(*NewSingleInstance)(char *instance_name);
+	void (*FreeSingleInstance)(void *data);
+	void (*GetMemInfo)(MEMINFO *info);
+	void (*Yield)();
+} OS_DISPATCH_TABLE;
+
+// OS 固有ヘッダのインクルード
+#ifdef	OS_WIN32
+#include <Mayaqua/Win32.h>
+#else	//OS_WIN32
+#include <Mayaqua/Unix.h>
+#endif	// OS_WIN32
+
+#endif	// OS_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Object.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Object.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Object.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,525 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Object.c
+// オブジェクト管理コード
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// 試しにロックをかけてみるスレッド
+void CheckDeadLockThread(THREAD *t, void *param)
+{
+	DEADCHECK *c = (DEADCHECK *)param;
+
+	if (t == NULL || c == NULL)
+	{
+		return;
+	}
+
+	NoticeThreadInit(t);
+
+	Lock(c->Lock);
+	Unlock(c->Lock);
+	c->Unlocked = true;
+}
+
+// デッドロックの検出
+void CheckDeadLock(LOCK *lock, UINT timeout, char *name)
+{
+	DEADCHECK c;
+	THREAD *t;
+	char msg[MAX_PATH];
+
+	if (lock == NULL)
+	{
+		return;
+	}
+	if (name == NULL)
+	{
+		name = "Unknown";
+	}
+
+	Format(msg, sizeof(msg), "error: CheckDeadLock() Failed: %s\n", name);
+
+	Zero(&c, sizeof(c));
+	c.Lock = lock;
+	c.Timeout = timeout;
+	c.Unlocked = false;
+
+	t = NewThread(CheckDeadLockThread, &c);
+	WaitThreadInit(t);
+	if (WaitThread(t, timeout) == false)
+	{
+		if (c.Unlocked == false)
+		{
+			// デッドロック発生
+			AbortExitEx(msg);
+		}
+		else
+		{
+			WaitThread(t, INFINITE);
+		}
+	}
+
+	ReleaseThread(t);
+}
+
+// ロックオブジェクトの作成
+LOCK *NewLockMain()
+{
+	LOCK *lock;
+	UINT retry = 0;
+
+	while (true)
+	{
+		if ((retry++) > OBJECT_ALLOC__MAX_RETRY)
+		{
+			AbortExitEx("error: OSNewLock() failed.\n\n");
+		}
+		lock = OSNewLock();
+		if (lock != NULL)
+		{
+			break;
+		}
+		SleepThread(OBJECT_ALLOC_FAIL_SLEEP_TIME);
+	}
+
+	return lock;
+}
+LOCK *NewLock()
+{
+	LOCK *lock = NewLockMain();
+
+	// KS
+	KS_INC(KS_NEWLOCK_COUNT);
+	KS_INC(KS_CURRENT_LOCK_COUNT);
+
+	return lock;
+}
+
+// ロックオブジェクトの削除
+void DeleteLock(LOCK *lock)
+{
+	// 引数チェック
+	if (lock == NULL)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_DELETELOCK_COUNT);
+	KS_DEC(KS_CURRENT_LOCK_COUNT);
+
+	OSDeleteLock(lock);
+}
+
+// ロック
+bool LockInner(LOCK *lock)
+{
+	// 引数チェック
+	if (lock == NULL)
+	{
+		return false;
+	}
+
+	// KS
+	KS_INC(KS_LOCK_COUNT);
+	KS_INC(KS_CURRENT_LOCKED_COUNT);
+
+	return OSLock(lock);
+}
+
+// ロック解除
+void UnlockInner(LOCK *lock)
+{
+	// 引数チェック
+	if (lock == NULL)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_UNLOCK_COUNT);
+	KS_DEC(KS_CURRENT_LOCKED_COUNT);
+
+	OSUnlock(lock);
+}
+
+// カウンタの作成
+COUNTER *NewCounter()
+{
+	COUNTER *c;
+
+	// メモリ確保
+	c = Malloc(sizeof(COUNTER));
+
+	// 初期化
+	c->Ready = true;
+	c->c = 0;
+
+	// ロック作成
+	c->lock = NewLock();
+
+	// KS
+	KS_INC(KS_NEW_COUNTER_COUNT);
+
+	return c;
+}
+
+// カウンタの削除
+void DeleteCounter(COUNTER *c)
+{
+	// 引数チェック
+	if (c == NULL)
+	{
+		return;
+	}
+
+	// KS
+	KS_INC(KS_DELETE_COUNTER_COUNT);
+	KS_SUB(KS_CURRENT_COUNT, c->c);
+
+	DeleteLock(c->lock);
+	Free(c);
+}
+
+// カウント値の取得
+UINT Count(COUNTER *c)
+{
+	UINT ret;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return 0;
+	}
+	if (c->Ready == false)
+	{
+		return 0;
+	}
+
+	Lock(c->lock);
+	{
+		if (c->Ready == false)
+		{
+			ret = 0;
+		}
+		else
+		{
+			ret = c->c;
+		}
+	}
+	Unlock(c->lock);
+
+	return ret;
+}
+
+// インクリメント
+UINT Inc(COUNTER *c)
+{
+	UINT ret;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return 0;
+	}
+	if (c->Ready == false)
+	{
+		return 0;
+	}
+
+	Lock(c->lock);
+	{
+		if (c->Ready == false)
+		{
+			ret = 0;
+		}
+		else
+		{
+			c->c++;
+			ret = c->c;
+		}
+	}
+	Unlock(c->lock);
+
+	// KS
+	KS_INC(KS_INC_COUNT);
+	KS_INC(KS_CURRENT_COUNT);
+
+	return ret;
+}
+
+// デクリメント
+UINT Dec(COUNTER *c)
+{
+	UINT ret;
+	// 引数チェック
+	if (c == NULL)
+	{
+		return 0;
+	}
+	if (c->Ready == false)
+	{
+		return 0;
+	}
+
+	Lock(c->lock);
+	{
+		if (c->Ready == false)
+		{
+			ret = 0;
+		}
+		else
+		{
+			if (c->c != 0)
+			{
+				c->c--;
+				ret = c->c;
+			}
+			else
+			{
+				ret = 0;
+			}
+		}
+	}
+	Unlock(c->lock);
+
+	// KS
+	KS_INC(KS_DEC_COUNT);
+	KS_DEC(KS_CURRENT_COUNT);
+
+	return ret;
+}
+
+
+// 参照カウンタの解放
+UINT Release(REF *ref)
+{
+	UINT c;
+	// 引数チェック
+	if (ref == NULL)
+	{
+		return 0;
+	}
+
+	// KS
+	KS_INC(KS_RELEASE_COUNT);
+	KS_DEC(KS_CURRENT_REFED_COUNT);
+
+	c = Dec(ref->c);
+	if (c == 0)
+	{
+		// KS
+		KS_DEC(KS_CURRENT_REF_COUNT);
+		KS_INC(KS_FREEREF_COUNT);
+
+		DeleteCounter(ref->c);
+		ref->c = 0;
+		Free(ref);
+	}
+	return c;
+}
+
+// 参照カウンタの増加
+UINT AddRef(REF *ref)
+{
+	UINT c;
+	// 引数チェック
+	if (ref == NULL)
+	{
+		return 0;
+	}
+
+	c = Inc(ref->c);
+
+	// KS
+	KS_INC(KS_ADDREF_COUNT);
+	KS_INC(KS_CURRENT_REFED_COUNT);
+
+	return c;
+}
+
+// 参照カウンタ作成
+REF *NewRef()
+{
+	REF *ref;
+
+	// メモリ確保
+	ref = Malloc(sizeof(REF));
+
+	// カウンタ作成
+	ref->c = NewCounter();
+
+	// 1 回だけインクリメント
+	Inc(ref->c);
+
+	// KS
+	KS_INC(KS_NEWREF_COUNT);
+	KS_INC(KS_CURRENT_REF_COUNT);
+	KS_INC(KS_ADDREF_COUNT);
+	KS_INC(KS_CURRENT_REFED_COUNT);
+
+	return ref;
+}
+
+// イベントオブジェクトの作成
+EVENT *NewEvent()
+{
+	// メモリ確保
+	EVENT *e = Malloc(sizeof(EVENT));
+
+	// 参照カウンタ
+	e->ref = NewRef();
+
+	// イベント初期化
+	OSInitEvent(e);
+
+	// KS
+	KS_INC(KS_NEWEVENT_COUNT);
+
+	return e;
+}
+
+// イベントの解放
+void ReleaseEvent(EVENT *e)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	if (Release(e->ref) == 0)
+	{
+		CleanupEvent(e);
+	}
+}
+
+// イベントの削除
+void CleanupEvent(EVENT *e)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	// イベント解放
+	OSFreeEvent(e);
+
+	// メモリ解放
+	Free(e);
+
+	// KS
+	KS_INC(KS_FREEEVENT_COUNT);
+}
+
+// イベントのセット
+void Set(EVENT *e)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	OSSetEvent(e);
+}
+
+// イベントの待機
+bool Wait(EVENT *e, UINT timeout)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return false;
+	}
+
+	// KS
+	KS_INC(KS_WAIT_COUNT);
+
+	return OSWaitEvent(e, timeout);
+}
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Object.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Object.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Object.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,181 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Object.h
+// Object.c のヘッダ
+
+#ifndef	OBJECT_H
+#define	OBJECT_H
+
+
+// 定数
+#define	OBJECT_ALLOC_FAIL_SLEEP_TIME		150
+#define	OBJECT_ALLOC__MAX_RETRY				30
+
+// ロックオブジェクト
+struct LOCK
+{
+	void *pData;
+	BOOL Ready;
+#ifdef	OS_UNIX
+	UINT thread_id;
+	UINT locked_count;
+#endif	// OS_UNIX
+#ifdef	_DEBUG
+	char *FileName;
+	UINT Line;
+	UINT ThreadId;
+#endif	// _DEBUG
+};
+
+// カウンタオブジェクト
+struct COUNTER
+{
+	LOCK *lock;
+	UINT c;
+	bool Ready;
+};
+
+// 参照カウンタ
+struct REF
+{
+	COUNTER *c;
+};
+
+// イベントオブジェクト
+struct EVENT
+{
+	REF *ref;
+	void *pData;
+};
+
+// デッドロック検出
+struct DEADCHECK
+{
+	LOCK *Lock;
+	UINT Timeout;
+	bool Unlocked;
+};
+
+
+// ロック関数
+#ifndef	_DEBUG
+
+#define	Lock(lock)		LockInner((lock))
+#define	Unlock(lock)	UnlockInner((lock))
+
+#else	// _DEBUG
+
+#define	Lock(lock)			\
+	{						\
+		LockInner(lock);	\
+		if (lock != NULL) { lock->FileName = __FILE__; lock->Line = __LINE__; lock->ThreadId = ThreadId();}	\
+	}
+
+#define	Unlock(lock)		\
+	{						\
+		if (lock != NULL) { lock->FileName = NULL; lock->Line = 0; lock->ThreadId = 0;}	\
+		UnlockInner(lock);	\
+	}
+
+#endif	// _DEBUG
+
+
+// 関数プロトタイプ
+LOCK *NewLock();
+LOCK *NewLockMain();
+void DeleteLock(LOCK *lock);
+COUNTER *NewCounter();
+void UnlockInner(LOCK *lock);
+bool LockInner(LOCK *lock);
+void DeleteCounter(COUNTER *c);
+UINT Count(COUNTER *c);
+UINT Inc(COUNTER *c);
+UINT Dec(COUNTER *c);
+UINT Release(REF *ref);
+UINT AddRef(REF *ref);
+REF *NewRef();
+EVENT *NewEvent();
+void ReleaseEvent(EVENT *e);
+void CleanupEvent(EVENT *e);
+void Set(EVENT *e);
+bool Wait(EVENT *e, UINT timeout);
+void CheckDeadLock(LOCK *lock, UINT timeout, char *name);
+void CheckDeadLockThread(THREAD *t, void *param);
+
+#endif	// OBJECT_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Pack.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Pack.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Pack.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,815 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Pack.c
+// データパッケージコード
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// BUF を PACK に変換
+PACK *BufToPack(BUF *b)
+{
+	PACK *p;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	p = NewPack();
+	if (ReadPack(b, p) == false)
+	{
+		FreePack(p);
+		return NULL;
+	}
+
+	return p;
+}
+
+// PACK を BUF に変換
+BUF *PackToBuf(PACK *p)
+{
+	BUF *b;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return NULL;
+	}
+
+	b = NewBuf();
+	WritePack(b, p);
+
+	return b;
+}
+
+// PACK を読み込む
+bool ReadPack(BUF *b, PACK *p)
+{
+	UINT i, num;
+	// 引数チェック
+	if (b == NULL || p == NULL)
+	{
+		return false;
+	}
+
+	// ELEMENT 数
+	num = ReadBufInt(b);
+	if (num > MAX_ELEMENT_NUM)
+	{
+		// 個数オーバー
+		return false;
+	}
+
+	// ELEMENT を読み込む
+	for (i = 0;i < num;i++)
+	{
+		ELEMENT *e;
+		e = ReadElement(b);
+		if (AddElement(p, e) == false)
+		{
+			// 追加エラー
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// PACK を書き出す
+void WritePack(BUF *b, PACK *p)
+{
+	UINT i;
+	// 引数チェック
+	if (b == NULL || p == NULL)
+	{
+		return;
+	}
+
+	// ELEMENT 数
+	WriteBufInt(b, LIST_NUM(p->elements));
+
+	// ELEMENT を書き出す
+	for (i = 0;i < LIST_NUM(p->elements);i++)
+	{
+		ELEMENT *e = LIST_DATA(p->elements, i);
+		WriteElement(b, e);
+	}
+}
+
+// ELEMENT を読み込む
+ELEMENT *ReadElement(BUF *b)
+{
+	UINT i;
+	char name[MAX_ELEMENT_NAME_LEN + 1];
+	UINT type, num_value;
+	VALUE **values;
+	ELEMENT *e;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	// 名前
+	if (ReadBufStr(b, name, sizeof(name)) == false)
+	{
+		return NULL;
+	}
+
+	// 項目の種類
+	type = ReadBufInt(b);
+
+	// 項目数
+	num_value = ReadBufInt(b);
+	if (num_value > MAX_VALUE_NUM)
+	{
+		// 個数オーバー
+		return NULL;
+	}
+
+	// VALUE
+	values = (VALUE **)Malloc(sizeof(VALUE *) * num_value);
+	for (i = 0;i < num_value;i++)
+	{
+		values[i] = ReadValue(b, type);
+	}
+
+	// ELEMENT を作成
+	e = NewElement(name, type, num_value, values);
+
+	Free(values);
+
+	return e;
+}
+
+// ELEMENT を書き出す
+void WriteElement(BUF *b, ELEMENT *e)
+{
+	UINT i;
+	// 引数チェック
+	if (b == NULL || e == NULL)
+	{
+		return;
+	}
+
+	// 名前
+	WriteBufStr(b, e->name);
+	// 項目の種類
+	WriteBufInt(b, e->type);
+	// 項目数
+	WriteBufInt(b, e->num_value);
+	// VALUE
+	for (i = 0;i < e->num_value;i++)
+	{
+		VALUE *v = e->values[i];
+		WriteValue(b, v, e->type);
+	}
+}
+
+// VALUE を読み込む
+VALUE *ReadValue(BUF *b, UINT type)
+{
+	UINT len;
+	BYTE *u;
+	void *data;
+	char *str;
+	wchar_t *unistr;
+	UINT unistr_size;
+	UINT size;
+	UINT u_size;
+	VALUE *v = NULL;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	// データ項目
+	switch (type)
+	{
+	case VALUE_INT:			// 整数
+		v = NewIntValue(ReadBufInt(b));
+		break;
+	case VALUE_INT64:
+		v = NewInt64Value(ReadBufInt64(b));
+		break;
+	case VALUE_DATA:		// データ
+		size = ReadBufInt(b);
+		if (size > MAX_VALUE_SIZE)
+		{
+			// サイズオーバー
+			break;
+		}
+		data = Malloc(size);
+		if (ReadBuf(b, data, size) != size)
+		{
+			// 読み込み失敗
+			Free(data);
+			break;
+		}
+		v = NewDataValue(data, size);
+		Free(data);
+		break;
+	case VALUE_STR:			// ANSI 文字列
+		len = ReadBufInt(b);
+		if ((len + 1) > MAX_VALUE_SIZE)
+		{
+			// サイズオーバー
+			break;
+		}
+		str = Malloc(len + 1);
+		// 文字列本体
+		if (ReadBuf(b, str, len) != len)
+		{
+			// 読み込み失敗
+			Free(str);
+			break;
+		}
+		str[len] = 0;
+		v = NewStrValue(str);
+		Free(str);
+		break;
+	case VALUE_UNISTR:		// Unicode 文字列
+		u_size = ReadBufInt(b);
+		if (u_size > MAX_VALUE_SIZE)
+		{
+			// サイズオーバー
+			break;
+		}
+		// UTF-8 の読み込み
+		u = ZeroMalloc(u_size + 1);
+		if (ReadBuf(b, u, u_size) != u_size)
+		{
+			// 読み込み失敗
+			Free(u);
+			break;
+		}
+		// Unicode 文字列に変換
+		unistr_size = CalcUtf8ToUni(u, u_size);
+		if (unistr_size == 0)
+		{
+			Free(u);
+			break;
+		}
+		unistr = Malloc(unistr_size);
+		Utf8ToUni(unistr, unistr_size, u, u_size);
+		Free(u);
+		v = NewUniStrValue(unistr);
+		Free(unistr);
+		break;
+	}
+
+	return v;
+}
+
+// VALUE を書き出す
+void WriteValue(BUF *b, VALUE *v, UINT type)
+{
+	UINT len;
+	BYTE *u;
+	UINT u_size;
+	// 引数チェック
+	if (b == NULL || v == NULL)
+	{
+		return;
+	}
+
+	// データ項目
+	switch (type)
+	{
+	case VALUE_INT:			// 整数
+		WriteBufInt(b, v->IntValue);
+		break;
+	case VALUE_INT64:		// 64 bit 整数
+		WriteBufInt64(b, v->Int64Value);
+		break;
+	case VALUE_DATA:		// データ
+		// サイズ
+		WriteBufInt(b, v->Size);
+		// 本体
+		WriteBuf(b, v->Data, v->Size);
+		break;
+	case VALUE_STR:			// ANSI 文字列
+		len = StrLen(v->Str);
+		// 長さ
+		WriteBufInt(b, len);
+		// 文字列本体
+		WriteBuf(b, v->Str, len);
+		break;
+	case VALUE_UNISTR:		// Unicode 文字列
+		// UTF-8 に変換する
+		u_size = CalcUniToUtf8(v->UniStr) + 1;
+		u = ZeroMalloc(u_size);
+		UniToUtf8(u, u_size, v->UniStr);
+		// サイズ
+		WriteBufInt(b, u_size);
+		// UTF-8 文字列本体
+		WriteBuf(b, u, u_size);
+		Free(u);
+		break;
+	}
+}
+
+// データサイズの取得
+UINT GetDataValueSize(ELEMENT *e, UINT index)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return 0;
+	}
+	if (e->values == NULL)
+	{
+		return 0;
+	}
+	if (index >= e->num_value)
+	{
+		return 0;
+	}
+	if (e->values[index] == NULL)
+	{
+		return 0;
+	}
+
+	return e->values[index]->Size;
+}
+
+// データの取得
+void *GetDataValue(ELEMENT *e, UINT index)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return NULL;
+	}
+	if (e->values == NULL)
+	{
+		return NULL;
+	}
+	if (index >= e->num_value)
+	{
+		return NULL;
+	}
+	if (e->values[index] == NULL)
+	{
+		return NULL;
+	}
+
+	return e->values[index]->Data;
+}
+
+// Unicode 文字列型の取得
+wchar_t *GetUniStrValue(ELEMENT *e, UINT index)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return 0;
+	}
+	if (index >= e->num_value)
+	{
+		return 0;
+	}
+
+	return e->values[index]->UniStr;
+}
+
+// ANSI 文字列型の取得
+char *GetStrValue(ELEMENT *e, UINT index)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return 0;
+	}
+	if (index >= e->num_value)
+	{
+		return 0;
+	}
+
+	return e->values[index]->Str;
+}
+
+// 64 bit 整数型値の取得
+UINT64 GetInt64Value(ELEMENT *e, UINT index)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return 0;
+	}
+	if (index >= e->num_value)
+	{
+		return 0;
+	}
+
+	return e->values[index]->Int64Value;
+}
+
+// 整数型値の取得
+UINT GetIntValue(ELEMENT *e, UINT index)
+{
+	// 引数チェック
+	if (e == NULL)
+	{
+		return 0;
+	}
+	if (index >= e->num_value)
+	{
+		return 0;
+	}
+
+	return e->values[index]->IntValue;
+}
+
+// PACK のソート関数
+int ComparePackName(void *p1, void *p2)
+{
+	ELEMENT *o1, *o2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	o1 = *(ELEMENT **)p1;
+	o2 = *(ELEMENT **)p2;
+	if (o1 == NULL || o2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(o1->name, o2->name);
+}
+
+// VALUE の削除
+void FreeValue(VALUE *v, UINT type)
+{
+	// 引数チェック
+	if (v == NULL)
+	{
+		return;
+	}
+
+	switch (type)
+	{
+	case VALUE_INT:
+	case VALUE_INT64:
+		break;
+	case VALUE_DATA:
+		Free(v->Data);
+		break;
+	case VALUE_STR:
+		Free(v->Str);
+		break;
+	case VALUE_UNISTR:
+		Free(v->UniStr);
+		break;
+	}
+
+	// メモリ解放
+	Free(v);
+}
+
+// Unicode 文字列型の VALUE の作成
+VALUE *NewUniStrValue(wchar_t *str)
+{
+	VALUE *v;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	// メモリ確保
+	v = Malloc(sizeof(VALUE));
+
+	// 文字列コピー
+	v->Size = UniStrSize(str);
+	v->UniStr = Malloc(v->Size);
+	UniStrCpy(v->UniStr, v->Size, str);
+
+	UniTrim(v->UniStr);
+
+	return v;
+}
+
+// ANSI 文字列型の VALUE の作成
+VALUE *NewStrValue(char *str)
+{
+	VALUE *v;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	// メモリ確保
+	v = Malloc(sizeof(VALUE));
+
+	// 文字列コピー
+	v->Size = StrLen(str) + 1;
+	v->Str = Malloc(v->Size);
+	StrCpy(v->Str, v->Size, str);
+
+	Trim(v->Str);
+
+	return v;
+}
+
+// データ型の VALUE の作成
+VALUE *NewDataValue(void *data, UINT size)
+{
+	VALUE *v;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return NULL;
+	}
+
+	// メモリ確保
+	v = Malloc(sizeof(VALUE));
+
+	// データコピー
+	v->Size = size;
+	v->Data = Malloc(v->Size);
+	Copy(v->Data, data, size);
+
+	return v;
+}
+
+// 64 bit 整数型の VALUE の作成
+VALUE *NewInt64Value(UINT64 i)
+{
+	VALUE *v;
+
+	v = Malloc(sizeof(VALUE));
+	v->Int64Value = i;
+	v->Size = sizeof(UINT64);
+
+	return v;
+}
+
+// 整数型の VALUE の作成
+VALUE *NewIntValue(UINT i)
+{
+	VALUE *v;
+
+	// メモリ確保
+	v = Malloc(sizeof(VALUE));
+	v->IntValue = i;
+	v->Size = sizeof(UINT);
+
+	return v;
+}
+
+// ELEMENT の削除
+void FreeElement(ELEMENT *e)
+{
+	UINT i;
+	// 引数チェック
+	if (e == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < e->num_value;i++)
+	{
+		FreeValue(e->values[i], e->type);
+	}
+	Free(e->values);
+
+	Free(e);
+}
+
+// ELEMENT の作成
+ELEMENT *NewElement(char *name, UINT type, UINT num_value, VALUE **values)
+{
+	ELEMENT *e;
+	UINT i;
+	// 引数チェック
+	if (name == NULL || num_value == 0 || values == NULL)
+	{
+		return NULL;
+	}
+
+	// メモリ確保
+	e = Malloc(sizeof(ELEMENT));
+	StrCpy(e->name, sizeof(e->name), name);
+	e->num_value = num_value;
+	e->type = type;
+
+	// 要素へのポインタリストのコピー
+	e->values = (VALUE **)Malloc(sizeof(VALUE *) * num_value);
+	for (i = 0;i < e->num_value;i++)
+	{
+		e->values[i] = values[i];
+	}
+
+	return e;
+}
+
+// PACK から ELEMENT を検索して取得
+ELEMENT *GetElement(PACK *p, char *name, UINT type)
+{
+	ELEMENT t;
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return NULL;
+	}
+
+	// 検索
+	StrCpy(t.name, sizeof(t.name), name);
+	e = Search(p->elements, &t);
+
+	if (e == NULL)
+	{
+		return NULL;
+	}
+
+	// 型検査
+	if (type != INFINITE)
+	{
+		if (e->type != type)
+		{
+			return NULL;
+		}
+	}
+
+	return e;
+}
+
+// PACK から ELEMENT を削除
+void DelElement(PACK *p, char *name)
+{
+	ELEMENT *e;
+	// 引数チェック
+	if (p == NULL || name == NULL)
+	{
+		return;
+	}
+
+	e = GetElement(p, name, INFINITE);
+	if (e != NULL)
+	{
+		Delete(p->elements, e);
+
+		FreeElement(e);
+	}
+}
+
+// PACK に ELEMENT を追加
+bool AddElement(PACK *p, ELEMENT *e)
+{
+	// 引数チェック
+	if (p == NULL || e == NULL)
+	{
+		return false;
+	}
+
+	// サイズチェック
+	if (LIST_NUM(p->elements) >= MAX_ELEMENT_NUM)
+	{
+		// これ以上追加できない
+		FreeElement(e);
+		return false;
+	}
+
+	// 同じ名前が存在しないかどうかチェック
+	if (GetElement(p, e->name, INFINITE))
+	{
+		// 存在している
+		FreeElement(e);
+		return false;
+	}
+
+	if (e->num_value == 0)
+	{
+		// 項目が 1 つも存在していない VALUE は追加できない
+		FreeElement(e);
+		return false;
+	}
+
+	// 追加
+	Add(p->elements, e);
+	return true;
+}
+
+// PACK オブジェクトの解放
+void FreePack(PACK *p)
+{
+	UINT i;
+	ELEMENT **elements;
+	// 引数チェック
+	if (p == NULL)
+	{
+		return;
+	}
+
+	elements = ToArray(p->elements);
+	for (i = 0;i < LIST_NUM(p->elements);i++)
+	{
+		FreeElement(elements[i]);
+	}
+	Free(elements);
+
+	ReleaseList(p->elements);
+	Free(p);
+}
+
+// PACK オブジェクトの作成
+PACK *NewPack()
+{
+	PACK *p;
+
+	// メモリ確保
+	p = MallocEx(sizeof(PACK), true);
+
+	// リスト作成
+	p->elements = NewListFast(ComparePackName);
+
+	return p;
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Pack.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Pack.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Pack.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,170 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Pack.h
+// Pack.c のヘッダ
+
+#ifndef	PACK_H
+#define	PACK_H
+
+// 定数
+#ifdef CPU_64
+
+#define	MAX_VALUE_SIZE			(384 * 1024 * 1024)	// 1 つの VALUE に格納できるデータサイズ
+#define	MAX_VALUE_NUM			262144	// 1 つの ELEMENT に格納できる最大 VALUE 数
+#define	MAX_ELEMENT_NAME_LEN	63		// ELEMENT に付けることのできる名前の長さ
+#define	MAX_ELEMENT_NUM			262144	// 1 つの PACK に格納できる最大 ELEMENT 数
+#define	MAX_PACK_SIZE			(512 * 1024 * 1024)	// シリアル化された PACK の最大サイズ
+
+#else	// CPU_64
+
+#define	MAX_VALUE_SIZE			(96 * 1024 * 1024)	// 1 つの VALUE に格納できるデータサイズ
+#define	MAX_VALUE_NUM			65536	// 1 つの ELEMENT に格納できる最大 VALUE 数
+#define	MAX_ELEMENT_NAME_LEN	63		// ELEMENT に付けることのできる名前の長さ
+#define	MAX_ELEMENT_NUM			131072	// 1 つの PACK に格納できる最大 ELEMENT 数
+#define	MAX_PACK_SIZE			(128 * 1024 * 1024)	// シリアル化された PACK の最大サイズ
+
+#endif	// CPU_64
+
+// VALUE の種類
+#define	VALUE_INT			0		// 整数型
+#define	VALUE_DATA			1		// データ型
+#define	VALUE_STR			2		// ANSI 文字列型
+#define	VALUE_UNISTR		3		// Unicode 文字列型
+#define	VALUE_INT64			4		// 64 bit 整数型
+
+// VALUE オブジェクト
+struct VALUE
+{
+	UINT Size;				// サイズ
+	UINT IntValue;			// 整数値
+	void *Data;				// データ
+	char *Str;				// ANSI 文字列
+	wchar_t *UniStr;		// Unicode 文字列
+	UINT64 Int64Value;		// 64 bit 整数型
+};
+
+// ELEMENT オブジェクト
+struct ELEMENT
+{
+	char name[MAX_ELEMENT_NAME_LEN + 1];	// 要素名
+	UINT num_value;			// 値の数 (>=1)
+	UINT type;				// 型
+	VALUE **values;			// 値へのポインタのリスト
+};
+
+// PACK オブジェクト
+struct PACK
+{
+	LIST *elements;			// 要素リスト
+};
+
+
+// 関数プロトタイプ
+PACK *NewPack();
+bool AddElement(PACK *p, ELEMENT *e);
+void DelElement(PACK *p, char *name);
+ELEMENT *GetElement(PACK *p, char *name, UINT type);
+void FreePack(PACK *p);
+ELEMENT *NewElement(char *name, UINT type, UINT num_value, VALUE **values);
+VALUE *NewIntValue(UINT i);
+VALUE *NewDataValue(void *data, UINT size);
+VALUE *NewStrValue(char *str);
+VALUE *NewUniStrValue(wchar_t *str);
+void FreeValue(VALUE *v, UINT type);
+int ComparePackName(void *p1, void *p2);
+void FreeElement(ELEMENT *e);
+UINT GetValueNum(ELEMENT *e);
+UINT GetIntValue(ELEMENT *e, UINT index);
+UINT64 GetInt64Value(ELEMENT *e, UINT index);
+char *GetStrValue(ELEMENT *e, UINT index);
+wchar_t *GetUniStrValue(ELEMENT *e, UINT index);
+UINT GetDataValueSize(ELEMENT *e, UINT index);
+void *GetDataValue(ELEMENT *e, UINT index);
+BUF *PackToBuf(PACK *p);
+void WritePack(BUF *b, PACK *p);
+void WriteElement(BUF *b, ELEMENT *e);
+void WriteValue(BUF *b, VALUE *v, UINT type);
+PACK *BufToPack(BUF *b);
+bool ReadPack(BUF *b, PACK *p);
+ELEMENT *ReadElement(BUF *b);
+VALUE *ReadValue(BUF *b, UINT type);
+void Bit160ToStr(char *str, UCHAR *data);
+void Bit128ToStr(char *str, UCHAR *data);
+VALUE *NewInt64Value(UINT64 i);
+
+#endif	// PACK_H
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Secure.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Secure.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Secure.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2188 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Secure.c
+// セキュリティトークン管理モジュール
+
+#define	SECURE_C
+#define	ENCRYPT_C
+
+#ifdef	WIN32
+#include <windows.h>
+#endif	// WIN32
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/rand.h>
+#include <openssl/engine.h>
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include <openssl/pkcs7.h>
+#include <openssl/pkcs12.h>
+#include <openssl/rc4.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Mayaqua/cryptoki.h>
+
+
+#define	MAX_OBJ				1024		// ハードウェア内の最大オブジェクト数 (想定)
+
+#define	A_SIZE(a, i)		(a[(i)].ulValueLen)
+#define	A_SET(a, i, value, size)	(a[i].pValue = value;a[i].ulValueLen = size;)
+
+#ifdef	OS_WIN32
+// Win32 用コード
+
+// Win32 用 DLL 読み込み
+HINSTANCE Win32SecureLoadLibraryEx(char *dllname, DWORD flags)
+{
+	char tmp1[MAX_PATH];
+	char tmp2[MAX_PATH];
+	char tmp3[MAX_PATH];
+	HINSTANCE h;
+	// 引数チェック
+	if (dllname == NULL)
+	{
+		return NULL;
+	}
+
+	Format(tmp1, sizeof(tmp1), "%s\\%s", MsGetSystem32Dir(), dllname);
+	Format(tmp2, sizeof(tmp2), "%s\\JPKI\\%s", MsGetProgramFilesDir(), dllname);
+	Format(tmp3, sizeof(tmp3), "%s\\LGWAN\\%s", MsGetProgramFilesDir(), dllname);
+
+	h = LoadLibraryEx(dllname, NULL, flags);
+	if (h != NULL)
+	{
+		return h;
+	}
+
+	h = LoadLibraryEx(tmp1, NULL, flags);
+	if (h != NULL)
+	{
+		return h;
+	}
+
+	h = LoadLibraryEx(tmp2, NULL, flags);
+	if (h != NULL)
+	{
+		return h;
+	}
+
+	h = LoadLibraryEx(tmp3, NULL, flags);
+	if (h != NULL)
+	{
+		return h;
+	}
+
+	return NULL;
+}
+
+// 指定したデバイスがインストールされているか調査
+bool Win32IsDeviceSupported(SECURE_DEVICE *dev)
+{
+	HINSTANCE hInst;
+	// 引数チェック
+	if (dev == NULL)
+	{
+		return false;
+	}
+
+	// DLL が読み込み可能かチェック
+	hInst = Win32SecureLoadLibraryEx(dev->ModuleName, DONT_RESOLVE_DLL_REFERENCES);
+	if (hInst == NULL)
+	{
+		return false;
+	}
+
+	FreeLibrary(hInst);
+
+	return true;
+}
+
+// デバイスモジュールの読み込み
+bool Win32LoadSecModule(SECURE *sec)
+{
+	SEC_DATA_WIN32 *w;
+	HINSTANCE hInst;
+	CK_FUNCTION_LIST_PTR api = NULL;
+	CK_RV (*get_function_list)(CK_FUNCTION_LIST_PTR_PTR);
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+
+	if (sec->Dev->Id == 9)
+	{
+		char username[MAX_SIZE];
+		DWORD size;
+		// 住基ネットのデバイスドライバでは、Software\JPKI レジストリキーの内容を
+		// SYSTEM の HKLU でも持っていなければならないので、もし持っていない場合は
+		// 別のユーザーの値からコピーする
+//		if (MsRegIsValue(REG_CURRENT_USER, "Software\\JPKI", "Name") == false ||
+//			MsRegIsValue(REG_CURRENT_USER, "Software\\JPKI", "RWType") == false)
+		size = sizeof(username);
+		GetUserName(username, &size);
+		if (StrCmpi(username, "System") == 0)
+		{
+			TOKEN_LIST *t = MsRegEnumKey(REG_USERS, NULL);
+
+			if (t != NULL)
+			{
+				UINT i;
+
+				for (i = 0;i < t->NumTokens;i++)
+				{
+					char tmp[MAX_PATH];
+
+					if (StrCmpi(t->Token[i], ".DEFAULT") != 0 && StrCmpi(t->Token[i], "S-1-5-18") != 0)
+					{
+						Format(tmp, sizeof(tmp), "%s\\Software\\JPKI", t->Token[i]);
+
+						if (MsRegIsValue(REG_USERS, tmp, "Name") && MsRegIsValue(REG_USERS, tmp, "RWType"))
+						{
+							char *name = MsRegReadStr(REG_USERS, tmp, "Name");
+							char *port = MsRegReadStr(REG_USERS, tmp, "Port");
+							UINT type = MsRegReadInt(REG_USERS, tmp, "RWType");
+
+							MsRegWriteStr(REG_CURRENT_USER, "Software\\JPKI", "Name", name);
+							MsRegWriteStr(REG_CURRENT_USER, "Software\\JPKI", "Port", port);
+							MsRegWriteInt(REG_CURRENT_USER, "Software\\JPKI", "RWType", type);
+
+							Free(name);
+							Free(port);
+							break;
+						}
+					}
+				}
+
+				FreeToken(t);
+			}
+		}
+	}
+
+	// ライブラリのロード
+	hInst = Win32SecureLoadLibraryEx(sec->Dev->ModuleName, 0);
+	if (hInst == NULL)
+	{
+		// 失敗
+		return false;
+	}
+
+	// API の取得
+	get_function_list = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))
+		GetProcAddress(hInst, "C_GetFunctionList");
+
+	if (get_function_list == NULL)
+	{
+		// 失敗
+		FreeLibrary(hInst);
+		return false;
+	}
+
+	get_function_list(&api);
+	if (api == NULL)
+	{
+		// 失敗
+		FreeLibrary(hInst);
+		return false;
+	}
+
+	sec->Data = ZeroMalloc(sizeof(SEC_DATA_WIN32));
+	w = sec->Data;
+
+	w->hInst = hInst;
+	sec->Api = api;
+
+	return true;
+}
+
+// デバイスモジュールのアンロード
+void Win32FreeSecModule(SECURE *sec)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+	if (sec->Data == NULL)
+	{
+		return;
+	}
+
+	// アンロード
+	FreeLibrary(sec->Data->hInst);
+	Free(sec->Data);
+
+	sec->Data = NULL;
+}
+
+#endif	// OS_WIN32
+
+
+// 指定されたデバイスが JPKI かどうか
+bool IsJPKI(bool id)
+{
+	if (id == 9 || id == 13)
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// セキュアデバイスの秘密鍵を名前を指定して署名
+bool SignSec(SECURE *sec, char *name, void *dst, void *src, UINT size)
+{
+	SEC_OBJ *obj;
+	UINT ret;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (name == NULL || dst == NULL || src == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+
+	obj = FindSecObject(sec, name, SEC_K);
+	if (obj == NULL)
+	{
+		return false;
+	}
+
+	ret = SignSecByObject(sec, obj, dst, src, size);
+
+	FreeSecObject(obj);
+
+	return ret;
+}
+
+// セキュアデバイスの秘密鍵で署名
+bool SignSecByObject(SECURE *sec, SEC_OBJ *obj, void *dst, void *src, UINT size)
+{
+	CK_MECHANISM mechanism = {CKM_RSA_PKCS, NULL, 0};
+	UINT ret;
+	UCHAR hash[SIGN_HASH_SIZE];
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (obj == NULL || dst == NULL || src == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+	if (sec->LoginFlag == false && obj->Private)
+	{
+		sec->Error = SEC_ERROR_NOT_LOGIN;
+		return false;
+	}
+	if (obj->Type != SEC_K)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+
+	// ハッシュ
+	HashForSign(hash, sizeof(hash), src, size);
+
+	// 署名初期化
+	ret = sec->Api->C_SignInit(sec->SessionId, &mechanism, obj->Object);
+	if (ret != CKR_OK)
+	{
+		// 失敗
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		Debug("C_SignInit Error: 0x%x\n", ret);
+		return false;
+	}
+
+	// 署名実行
+	size = 128;
+	ret = sec->Api->C_Sign(sec->SessionId, hash, sizeof(hash), dst, &size);
+	if (ret != CKR_OK || size != 128)
+	{
+		// 失敗
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		Debug("C_Sign Error: 0x%x\n", ret);
+		return false;
+	}
+
+	return true;
+}
+
+// PIN コードの変更
+bool ChangePin(SECURE *sec, char *old_pin, char *new_pin)
+{
+	// 引数チェック
+	if (sec == NULL || old_pin == NULL || new_pin == NULL)
+	{
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+	if (sec->LoginFlag == false)
+	{
+		sec->Error = SEC_ERROR_NOT_LOGIN;
+		return false;
+	}
+	if (sec->IsReadOnly)
+	{
+		sec->Error = SEC_ERROR_OPEN_SESSION;
+		return false;
+	}
+
+	// PIN 変更
+	if (sec->Api->C_SetPIN(sec->SessionId, old_pin, StrLen(old_pin),
+		new_pin, StrLen(new_pin)) != CKR_OK)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 秘密鍵オブジェクトの書き込み
+bool WriteSecKey(SECURE *sec, bool private_obj, char *name, K *k)
+{
+	UINT key_type = CKK_RSA;
+	CK_BBOOL b_true = true, b_false = false, b_private_obj = private_obj;
+	UINT obj_class = CKO_PRIVATE_KEY;
+	UINT object;
+	UINT ret;
+	BUF *b;
+	RSA *rsa;
+	UCHAR modules[MAX_SIZE], pub[MAX_SIZE], pri[MAX_SIZE], prime1[MAX_SIZE], prime2[MAX_SIZE];
+	CK_ATTRIBUTE a[] =
+	{
+		{CKA_MODULUS,			modules,		0},		// 0
+		{CKA_PUBLIC_EXPONENT,	pub,			0},		// 1
+		{CKA_PRIVATE_EXPONENT,	pri,			0},		// 2
+		{CKA_PRIME_1,			prime1,			0},		// 3
+		{CKA_PRIME_2,			prime2,			0},		// 4
+		{CKA_CLASS,				&obj_class,		sizeof(obj_class)},
+		{CKA_TOKEN,				&b_true,		sizeof(b_true)},
+		{CKA_PRIVATE,			&b_private_obj,	sizeof(b_private_obj)},
+		{CKA_LABEL,				name,			StrLen(name)},
+		{CKA_KEY_TYPE,			&key_type,		sizeof(key_type)},
+		{CKA_DERIVE,			&b_false,		sizeof(b_false)},
+		{CKA_SUBJECT,			name,			StrLen(name)},
+		{CKA_SENSITIVE,			&b_true,		sizeof(b_true)},
+		{CKA_DECRYPT,			&b_true,		sizeof(b_true)},
+		{CKA_SIGN,				&b_true,		sizeof(b_true)},
+		{CKA_SIGN_RECOVER,		&b_false,		sizeof(b_false)},
+		{CKA_EXTRACTABLE,		&b_false,		sizeof(b_false)},
+		{CKA_MODIFIABLE,		&b_false,		sizeof(b_false)},
+	};
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (name == NULL || k == NULL || k->private_key == false)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+	if (sec->LoginFlag == false && private_obj)
+	{
+		sec->Error = SEC_ERROR_NOT_LOGIN;
+		return false;
+	}
+
+	// 数値データ生成
+	rsa = k->pkey->pkey.rsa;
+	if (rsa == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	b = BigNumToBuf(rsa->n);
+	ReadBuf(b, modules, sizeof(modules));
+	A_SIZE(a, 0) = b->Size;
+	FreeBuf(b);
+
+	b = BigNumToBuf(rsa->e);
+	ReadBuf(b, pub, sizeof(pub));
+	A_SIZE(a, 1) = b->Size;
+	FreeBuf(b);
+
+	b = BigNumToBuf(rsa->d);
+	ReadBuf(b, pri, sizeof(pri));
+	A_SIZE(a, 2) = b->Size;
+	FreeBuf(b);
+
+	b = BigNumToBuf(rsa->p);
+	ReadBuf(b, prime1, sizeof(prime1));
+	A_SIZE(a, 3) = b->Size;
+	FreeBuf(b);
+
+	b = BigNumToBuf(rsa->q);
+	ReadBuf(b, prime2, sizeof(prime2));
+	A_SIZE(a, 4) = b->Size;
+	FreeBuf(b);
+
+	// 古い鍵があれば削除
+	if (CheckSecObject(sec, name, SEC_K))
+	{
+		DeleteSecKey(sec, name);
+	}
+
+	// 作成
+	if ((ret = sec->Api->C_CreateObject(sec->SessionId, a, sizeof(a) / sizeof(a[0]), &object)) != CKR_OK)
+	{
+		// 失敗
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		Debug("ret: 0x%x\n", ret);
+		return false;
+	}
+
+	// キャッシュ消去
+	EraseEnumSecObjectCache(sec);
+
+	return true;
+}
+
+// 証明書オブジェクトを名前を指定して読み込み
+X *ReadSecCert(SECURE *sec, char *name)
+{
+	SEC_OBJ *obj;
+	X *x;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+
+	// 検索
+	obj = FindSecObject(sec, name, SEC_X);
+	if (obj == NULL)
+	{
+		return false;
+	}
+
+	// 取得
+	x = ReadSecCertFromObject(sec, obj);
+
+	FreeSecObject(obj);
+
+	return x;
+}
+
+// 証明書オブジェクトの読み込み
+X *ReadSecCertFromObject(SECURE *sec, SEC_OBJ *obj)
+{
+	UINT size;
+	X *x;
+	UCHAR value[4096];
+	BUF *b;
+	CK_ATTRIBUTE get[] =
+	{
+		{CKA_VALUE,		value,		sizeof(value)},
+	};
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+	if (sec->LoginFlag == false && obj->Private)
+	{
+		sec->Error = SEC_ERROR_NOT_LOGIN;
+		return false;
+	}
+	if (obj->Type != SEC_X)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+
+	// 取得
+	if (sec->Api->C_GetAttributeValue(
+		sec->SessionId, obj->Object, get, sizeof(get) / sizeof(get[0])) != CKR_OK)
+	{
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		return 0;
+	}
+
+	size = A_SIZE(get, 0);
+
+	// 変換
+	b = NewBuf();
+	WriteBuf(b, value, size);
+	SeekBuf(b, 0, 0);
+
+	x = BufToX(b, false);
+	if (x == NULL)
+	{
+		sec->Error = SEC_ERROR_INVALID_CERT;
+	}
+
+	FreeBuf(b);
+
+	return x;
+}
+
+// 証明書オブジェクトの書き込み
+bool WriteSecCert(SECURE *sec, bool private_obj, char *name, X *x)
+{
+	UINT obj_class = CKO_CERTIFICATE;
+	CK_BBOOL b_true = true, b_false = false, b_private_obj = private_obj;
+	UINT cert_type = CKC_X_509;
+	CK_DATE start_date, end_date;
+	UCHAR subject[MAX_SIZE];
+	UCHAR issuer[MAX_SIZE];
+	wchar_t w_subject[MAX_SIZE];
+	wchar_t w_issuer[MAX_SIZE];
+	UCHAR serial_number[MAX_SIZE];
+	UCHAR value[4096];
+	UINT ret;
+	BUF *b;
+	UINT object;
+	CK_ATTRIBUTE a[] =
+	{
+		{CKA_SUBJECT,			subject,		0},			// 0
+		{CKA_ISSUER,			issuer,			0},			// 1
+		{CKA_SERIAL_NUMBER,		serial_number,	0},			// 2
+		{CKA_VALUE,				value,			0},			// 3
+		{CKA_CLASS,				&obj_class,		sizeof(obj_class)},
+		{CKA_TOKEN,				&b_true,		sizeof(b_true)},
+		{CKA_PRIVATE,			&b_private_obj,	sizeof(b_private_obj)},
+		{CKA_LABEL,				name,			StrLen(name)},
+		{CKA_CERTIFICATE_TYPE,	&cert_type,		sizeof(cert_type)},
+#if	0		// 失敗するトークンがあるのでこれは使わない
+		{CKA_START_DATE,		&start_date,	sizeof(start_date)},
+		{CKA_END_DATE,			&end_date,		sizeof(end_date)},
+#endif
+	};
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (name == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+	if (sec->LoginFlag == false && private_obj)
+	{
+		sec->Error = SEC_ERROR_NOT_LOGIN;
+		return false;
+	}
+
+	// 証明書をバッファにコピー
+	b = XToBuf(x, false);
+	if (b == NULL)
+	{
+		sec->Error = SEC_ERROR_INVALID_CERT;
+		return false;
+	}
+	if (b->Size > sizeof(value))
+	{
+		// サイズが大きすぎる
+		FreeBuf(b);
+		sec->Error = SEC_ERROR_DATA_TOO_BIG;
+		return false;
+	}
+	Copy(value, b->Buf, b->Size);
+	A_SIZE(a, 3) = b->Size;
+	FreeBuf(b);
+
+	// Subject と Issuer を UTF-8 にエンコードして格納
+	GetPrintNameFromName(w_subject, sizeof(w_subject), x->subject_name);
+	UniToUtf8(subject, sizeof(subject), w_subject);
+	A_SIZE(a, 0) = StrLen(subject);
+	if (x->root_cert == false)
+	{
+		GetPrintNameFromName(w_issuer, sizeof(w_issuer), x->issuer_name);
+		UniToUtf8(issuer, sizeof(issuer), w_issuer);
+		A_SIZE(a, 1) = StrLen(issuer);
+	}
+
+	// シリアル番号をコピー
+	Copy(serial_number, x->serial->data, MIN(x->serial->size, sizeof(serial_number)));
+	A_SIZE(a, 2) = MIN(x->serial->size, sizeof(serial_number));
+
+	// 有効期限情報
+	UINT64ToCkDate(&start_date, SystemToLocal64(x->notBefore));
+	UINT64ToCkDate(&end_date, SystemToLocal64(x->notAfter));
+
+	// 同一の名前のオブジェクトがあれば削除
+	if (CheckSecObject(sec, name, SEC_X))
+	{
+		DeleteSecCert(sec, name);
+	}
+
+	// 作成
+	if ((ret = sec->Api->C_CreateObject(sec->SessionId, a, sizeof(a) / sizeof(a[0]), &object)) != CKR_OK)
+	{
+		// 失敗
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		Debug("Error: 0x%02x\n", ret);
+		return false;
+	}
+
+	// キャッシュ消去
+	EraseEnumSecObjectCache(sec);
+
+	return true;
+}
+
+// 秘密鍵オブジェクトの削除
+bool DeleteSecKey(SECURE *sec, char *name)
+{
+	return DeleteSecObjectByName(sec, name, SEC_K);
+}
+
+// 証明書オブジェクトの削除
+bool DeleteSecCert(SECURE *sec, char *name)
+{
+	return DeleteSecObjectByName(sec, name, SEC_X);
+}
+
+// CK_DATE を 64 bit 時刻に変換
+UINT64 CkDateToUINT64(struct CK_DATE *ck_date)
+{
+	SYSTEMTIME st;
+	char year[32], month[32], day[32];
+	// 引数チェック
+	if (ck_date == NULL)
+	{
+		return 0;
+	}
+
+	Zero(year, sizeof(year));
+	Zero(month, sizeof(month));
+	Zero(day, sizeof(day));
+
+	Copy(year, ck_date->year, 4);
+	Copy(month, ck_date->month, 2);
+	Copy(day, ck_date->day, 2);
+
+	st.wYear = ToInt(year);
+	st.wMonth = ToInt(month);
+	st.wDay = ToInt(day);
+
+	return SystemToUINT64(&st);
+}
+
+// 64 bit 時刻を CK_DATE に変換
+void UINT64ToCkDate(void *p_ck_date, UINT64 time64)
+{
+	SYSTEMTIME st;
+	char year[32], month[32], day[32];
+	struct CK_DATE *ck_date = (CK_DATE *)p_ck_date;
+	// 引数チェック
+	if (ck_date == NULL)
+	{
+		return;
+	}
+
+	UINT64ToSystem(&st, time64);
+
+	Format(year, sizeof(year), "%04u", st.wYear);
+	Format(month, sizeof(month), "%04u", st.wMonth);
+	Format(day, sizeof(day), "%04u", st.wDay);
+
+	Zero(ck_date, sizeof(CK_DATE));
+
+	Copy(ck_date->year, year, 4);
+	Copy(ck_date->month, month, 2);
+	Copy(ck_date->day, day, 2);
+}
+
+// オブジェクトを名前で指定して削除
+bool DeleteSecObjectByName(SECURE *sec, char *name, UINT type)
+{
+	bool ret;
+	SEC_OBJ *obj;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (name == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+
+	// オブジェクト取得
+	obj = FindSecObject(sec, name, type);
+	if (obj == NULL)
+	{
+		// 失敗
+		return false;
+	}
+
+	// オブジェクト削除
+	ret = DeleteSecObject(sec, obj);
+
+	// メモリ解放
+	FreeSecObject(obj);
+
+	return ret;
+}
+
+// データの削除
+bool DeleteSecData(SECURE *sec, char *name)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (name == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+
+	return DeleteSecObjectByName(sec, name, SEC_DATA);
+}
+
+// セキュアオブジェクトの削除
+bool DeleteSecObject(SECURE *sec, SEC_OBJ *obj)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (obj == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+	if (sec->LoginFlag == false && obj->Private)
+	{
+		sec->Error = SEC_ERROR_NOT_LOGIN;
+		return false;
+	}
+
+	// オブジェクト消去
+	if (sec->Api->C_DestroyObject(sec->SessionId, obj->Object) != CKR_OK)
+	{
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		return false;
+	}
+
+	// キャッシュ消去
+	DeleteSecObjFromEnumCache(sec, obj->Name, obj->Type);
+
+	return true;
+}
+
+// キャッシュから指定した名前のオブジェクトを削除する
+void DeleteSecObjFromEnumCache(SECURE *sec, char *name, UINT type)
+{
+	UINT i;
+	// 引数チェック
+	if (sec == NULL || name == NULL || sec->EnumCache == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(sec->EnumCache);i++)
+	{
+		SEC_OBJ *obj = LIST_DATA(sec->EnumCache, i);
+
+		if (StrCmpi(obj->Name, name) == 0)
+		{
+			if (obj->Type == type)
+			{
+				Delete(sec->EnumCache, obj);
+				FreeSecObject(obj);
+				break;
+			}
+		}
+	}
+}
+
+// セキュアオブジェクトを名前で検索して読み込む
+int ReadSecData(SECURE *sec, char *name, void *data, UINT size)
+{
+	UINT ret = 0;
+	SEC_OBJ *obj;
+	// 引数チェック
+	if (sec == NULL || name == NULL || data == NULL)
+	{
+		return 0;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return 0;
+	}
+
+	// 読み込み
+	obj = FindSecObject(sec, name, SEC_DATA);
+	if (obj == NULL)
+	{
+		// 見つからない
+		return 0;
+	}
+
+	// 読み込む
+	ret = ReadSecDataFromObject(sec, obj, data, size);
+
+	FreeSecObject(obj);
+
+	return ret;
+}
+
+// キャッシュ消去
+void EraseEnumSecObjectCache(SECURE *sec)
+{
+	// 引数チェック
+	if (sec == NULL || sec->EnumCache == NULL)
+	{
+		return;
+	}
+
+	FreeEnumSecObject(sec->EnumCache);
+	sec->EnumCache = NULL;
+}
+
+// セキュアオブジェクトの存在をチェックする
+bool CheckSecObject(SECURE *sec, char *name, UINT type)
+{
+	SEC_OBJ *obj;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (name == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return 0;
+	}
+
+	obj = FindSecObject(sec, name, type);
+
+	if (obj == NULL)
+	{
+		return false;
+	}
+	else
+	{
+		FreeSecObject(obj);
+		return true;
+	}
+}
+
+// セキュアオブジェクト構造体のクローンの作成
+SEC_OBJ *CloneSecObject(SEC_OBJ *obj)
+{
+	SEC_OBJ *ret;
+	// 引数チェック
+	if (obj == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(SEC_OBJ));
+	ret->Name = CopyStr(obj->Name);
+	ret->Object = obj->Object;
+	ret->Private = obj->Private;
+	ret->Type = obj->Type;
+
+	return ret;
+}
+
+// セキュアオブジェクトを名前で検索して取得する
+SEC_OBJ *FindSecObject(SECURE *sec, char *name, UINT type)
+{
+	LIST *o;
+	UINT i;
+	SEC_OBJ *ret = NULL;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return NULL;
+	}
+	if (name == NULL)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return NULL;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return 0;
+	}
+
+	// 列挙
+	o = EnumSecObject(sec);
+	if (o == NULL)
+	{
+		return NULL;
+	}
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		SEC_OBJ *obj = LIST_DATA(o, i);
+
+		if (obj->Type == type || type == INFINITE)
+		{
+			if (StrCmpi(obj->Name, name) == 0)
+			{
+				ret = CloneSecObject(obj);
+				break;
+			}
+		}
+	}
+	FreeEnumSecObject(o);
+
+	if (ret == NULL)
+	{
+		sec->Error = SEC_ERROR_OBJ_NOT_FOUND;
+	}
+
+	return ret;
+}
+
+// セキュアオブジェクトの読み込み
+int ReadSecDataFromObject(SECURE *sec, SEC_OBJ *obj, void *data, UINT size)
+{
+	UCHAR buf[MAX_SEC_DATA_SIZE];
+	UINT i;
+	CK_ATTRIBUTE get[] =
+	{
+		{CKA_VALUE,	 buf,	sizeof(buf)},
+	};
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return 0;
+	}
+	if (obj == NULL || data == NULL || size == 0)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return 0;
+	}
+	if (obj->Type != SEC_DATA)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return 0;
+	}
+	if (sec->LoginFlag == false && obj->Private)
+	{
+		sec->Error = SEC_ERROR_NOT_LOGIN;
+		return 0;
+	}
+
+	// 取得
+	if (sec->Api->C_GetAttributeValue(
+		sec->SessionId, obj->Object, get, sizeof(get) / sizeof(get[0])) != CKR_OK)
+	{
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		return 0;
+	}
+
+	// 結果の返却
+	i = get[0].ulValueLen;
+	if (i > MAX_SEC_DATA_SIZE || i > size)
+	{
+		// データが大きすぎる
+		sec->Error = SEC_ERROR_DATA_TOO_BIG;
+		return 0;
+	}
+
+	// メモリコピー
+	Copy(data, buf, i);
+
+	return i;
+}
+
+// セキュアオブジェクトの列挙結果の解放
+void FreeEnumSecObject(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		SEC_OBJ *obj = LIST_DATA(o, i);
+
+		FreeSecObject(obj);
+	}
+
+	ReleaseList(o);
+}
+
+// セキュアオブジェクトの解放
+void FreeSecObject(SEC_OBJ *obj)
+{
+	// 引数チェック
+	if (obj == NULL)
+	{
+		return;
+	}
+
+	Free(obj->Name);
+	Free(obj);
+}
+
+// セキュアオブジェクト列挙結果のクローン
+LIST *CloneEnumSecObject(LIST *o)
+{
+	LIST *ret;
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	ret = NewListFast(NULL);
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		SEC_OBJ *obj = LIST_DATA(o, i);
+
+		Add(ret, CloneSecObject(obj));
+	}
+
+	return ret;
+}
+
+// セキュアオブジェクトの列挙
+LIST *EnumSecObject(SECURE *sec)
+{
+	CK_BBOOL b_true = true, b_false = false;
+	UINT objects[MAX_OBJ];
+	UINT i;
+	UINT ret;
+	LIST *o;
+	CK_ATTRIBUTE dummy[1];
+	CK_ATTRIBUTE a[] =
+	{
+		{CKA_TOKEN,		&b_true,		sizeof(b_true)},
+	};
+	UINT num_objects = MAX_OBJ;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return NULL;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return NULL;
+	}
+
+	Zero(dummy, sizeof(dummy));
+
+	// キャッシュがあればキャッシュを返す
+	if (sec->EnumCache != NULL)
+	{
+		return CloneEnumSecObject(sec->EnumCache);
+	}
+
+	// 列挙
+//	if (sec->Dev->Id != 2 && sec->Dev->Id != 14)
+//	{
+		// 通常のトークン
+		ret = sec->Api->C_FindObjectsInit(sec->SessionId, a, sizeof(a) / sizeof(a[0]));
+//	}
+//	else
+//	{
+		// ePass と SafeSign
+//		ret = sec->Api->C_FindObjectsInit(sec->SessionId, dummy, 0);
+//	}
+
+	if (ret != CKR_OK)
+	{
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		return NULL;
+	}
+	if (sec->Api->C_FindObjects(sec->SessionId, objects, sizeof(objects) / sizeof(objects[0]), &num_objects) != CKR_OK)
+	{
+		sec->Api->C_FindObjectsFinal(sec->SessionId);
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		return NULL;
+	}
+	sec->Api->C_FindObjectsFinal(sec->SessionId);
+
+	o = NewListFast(NULL);
+
+	for (i = 0;i < num_objects;i++)
+	{
+		char label[MAX_SIZE];
+		UINT obj_class = 0;
+		bool priv = false;
+		CK_ATTRIBUTE get[] =
+		{
+			{CKA_LABEL, label, sizeof(label) - 1},
+			{CKA_CLASS, &obj_class, sizeof(obj_class)},
+			{CKA_PRIVATE, &priv, sizeof(priv)},
+		};
+
+		Zero(label, sizeof(label));
+
+		if (sec->Api->C_GetAttributeValue(sec->SessionId, objects[i],
+			get, sizeof(get) / sizeof(get[0])) == CKR_OK)
+		{
+			UINT type = INFINITE;
+
+			switch (obj_class)
+			{
+			case CKO_DATA:
+				// データ
+				type = SEC_DATA;
+				break;
+
+			case CKO_CERTIFICATE:
+				// 証明書
+				type = SEC_X;
+				break;
+
+			case CKO_PUBLIC_KEY:
+				// 公開鍵
+				type = SEC_P;
+				break;
+
+			case CKO_PRIVATE_KEY:
+				// 秘密鍵
+				type = SEC_K;
+				break;
+			}
+
+			if (type != INFINITE)
+			{
+				SEC_OBJ *obj = ZeroMalloc(sizeof(SEC_OBJ));
+
+				obj->Type = type;
+				obj->Object = objects[i];
+				obj->Private = (priv == false) ? false : true;
+				EnSafeStr(label, '?');
+				TruncateCharFromStr(label, '?');
+				obj->Name = CopyStr(label);
+
+				Add(o, obj);
+			}
+		}
+	}
+
+	// キャッシュ作成
+	sec->EnumCache = CloneEnumSecObject(o);
+
+	return o;
+}
+
+// データを書き込む
+bool WriteSecData(SECURE *sec, bool private_obj, char *name, void *data, UINT size)
+{
+	UINT object_class = CKO_DATA;
+	CK_BBOOL b_true = true, b_false = false, b_private_obj = private_obj;
+	UINT object;
+	CK_ATTRIBUTE a[] =
+	{
+		{CKA_TOKEN,		&b_true,		sizeof(b_true)},
+		{CKA_CLASS,		&object_class,	sizeof(object_class)},
+		{CKA_PRIVATE,	&b_private_obj,	sizeof(b_private_obj)},
+		{CKA_LABEL,		name,			StrLen(name)},
+		{CKA_VALUE,		data,			size},
+	};
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+	}
+	if (private_obj && sec->LoginFlag == false)
+	{
+		sec->Error = SEC_ERROR_NOT_LOGIN;
+		return false;
+	}
+	if (name == NULL || data == NULL || size == 0)
+	{
+		sec->Error = SEC_ERROR_BAD_PARAMETER;
+		return false;
+	}
+	if (size > MAX_SEC_DATA_SIZE)
+	{
+		sec->Error = SEC_ERROR_DATA_TOO_BIG;
+		return false;
+	}
+
+	// 同名のオブジェクトがあれば削除
+	if (CheckSecObject(sec, name, SEC_DATA))
+	{
+		DeleteSecData(sec, name);
+	}
+
+	// オブジェクト作成
+	if (sec->Api->C_CreateObject(sec->SessionId, a, sizeof(a) / sizeof(a[0]), &object) != CKR_OK)
+	{
+		sec->Error = SEC_ERROR_HARDWARE_ERROR;
+		return false;
+	}
+
+	// キャッシュ消去
+	EraseEnumSecObjectCache(sec);
+
+	return true;
+}
+
+// キャッシュに新規作成したオブジェクトの情報を追加する
+void AddSecObjToEnumCache(SECURE *sec, char *name, UINT type, bool private_obj, UINT object)
+{
+	SEC_OBJ *obj;
+	// 引数チェック
+	if (sec == NULL || name == NULL || sec->EnumCache == NULL)
+	{
+		return;
+	}
+
+	obj = ZeroMalloc(sizeof(SEC_OBJ));
+	obj->Name = CopyStr(name);
+	obj->Object = object;
+	obj->Private = private_obj;
+	obj->Type = type;
+
+	Add(sec->EnumCache, obj);
+}
+
+// トークン情報を表示
+void PrintSecInfo(SECURE *sec)
+{
+	SEC_INFO *s;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+
+	s = sec->Info;
+	if (s == NULL)
+	{
+		Print("No Token Info.\n");
+		return;
+	}
+
+	Print(
+		"               Label: %S\n"
+		"      ManufacturerId: %S\n"
+		"               Model: %S\n"
+		"        SerialNumber: %S\n"
+		"          MaxSession: %u\n"
+		"        MaxRWSession: %u\n"
+		"           MinPinLen: %u\n"
+		"           MaxPinLen: %u\n"
+		"   TotalPublicMemory: %u\n"
+		"    FreePublicMemory: %u\n"
+		"  TotalPrivateMemory: %u\n"
+		"   FreePrivateMemory: %u\n"
+		"     HardwareVersion: %s\n"
+		"     FirmwareVersion: %s\n",
+		s->Label, s->ManufacturerId, s->Model, s->SerialNumber,
+		s->MaxSession, s->MaxRWSession, s->MinPinLen, s->MaxPinLen,
+		s->TotalPublicMemory, s->FreePublicMemory, s->TotalPrivateMemory,
+		s->FreePrivateMemory, s->HardwareVersion, s->FirmwareVersion
+		);
+}
+
+// トークン情報を取得
+void GetSecInfo(SECURE *sec)
+{
+	CK_TOKEN_INFO token_info;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+	if (sec->Info != NULL)
+	{
+		return;
+	}
+
+	// 取得
+	Zero(&token_info, sizeof(token_info));
+	if (sec->Api->C_GetTokenInfo(sec->SlotIdList[sec->SessionSlotNumber], &token_info) != CKR_OK)
+	{
+		// 失敗
+		return;
+	}
+
+	sec->Info = TokenInfoToSecInfo(&token_info);
+}
+
+// トークン情報を解放
+void FreeSecInfo(SECURE *sec)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+	if (sec->Info == NULL)
+	{
+		return;
+	}
+
+	FreeSecInfoMemory(sec->Info);
+	sec->Info = NULL;
+}
+
+// トークン情報を SEC_INFO に変換
+SEC_INFO *TokenInfoToSecInfo(void *p_t)
+{
+	SEC_INFO *s;
+	char buf[MAX_SIZE];
+	CK_TOKEN_INFO *t = (CK_TOKEN_INFO *)p_t;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	s = ZeroMalloc(sizeof(SEC_INFO));
+
+	// Label
+	Zero(buf, sizeof(buf));
+	Copy(buf, t->label, sizeof(t->label));
+	s->Label = ZeroMalloc(CalcUtf8ToUni(buf, 0));
+	Utf8ToUni(s->Label, 0, buf, 0);
+
+	// ManufacturerId
+	Zero(buf, sizeof(buf));
+	Copy(buf, t->manufacturerID, sizeof(t->manufacturerID));
+	s->ManufacturerId = ZeroMalloc(CalcUtf8ToUni(buf, 0));
+	Utf8ToUni(s->ManufacturerId, 0, buf, 0);
+
+	// Model
+	Zero(buf, sizeof(buf));
+	Copy(buf, t->model, sizeof(t->model));
+	s->Model = ZeroMalloc(CalcUtf8ToUni(buf, 0));
+	Utf8ToUni(s->Model, 0, buf, 0);
+
+	// SerialNumber
+	Zero(buf, sizeof(buf));
+	Copy(buf, t->serialNumber, sizeof(t->serialNumber));
+	s->SerialNumber = ZeroMalloc(CalcUtf8ToUni(buf, 0));
+	Utf8ToUni(s->SerialNumber, 0, buf, 0);
+
+	// 数値
+	s->MaxSession = t->ulMaxSessionCount;
+	s->MaxRWSession = t->ulMaxRwSessionCount;
+	s->MinPinLen = t->ulMinPinLen;
+	s->MaxPinLen = t->ulMaxPinLen;
+	s->TotalPublicMemory = t->ulTotalPublicMemory;
+	s->FreePublicMemory = t->ulFreePublicMemory;
+	s->TotalPrivateMemory = t->ulTotalPrivateMemory;
+	s->FreePrivateMemory = t->ulFreePrivateMemory;
+
+	// ハードウェアバージョン
+	Format(buf, sizeof(buf), "%u.%02u", t->hardwareVersion.major, t->hardwareVersion.minor);
+	s->HardwareVersion = CopyStr(buf);
+
+	// ファームウェアバージョン
+	Format(buf, sizeof(buf), "%u.%02u", t->firmwareVersion.major, t->firmwareVersion.minor);
+	s->FirmwareVersion = CopyStr(buf);
+
+	return s;
+}
+
+// SEC_INFO のメモリを解放
+void FreeSecInfoMemory(SEC_INFO *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	Free(s->Label);
+	Free(s->ManufacturerId);
+	Free(s->Model);
+	Free(s->SerialNumber);
+	Free(s->HardwareVersion);
+	Free(s->FirmwareVersion);
+	Free(s);
+}
+
+// ログアウトする
+void LogoutSec(SECURE *sec)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+	if (sec->LoginFlag == false)
+	{
+		return;
+	}
+
+	// ログアウト
+	sec->Api->C_Logout(sec->SessionId);
+
+	// キャッシュ消去
+	EraseEnumSecObjectCache(sec);
+
+	sec->LoginFlag = false;
+}
+
+// ログインする
+bool LoginSec(SECURE *sec, char *pin)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (sec->SessionCreated == false)
+	{
+		sec->Error = SEC_ERROR_NO_SESSION;
+		return false;
+
+	}
+	if (sec->LoginFlag)
+	{
+		sec->Error = SEC_ERROR_ALREADY_LOGIN;
+		return false;
+	}
+	if (pin == NULL)
+	{
+		sec->Error = SEC_ERROR_NO_PIN_STR;
+		return false;
+	}
+
+	// ログイン
+	if (sec->Api->C_Login(sec->SessionId, CKU_USER, pin, StrLen(pin)) != CKR_OK)
+	{
+		// ログイン失敗
+		sec->Error = SEC_ERROR_BAD_PIN_CODE;
+		return false;
+	}
+
+	// キャッシュ消去
+	EraseEnumSecObjectCache(sec);
+
+	sec->LoginFlag = true;
+
+	return true;
+}
+
+// セッションを閉じる
+void CloseSecSession(SECURE *sec)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+	if (sec->SessionCreated == false)
+	{
+		return;
+	}
+
+	// セッションを閉じる
+	sec->Api->C_CloseSession(sec->SessionId);
+
+	sec->SessionCreated = false;
+	sec->SessionId = 0;
+	sec->SessionSlotNumber = 0;
+
+	FreeSecInfo(sec);
+
+	// キャッシュ消去
+	EraseEnumSecObjectCache(sec);
+}
+
+// セッションを開く
+bool OpenSecSession(SECURE *sec, UINT slot_number)
+{
+	UINT err = 0;
+	UINT session;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+	if (sec->SessionCreated)
+	{
+		// すでに作成されている
+		sec->Error = SEC_ERROR_SESSION_EXISTS;
+		return false;
+	}
+	if (slot_number >= sec->NumSlot)
+	{
+		// スロット番号不正
+		sec->Error = SEC_ERROR_INVALID_SLOT_NUMBER;
+		return false;
+	}
+
+	// セッション作成
+	if ((err = sec->Api->C_OpenSession(sec->SlotIdList[slot_number],
+		CKF_RW_SESSION | CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK)
+	{
+		// 読み書きモードでのセッション初期化に失敗した
+		// 読み取り専用モードかな？
+		if ((err = sec->Api->C_OpenSession(sec->SlotIdList[slot_number],
+			CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK)
+		{
+			// 作成失敗
+			sec->Error = SEC_ERROR_OPEN_SESSION;
+			return false;
+		}
+		else
+		{
+			sec->IsReadOnly = true;
+		}
+	}
+
+	sec->SessionCreated = true;
+	sec->SessionId = session;
+	sec->SessionSlotNumber = slot_number;
+
+	// トークン情報を取得
+	GetSecInfo(sec);
+
+	return true;
+}
+
+// セキュアデバイスを閉じる
+void CloseSec(SECURE *sec)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+
+	// ログアウトする
+	LogoutSec(sec);
+
+	// セッションを閉じる
+	CloseSecSession(sec);
+
+	// トークン情報を解放
+	FreeSecInfo(sec);
+
+	// スロットリストメモリの解放
+	if (sec->SlotIdList != NULL)
+	{
+		Free(sec->SlotIdList);
+		sec->SlotIdList = NULL;
+	}
+
+	// モジュールのアンロード
+	FreeSecModule(sec);
+
+	// メモリ解放
+	DeleteLock(sec->lock);
+	Free(sec);
+}
+
+// セキュアデバイスを開く
+SECURE *OpenSec(UINT id)
+{
+	SECURE_DEVICE *dev = GetSecureDevice(id);
+	SECURE *sec;
+	UINT err;
+
+	if (dev == NULL)
+	{
+		return NULL;
+	}
+
+	sec = ZeroMalloc(sizeof(SECURE));
+
+	sec->lock = NewLock();
+	sec->Error = SEC_ERROR_NOERROR;
+	sec->Dev = dev;
+
+	// ePass かどうか取得する
+	if (SearchStrEx(dev->DeviceName, "epass", 0, false) != INFINITE)
+	{
+		sec->IsEPass1000 = true;
+	}
+
+	// モジュールのロード
+	if (LoadSecModule(sec) == false)
+	{
+		CloseSec(sec);
+		return NULL;
+	}
+
+	// スロット一覧の取得
+	sec->NumSlot = 0;
+	if ((err = sec->Api->C_GetSlotList(true, NULL, &sec->NumSlot)) != CKR_OK || sec->NumSlot == 0)
+	{
+		// 失敗
+		FreeSecModule(sec);
+		CloseSec(sec);
+		return NULL;
+	}
+
+	sec->SlotIdList = (UINT *)ZeroMalloc(sizeof(UINT *) * sec->NumSlot);
+
+	if (sec->Api->C_GetSlotList(TRUE, sec->SlotIdList, &sec->NumSlot) != CKR_OK)
+	{
+		// 失敗
+		Free(sec->SlotIdList);
+		sec->SlotIdList = NULL;
+		FreeSecModule(sec);
+		CloseSec(sec);
+		return NULL;
+	}
+
+	return sec;
+}
+
+// セキュアデバイスのモジュールをロードする
+bool LoadSecModule(SECURE *sec)
+{
+	bool ret = false;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return false;
+	}
+
+#ifdef	OS_WIN32
+	ret = Win32LoadSecModule(sec);
+#endif	// OS_WIN32
+
+	// 初期化
+	if (sec->Api->C_Initialize(NULL) != CKR_OK)
+	{
+		// 初期化失敗
+		FreeSecModule(sec);
+		return false;
+	}
+
+	sec->Initialized = true;
+
+	return ret;
+}
+
+// セキュアデバイスのモジュールをアンロードする
+void FreeSecModule(SECURE *sec)
+{
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+
+	if (sec->Initialized)
+	{
+		// 初期化済みなので解放する
+		sec->Api->C_Finalize(NULL);
+		sec->Initialized = false;
+	}
+
+#ifdef	OS_WIN32
+	Win32FreeSecModule(sec);
+#endif	// OS_WIN32
+
+}
+
+
+// セキュアデバイスを取得する
+SECURE_DEVICE *GetSecureDevice(UINT id)
+{
+	UINT i;
+
+	if (id == 0)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(SecureDeviceList);i++)
+	{
+		SECURE_DEVICE *dev = LIST_DATA(SecureDeviceList, i);
+
+		if (dev->Id == id)
+		{
+			return dev;
+		}
+	}
+
+	return NULL;
+}
+
+// セキュアデバイスの ID を確認する
+bool CheckSecureDeviceId(UINT id)
+{
+	UINT i;
+
+	for (i = 0;i < LIST_NUM(SecureDeviceList);i++)
+	{
+		SECURE_DEVICE *dev = LIST_DATA(SecureDeviceList, i);
+
+		if (dev->Id == id)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// サポートされているデバイスリストを取得する
+LIST *GetSecureDeviceList()
+{
+	return GetSupportedDeviceList();
+}
+
+// サポートされているデバイスリストを取得する
+LIST *GetSupportedDeviceList()
+{
+	// 参照カウントの増加
+	AddRef(SecureDeviceList->ref);
+
+	return SecureDeviceList;
+}
+
+// 指定したデバイスがインストールされていて利用可能かどうか調べる
+bool IsDeviceSupported(SECURE_DEVICE *dev)
+{
+	bool b = false;
+#ifdef	OS_WIN32
+	b = Win32IsDeviceSupported(dev);
+#endif	// OS_WIN32
+	return b;
+}
+
+// セキュアデバイスリストの初期化
+void InitSecureDeviceList()
+{
+	UINT i, num_supported_list;
+	SecureDeviceList = NewList(NULL);
+
+	num_supported_list = sizeof(SupportedList) / sizeof(SECURE_DEVICE);
+	for (i = 0; i < num_supported_list;i++)
+	{
+		SECURE_DEVICE *dev = &SupportedList[i];
+
+		// サポートチェック
+		if (IsDeviceSupported(dev))
+		{
+			// サポートされているのでリストに追加
+			Add(SecureDeviceList, dev);
+		}
+	}
+}
+
+// テストメイン処理
+void TestSecMain(SECURE *sec)
+{
+	char *test_str = "SoftEther UT-VPN";
+	K *public_key, *private_key;
+	// 引数チェック
+	if (sec == NULL)
+	{
+		return;
+	}
+
+	Print("test_str: \"%s\"\n", test_str);
+
+	Print("Writing Data...\n");
+	if (WriteSecData(sec, true, "test_str", test_str, StrLen(test_str)) == false)
+	{
+		Print("WriteSecData() Failed.\n");
+	}
+	else
+	{
+		char data[MAX_SIZE];
+		Zero(data, sizeof(data));
+		Print("Reading Data...\n");
+		if (ReadSecData(sec, "test_str", data, sizeof(data)) == false)
+		{
+			Print("ReadSecData() Failed.\n");
+		}
+		else
+		{
+			Print("test_str: \"%s\"\n", data);
+		}
+		Print("Deleting Data...\n");
+		DeleteSecData(sec, "test_str");
+	}
+
+	Print("Generating Key...\n");
+	if (RsaGen(&private_key, &public_key, 1024) == false)
+	{
+		Print("RsaGen() Failed.\n");
+	}
+	else
+	{
+		X *cert;
+		NAME *name;
+		X_SERIAL *serial;
+		UINT num = 0x11220000;
+
+		Print("Creating Cert...\n");
+		serial = NewXSerial(&num, sizeof(UINT));
+		name = NewName(L"Test", L"Test", L"Test", L"JP", L"Test", L"Test");
+		cert = NewRootX(public_key, private_key, name, 365, NULL);
+		FreeXSerial(serial);
+		if (cert == NULL)
+		{
+			Print("NewRootX() Failed.\n");
+		}
+		else
+		{
+			Print("Writing Cert...\n");
+			DeleteSecData(sec, "test_cer");
+			if (WriteSecCert(sec, true, "test_cer", cert) == false)
+			{
+				Print("WriteSecCert() Failed.\n");
+			}
+			else
+			{
+				X *x;
+				Print("Reading Cert...\n");
+				x = ReadSecCert(sec, "test_cer");
+				if (x == NULL)
+				{
+					Print("ReadSecCert() Failed.\n");
+				}
+				else
+				{
+					Print("Checking two Certs... ");
+					if (CompareX(x, cert) == false)
+					{
+						Print("[FAILED]\n");
+					}
+					else
+					{
+						Print("Ok.\n");
+					}
+					FreeX(x);
+				}
+				if (cert != NULL)
+				{
+					X *x;
+					XToFile(cert, "cert_tmp.cer", true);
+					x = FileToX("cert_tmp.cer");
+					if (CompareX(x, cert) == false)
+					{
+						Print("[FAILED]\n");
+					}
+					else
+					{
+						Print("Ok.\n");
+						Print("Writing Private Key...\n");
+						DeleteSecKey(sec, "test_key");
+						if (WriteSecKey(sec, true, "test_key", private_key) == false)
+						{
+							Print("WriteSecKey() Failed.\n");
+						}
+						else
+						{
+							UCHAR sign_cpu[128];
+							UCHAR sign_sec[128];
+							K *pub = GetKFromX(cert);
+							Print("Ok.\n");
+							Print("Signing Data by CPU...\n");
+							if (RsaSign(sign_cpu, test_str, StrLen(test_str), private_key) == false)
+							{
+								Print("RsaSign() Failed.\n");
+							}
+							else
+							{
+								Print("Ok.\n");
+								Print("sign_cpu: ");
+								PrintBin(sign_cpu, sizeof(sign_cpu));
+								Print("Signing Data by %s..\n", sec->Dev->DeviceName);
+								if (SignSec(sec, "test_key", sign_sec, test_str, StrLen(test_str)) == false)
+								{
+									Print("SignSec() Failed.\n");
+								}
+								else
+								{
+									Print("Ok.\n");
+									Print("sign_sec: ");
+									PrintBin(sign_sec, sizeof(sign_sec));
+									Print("Compare...");
+									if (Cmp(sign_sec, sign_cpu, sizeof(sign_cpu)) == 0)
+									{
+										Print("Ok.\n");
+										Print("Verify...");
+										if (RsaVerify(test_str, StrLen(test_str),
+											sign_sec, pub) == false)
+										{
+											Print("[FAILED]\n");
+										}
+										else
+										{
+											Print("Ok.\n");
+										}
+									}
+									else
+									{
+										Print("[DIFFIRENT]\n");
+									}
+								}
+							}
+							Print("Deleting test_key...\n");
+//							DeleteSecKey(sec, "test_key");
+							FreeK(pub);
+						}
+					}
+					FreeX(x);
+				}
+			}
+			Print("Deleting Cert..\n");
+//			DeleteSecCert(sec, "test_cer");
+			FreeX(cert);
+		}
+		FreeName(name);
+		FreeK(private_key);
+		FreeK(public_key);
+	}
+}
+
+// セキュリティデバイスのテスト
+void TestSec()
+{
+	UINT i;
+	LIST *secure_device_list;
+	Print("Secure Device Test Program\n"
+		"Copyright (C) 2004-2010 SoftEther Corporation. All Rights Reserved.\n\n");
+
+	// セキュアデバイスリストの取得
+	secure_device_list = GetSecureDeviceList();
+	if (secure_device_list != NULL)
+	{
+		UINT use_device_id;
+		char tmp[MAX_SIZE];
+		Print("--- Secure Device List ---\n");
+		for (i = 0;i < LIST_NUM(secure_device_list);i++)
+		{
+			SECURE_DEVICE *dev = LIST_DATA(secure_device_list, i);
+			Print("%2u - %s\n", dev->Id, dev->DeviceName);
+		}
+		Print("\n");
+		Print("Device ID >");
+		GetLine(tmp, sizeof(tmp));
+		use_device_id = ToInt(tmp);
+		if (use_device_id == 0)
+		{
+			Print("Canceled.\n");
+		}
+		else
+		{
+			SECURE *sec = OpenSec(use_device_id);
+			Print("Opening Device...\n");
+			if (sec == NULL)
+			{
+				Print("OpenSec() Failed.\n");
+			}
+			else
+			{
+				Print("Opening Session...\n");
+				if (OpenSecSession(sec, 0) == false)
+				{
+					Print("OpenSecSession() Failed.\n");
+				}
+				else
+				{
+					while (true)
+					{
+						char pin[MAX_SIZE];
+						Print("PIN Code >");
+						GetLine(pin, sizeof(pin));
+						Trim(pin);
+						if (StrLen(pin) == 0)
+						{
+							Print("Canceled.\n");
+							break;
+						}
+						else
+						{
+							Print("Login...\n");
+							if (LoginSec(sec, pin))
+							{
+								TestSecMain(sec);
+								Print("Logout...\n");
+								LogoutSec(sec);
+								break;
+							}
+							else
+							{
+								Print("Login Failed. Please Try Again.\n");
+							}
+						}
+					}
+					Print("Closing Session...\n");
+					CloseSecSession(sec);
+				}
+				Print("Closing Device...\n");
+				CloseSec(sec);
+			}
+		}
+		ReleaseList(secure_device_list);
+	}
+	else
+	{
+		Print("GetSecureDeviceList() Error.\n");
+	}
+}
+
+// セキュアデバイスリストの解放
+void FreeSecureDeviceList()
+{
+	ReleaseList(SecureDeviceList);
+}
+
+// セキュリティトークンモジュールの初期化
+void InitSecure()
+{
+	// セキュアデバイスリストの初期化
+	InitSecureDeviceList();
+}
+
+// セキュリティトークンモジュールの解放
+void FreeSecure()
+{
+	// セキュアデバイスリストの解放
+	FreeSecureDeviceList();
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Secure.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Secure.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Secure.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,294 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Secure.h
+// Secure.c のヘッダ
+
+#ifndef	SECURE_H
+#define	SECURE_H
+
+// 定数
+#define	MAX_SEC_DATA_SIZE		4096
+
+// PKCS#11 関係の型宣言
+#ifndef	SECURE_C
+typedef struct CK_FUNCTION_LIST *CK_FUNCTION_LIST_PTR;
+typedef struct SEC_DATA_WIN32	SEC_DATA_WIN32;
+typedef struct CK_TOKEN_INFO	CK_TOKEN_INFO;
+typedef struct CK_DATE			CK_DATE;
+#endif	// SECURE_C
+
+// セキュアデバイス
+struct SECURE_DEVICE
+{
+	UINT Id;								// デバイス ID
+	UINT Type;								// 種類
+	char *DeviceName;						// デバイス名
+	char *Manufacturer;						// 製造元
+	char *ModuleName;						// モジュール名
+};
+
+// セキュアデバイスの種類
+#define	SECURE_IC_CARD				0		// IC カード
+#define	SECURE_USB_TOKEN			1		// USB トークン
+
+// セキュアデバイス情報
+struct SEC_INFO
+{
+	wchar_t *Label;							// ラベル
+	wchar_t *ManufacturerId;					// 製造元 ID
+	wchar_t *Model;							// モデル
+	wchar_t *SerialNumber;						// シリアル番号
+	UINT MaxSession;						// 最大セッション数
+	UINT MaxRWSession;						// 最大 R/W セッション数
+	UINT MinPinLen;							// 最小 PIN 文字列長
+	UINT MaxPinLen;							// 最大 PIN 文字列長
+	UINT TotalPublicMemory;					// 合計メモリ容量 (Public)
+	UINT FreePublicMemory;					// 空きメモリ容量 (Private)
+	UINT TotalPrivateMemory;				// 合計メモリ容量 (Public)
+	UINT FreePrivateMemory;					// 空きメモリ容量 (Private)
+	char *HardwareVersion;					// ハードウェアバージョン
+	char *FirmwareVersion;					// ファームウェアバージョン
+};
+
+// セキュアデバイス構造体
+struct SECURE
+{
+	LOCK *lock;								// ロック
+	SECURE_DEVICE *Dev;						// デバイス情報
+	UINT Error;								// 最後に発生したエラー
+	struct CK_FUNCTION_LIST *Api;			// API
+	bool Initialized;						// 初期化フラグ
+	UINT NumSlot;							// スロット数
+	UINT *SlotIdList;						// スロット ID リスト
+	bool SessionCreated;					// セッション作成フラグ
+	UINT SessionId;							// セッション ID
+	UINT SessionSlotNumber;					// セッションのスロット ID
+	bool LoginFlag;							// ログイン済みフラグ
+	SEC_INFO *Info;							// トークン情報
+	LIST *EnumCache;						// 列挙キャッシュ
+
+	// ドライバごとに異なる挙動をするための属性値
+	bool IsEPass1000;						// ePass 1000
+	bool IsReadOnly;						// 読み取り専用モード
+
+#ifdef	OS_WIN32
+	struct SEC_DATA_WIN32 *Data;			// データ
+#endif	// OS_WIN32
+};
+
+// セキュアデバイスオブジェクト構造体
+struct SEC_OBJ
+{
+	UINT Type;								// オブジェクトの種類
+	UINT Object;							// オブジェクトハンドル
+	bool Private;							// プライベートフラグ
+	char *Name;								// 名前
+};
+
+#define	SEC_ERROR_NOERROR				0	// エラー無し
+#define	SEC_ERROR_INVALID_SLOT_NUMBER	1	// スロット番号が不正
+#define	SEC_ERROR_OPEN_SESSION			2	// セッション作成失敗
+#define	SEC_ERROR_SESSION_EXISTS		3	// すでにセッションが存在する
+#define	SEC_ERROR_NO_PIN_STR			4	// PIN 文字列が指定されていない
+#define	SEC_ERROR_ALREADY_LOGIN			5	// すでにログインしている
+#define	SEC_ERROR_BAD_PIN_CODE			6	// PIN コードが不正
+#define	SEC_ERROR_NO_SESSION			7	// セッションが存在しない
+#define	SEC_ERROR_DATA_TOO_BIG			8	// データが大きすぎる
+#define	SEC_ERROR_NOT_LOGIN				9	// ログインしていない
+#define	SEC_ERROR_BAD_PARAMETER			10	// パラメータ不正
+#define	SEC_ERROR_HARDWARE_ERROR		11	// ハードウェアエラー
+#define	SEC_ERROR_OBJ_NOT_FOUND			12	// オブジェクトが見つからない
+#define	SEC_ERROR_INVALID_CERT			13	// 証明書が不正
+
+
+#define	SEC_DATA						0	// データ
+#define	SEC_X							1	// 証明書
+#define	SEC_K							2	// 秘密鍵
+#define	SEC_P							3	// 公開鍵
+
+
+
+// 関数プロトタイプ
+void InitSecure();
+void FreeSecure();
+void InitSecureDeviceList();
+void FreeSecureDeviceList();
+bool IsDeviceSupported(SECURE_DEVICE *dev);
+LIST *GetSupportedDeviceList();
+LIST *GetSecureDeviceList();
+bool CheckSecureDeviceId(UINT id);
+SECURE_DEVICE *GetSecureDevice(UINT id);
+SECURE *OpenSec(UINT id);
+void CloseSec(SECURE *sec);
+bool OpenSecSession(SECURE *sec, UINT slot_number);
+void CloseSecSession(SECURE *sec);
+bool LoginSec(SECURE *sec, char *pin);
+void LogoutSec(SECURE *sec);
+void PrintSecInfo(SECURE *sec);
+LIST *EnumSecObject(SECURE *sec);
+void FreeSecObject(SEC_OBJ *obj);
+void FreeEnumSecObject(LIST *o);
+SEC_OBJ *FindSecObject(SECURE *sec, char *name, UINT type);
+bool CheckSecObject(SECURE *sec, char *name, UINT type);
+bool DeleteSecObjectByName(SECURE *sec, char *name, UINT type);
+SEC_OBJ *CloneSecObject(SEC_OBJ *obj);
+LIST *CloneEnumSecObject(LIST *o);
+void EraseEnumSecObjectCache(SECURE *sec);
+void DeleteSecObjFromEnumCache(SECURE *sec, char *name, UINT type);
+void AddSecObjToEnumCache(SECURE *sec, char *name, UINT type, bool private_obj, UINT object);
+bool WriteSecData(SECURE *sec, bool private_obj, char *name, void *data, UINT size);
+int ReadSecDataFromObject(SECURE *sec, SEC_OBJ *obj, void *data, UINT size);
+int ReadSecData(SECURE *sec, char *name, void *data, UINT size);
+bool DeleteSecObject(SECURE *sec, SEC_OBJ *obj);
+bool DeleteSecData(SECURE *sec, char *name);
+void UINT64ToCkDate(void *p_ck_date, UINT64 time64);
+bool WriteSecCert(SECURE *sec, bool private_obj, char *name, X *x);
+bool DeleteSecCert(SECURE *sec, char *name);
+X *ReadSecCertFromObject(SECURE *sec, SEC_OBJ *obj);
+X *ReadSecCert(SECURE *sec, char *name);
+bool WriteSecKey(SECURE *sec, bool private_obj, char *name, K *k);
+bool DeleteSecKey(SECURE *sec, char *name);
+bool SignSecByObject(SECURE *sec, SEC_OBJ *obj, void *dst, void *src, UINT size);
+bool SignSec(SECURE *sec, char *name, void *dst, void *src, UINT size);
+bool ChangePin(SECURE *sec, char *old_pin, char *new_pin);
+void TestSec();
+void TestSecMain(SECURE *sec);
+bool IsJPKI(bool id);
+
+bool LoadSecModule(SECURE *sec);
+void FreeSecModule(SECURE *sec);
+void GetSecInfo(SECURE *sec);
+void FreeSecInfo(SECURE *sec);
+SEC_INFO *TokenInfoToSecInfo(void *p_t);
+void FreeSecInfoMemory(SEC_INFO *s);
+
+#ifdef	OS_WIN32
+
+bool Win32IsDeviceSupported(SECURE_DEVICE *dev);
+bool Win32LoadSecModule(SECURE *sec);
+void Win32FreeSecModule(SECURE *sec);
+
+#endif	// OS_WIN32
+
+
+#ifdef	SECURE_C
+// 内部データ構造関連
+
+// サポートしているセキュアデバイスリスト
+static LIST *SecureDeviceList = NULL;
+
+// サポートしているハードウェアリスト
+// Q. なぜこのような静的なリストになっているのか? 動的に追加できないのか?
+// A. 今のところ、手抜きのためこのような実装になっている。
+SECURE_DEVICE SupportedList[] =
+{
+	{1,		SECURE_IC_CARD,		"Standard-9 IC Card",	"Dai Nippon Printing",	"DNPS9P11.DLL"},
+	{2,		SECURE_USB_TOKEN,	"ePass 1000",			"Feitian Technologies",	"EP1PK111.DLL"},
+	{3,		SECURE_IC_CARD,		"DNP Felica",			"Dai Nippon Printing",	"DNPFP11.DLL"},
+	{4,		SECURE_USB_TOKEN,	"eToken",				"Aladdin",				"ETPKCS11.DLL"},
+	{5,		SECURE_IC_CARD,		"Standard-9 IC Card",	"Fujitsu",				"F3EZSCL2.DLL"},
+	{6,		SECURE_IC_CARD,		"ASECard",				"Athena",				"ASEPKCS.DLL"},
+	{7,		SECURE_IC_CARD,		"Gemplus IC Card",		"Gemplus",				"PK2PRIV.DLL"},
+	{8,		SECURE_IC_CARD,		"1-Wire & iButton",		"DALLAS SEMICONDUCTOR",	"DSPKCS.DLL"},
+	{9,		SECURE_IC_CARD,		"JPKI IC Card",			"Japanese Government",	"JPKIPKCS11.DLL"},
+	{10,	SECURE_IC_CARD,		"LGWAN IC Card",		"Japanese Government",	"P11STD9.DLL"},
+	{11,	SECURE_IC_CARD,		"LGWAN IC Card",		"Japanese Government",	"P11STD9A.DLL"},
+	{12,	SECURE_USB_TOKEN,	"iKey 1000",			"Rainbow Technologies",	"K1PK112.DLL"},
+	{13,	SECURE_IC_CARD,		"JPKI IC Card #2",		"Japanese Government",	"libmusclepkcs11.dll"},
+	{14,	SECURE_USB_TOKEN,	"SafeSign",				"A.E.T.",				"aetpkss1.dll"},
+	{15,	SECURE_USB_TOKEN,	"LOCK STAR-PKI",		"Logicaltech Co.,LTD",	"LTPKCS11.dll"},
+	{16,	SECURE_USB_TOKEN,	"ePass 2000",			"Feitian Technologies",	"ep2pk11.dll"},
+	{17,	SECURE_IC_CARD,		"myuToken",				"iCanal Inc.",			"icardmodpk.dll"},
+};
+
+#ifdef	OS_WIN32
+
+// Win32 用内部データ
+typedef struct SEC_DATA_WIN32
+{
+	HINSTANCE hInst;
+} SEC_DATA_WIN32;
+
+#endif	// OS_WIN32
+
+#endif	// SECURE_C
+
+#endif	// SECURE_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Str.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Str.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Str.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,3068 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Str.c
+// 文字列処理ルーチン
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// トークン関数の呼び出し用ロック処理
+LOCK *token_lock = NULL;
+static char *default_spliter = " ,\t\r\n";
+
+typedef struct BYTESTR
+{
+	UINT64 base_value;
+	char *string;
+} BYTESTR;
+
+static BYTESTR bytestr[] =
+{
+	{0, "PBytes"},
+	{0, "TBytes"},
+	{0, "GBytes"},
+	{0, "MBytes"},
+	{0, "KBytes"},
+	{0, "Bytes"},
+};
+
+// HEX 文字列を 64 bit 整数に変換
+UINT64 HexToInt64(char *str)
+{
+	UINT len, i;
+	UINT64 ret = 0;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+	{
+		str += 2;
+	}
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		char c = str[i];
+
+		if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
+		{
+			ret = ret * 16ULL + (UINT64)HexTo4Bit(c);
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	return ret;
+}
+
+// HEX 文字列を 32 bit 整数に変換
+UINT HexToInt(char *str)
+{
+	UINT len, i;
+	UINT ret = 0;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
+	{
+		str += 2;
+	}
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		char c = str[i];
+
+		if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
+		{
+			ret = ret * 16 + (UINT)HexTo4Bit(c);
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	return ret;
+}
+
+// 64 bit 整数を HEX に変換
+void ToHex64(char *str, UINT64 value)
+{
+	char tmp[MAX_SIZE];
+	UINT wp = 0;
+	UINT len, i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	// 空文字に設定
+	StrCpy(tmp, 0, "");
+
+	// 末尾桁から追加する
+	while (true)
+	{
+		UINT a = (UINT)(value % (UINT64)16);
+		value = value / (UINT)16;
+		tmp[wp++] = FourBitToHex(a);
+		if (value == 0)
+		{
+			tmp[wp++] = 0;
+			break;
+		}
+	}
+
+	// 逆順にする
+	len = StrLen(tmp);
+	for (i = 0;i < len;i++)
+	{
+		str[len - i - 1] = tmp[i];
+	}
+	str[len] = 0;
+}
+
+// 32 bit 整数を HEX に変換
+void ToHex(char *str, UINT value)
+{
+	char tmp[MAX_SIZE];
+	UINT wp = 0;
+	UINT len, i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	// 空文字に設定
+	StrCpy(tmp, 0, "");
+
+	// 末尾桁から追加する
+	while (true)
+	{
+		UINT a = (UINT)(value % (UINT)16);
+		value = value / (UINT)16;
+		tmp[wp++] = FourBitToHex(a);
+		if (value == 0)
+		{
+			tmp[wp++] = 0;
+			break;
+		}
+	}
+
+	// 逆順にする
+	len = StrLen(tmp);
+	for (i = 0;i < len;i++)
+	{
+		str[len - i - 1] = tmp[i];
+	}
+	str[len] = 0;
+}
+
+// 4 bit 数値を 16 進文字列に変換
+char FourBitToHex(UINT value)
+{
+	value = value % 16;
+
+	if (value <= 9)
+	{
+		return '0' + value;
+	}
+	else
+	{
+		return 'a' + (value - 10);
+	}
+}
+
+// 16 進文字列を 4 bit 整数に変換
+UINT HexTo4Bit(char c)
+{
+	if ('0' <= c && c <= '9')
+	{
+		return c - '0';
+	}
+	else if ('a' <= c && c <= 'f')
+	{
+		return c - 'a' + 10;
+	}
+	else if ('A' <= c && c <= 'F')
+	{
+		return c - 'A' + 10;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
+// 標準のトークン区切り文字を取得する
+char *DefaultTokenSplitChars()
+{
+	return " ,\t\r\n";
+}
+
+// 指定された文字が文字列に含まれるかどうかチェック
+bool IsCharInStr(char *str, char c)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		if (str[i] == c)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// 文字列からトークンを切り出す (区切り文字間の空間を無視しない)
+TOKEN_LIST *ParseTokenWithNullStr(char *str, char *split_chars)
+{
+	LIST *o;
+	UINT i, len;
+	BUF *b;
+	char zero = 0;
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NullToken();
+	}
+	if (split_chars == NULL)
+	{
+		split_chars = DefaultTokenSplitChars();
+	}
+
+	b = NewBuf();
+	o = NewListFast(NULL);
+
+	len = StrLen(str);
+
+	for (i = 0;i < (len + 1);i++)
+	{
+		char c = str[i];
+		bool flag = IsCharInStr(split_chars, c);
+
+		if (c == '\0')
+		{
+			flag = true;
+		}
+
+		if (flag == false)
+		{
+			WriteBuf(b, &c, sizeof(char));
+		}
+		else
+		{
+			WriteBuf(b, &zero, sizeof(char));
+
+			Insert(o, CopyStr((char *)b->Buf));
+			ClearBuf(b);
+		}
+	}
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+	FreeBuf(b);
+
+	return t;
+}
+
+// 文字列からトークンを切り出す (区切り文字間の空間を無視する)
+TOKEN_LIST *ParseTokenWithoutNullStr(char *str, char *split_chars)
+{
+	LIST *o;
+	UINT i, len;
+	bool last_flag;
+	BUF *b;
+	char zero = 0;
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NullToken();
+	}
+	if (split_chars == NULL)
+	{
+		split_chars = DefaultTokenSplitChars();
+	}
+
+	b = NewBuf();
+	o = NewListFast(NULL);
+
+	len = StrLen(str);
+	last_flag = false;
+
+	for (i = 0;i < (len + 1);i++)
+	{
+		char c = str[i];
+		bool flag = IsCharInStr(split_chars, c);
+
+		if (c == '\0')
+		{
+			flag = true;
+		}
+
+		if (flag == false)
+		{
+			WriteBuf(b, &c, sizeof(char));
+		}
+		else
+		{
+			if (last_flag == false)
+			{
+				WriteBuf(b, &zero, sizeof(char));
+
+				if ((StrLen((char *)b->Buf)) != 0)
+				{
+					Insert(o, CopyStr((char *)b->Buf));
+				}
+				ClearBuf(b);
+			}
+		}
+
+		last_flag = flag;
+	}
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+	FreeBuf(b);
+
+	return t;
+}
+
+// 文字列が含まれているかどうかチェック
+bool InStr(char *str, char *keyword)
+{
+	return InStrEx(str, keyword, false);
+}
+bool InStrEx(char *str, char *keyword, bool case_sensitive)
+{
+	// 引数チェック
+	if (IsEmptyStr(str) || IsEmptyStr(keyword))
+	{
+		return false;
+	}
+
+	if (SearchStrEx(str, keyword, 0, case_sensitive) == INFINITE)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// INI から値を取得
+UINT IniIntValue(LIST *o, char *key)
+{
+	INI_ENTRY *e;
+	// 引数チェック
+	if (o == NULL || key == NULL)
+	{
+		return 0;
+	}
+
+	e = GetIniEntry(o, key);
+	if (e == NULL)
+	{
+		return 0;
+	}
+
+	return ToInt(e->Value);
+}
+UINT64 IniInt64Value(LIST *o, char *key)
+{
+	INI_ENTRY *e;
+	// 引数チェック
+	if (o == NULL || key == NULL)
+	{
+		return 0;
+	}
+
+	e = GetIniEntry(o, key);
+	if (e == NULL)
+	{
+		return 0;
+	}
+
+	return ToInt64(e->Value);
+}
+char *IniStrValue(LIST *o, char *key)
+{
+	INI_ENTRY *e;
+	// 引数チェック
+	if (o == NULL || key == NULL)
+	{
+		return 0;
+	}
+
+	e = GetIniEntry(o, key);
+	if (e == NULL)
+	{
+		return "";
+	}
+
+	return e->Value;
+}
+wchar_t *IniUniStrValue(LIST *o, char *key)
+{
+	INI_ENTRY *e;
+	// 引数チェック
+	if (o == NULL || key == NULL)
+	{
+		return 0;
+	}
+
+	e = GetIniEntry(o, key);
+	if (e == NULL)
+	{
+		return L"";
+	}
+
+	return e->UnicodeValue;
+}
+
+// INI を解放する
+void FreeIni(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		INI_ENTRY *e = LIST_DATA(o, i);
+
+		Free(e->Key);
+		Free(e->Value);
+		Free(e->UnicodeValue);
+
+		Free(e);
+	}
+
+	ReleaseList(o);
+}
+
+// INI ファイルのエントリを取得する
+INI_ENTRY *GetIniEntry(LIST *o, char *key)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL || key == NULL)
+	{
+		return NULL;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		INI_ENTRY *e = LIST_DATA(o, i);
+
+		if (StrCmpi(e->Key, key) == 0)
+		{
+			return e;
+		}
+	}
+
+	return NULL;
+}
+
+// INI ファイルを読み込む
+LIST *ReadIni(BUF *b)
+{
+	LIST *o;
+	// 引数チェック
+	if (b == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(NULL);
+
+	SeekBuf(b, 0, 0);
+
+	while (true)
+	{
+		char *line = CfgReadNextLine(b);
+
+		if (line == NULL)
+		{
+			break;
+		}
+
+		Trim(line);
+
+		if (IsEmptyStr(line) == false)
+		{
+			if (StartWith(line, "#") == false &&
+				StartWith(line, "//") == false &&
+				StartWith(line, ";") == false)
+			{
+				char *key, *value;
+				UINT size = StrLen(line) + 1;
+
+				key = ZeroMalloc(size);
+				value = ZeroMalloc(size);
+
+				if (GetKeyAndValue(line, key, size, value, size, NULL))
+				{
+					UINT uni_size;
+					INI_ENTRY *e = ZeroMalloc(sizeof(INI_ENTRY));
+					e->Key = CopyStr(key);
+					e->Value = CopyStr(value);
+
+					uni_size = CalcUtf8ToUni((BYTE *)value, StrLen(value));
+					e->UnicodeValue = ZeroMalloc(uni_size);
+					Utf8ToUni(e->UnicodeValue, uni_size, (BYTE *)value, StrLen(value));
+
+					Add(o, e);
+				}
+
+				Free(key);
+				Free(value);
+			}
+		}
+
+		Free(line);
+	}
+
+	return o;
+}
+
+// 指定された文字が区切り文字かどうかチェック
+bool IsSplitChar(char c, char *split_str)
+{
+	UINT i, len;
+	char c_upper = ToUpper(c);
+	if (split_str == NULL)
+	{
+		split_str = default_spliter;
+	}
+
+	len = StrLen(split_str);
+
+	for (i = 0;i < len;i++)
+	{
+		if (ToUpper(split_str[i]) == c_upper)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// 文字列からキーと値を取得する
+bool GetKeyAndValue(char *str, char *key, UINT key_size, char *value, UINT value_size, char *split_str)
+{
+	UINT mode = 0;
+	UINT wp1 = 0, wp2 = 0;
+	UINT i, len;
+	char *key_tmp, *value_tmp;
+	bool ret = false;
+	if (split_str == NULL)
+	{
+		split_str = default_spliter;
+	}
+
+	len = StrLen(str);
+
+	key_tmp = ZeroMalloc(len + 1);
+	value_tmp = ZeroMalloc(len + 1);
+
+	for (i = 0;i < len;i++)
+	{
+		char c = str[i];
+
+		switch (mode)
+		{
+		case 0:
+			if (IsSplitChar(c, split_str) == false)
+			{
+				mode = 1;
+				key_tmp[wp1] = c;
+				wp1++;
+			}
+			break;
+
+		case 1:
+			if (IsSplitChar(c, split_str) == false)
+			{
+				key_tmp[wp1] = c;
+				wp1++;
+			}
+			else
+			{
+				mode = 2;
+			}
+			break;
+
+		case 2:
+			if (IsSplitChar(c, split_str) == false)
+			{
+				mode = 3;
+				value_tmp[wp2] = c;
+				wp2++;
+			}
+			break;
+
+		case 3:
+			value_tmp[wp2] = c;
+			wp2++;
+			break;
+		}
+	}
+
+	if (mode != 0)
+	{
+		ret = true;
+		StrCpy(key, key_size, key_tmp);
+		StrCpy(value, value_size, value_tmp);
+	}
+
+	Free(key_tmp);
+	Free(value_tmp);
+
+	return ret;
+}
+
+// 指定した文字の列を生成する
+char *MakeCharArray(char c, UINT count)
+{
+	UINT i;
+	char *ret = Malloc(count + 1);
+
+	for (i = 0;i < count;i++)
+	{
+		ret[i] = c;
+	}
+
+	ret[count] = 0;
+
+	return ret;
+}
+void MakeCharArray2(char *str, char c, UINT count)
+{
+	UINT i;
+
+	for (i = 0;i < count;i++)
+	{
+		str[i] = c;
+	}
+
+	str[count] = 0;
+}
+
+// 指定した文字列の横幅を取得する
+UINT StrWidth(char *str)
+{
+	wchar_t *s;
+	UINT ret;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	s = CopyStrToUni(str);
+	ret = UniStrWidth(s);
+	Free(s);
+
+	return ret;
+}
+
+// 指定した文字列がすべて大文字かどうかチェックする
+bool IsAllUpperStr(char *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	len = StrLen(str);
+
+	for (i = 0;i < len;i++)
+	{
+		char c = str[i];
+
+		if ((c >= '0' && c <= '9') ||
+			(c >= 'A' && c <= 'Z'))
+		{
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	return true;
+}
+
+// 改行コードを正規化する
+char *NormalizeCrlf(char *str)
+{
+	char *ret;
+	UINT ret_size, i, len, wp;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = StrLen(str);
+	ret_size = sizeof(char) * (len + 32) * 2;
+	ret = Malloc(ret_size);
+
+	wp = 0;
+
+	for (i = 0;i < len;i++)
+	{
+		char c = str[i];
+
+		switch (c)
+		{
+		case '\r':
+			if (str[i + 1] == '\n')
+			{
+				i++;
+			}
+			ret[wp++] = '\r';
+			ret[wp++] = '\n';
+			break;
+
+		case '\n':
+			ret[wp++] = '\r';
+			ret[wp++] = '\n';
+			break;
+
+		default:
+			ret[wp++] = c;
+			break;
+		}
+	}
+
+	ret[wp++] = 0;
+
+	return ret;
+}
+
+// トークンリストを重複の無いものに変換する
+TOKEN_LIST *UniqueToken(TOKEN_LIST *t)
+{
+	UINT i, num, j, n;
+	TOKEN_LIST *ret;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	num = 0;
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		bool exists = false;
+
+		for (j = 0;j < i;j++)
+		{
+			if (StrCmpi(t->Token[j], t->Token[i]) == 0)
+			{
+				exists = true;
+				break;
+			}
+		}
+
+		if (exists == false)
+		{
+			num++;
+		}
+	}
+
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->Token = ZeroMalloc(sizeof(char *) * num);
+	ret->NumTokens = num;
+
+	n = 0;
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		bool exists = false;
+
+		for (j = 0;j < i;j++)
+		{
+			if (StrCmpi(t->Token[j], t->Token[i]) == 0)
+			{
+				exists = true;
+				break;
+			}
+		}
+
+		if (exists == false)
+		{
+			ret->Token[n++] = CopyStr(t->Token[i]);
+		}
+	}
+
+	return ret;
+}
+
+// バイト文字列に変換する (1,000 単位)
+void ToStrByte1000(char *str, UINT size, UINT64 v)
+{
+	UINT i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	// gcc での警告対策
+	bytestr[0].base_value = 1000000000UL;
+	bytestr[0].base_value *= 1000UL;
+	bytestr[0].base_value *= 1000UL;
+	bytestr[1].base_value = 1000000000UL;
+	bytestr[1].base_value *= 1000UL;
+	bytestr[2].base_value = 1000000000UL;
+	bytestr[3].base_value = 1000000UL;
+	bytestr[4].base_value = 1000UL;
+	bytestr[5].base_value = 0UL;
+
+	for (i = 0;i < sizeof(bytestr) / sizeof(bytestr[0]);i++)
+	{
+		BYTESTR *b = &bytestr[i];
+
+		if ((v * 11UL) / 10UL >= b->base_value)
+		{
+			if (b->base_value != 0)
+			{
+				double d = (double)v / (double)b->base_value;
+				Format(str, size, "%.2f %s", d, b->string);
+			}
+			else
+			{
+				Format(str, size, "%I64u %s", v, b->string);
+			}
+
+			break;
+		}
+	}
+}
+
+// バイト文字列に変換する
+void ToStrByte(char *str, UINT size, UINT64 v)
+{
+	UINT i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	// gcc での警告対策
+	bytestr[0].base_value = 1073741824UL;
+	bytestr[0].base_value *= 1024UL;
+	bytestr[0].base_value *= 1024UL;
+	bytestr[1].base_value = 1073741824UL;
+	bytestr[1].base_value *= 1024UL;
+	bytestr[2].base_value = 1073741824UL;
+	bytestr[3].base_value = 1048576UL;
+	bytestr[4].base_value = 1024UL;
+	bytestr[5].base_value = 0UL;
+
+	for (i = 0;i < sizeof(bytestr) / sizeof(bytestr[0]);i++)
+	{
+		BYTESTR *b = &bytestr[i];
+
+		if ((v * 11UL) / 10UL >= b->base_value)
+		{
+			if (b->base_value != 0)
+			{
+				double d = (double)v / (double)b->base_value;
+				Format(str, size, "%.2f %s", d, b->string);
+			}
+			else
+			{
+				Format(str, size, "%I64u %s", v, b->string);
+			}
+
+			break;
+		}
+	}
+}
+
+// 数字を文字列に変換して 3 桁ずつカンマで区切る
+void ToStr3(char *str, UINT size, UINT64 v)
+{
+	char tmp[128];
+	char tmp2[128];
+	UINT i, len, wp;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	ToStr64(tmp, v);
+
+	wp = 0;
+	len = StrLen(tmp);
+
+	for (i = len - 1;((int)i) >= 0;i--)
+	{
+		tmp2[wp++] = tmp[i];
+	}
+	tmp2[wp++] = 0;
+
+	wp = 0;
+
+	for (i = 0;i < len;i++)
+	{
+		if (i != 0 && (i % 3) == 0)
+		{
+			tmp[wp++] = ',';
+		}
+		tmp[wp++] = tmp2[i];
+	}
+	tmp[wp++] = 0;
+	wp = 0;
+	len = StrLen(tmp);
+
+	for (i = len - 1;((int)i) >= 0;i--)
+	{
+		tmp2[wp++] = tmp[i];
+	}
+	tmp2[wp++] = 0;
+
+	StrCpy(str, size, tmp2);
+}
+
+// MAC アドレスを文字列にする
+void MacToStr(char *str, UINT size, UCHAR *mac_address)
+{
+	// 引数チェック
+	if (str == NULL || mac_address == NULL)
+	{
+		return;
+	}
+
+	Format(str, size, "%02X-%02X-%02X-%02X-%02X-%02X",
+		mac_address[0],
+		mac_address[1],
+		mac_address[2],
+		mac_address[3],
+		mac_address[4],
+		mac_address[5]);
+}
+
+// 文字列が空かどうか調べる
+bool IsEmptyStr(char *str)
+{
+	char *s;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return true;
+	}
+
+	s = CopyStr(str);
+	Trim(s);
+
+	if (StrLen(s) == 0)
+	{
+		Free(s);
+		return true;
+	}
+	else
+	{
+		Free(s);
+		return false;
+	}
+}
+
+// トークンリストを文字列リストに変換する
+LIST *TokenListToList(TOKEN_LIST *t)
+{
+	UINT i;
+	LIST *o;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(NULL);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		Insert(o, CopyStr(t->Token[i]));
+	}
+
+	return o;
+}
+
+// 文字列リストをトークンリストに変換する
+TOKEN_LIST *ListToTokenList(LIST *o)
+{
+	UINT i;
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		t->Token[i] = CopyStr(LIST_DATA(o, i));
+	}
+
+	return t;
+}
+
+// 文字列リストを解放する
+void FreeStrList(LIST *o)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		char *s = LIST_DATA(o, i);
+		Free(s);
+	}
+
+	ReleaseList(o);
+}
+
+// 文字列リストを文字列に変換する
+BUF *StrListToStr(LIST *o)
+{
+	BUF *b;
+	UINT i;
+	char c;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return NULL;
+	}
+	b = NewBuf();
+
+	for (i = 0;i < LIST_NUM(o);i++)
+	{
+		char *s = LIST_DATA(o, i);
+		WriteBuf(b, s, StrLen(s) + 1);
+	}
+
+	c = 0;
+	WriteBuf(b, &c, 1);
+
+	SeekBuf(b, 0, 0);
+
+	return b;
+}
+
+// 文字列 (NULL区切り) をリストに変換する
+LIST *StrToStrList(char *str, UINT size)
+{
+	LIST *o;
+	char *tmp;
+	UINT tmp_size;
+	UINT i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(NULL);
+
+	i = 0;
+	while (true)
+	{
+		if (i >= size)
+		{
+			break;
+		}
+		if (*str == 0)
+		{
+			break;
+		}
+
+		tmp_size = StrSize(str);
+		tmp = ZeroMalloc(tmp_size);
+		StrCpy(tmp, tmp_size, str);
+		Add(o, tmp);
+		str += StrLen(str) + 1;
+		i++;
+	}
+
+	return o;
+}
+
+// 指定された文字列が数字かどうかチェック
+bool IsNum(char *str)
+{
+	char c;
+	UINT i, len;
+	UINT n = 0;
+	char tmp[MAX_SIZE];
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(tmp, sizeof(tmp), str);
+	Trim(tmp);
+
+	if (StrLen(tmp) == 0)
+	{
+		return false;
+	}
+
+	t = ParseToken(tmp, " ");
+
+	if (t->NumTokens >= 1)
+	{
+		StrCpy(tmp, sizeof(tmp), t->Token[0]);
+	}
+
+	FreeToken(t);
+
+	len = StrLen(tmp);
+	for (i = 0;i < len;i++)
+	{
+		bool b = false;
+		c = tmp[i];
+		if (('0' <= c && c <= '9') || (c == '+') || (c == '-') || (c == ','))
+		{
+			b = true;
+		}
+
+		if (b == false)
+		{
+			return false;
+		}
+	}
+
+	for (i = 0;i < len;i++)
+	{
+		c = tmp[i];
+		if (c == '-')
+		{
+			n++;
+		}
+	}
+	if (n >= 2)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 中身が無いトークンリスト
+TOKEN_LIST *NullToken()
+{
+	TOKEN_LIST *ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->Token = ZeroMalloc(0);
+
+	return ret;
+}
+
+// トークンリストのコピー
+TOKEN_LIST *CopyToken(TOKEN_LIST *src)
+{
+	TOKEN_LIST *ret;
+	UINT i;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return NULL;
+	}
+
+	ret = ZeroMalloc(sizeof(TOKEN_LIST));
+	ret->NumTokens = src->NumTokens;
+	ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+	for (i = 0;i < ret->NumTokens;i++)
+	{
+		ret->Token[i] = CopyStr(src->Token[i]);
+	}
+
+	return ret;
+}
+
+// コマンドラインをパースする
+TOKEN_LIST *ParseCmdLine(char *str)
+{
+	TOKEN_LIST *t;
+	LIST *o;
+	UINT i, len, wp, mode;
+	char c;
+	char *tmp;
+	bool ignore_space = false;
+	// 引数チェック
+	if (str == NULL)
+	{
+		// トークン無し
+		return NullToken();
+	}
+
+	o = NewListFast(NULL);
+	tmp = Malloc(StrSize(str) + 32);
+
+	wp = 0;
+	mode = 0;
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		c = str[i];
+
+		switch (mode)
+		{
+		case 0:
+			// 次のトークンを発見するモード
+			if (c == ' ' || c == '\t')
+			{
+				// 次の文字へ進める
+			}
+			else
+			{
+				// トークンの開始
+				if (c == '\"')
+				{
+					if (str[i + 1] == '\"')
+					{
+						// 2 重の " は 1 個の " 文字として見なす
+						tmp[wp++] = '\"';
+						i++;
+					}
+					else
+					{
+						// 1 個の " はスペース無視フラグを有効にする
+						ignore_space = true;
+					}
+				}
+				else
+				{
+					tmp[wp++] = c;
+				}
+
+				mode = 1;
+			}
+			break;
+
+		case 1:
+			if (ignore_space == false && (c == ' ' || c == '\t'))
+			{
+				// トークンの終了
+				tmp[wp++] = 0;
+				wp = 0;
+
+				Insert(o, CopyStr(tmp));
+				mode = 0;
+			}
+			else
+			{
+				if (c == '\"')
+				{
+					if (str[i + 1] == '\"')
+					{
+						// 2 重の " は 1 個の " 文字として見なす
+						tmp[wp++] = L'\"';
+						i++;
+					}
+					else
+					{
+						if (ignore_space == false)
+						{
+							// 1 個の " はスペース無視フラグを有効にする
+							ignore_space = true;
+						}
+						else
+						{
+							// スペース無視フラグを無効にする
+							ignore_space = false;
+						}
+					}
+				}
+				else
+				{
+					tmp[wp++] = c;
+				}
+			}
+			break;
+		}
+	}
+
+	if (wp != 0)
+	{
+		tmp[wp++] = 0;
+		Insert(o, CopyStr(tmp));
+	}
+
+	Free(tmp);
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+
+	return t;
+}
+
+// 64bit 整数を文字列に変換
+void ToStr64(char *str, UINT64 value)
+{
+	char tmp[MAX_SIZE];
+	UINT wp = 0;
+	UINT len, i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	// 空文字に設定
+	StrCpy(tmp, 0, "");
+
+	// 末尾桁から追加する
+	while (true)
+	{
+		UINT a = (UINT)(value % (UINT64)10);
+		value = value / (UINT64)10;
+		tmp[wp++] = (char)('0' + a);
+		if (value == 0)
+		{
+			tmp[wp++] = 0;
+			break;
+		}
+	}
+
+	// 逆順にする
+	len = StrLen(tmp);
+	for (i = 0;i < len;i++)
+	{
+		str[len - i - 1] = tmp[i];
+	}
+	str[len] = 0;
+}
+
+// 文字列を 64bit 整数に変換
+UINT64 ToInt64(char *str)
+{
+	UINT len, i;
+	UINT64 ret = 0;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		char c = str[i];
+		if (c != ',')
+		{
+			if ('0' <= c && c <= '9')
+			{
+				ret = ret * (UINT64)10 + (UINT64)(c - '0');
+			}
+			else
+			{
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+// str が key で終了するかどうかチェック
+bool EndWith(char *str, char *key)
+{
+	UINT str_len;
+	UINT key_len;
+	// 引数チェック
+	if (str == NULL || key == NULL)
+	{
+		return false;
+	}
+
+	// 比較
+	str_len = StrLen(str);
+	key_len = StrLen(key);
+	if (str_len < key_len)
+	{
+		return false;
+	}
+
+	if (StrCmpi(str + (str_len - key_len), key) == 0)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+// str が key で始まるかどうかチェック
+bool StartWith(char *str, char *key)
+{
+	UINT str_len;
+	UINT key_len;
+	char *tmp;
+	bool ret;
+	// 引数チェック
+	if (str == NULL || key == NULL)
+	{
+		return false;
+	}
+
+	// 比較
+	str_len = StrLen(str);
+	key_len = StrLen(key);
+	if (str_len < key_len)
+	{
+		return false;
+	}
+	if (str_len == 0 || key_len == 0)
+	{
+		return false;
+	}
+	tmp = CopyStr(str);
+	tmp[key_len] = 0;
+
+	if (StrCmpi(tmp, key) == 0)
+	{
+		ret = true;
+	}
+	else
+	{
+		ret = false;
+	}
+
+	Free(tmp);
+
+	return ret;
+}
+
+// バイナリデータを表示
+void PrintBin(void *data, UINT size)
+{
+	char *tmp;
+	UINT i;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return;
+	}
+
+	i = size * 3 + 1;
+	tmp = Malloc(i);
+	BinToStrEx(tmp, i, data, size);
+	Print("%s\n", tmp);
+	Free(tmp);
+}
+
+// 文字列を MAC アドレスに変換する
+bool StrToMac(UCHAR *mac_address, char *str)
+{
+	BUF *b;
+	// 引数チェック
+	if (mac_address == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	b = StrToBin(str);
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	if (b->Size != 6)
+	{
+		FreeBuf(b);
+		return false;
+	}
+
+	Copy(mac_address, b->Buf, 6);
+
+	FreeBuf(b);
+
+	return true;
+}
+
+// 16 進文字列をバイナリデータに変換する
+BUF *StrToBin(char *str)
+{
+	BUF *b;
+	UINT len, i;
+	char tmp[3];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = StrLen(str);
+	tmp[0] = 0;
+	b = NewBuf();
+	for (i = 0;i < len;i++)
+	{
+		char c = str[i];
+		c = ToUpper(c);
+		if (('0' <= c && c <= '9') || ('A' <= c && c <= 'F'))
+		{
+			if (tmp[0] == 0)
+			{
+				tmp[0] = c;
+				tmp[1] = 0;
+			}
+			else if (tmp[1] == 0)
+			{
+				UCHAR data;
+				char tmp2[64];
+				tmp[1] = c;
+				tmp[2] = 0;
+				StrCpy(tmp2, sizeof(tmp2), "0x");
+				StrCat(tmp2, sizeof(tmp2), tmp);
+				data = (UCHAR)strtoul(tmp2, NULL, 0);
+				WriteBuf(b, &data, 1);
+				Zero(tmp, sizeof(tmp));	
+			}
+		}
+		else if (c == ' ' || c == ',' || c == '-' || c == ':')
+		{
+			// 何もしない
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	return b;
+}
+
+// バイナリデータを 16 進文字列に変換する (スペースも入れる)
+void BinToStrEx(char *str, UINT str_size, void *data, UINT data_size)
+{
+	char *tmp;
+	UCHAR *buf = (UCHAR *)data;
+	UINT size;
+	UINT i;
+	// 引数チェック
+	if (str == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// サイズの計算
+	size = data_size * 3 + 1;
+	// メモリ確保
+	tmp = ZeroMalloc(size);
+	// 変換
+	for (i = 0;i < data_size;i++)
+	{
+		Format(&tmp[i * 3], 0, "%02X ", buf[i]);
+	}
+	Trim(tmp);
+	// コピー
+	StrCpy(str, str_size, tmp);
+	// メモリ解放
+	Free(tmp);
+}
+void BinToStrEx2(char *str, UINT str_size, void *data, UINT data_size, char padding_char)
+{
+	char *tmp;
+	UCHAR *buf = (UCHAR *)data;
+	UINT size;
+	UINT i;
+	// 引数チェック
+	if (str == NULL || data == NULL)
+	{
+		return;
+	}
+
+	// サイズの計算
+	size = data_size * 3 + 1;
+	// メモリ確保
+	tmp = ZeroMalloc(size);
+	// 変換
+	for (i = 0;i < data_size;i++)
+	{
+		Format(&tmp[i * 3], 0, "%02X%c", buf[i], padding_char);
+	}
+	if (StrLen(tmp) >= 1)
+	{
+		if (tmp[StrLen(tmp) - 1] == padding_char)
+		{
+			tmp[StrLen(tmp) - 1] = 0;
+		}
+	}
+	// コピー
+	StrCpy(str, str_size, tmp);
+	// メモリ解放
+	Free(tmp);
+}
+// バイナリデータを文字列に変換してコピーする
+char *CopyBinToStrEx(void *data, UINT data_size)
+{
+	char *ret;
+	UINT size;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return NULL;
+	}
+
+	size = data_size * 3 + 1;
+	ret = ZeroMalloc(size);
+
+	BinToStrEx(ret, size, data, data_size);
+
+	return ret;
+}
+char *CopyBinToStr(void *data, UINT data_size)
+{
+	char *ret;
+	UINT size;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return NULL;
+	}
+
+	size = data_size * 2 + 1;
+	ret = ZeroMalloc(size);
+
+	BinToStr(ret, size, data, data_size);
+
+	return ret;
+}
+
+// バイナリデータを 16 進文字列に変換する
+void BinToStr(char *str, UINT str_size, void *data, UINT data_size)
+{
+	char *tmp;
+	UCHAR *buf = (UCHAR *)data;
+	UINT size;
+	UINT i;
+	// 引数チェック
+	if (str == NULL || data == NULL)
+	{
+		if (str != NULL)
+		{
+			str[0] = 0;
+		}
+		return;
+	}
+
+	// サイズの計算
+	size = data_size * 2 + 1;
+	// メモリ確保
+	tmp = ZeroMalloc(size);
+	// 変換
+	for (i = 0;i < data_size;i++)
+	{
+		sprintf(&tmp[i * 2], "%02X", buf[i]);
+	}
+	// コピー
+	StrCpy(str, str_size, tmp);
+	// メモリ解放
+	Free(tmp);
+}
+void BinToStrW(wchar_t *str, UINT str_size, void *data, UINT data_size)
+{
+	char *tmp;
+	UINT tmp_size;
+	// 引数チェック
+	if (str == NULL || data == NULL)
+	{
+		if (str != NULL)
+		{
+			str[0] = 0;
+		}
+		return;
+	}
+
+	tmp_size = (data_size * 2 + 4) * sizeof(wchar_t);
+	tmp = ZeroMalloc(tmp_size);
+
+	BinToStr(tmp, tmp_size, data, data_size);
+
+	StrToUni(str, str_size, tmp);
+
+	Free(tmp);
+}
+
+// 160 ビット列を文字列にする
+void Bit160ToStr(char *str, UCHAR *data)
+{
+	// 引数チェック
+	if (str == NULL || data == NULL)
+	{
+		return;
+	}
+
+	Format(str, 0,
+		"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+		data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], 
+		data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19]);
+}
+
+// 128 ビット列を文字列にする
+void Bit128ToStr(char *str, UCHAR *data)
+{
+	// 引数チェック
+	if (str == NULL || data == NULL)
+	{
+		return;
+	}
+
+	Format(str, 0,
+		"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
+		data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], 
+		data[10], data[11], data[12], data[13], data[14], data[15]);
+}
+
+// 文字列をコピーする
+char *CopyStr(char *str)
+{
+	UINT len;
+	char *dst;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NULL;
+	}
+
+	len = StrLen(str);
+	dst = Malloc(len + 1);
+	StrCpy(dst, len + 1, str);
+	return dst;
+}
+
+// 安全な文字列かどうかチェック
+bool IsSafeStr(char *str)
+{
+	UINT i, len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		if (IsSafeChar(str[i]) == false)
+		{
+			return false;
+		}
+	}
+	if (str[0] == ' ')
+	{
+		return false;
+	}
+	if (len != 0)
+	{
+		if (str[len - 1] == ' ')
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+// 安全な文字かどうかチェック
+bool IsSafeChar(char c)
+{
+	UINT i, len;
+	char *check_str =
+		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+		"abcdefghijklmnopqrstuvwxyz"
+		"0123456789"
+		" ()-_#%&.";
+
+	len = StrLen(check_str);
+	for (i = 0;i < len;i++)
+	{
+		if (c == check_str[i])
+		{
+			return true;
+		}
+	}
+	return false;
+}
+
+// 文字列から指定した文字を削除する
+void TruncateCharFromStr(char *str, char replace)
+{
+	char *src,*dst;
+
+	if (str == NULL)
+	{
+		return;
+	}
+
+	src = dst = str;
+
+	while(*src != '\0')
+	{
+		if(*src != replace)
+		{
+			*dst = *src;
+			dst++;
+		}
+		src++;
+	}
+	*dst = *src;
+
+	//BUF *b = NewBuf();
+	//UINT i, len;
+	//char zero = 0;
+
+	//len = StrLen(str);
+	//for (i = 0;i < len;i++)
+	//{
+	//	char c = str[i];
+
+	//	if (c != replace)
+	//	{
+	//		WriteBuf(b, &c, 1);
+	//	}
+	//}
+
+	//if (b->Size == 0)
+	//{
+	//	char c = '_';
+	//	WriteBuf(b, &c, 1);
+	//}
+
+	//WriteBuf(b, &zero, 1);
+
+	//StrCpy(str, 0, b->Buf);
+
+	//FreeBuf(b);
+}
+
+// 安全な文字以外を置き換える
+void EnSafeStr(char *str, char replace)
+{
+	if (str == NULL)
+	{
+		return;
+	}
+
+	while(*str != '\0')
+	{
+		if(IsSafeChar(*str) == false)
+		{
+			*str = replace;
+		}
+		str++;
+	}
+}
+
+// 文字列ライブラリの動作チェック
+bool CheckStringLibrary()
+{
+	wchar_t *compare_str = L"TEST_TEST_123_123456789012345";
+	char *teststr = "TEST";
+	wchar_t *testunistr = L"TEST";
+	wchar_t tmp[64];
+	UINT i1 = 123;
+	UINT64 i2 = 123456789012345ULL;
+
+	UniFormat(tmp, sizeof(tmp), L"%S_%s_%u_%I64u", teststr, testunistr,
+		i1, i2);
+
+	if (UniStrCmpi(tmp, compare_str) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 文字列ライブラリの初期化
+void InitStringLibrary()
+{
+	// トークン用ロックの作成
+	token_lock = NewLock();
+
+	// 国際ライブラリの初期化
+	InitInternational();
+
+	// 動作チェック
+	if (CheckStringLibrary() == false)
+	{
+#ifdef	OS_WIN32
+		Alert("String Library Init Failed.\r\nPlease check your locale settings.", NULL);
+#else	// OS_WIN32
+		Alert("String Library Init Failed.\r\nPlease check your locale settings and iconv() libraries.", NULL);
+#endif	// OS_WIN32
+		exit(0);
+	}
+}
+
+// 文字列ライブラリの解放
+void FreeStringLibrary()
+{
+	// 国際ライブラリの解放
+	FreeInternational();
+
+	// トークン用ロックの解放
+	DeleteLock(token_lock);
+	token_lock = NULL;
+}
+
+// 文字列の置換 (大文字小文字を区別しない)
+UINT ReplaceStri(char *dst, UINT size, char *string, char *old_keyword, char *new_keyword)
+{
+	return ReplaceStrEx(dst, size, string, old_keyword, new_keyword, false);
+}
+
+// 文字列の置換 (大文字小文字を区別する)
+UINT ReplaceStr(char *dst, UINT size, char *string, char *old_keyword, char *new_keyword)
+{
+	return ReplaceStrEx(dst, size, string, old_keyword, new_keyword, true);
+}
+
+// 文字列の置換
+UINT ReplaceStrEx(char *dst, UINT size, char *string, char *old_keyword, char *new_keyword, bool case_sensitive)
+{
+	UINT i, j, num;
+	UINT len_string, len_old, len_new;
+	UINT len_ret;
+	UINT wp;
+	char *ret;
+	// 引数チェック
+	if (string == NULL || old_keyword == NULL || new_keyword == NULL)
+	{
+		return 0;
+	}
+
+	// 文字列長の取得
+	len_string = StrLen(string);
+	len_old = StrLen(old_keyword);
+	len_new = StrLen(new_keyword);
+
+	// 最終文字列長の計算
+	len_ret = CalcReplaceStrEx(string, old_keyword, new_keyword, case_sensitive);
+	// メモリ確保
+	ret = Malloc(len_ret + 1);
+	ret[len_ret] = '\0';
+
+	// 検索と置換
+	i = 0;
+	j = 0;
+	num = 0;
+	wp = 0;
+	while (true)
+	{
+		i = SearchStrEx(string, old_keyword, i, case_sensitive);
+		if (i == INFINITE)
+		{
+			Copy(ret + wp, string + j, len_string - j);
+			wp += len_string - j;
+			break;
+		}
+		num++;
+		Copy(ret + wp, string + j, i - j);
+		wp += i - j;
+		Copy(ret + wp, new_keyword, len_new);
+		wp += len_new;
+		i += len_old;
+		j = i;
+	}
+
+	// 検索結果のコピー
+	StrCpy(dst, size, ret);
+
+	// メモリ解放
+	Free(ret);
+
+	return num;
+}
+
+// 文字列の置換後の文字列長を計算する
+UINT CalcReplaceStrEx(char *string, char *old_keyword, char *new_keyword, bool case_sensitive)
+{
+	UINT i, num;
+	UINT len_string, len_old, len_new;
+	// 引数チェック
+	if (string == NULL || old_keyword == NULL || new_keyword == NULL)
+	{
+		return 0;
+	}
+
+	// 文字列長の取得
+	len_string = StrLen(string);
+	len_old = StrLen(old_keyword);
+	len_new = StrLen(new_keyword);
+
+	if (len_old == len_new)
+	{
+		return len_string;
+	}
+
+	// 検索処理
+	num = 0;
+	i = 0;
+	while (true)
+	{
+		i = SearchStrEx(string, old_keyword, i, case_sensitive);
+		if (i == INFINITE)
+		{
+			break;
+		}
+		i += len_old;
+		num++;
+	}
+
+	// 計算
+	return len_string + len_new * num - len_old * num;
+}
+
+// 文字列の検索 (大文字 / 小文字を区別する)
+UINT SearchStr(char *string, char *keyword, UINT start)
+{
+	return SearchStrEx(string, keyword, start, true);
+}
+
+// 文字列の検索 (大文字 / 小文字を区別しない)
+UINT SearchStri(char *string, char *keyword, UINT start)
+{
+	return SearchStrEx(string, keyword, start, false);
+}
+
+// 文字列 string から文字列 keyword を検索して最初に見つかった文字の場所を返す
+// (1文字目に見つかったら 0, 見つからなかったら INFINITE)
+UINT SearchStrEx(char *string, char *keyword, UINT start, bool case_sensitive)
+{
+	UINT len_string, len_keyword;
+	UINT i;
+	char *cmp_string, *cmp_keyword;
+	bool found;
+	// 引数チェック
+	if (string == NULL || keyword == NULL)
+	{
+		return INFINITE;
+	}
+
+	// string の長さを取得
+	len_string = StrLen(string);
+	if (len_string <= start)
+	{
+		// start の値が不正
+		return INFINITE;
+	}
+
+	// keyword の長さを取得
+	len_keyword = StrLen(keyword);
+	if (len_keyword == 0)
+	{
+		// キーワードが無い
+		return INFINITE;
+	}
+
+	if ((len_string - start) < len_keyword)
+	{
+		// キーワードの長さのほうが長い
+		return INFINITE;
+	}
+
+	if (case_sensitive)
+	{
+		cmp_string = string;
+		cmp_keyword = keyword;
+	}
+	else
+	{
+		cmp_string = Malloc(len_string + 1);
+		StrCpy(cmp_string, len_string + 1, string);
+		cmp_keyword = Malloc(len_keyword + 1);
+		StrCpy(cmp_keyword, len_keyword + 1, keyword);
+		StrUpper(cmp_string);
+		StrUpper(cmp_keyword);
+	}
+
+	// 検索
+	found = false;
+	for (i = start;i < (len_string - len_keyword + 1);i++)
+	{
+		// 比較する
+		if (!strncmp(&cmp_string[i], cmp_keyword, len_keyword))
+		{
+			// 発見した
+			found = true;
+			break;
+		}
+	}
+
+	if (case_sensitive == false)
+	{
+		// メモリ解放
+		Free(cmp_keyword);
+		Free(cmp_string);
+	}
+
+	if (found == false)
+	{
+		return INFINITE;
+	}
+	return i;
+}
+
+// 指定した文字がトークンリスト内にあるかどうか調べる
+bool IsInToken(TOKEN_LIST *t, char *str)
+{
+	UINT i;
+	// 引数チェック
+	if (t == NULL || str == NULL)
+	{
+		return false;
+	}
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		if (StrCmpi(t->Token[i], str) == 0)
+		{
+			return true;
+		}
+	}
+
+	return false;
+}
+
+// トークンリストの解放
+void FreeToken(TOKEN_LIST *tokens)
+{
+	UINT i;
+	if (tokens == NULL)
+	{
+		return;
+	}
+	for (i = 0;i < tokens->NumTokens;i++)
+	{
+		if (tokens->Token[i] != 0)
+		{
+			Free(tokens->Token[i]);
+		}
+	}
+	Free(tokens->Token);
+	Free(tokens);
+}
+
+// トークンのパース
+TOKEN_LIST *ParseToken(char *src, char *separator)
+{
+	TOKEN_LIST *ret;
+	char *tmp;
+	char *str1, *str2;
+	UINT len;
+	UINT num;
+	if (src == NULL)
+	{
+		ret = ZeroMalloc(sizeof(TOKEN_LIST));
+		ret->Token = ZeroMalloc(0);
+		return ret;
+	}
+	if (separator == NULL)
+	{
+		separator = " ,\t\r\n";
+	}
+	len = StrLen(src);
+	str1 = Malloc(len + 1);
+	str2 = Malloc(len + 1);
+	StrCpy(str1, 0, src);
+	StrCpy(str2, 0, src);
+
+	Lock(token_lock);
+	{
+		tmp = strtok(str1, separator);
+		num = 0;
+		while (tmp != NULL)
+		{
+			num++;
+			tmp = strtok(NULL, separator);
+		}
+		ret = Malloc(sizeof(TOKEN_LIST));
+		ret->NumTokens = num;
+		ret->Token = (char **)Malloc(sizeof(char *) * num);
+		num = 0;
+		tmp = strtok(str2, separator);
+		while (tmp != NULL)
+		{
+			ret->Token[num] = (char *)Malloc(StrLen(tmp) + 1);
+			StrCpy(ret->Token[num], 0, tmp);
+			num++;
+			tmp = strtok(NULL, separator);
+		}
+	}
+	Unlock(token_lock);
+
+	Free(str1);
+	Free(str2);
+	return ret;
+}
+
+// 1 行を標準入力から取得
+bool GetLine(char *str, UINT size)
+{
+	bool ret;
+	wchar_t *unistr;
+	UINT unistr_size = (size + 1) * sizeof(wchar_t);
+
+	unistr = Malloc(unistr_size);
+
+	ret = UniGetLine(unistr, unistr_size);
+
+	UniToStr(str, size, unistr);
+
+	Free(unistr);
+
+	return ret;
+}
+
+// 末尾の \r \n を削除
+void TrimCrlf(char *str)
+{
+	UINT len;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	len = StrLen(str);
+	if (len == 0)
+	{
+		return;
+	}
+
+	if (str[len - 1] == '\n')
+	{
+		if (len >= 2 && str[len - 2] == '\r')
+		{
+			str[len - 2] = 0;
+		}
+		str[len - 1] = 0;
+	}
+	else if (str[len - 1] == '\r')
+	{
+		str[len - 1] = 0;
+	}
+}
+
+// 文字列の左右の空白を削除
+void Trim(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	// 左側を trim
+	TrimLeft(str);
+
+	// 右側を trim
+	TrimRight(str);
+}
+
+// 文字列の右側の空白を削除
+void TrimRight(char *str)
+{
+	char *buf, *tmp;
+	UINT len, i, wp, wp2;
+	BOOL flag;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	len = StrLen(str);
+	if (len == 0)
+	{
+		return;
+	}
+	if (str[len - 1] != ' ' && str[len - 1] != '\t')
+	{
+		return;
+	}
+
+	buf = Malloc(len + 1);
+	tmp = Malloc(len + 1);
+	flag = FALSE;
+	wp = 0;
+	wp2 = 0;
+	for (i = 0;i < len;i++)
+	{
+		if (str[i] != ' ' && str[i] != '\t')
+		{
+			Copy(buf + wp, tmp, wp2);
+			wp += wp2;
+			wp2 = 0;
+			buf[wp++] = str[i];
+		}
+		else
+		{
+			tmp[wp2++] = str[i];
+		}
+	}
+	buf[wp] = 0;
+	StrCpy(str, 0, buf);
+	Free(buf);
+	Free(tmp);
+}
+
+// 文字列の左側の空白を削除
+void TrimLeft(char *str)
+{
+	char *buf;
+	UINT len, i, wp;
+	BOOL flag;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+	len = StrLen(str);
+	if (len == 0)
+	{
+		return;
+	}
+	if (str[0] != ' ' && str[0] != '\t')
+	{
+		return;
+	}
+
+	buf = Malloc(len + 1);
+	flag = FALSE;
+	wp = 0;
+	for (i = 0;i < len;i++)
+	{
+		if (str[i] != ' ' && str[i] != '\t')
+		{
+			flag = TRUE;
+		}
+		if (flag)
+		{
+			buf[wp++] = str[i];
+		}
+	}
+	buf[wp] = 0;
+	StrCpy(str, 0, buf);
+	Free(buf);
+}
+
+// 整数を 16 進文字列に変換 (8桁固定)
+void ToStrx8(char *str, UINT i)
+{
+	sprintf(str, "0x%08x", i);
+}
+
+// 整数を 16 進文字列に変換
+void ToStrx(char *str, UINT i)
+{
+	sprintf(str, "0x%02x", i);
+}
+
+// 符号付整数を文字列に変換
+void ToStri(char *str, int i)
+{
+	sprintf(str, "%i", i);
+}
+
+// 整数を文字列に変換
+void ToStr(char *str, UINT i)
+{
+	sprintf(str, "%u", i);
+}
+
+// 文字列を符号付整数に変換
+int ToInti(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	return (int)ToInt(str);
+}
+
+// 文字列を bool に変換
+bool ToBool(char *str)
+{
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(tmp, sizeof(tmp), str);
+	Trim(tmp);
+
+	if (IsEmptyStr(tmp))
+	{
+		return false;
+	}
+
+	if (ToInt(tmp) != 0)
+	{
+		return true;
+	}
+
+	if (StartWith("true", tmp))
+	{
+		return true;
+	}
+
+	if (StartWith("yes", tmp))
+	{
+		return true;
+	}
+
+	if (StartWith(tmp, "true"))
+	{
+		return true;
+	}
+
+	if (StartWith(tmp, "yes"))
+	{
+		return true;
+	}
+
+	return false;
+}
+
+// 文字列を整数に変換
+UINT ToInt(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	// 8 進数表記を無視する
+	while (true)
+	{
+		if (*str != '0')
+		{
+			break;
+		}
+		if ((*(str + 1) == 'x') || (*(str + 1) == 'X'))
+		{
+			break;
+		}
+		str++;
+	}
+
+	return (UINT)strtoul(str, NULL, 0);
+}
+
+// 64bit 整数のためのフォーマット文字列を置換する
+char *ReplaceFormatStringFor64(char *fmt)
+{
+	char *tmp;
+	char *ret;
+	UINT tmp_size;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return NULL;
+	}
+
+	tmp_size = StrSize(fmt) * 2;
+	tmp = ZeroMalloc(tmp_size);
+
+#ifdef	OS_WIN32
+	ReplaceStrEx(tmp, tmp_size, fmt, "%ll", "%I64", false);
+#else	// OS_WIN32
+	ReplaceStrEx(tmp, tmp_size, fmt, "%I64", "%ll", false);
+#endif	// OS_WIN32
+
+	ret = CopyStr(tmp);
+	Free(tmp);
+
+	return ret;
+}
+
+// 文字列を画面に表示する
+void PrintStr(char *str)
+{
+	wchar_t *unistr = NULL;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_UNIX
+	fputs(str, stdout);
+#else	// OS_UNIX
+	unistr = CopyStrToUni(str);
+	UniPrintStr(unistr);
+	Free(unistr);
+#endif	// OS_UNIX
+}
+
+// 文字列を引数付きで表示する
+void PrintArgs(char *fmt, va_list args)
+{
+	wchar_t *ret;
+	wchar_t *fmt_wchar;
+	char *tmp;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+
+	fmt_wchar = CopyStrToUni(fmt);
+	ret = InternalFormatArgs(fmt_wchar, args, true);
+
+	tmp = CopyUniToStr(ret);
+	PrintStr(tmp);
+	Free(tmp);
+
+	Free(ret);
+	Free(fmt_wchar);
+}
+
+// 文字列を表示する
+void Print(char *fmt, ...)
+{
+	va_list args;
+	if (fmt == NULL)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	PrintArgs(fmt, args);
+	va_end(args);
+}
+
+// デバッグ文字列を引数付きで表示する
+void DebugArgs(char *fmt, va_list args)
+{
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+	if (g_debug == false)
+	{
+		return;
+	}
+
+	PrintArgs(fmt, args);
+}
+
+// デバッグ文字列を表示する
+void Debug(char *fmt, ...)
+{
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return;
+	}
+	if (g_debug == false)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+
+	DebugArgs(fmt, args);
+
+	va_end(args);
+}
+
+// 文字列をフォーマットして結果を返す
+char *CopyFormat(char *fmt, ...)
+{
+	char *buf;
+	char *ret;
+	UINT size;
+	va_list args;
+	// 引数チェック
+	if (fmt == NULL)
+	{
+		return NULL;
+	}
+
+	size = MAX(StrSize(fmt) * 10, MAX_SIZE * 10);
+	buf = Malloc(size);
+
+	va_start(args, fmt);
+	FormatArgs(buf, size, fmt, args);
+
+	ret = CopyStr(buf);
+	Free(buf);
+
+	va_end(args);
+	return ret;
+}
+
+// 文字列をフォーマットする
+void Format(char *buf, UINT size, char *fmt, ...)
+{
+	va_list args;
+	// 引数チェック
+	if (buf == NULL || fmt == NULL)
+	{
+		return;
+	}
+
+	va_start(args, fmt);
+	FormatArgs(buf, size, fmt, args);
+	va_end(args);
+}
+
+// 文字列をフォーマットする (引数リスト)
+void FormatArgs(char *buf, UINT size, char *fmt, va_list args)
+{
+	wchar_t *tag;
+	wchar_t *ret;
+	// 引数チェック
+	if (buf == NULL || fmt == NULL)
+	{
+		return;
+	}
+
+	tag = CopyStrToUni(fmt);
+	ret = InternalFormatArgs(tag, args, true);
+
+	UniToStr(buf, size, ret);
+	Free(ret);
+	Free(tag);
+}
+
+// 文字列を大文字・小文字を区別せずに比較する
+int StrCmpi(char *str1, char *str2)
+{
+	UINT i;
+	// 引数チェック
+	if (str1 == NULL && str2 == NULL)
+	{
+		return 0;
+	}
+	if (str1 == NULL)
+	{
+		return 1;
+	}
+	if (str2 == NULL)
+	{
+		return -1;
+	}
+
+	// 文字列比較
+	i = 0;
+	while (true)
+	{
+		char c1, c2;
+		c1 = ToUpper(str1[i]);
+		c2 = ToUpper(str2[i]);
+		if (c1 > c2)
+		{
+			return 1;
+		}
+		else if (c1 < c2)
+		{
+			return -1;
+		}
+		if (str1[i] == 0 || str2[i] == 0)
+		{
+			return 0;
+		}
+		i++;
+	}
+}
+
+// 文字列を比較する
+int StrCmp(char *str1, char *str2)
+{
+	// 引数チェック
+	if (str1 == NULL && str2 == NULL)
+	{
+		return 0;
+	}
+	if (str1 == NULL)
+	{
+		return 1;
+	}
+	if (str2 == NULL)
+	{
+		return -1;
+	}
+
+	return strcmp(str1, str2);
+}
+
+// 文字列を小文字にする
+void StrLower(char *str)
+{
+	UINT len, i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		str[i] = ToLower(str[i]);
+	}
+}
+
+// 文字列を大文字にする
+void StrUpper(char *str)
+{
+	UINT len, i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	len = StrLen(str);
+	for (i = 0;i < len;i++)
+	{
+		str[i] = ToUpper(str[i]);
+	}
+}
+
+// 文字を小文字にする
+char ToLower(char c)
+{
+	if ('A' <= c && c <= 'Z')
+	{
+		c += 'z' - 'Z';
+	}
+	return c;
+}
+
+// 文字を大文字にする
+char ToUpper(char c)
+{
+	if ('a' <= c && c <= 'z')
+	{
+		c += 'Z' - 'z';
+	}
+	return c;
+}
+
+// 文字列を結合
+UINT StrCat(char *dst, UINT size, char *src)
+{
+	UINT len1, len2, len_test;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return 0;
+	}
+
+	// KS
+	KS_INC(KS_STRCAT_COUNT);
+
+	if (size == 0)
+	{
+		// 長さを無視
+		size = 0x7fffffff;
+	}
+
+	len1 = StrLen(dst);
+	len2 = StrLen(src);
+	len_test = len1 + len2 + 1;
+	if (len_test > size)
+	{
+		if (len2 <= (len_test - size))
+		{
+			return 0;
+		}
+		len2 -= len_test - size;
+	}
+	Copy(dst + len1, src, len2);
+	dst[len1 + len2] = 0;
+
+	return len1 + len2;
+}
+UINT StrCatLeft(char *dst, UINT size, char *src)
+{
+	char *s;
+	// 引数チェック
+	if (dst == NULL || src == NULL)
+	{
+		return 0;
+	}
+
+	s = CopyStr(dst);
+	StrCpy(dst, size, src);
+	StrCat(dst, size, s);
+
+	Free(s);
+
+	return StrLen(dst);
+}
+
+// 文字列をコピー
+UINT StrCpy(char *dst, UINT size, char *src)
+{
+	UINT len;
+	// 引数チェック
+	if (dst == src)
+	{
+		return StrLen(src);
+	}
+	if (dst == NULL || src == NULL)
+	{
+		if (src == NULL && dst != NULL)
+		{
+			if (size >= 1)
+			{
+				dst[0] = '\0';
+			}
+		}
+		return 0;
+	}
+	if (size == 1)
+	{
+		dst[0] = '\0';
+		return 0;
+	}
+	if (size == 0)
+	{
+		// 長さを無視
+		size = 0x7fffffff;
+	}
+
+	// 長さをチェック
+	len = StrLen(src);
+	if (len <= (size - 1))
+	{
+		Copy(dst, src, len + 1);
+	}
+	else
+	{
+		len = size - 1;
+		Copy(dst, src, len);
+		dst[len] = '\0';
+	}
+
+	// KS
+	KS_INC(KS_STRCPY_COUNT);
+
+	return len;
+}
+
+// 文字列バッファが指定されたサイズに収まっているかどうかを確認
+bool StrCheckSize(char *str, UINT size)
+{
+	// 引数チェック
+	if (str == NULL || size == 0)
+	{
+		return false;
+	}
+
+	return StrCheckLen(str, size - 1);
+}
+
+// 文字列が指定された長さ以内であることを確認
+bool StrCheckLen(char *str, UINT len)
+{
+	UINT count = 0;
+	UINT i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+
+	// KS
+	KS_INC(KS_STRCHECK_COUNT);
+
+	for (i = 0;;i++)
+	{
+		if (str[i] == '\0')
+		{
+			return true;
+		}
+		count++;
+		if (count > len)
+		{
+			return false;
+		}
+	}
+}
+
+// 文字列を格納するために必要なメモリサイズを取得
+UINT StrSize(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	return StrLen(str) + 1;
+}
+
+// 文字列の長さを取得
+UINT StrLen(char *str)
+{
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	// KS
+	KS_INC(KS_STRLEN_COUNT);
+
+	return (UINT)strlen(str);
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Str.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Str.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Str.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,209 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Str.h
+// Str.c のヘッダ
+
+#ifndef	STR_H
+#define	STR_H
+
+// 文字列トークン
+struct TOKEN_LIST
+{
+	UINT NumTokens;
+	char **Token;
+};
+
+// INI_ENTRY
+struct INI_ENTRY
+{
+	char *Key;
+	char *Value;
+	wchar_t *UnicodeValue;
+};
+
+// 関数プロトタイプ
+UINT StrLen(char *str);
+UINT StrSize(char *str);
+bool StrCheckLen(char *str, UINT len);
+bool StrCheckSize(char *str, UINT size);
+UINT StrCpy(char *dst, UINT size, char *src);
+UINT StrCat(char *dst, UINT size, char *src);
+UINT StrCatLeft(char *dst, UINT size, char *src);
+char ToLower(char c);
+char ToUpper(char c);
+void StrUpper(char *str);
+void StrLower(char *str);
+int StrCmp(char *str1, char *str2);
+int StrCmpi(char *str1, char *str2);
+void FormatArgs(char *buf, UINT size, char *fmt, va_list args);
+void Format(char *buf, UINT size, char *fmt, ...);
+char *CopyFormat(char *fmt, ...);
+void Print(char *fmt, ...);
+void PrintArgs(char *fmt, va_list args);
+void PrintStr(char *str);
+void Debug(char *fmt, ...);
+void DebugArgs(char *fmt, va_list args);
+UINT ToInt(char *str);
+bool ToBool(char *str);
+int ToInti(char *str);
+void ToStr(char *str, UINT i);
+void ToStri(char *str, int i);
+void ToStrx(char *str, UINT i);
+void ToStrx8(char *str, UINT i);
+void TrimCrlf(char *str);
+void Trim(char *str);
+void TrimRight(char *str);
+void TrimLeft(char *str);
+bool GetLine(char *str, UINT size);
+void FreeToken(TOKEN_LIST *tokens);
+bool IsInToken(TOKEN_LIST *t, char *str);
+TOKEN_LIST *ParseToken(char *src, char *separator);
+void InitStringLibrary();
+void FreeStringLibrary();
+bool CheckStringLibrary();
+UINT SearchStrEx(char *string, char *keyword, UINT start, bool case_sensitive);
+UINT SearchStri(char *string, char *keyword, UINT start);
+UINT SearchStr(char *string, char *keyword, UINT start);
+UINT CalcReplaceStrEx(char *string, char *old_keyword, char *new_keyword, bool case_sensitive);
+UINT ReplaceStrEx(char *dst, UINT size, char *string, char *old_keyword, char *new_keyword, bool case_sensitive);
+UINT ReplaceStr(char *dst, UINT size, char *string, char *old_keyword, char *new_keyword);
+UINT ReplaceStri(char *dst, UINT size, char *string, char *old_keyword, char *new_keyword);
+bool IsSafeChar(char c);
+bool IsSafeStr(char *str);
+void EnSafeStr(char *str, char replace);
+void TruncateCharFromStr(char *str, char replace);
+char *CopyStr(char *str);
+void BinToStr(char *str, UINT str_size, void *data, UINT data_size);
+void BinToStrW(wchar_t *str, UINT str_size, void *data, UINT data_size);
+void PrintBin(void *data, UINT size);
+bool StartWith(char *str, char *key);
+bool EndWith(char *str, char *key);
+UINT64 ToInt64(char *str);
+void ToStr64(char *str, UINT64 value);
+char *ReplaceFormatStringFor64(char *fmt);
+TOKEN_LIST *ParseCmdLine(char *str);
+TOKEN_LIST *CopyToken(TOKEN_LIST *src);
+TOKEN_LIST *NullToken();
+bool IsNum(char *str);
+LIST *StrToStrList(char *str, UINT size);
+BUF *StrListToStr(LIST *o);
+void FreeStrList(LIST *o);
+TOKEN_LIST *ListToTokenList(LIST *o);
+LIST *TokenListToList(TOKEN_LIST *t);
+bool IsEmptyStr(char *str);
+void BinToStrEx(char *str, UINT str_size, void *data, UINT data_size);
+void BinToStrEx2(char *str, UINT str_size, void *data, UINT data_size, char padding_char);
+char *CopyBinToStrEx(void *data, UINT data_size);
+char *CopyBinToStr(void *data, UINT data_size);
+BUF *StrToBin(char *str);
+void MacToStr(char *str, UINT size, UCHAR *mac_address);
+void ToStr3(char *str, UINT size, UINT64 v);
+void ToStrByte(char *str, UINT size, UINT64 v);
+void ToStrByte1000(char *str, UINT size, UINT64 v);
+TOKEN_LIST *UniqueToken(TOKEN_LIST *t);
+char *NormalizeCrlf(char *str);
+bool IsAllUpperStr(char *str);
+UINT StrWidth(char *str);
+char *MakeCharArray(char c, UINT count);
+void MakeCharArray2(char *str, char c, UINT count);
+bool StrToMac(UCHAR *mac_address, char *str);
+bool IsSplitChar(char c, char *split_str);
+bool GetKeyAndValue(char *str, char *key, UINT key_size, char *value, UINT value_size, char *split_str);
+LIST *ReadIni(BUF *b);
+INI_ENTRY *GetIniEntry(LIST *o, char *key);
+void FreeIni(LIST *o);
+UINT IniIntValue(LIST *o, char *key);
+UINT64 IniInt64Value(LIST *o, char *key);
+char *IniStrValue(LIST *o, char *key);
+wchar_t *IniUniStrValue(LIST *o, char *key);
+bool InStr(char *str, char *keyword);
+bool InStrEx(char *str, char *keyword, bool case_sensitive);
+TOKEN_LIST *ParseTokenWithoutNullStr(char *str, char *split_chars);
+TOKEN_LIST *ParseTokenWithNullStr(char *str, char *split_chars);
+char *DefaultTokenSplitChars();
+bool IsCharInStr(char *str, char c);
+UINT HexTo4Bit(char c);
+char FourBitToHex(UINT value);
+void ToHex(char *str, UINT value);
+void ToHex64(char *str, UINT64 value);
+UINT HexToInt(char *str);
+UINT64 HexToInt64(char *str);
+
+
+#endif	// STR_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Table.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Table.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Table.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,865 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Table.c
+// 文字列テーブル読み込み & 管理ルーチン
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// TABLE のリスト
+static LIST *TableList = NULL;
+static wchar_t old_table_name[MAX_SIZE] = {0};		// 古いテーブル名
+
+// エラー文字列を Unicode で取得する
+wchar_t *GetUniErrorStr(UINT err)
+{
+	wchar_t *ret;
+	char name[MAX_SIZE];
+	Format(name, sizeof(name), "ERR_%u", err);
+
+	ret = GetTableUniStr(name);
+	if (UniStrLen(ret) != 0)
+	{
+		return ret;
+	}
+	else
+	{
+		return _UU("ERR_UNKNOWN");
+	}
+}
+
+// エラー文字列を取得する
+char *GetErrorStr(UINT err)
+{
+	char *ret;
+	char name[MAX_SIZE];
+	Format(name, sizeof(name), "ERR_%u", err);
+
+	ret = GetTableStr(name);
+	if (StrLen(ret) != 0)
+	{
+		return ret;
+	}
+	else
+	{
+		return _SS("ERR_UNKNOWN");
+	}
+}
+
+// テーブルから整数値をロードする
+UINT GetTableInt(char *name)
+{
+	char *str;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return 0;
+	}
+
+	str = GetTableStr(name);
+	return ToInt(str);
+}
+
+// テーブルから Unicode 文字列をロードする
+wchar_t *GetTableUniStr(char *name)
+{
+	TABLE *t;
+	// 引数チェック
+	if (name == NULL)
+	{
+//		Debug("%s: ************\n", name);
+		return L"";
+	}
+
+	// 検索
+	t = FindTable(name);
+	if (t == NULL)
+	{
+//		Debug("%s: UNICODE STRING NOT FOUND\n", name);
+		return L"";
+	}
+
+	return t->unistr;
+}
+
+// テーブルから文字列をロードする
+char *GetTableStr(char *name)
+{
+	TABLE *t;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return "";
+	}
+
+#ifdef	OS_WIN32
+	if (StrCmpi(name, "DEFAULT_FONT") == 0)
+	{
+		if (_II("LANG") == 2)
+		{
+			UINT os_type = GetOsType();
+			if (OS_IS_WINDOWS_9X(os_type) ||
+				GET_KETA(os_type, 100) <= 4)
+			{
+				// Windows 9x, Windows NT 4.0, Windows 2000, Windows XP, Windows Server 2003 の場合は SimSun フォントを利用する
+				return "SimSun";
+			}
+		}
+	}
+#endif	// OS_WIN32
+
+	// 検索
+	t = FindTable(name);
+	if (t == NULL)
+	{
+//		Debug("%s: ANSI STRING NOT FOUND\n", name);
+		return "";
+	}
+
+	return t->str;
+}
+
+// 指定した名前で始まる文字列名を取得する
+TOKEN_LIST *GetTableNameStartWith(char *str)
+{
+	UINT i;
+	UINT len;
+	LIST *o;
+	TOKEN_LIST *t;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (str == NULL)
+	{
+		return NullToken();
+	}
+
+	StrCpy(tmp, sizeof(tmp), str);
+	StrUpper(tmp);
+
+	len = StrLen(tmp);
+
+	o = NewListFast(NULL);
+
+	for (i = 0;i < LIST_NUM(TableList);i++)
+	{
+		TABLE *t = LIST_DATA(TableList, i);
+		UINT len2 = StrLen(t->name);
+
+		if (len2 >= len)
+		{
+			if (Cmp(t->name, tmp, len) == 0)
+			{
+				Insert(o, CopyStr(t->name));
+			}
+		}
+	}
+
+	t = ZeroMalloc(sizeof(TOKEN_LIST));
+	t->NumTokens = LIST_NUM(o);
+	t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		t->Token[i] = LIST_DATA(o, i);
+	}
+
+	ReleaseList(o);
+
+	return t;
+}
+
+// テーブルを検索する
+TABLE *FindTable(char *name)
+{
+	TABLE *t, tt;
+	// 引数チェック
+	if (name == NULL || TableList == NULL)
+	{
+		return NULL;
+	}
+
+	tt.name = CopyStr(name);
+	t = Search(TableList, &tt);
+	Free(tt.name);
+
+	return t;
+}
+
+// テーブル名を比較する関数
+int CmpTableName(void *p1, void *p2)
+{
+	TABLE *t1, *t2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	t1 = *(TABLE **)p1;
+	t2 = *(TABLE **)p2;
+	if (t1 == NULL || t2 == NULL)
+	{
+		return 0;
+	}
+
+	return StrCmpi(t1->name, t2->name);
+}
+
+// 1 行を解釈する
+TABLE *ParseTableLine(char *line, char *prefix, UINT prefix_size)
+{
+	UINT i, len;
+	UINT len_name;
+	UINT string_start;
+	char *name;
+	char *name2;
+	UINT name2_size;
+	wchar_t *unistr;
+	char *str;
+	UINT unistr_size, str_size;
+	TABLE *t;
+	// 引数チェック
+	if (line == NULL || prefix == NULL)
+	{
+		return NULL;
+	}
+	TrimLeft(line);
+
+	// 行無し
+	len = StrLen(line);
+	if (len == 0)
+	{
+		return NULL;
+	}
+
+	// コメント
+	if (line[0] == '#' || (line[0] == '/' && line[1] == '/'))
+	{
+		return NULL;
+	}
+
+	// 名前の終了位置まで検索
+	len_name = 0;
+	for (i = 0;;i++)
+	{
+		if (line[i] == 0)
+		{
+			// トークンが 1 つしか無い
+			return NULL;
+		}
+		if (line[i] == ' ' || line[i] == '\t')
+		{
+			break;
+		}
+		len_name++;
+	}
+
+	name = Malloc(len_name + 1);
+	StrCpy(name, len_name + 1, line);
+
+	string_start = len_name;
+	for (i = len_name;i < len;i++)
+	{
+		if (line[i] != ' ' && line[i] != '\t')
+		{
+			break;
+		}
+		string_start++;
+	}
+	if (i == len)
+	{
+		Free(name);
+		return NULL;
+	}
+
+	// アンエスケープ
+	UnescapeStr(&line[string_start]);
+
+	// Unicode に変換する
+	unistr_size = CalcUtf8ToUni(&line[string_start], StrLen(&line[string_start]));
+	if (unistr_size == 0)
+	{
+		Free(name);
+		return NULL;
+	}
+	unistr = Malloc(unistr_size);
+	Utf8ToUni(unistr, unistr_size, &line[string_start], StrLen(&line[string_start]));
+
+	// ANSI に変換する
+	str_size = CalcUniToStr(unistr);
+	if (str_size == 0)
+	{
+		str_size = 1;
+		str = Malloc(1);
+		str[0] = 0;
+	}
+	else
+	{
+		str = Malloc(str_size);
+		UniToStr(str, str_size, unistr);
+	}
+
+	if (StrCmpi(name, "PREFIX") == 0)
+	{
+		// プレフィックスが指定された
+		StrCpy(prefix, prefix_size, str);
+		Trim(prefix);
+
+		if (StrCmpi(prefix, "$") == 0 || StrCmpi(prefix, "NULL") == 0)
+		{
+			prefix[0] = 0;
+		}
+
+		Free(name);
+		Free(str);
+		Free(unistr);
+
+		return NULL;
+	}
+
+	name2_size = StrLen(name) + StrLen(prefix) + 2;
+	name2 = ZeroMalloc(name2_size);
+
+	if (prefix[0] != 0)
+	{
+		StrCat(name2, name2_size, prefix);
+		StrCat(name2, name2_size, "@");
+	}
+
+	StrCat(name2, name2_size, name);
+
+	Free(name);
+
+	// TABLE を作成する
+	t = Malloc(sizeof(TABLE));
+	StrUpper(name2);
+	t->name = name2;
+	t->str = str;
+	t->unistr = unistr;
+
+	return t;
+}
+
+// 文字列のアンエスケープ
+void UnescapeStr(char *src)
+{
+	UINT i, len, wp;
+	char *tmp;
+	// 引数チェック
+	if (src == NULL)
+	{
+		return;
+	}
+	
+	len = StrLen(src);
+	tmp = Malloc(len + 1);
+	wp = 0;
+	for (i = 0;i < len;i++)
+	{
+		if (src[i] == '\\')
+		{
+			i++;
+			switch (src[i])
+			{
+			case 0:
+				goto FINISH;
+			case '\\':
+				tmp[wp++] = '\\';
+				break;
+			case ' ':
+				tmp[wp++] = ' ';
+				break;
+			case 'n':
+			case 'N':
+				tmp[wp++] = '\n';
+				break;
+			case 'r':
+			case 'R':
+				tmp[wp++] = '\r';
+				break;
+			case 't':
+			case 'T':
+				tmp[wp++] = '\t';
+				break;
+			}
+		}
+		else
+		{
+			tmp[wp++] = src[i];
+		}
+	}
+FINISH:
+	tmp[wp++] = 0;
+	StrCpy(src, 0, tmp);
+	Free(tmp);
+}
+
+// テーブルを解放する
+void FreeTable()
+{
+	UINT i, num;
+	TABLE **tables;
+	if (TableList == NULL)
+	{
+		return;
+	}
+
+	TrackingDisable();
+
+	num = LIST_NUM(TableList);
+	tables = ToArray(TableList);
+	for (i = 0;i < num;i++)
+	{
+		TABLE *t = tables[i];
+		Free(t->name);
+		Free(t->str);
+		Free(t->unistr);
+		Free(t);
+	}
+	ReleaseList(TableList);
+	TableList = NULL;
+	Free(tables);
+
+	Zero(old_table_name, sizeof(old_table_name));
+
+	TrackingEnable();
+}
+
+// バッファから文字列テーブルを読み込む
+bool LoadTableFromBuf(BUF *b)
+{
+	char *tmp;
+	char prefix[MAX_SIZE];
+	// 引数チェック
+	if (b == NULL)
+	{
+		return false;
+	}
+
+	// すでにテーブルがある場合は削除する
+	FreeTable();
+
+	// リストを作成する
+	TableList = NewList(CmpTableName);
+
+	Zero(prefix, sizeof(prefix));
+
+	// バッファの内容を 1 行ずつ読んでいく
+	while (true)
+	{
+		TABLE *t;
+		tmp = CfgReadNextLine(b);
+		if (tmp == NULL)
+		{
+			break;
+		}
+		t = ParseTableLine(tmp, prefix, sizeof(prefix));
+		if (t != NULL)
+		{
+			// 登録する
+			Insert(TableList, t);
+		}
+		Free(tmp);
+	}
+
+	return true;
+}
+
+// Unicode 文字列キャッシュファイル名の生成
+void GenerateUnicodeCacheFileName(wchar_t *name, UINT size, wchar_t *strfilename, UINT strfilesize, UCHAR *filehash)
+{
+	wchar_t tmp[MAX_SIZE];
+	wchar_t hashstr[64];
+	wchar_t hashtemp[MAX_SIZE];
+	wchar_t exe[MAX_SIZE];
+	UCHAR hash[SHA1_SIZE];
+	// 引数チェック
+	if (name == NULL || strfilename == NULL || filehash == NULL)
+	{
+		return;
+	}
+
+	GetExeDirW(exe, sizeof(exe));
+	UniStrCpy(hashtemp, sizeof(hashtemp), strfilename);
+	BinToStrW(tmp, sizeof(tmp), filehash, MD5_SIZE);
+	UniStrCat(hashtemp, sizeof(hashtemp), tmp);
+	UniStrCat(hashtemp, sizeof(hashtemp), exe);
+	UniStrLower(hashtemp);
+
+	Hash(hash, hashtemp, UniStrLen(hashtemp) * sizeof(wchar_t), true);
+	BinToStrW(hashstr, sizeof(hashstr), hash, 4);
+	UniFormat(tmp, sizeof(tmp), UNICODE_CACHE_FILE, hashstr);
+	UniStrLower(tmp);
+
+#ifndef	OS_WIN32
+	UniStrCpy(exe, sizeof(exe), L"/tmp");
+#else	// OS_WIN32
+	StrToUni(exe, sizeof(exe), MsGetTempDir());
+#endif	// OS_WIN32
+
+	UniFormat(name, size, L"%s/%s", exe, tmp);
+	NormalizePathW(name, size, name);
+}
+
+// Unicode キャッシュの保存
+void SaveUnicodeCache(wchar_t *strfilename, UINT strfilesize, UCHAR *hash)
+{
+	UNICODE_CACHE c;
+	BUF *b;
+	UINT i;
+	IO *io;
+	wchar_t name[MAX_PATH];
+	UCHAR binhash[MD5_SIZE];
+	// 引数チェック
+	if (strfilename == NULL || hash == NULL)
+	{
+		return;
+	}
+
+	Zero(&c, sizeof(c));
+	UniToStr(c.StrFileName, sizeof(c.StrFileName), strfilename);
+	c.StrFileSize = strfilesize;
+	GetMachineName(c.MachineName, sizeof(c.MachineName));
+	c.OsType = GetOsInfo()->OsType;
+	Copy(c.hash, hash, MD5_SIZE);
+
+#ifdef	OS_UNIX
+	GetCurrentCharSet(c.CharSet, sizeof(c.CharSet));
+#else	// OS_UNIX
+	{
+		UINT id = MsGetThreadLocale();
+		Copy(c.CharSet, &id, sizeof(id));
+	}
+#endif	// OS_UNIX
+
+	b = NewBuf();
+	WriteBuf(b, &c, sizeof(c));
+
+	WriteBufInt(b, LIST_NUM(TableList));
+	for (i = 0;i < LIST_NUM(TableList);i++)
+	{
+		TABLE *t = LIST_DATA(TableList, i);
+		WriteBufInt(b, StrLen(t->name));
+		WriteBuf(b, t->name, StrLen(t->name));
+		WriteBufInt(b, StrLen(t->str));
+		WriteBuf(b, t->str, StrLen(t->str));
+		WriteBufInt(b, UniStrLen(t->unistr));
+		WriteBuf(b, t->unistr, UniStrLen(t->unistr) * sizeof(wchar_t));
+	}
+
+	Hash(binhash, b->Buf, b->Size, false);
+	WriteBuf(b, binhash, MD5_SIZE);
+
+	GenerateUnicodeCacheFileName(name, sizeof(name), strfilename, strfilesize, hash);
+
+	io = FileCreateW(name);
+	if (io != NULL)
+	{
+		SeekBuf(b, 0, 0);
+		BufToFile(io, b);
+		FileClose(io);
+	}
+
+	FreeBuf(b);
+}
+
+// Unicode キャッシュの読み込み
+bool LoadUnicodeCache(wchar_t *strfilename, UINT strfilesize, UCHAR *hash)
+{
+	UNICODE_CACHE c, t;
+	BUF *b;
+	UINT i, num;
+	IO *io;
+	wchar_t name[MAX_PATH];
+	UCHAR binhash[MD5_SIZE];
+	UCHAR binhash_2[MD5_SIZE];
+	// 引数チェック
+	if (strfilename == NULL || hash == NULL)
+	{
+		return false;
+	}
+
+	GenerateUnicodeCacheFileName(name, sizeof(name), strfilename, strfilesize, hash);
+
+	io = FileOpenW(name, false);
+	if (io == NULL)
+	{
+		return false;
+	}
+
+	b = FileToBuf(io);
+	if (b == NULL)
+	{
+		FileClose(io);
+		return false;
+	}
+
+	SeekBuf(b, 0, 0);
+	FileClose(io);
+
+	Hash(binhash, b->Buf, b->Size >= MD5_SIZE ? (b->Size - MD5_SIZE) : 0, false);
+	Copy(binhash_2, ((UCHAR *)b->Buf) + (b->Size >= MD5_SIZE ? (b->Size - MD5_SIZE) : 0), MD5_SIZE);
+	if (Cmp(binhash, binhash_2, MD5_SIZE) != 0)
+	{
+		FreeBuf(b);
+		return false;
+	}
+
+	Zero(&c, sizeof(c));
+	UniToStr(c.StrFileName, sizeof(c.StrFileName), strfilename);
+	c.StrFileSize = strfilesize;
+	DisableNetworkNameCache();
+	GetMachineName(c.MachineName, sizeof(c.MachineName));
+	EnableNetworkNameCache();
+	c.OsType = GetOsInfo()->OsType;
+	Copy(c.hash, hash, MD5_SIZE);
+
+#ifdef	OS_UNIX
+	GetCurrentCharSet(c.CharSet, sizeof(c.CharSet));
+#else	// OS_UNIX
+	{
+		UINT id = MsGetThreadLocale();
+		Copy(c.CharSet, &id, sizeof(id));
+	}
+#endif	// OS_UNIX
+
+	Zero(&t, sizeof(t));
+	ReadBuf(b, &t, sizeof(t));
+
+	if (Cmp(&c, &t, sizeof(UNICODE_CACHE)) != 0)
+	{
+		FreeBuf(b);
+		return false;
+	}
+
+	num = ReadBufInt(b);
+
+	FreeTable();
+	TableList = NewList(CmpTableName);
+
+	for (i = 0;i < num;i++)
+	{
+		UINT len;
+		TABLE *t = ZeroMalloc(sizeof(TABLE));
+
+		len = ReadBufInt(b);
+		t->name = ZeroMalloc(len + 1);
+		ReadBuf(b, t->name, len);
+
+		len = ReadBufInt(b);
+		t->str = ZeroMalloc(len + 1);
+		ReadBuf(b, t->str, len);
+
+		len = ReadBufInt(b);
+		t->unistr = ZeroMalloc((len + 1) * sizeof(wchar_t));
+		ReadBuf(b, t->unistr, len * sizeof(wchar_t));
+
+		Add(TableList, t);
+	}
+
+	FreeBuf(b);
+
+	Sort(TableList);
+
+	return true;
+}
+
+// 文字列テーブルを読み込む
+bool LoadTableMain(wchar_t *filename)
+{
+	BUF *b;
+	UINT64 t1, t2;
+	UCHAR hash[MD5_SIZE];
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return false;
+	}
+
+	if (MayaquaIsMinimalMode())
+	{
+		return true;
+	}
+
+	if (UniStrCmpi(old_table_name, filename) == 0)
+	{
+		// すでに読み込まれている
+		return true;
+	}
+
+	t1 = Tick64();
+
+	// ファイルを開く
+	b = ReadDumpW(filename);
+	if (b == NULL)
+	{
+		char tmp[MAX_SIZE];
+		StrCpy(tmp, sizeof(tmp), "Error: Can't read string tables (file not found).\r\nPlease check hamcore.utvpn.\r\n\r\n(First, reboot the computer. If this problem occurs again, please reinstall VPN software files.)");
+		Alert(tmp, NULL);
+		exit(0);
+		return false;
+	}
+
+	Hash(hash, b->Buf, b->Size, false);
+
+	if (LoadUnicodeCache(filename, b->Size, hash) == false)
+	{
+		if (LoadTableFromBuf(b) == false)
+		{
+			FreeBuf(b);
+			return false;
+		}
+
+		SaveUnicodeCache(filename, b->Size, hash);
+
+		Debug("Unicode Source: strtable.stb\n");
+	}
+	else
+	{
+		Debug("Unicode Source: unicode_cache\n");
+	}
+
+	FreeBuf(b);
+
+	SetLocale(_UU("DEFAULE_LOCALE"));
+
+	UniStrCpy(old_table_name, sizeof(old_table_name), filename);
+
+	t2 = Tick64();
+
+	if (StrCmpi(_SS("STRTABLE_ID"), STRTABLE_ID) != 0)
+	{
+		char tmp[MAX_SIZE];
+		StrCpy(tmp, sizeof(tmp), "Error: Can't read string tables (invalid version).\r\nPlease check hamcore.utvpn.\r\n\r\n(First, reboot the computer. If this problem occurs again, please reinstall VPN software files.)");
+		Alert(tmp, NULL);
+		exit(0);
+		return false;
+	}
+
+	Debug("Unicode File Read Cost: %u (%u Lines)\n", (UINT)(t2 - t1), LIST_NUM(TableList));
+
+	return true;
+}
+bool LoadTable(char *filename)
+{
+	wchar_t *filename_a = CopyStrToUni(filename);
+	bool ret = LoadTableW(filename_a);
+
+	Free(filename_a);
+
+	return ret;
+}
+bool LoadTableW(wchar_t *filename)
+{
+	bool ret;
+	BUF *b;
+	wchar_t replace_name[MAX_PATH];
+
+	Zero(replace_name, sizeof(replace_name));
+
+	TrackingDisable();
+
+	b = ReadDump("@table_name.txt");
+	if (b != NULL)
+	{
+		char *s = CfgReadNextLine(b);
+		if (s != NULL)
+		{
+			if (IsEmptyStr(s) == false)
+			{
+				StrToUni(replace_name, sizeof(replace_name), s);
+				filename = replace_name;
+			}
+
+			Free(s);
+		}
+		FreeBuf(b);
+	}
+
+	ret = LoadTableMain(filename);
+
+	TrackingEnable();
+
+	return ret;
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Table.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Table.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Table.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,143 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Table.h
+// Table.c のヘッダ
+
+#ifndef	TABLE_H
+#define	TABLE_H
+
+#define	UNICODE_CACHE_FILE		L".unicode_cache_%s.dat"
+
+// 言語定数
+#define SE_LANG_JAPANESE			0	// 日本語
+#define SE_LANG_ENGLISH				1	// 英語
+#define SE_LANG_CHINESE_ZH			2	// 中文 (簡体字)
+
+
+// 文字列テーブル
+struct TABLE
+{
+	char *name;
+	char *str;
+	wchar_t *unistr;
+};
+
+// Unicode キャッシュ構造体
+typedef struct UNICODE_CACHE
+{
+	char StrFileName[256];	// 文字列ファイル名
+	UINT StrFileSize;		// 文字列ファイルサイズ
+	char MachineName[256];	// マシン名
+	UINT OsType;			// OS の種類
+	UCHAR hash[MD5_SIZE];	// ハッシュ
+	UCHAR CharSet[64];		// 文字コードの種類
+} UNICODE_CACHE;
+
+// マクロ
+#define	_SS(name)		(GetTableStr((char *)(name)))
+#define	_UU(name)		(GetTableUniStr((char *)(name)))
+#define	_II(name)		(GetTableInt((char *)(name)))
+#define	_E(name)		(GetUniErrorStr((UINT)(name)))
+#define	_EA(name)		(GetErrorStr((UINT)(name)))
+#define _GETLANG()		(_II("LANG"))
+
+
+// 関数プロトタイプ
+bool LoadTable(char *filename);
+bool LoadTableW(wchar_t *filename);
+bool LoadTableMain(wchar_t *filename);
+bool LoadTableFromBuf(BUF *b);
+void FreeTable();
+TABLE *ParseTableLine(char *line, char *prefix, UINT prefix_size);
+void UnescapeStr(char *src);
+int CmpTableName(void *p1, void *p2);
+TABLE *FindTable(char *name);
+TOKEN_LIST *GetTableNameStartWith(char *str);
+char *GetTableStr(char *name);
+wchar_t *GetTableUniStr(char *name);
+char *GetErrorStr(UINT err);
+wchar_t *GetUniErrorStr(UINT err);
+UINT GetTableInt(char *name);
+void GenerateUnicodeCacheFileName(wchar_t *name, UINT size, wchar_t *strfilename, UINT strfilesize, UCHAR *filehash);
+void SaveUnicodeCache(wchar_t *strfilename, UINT strfilesize, UCHAR *hash);
+bool LoadUnicodeCache(wchar_t *strfilename, UINT strfilesize, UCHAR *hash);
+
+#endif	// TABLE_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tick64.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tick64.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tick64.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,370 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Tick64.c
+// 64bit リアルタイムクロックプログラム
+
+#ifdef	WIN32
+#include <windows.h>
+#endif	// WIN32
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <locale.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+static TICK64 *tk64 = NULL;
+static EVENT *halt_tick_event = NULL;
+
+// 高解像度時刻を取得
+UINT64 TickHighres64()
+{
+	UINT64 ret = 0;
+
+#ifdef	OS_WIN32
+
+	ret = (UINT64)(MsGetHiResTimeSpan(MsGetHiResCounter()) * 1000.0f);
+
+#else	// OS_WIN32
+
+	return Tick64();
+
+#endif	// OS_WIN32
+
+	return ret;
+}
+
+// Tick 値を時刻に変換
+UINT64 Tick64ToTime64(UINT64 tick)
+{
+	UINT64 ret = 0;
+	if (tick == 0)
+	{
+		return 0;
+	}
+	LockList(tk64->AdjustTime);
+	{
+		UINT i;
+		for (i = 0;i < LIST_NUM(tk64->AdjustTime);i++)
+		{
+			ADJUST_TIME *t = LIST_DATA(tk64->AdjustTime, i);
+			if (t->Tick <= tick)
+			{
+				ret = t->Time + (tick - t->Tick);
+			}
+		}
+	}
+	UnlockList(tk64->AdjustTime);
+	if (ret == 0)
+	{
+		ret++;
+	}
+	return ret;
+}
+
+// Tick 値を時刻に変換
+UINT64 TickToTime(UINT64 tick)
+{
+	return Tick64ToTime64(tick);
+}
+
+// Tick 値を取得
+UINT64 Tick64()
+{
+#ifdef	OS_WIN32
+	return Win32FastTick64();
+#else	// OS_WIN32
+	UINT64 tick64;
+	if (tk64 == NULL)
+	{
+		return 0;
+	}
+	Lock(tk64->TickLock);
+	{
+		tick64 = tk64->Tick;
+	}
+	Unlock(tk64->TickLock);
+	return tick64;
+#endif	// OS_WIN32
+}
+
+// リアルタイムクロック測定用スレッド
+void Tick64Thread(THREAD *thread, void *param)
+{
+	UINT n = 0;
+	bool first = false;
+	bool create_first_entry = true;
+	UINT tick_span;
+	// 引数チェック
+	if (thread == NULL)
+	{
+		return;
+	}
+
+#ifdef	OS_WIN32
+
+	// Win32 スレッドの優先順位を上げる
+	MsSetThreadPriorityRealtime();
+
+	tick_span = TICK64_SPAN_WIN32;
+
+#else	// OS_WIN32
+
+	// POSIX スレッドの優先順位を上げる
+	UnixSetThreadPriorityRealtime();
+
+	tick_span = TICK64_SPAN;
+
+#endif	// OS_WIN32
+
+	while (true)
+	{
+		UINT tick;
+		UINT64 tick64;
+
+#ifndef	OS_WIN32
+		tick = TickRealtime();		// 現在のシステムクロックを取得
+
+		if (tk64->LastTick > tick)
+		{
+			if ((tk64->LastTick - tick) >= (UINT64)0x0fffffff)
+			{
+				// tick の値が 1 周した
+				tk64->RoundCount++;
+			}
+			else
+			{
+				// tick の値が逆戻りした (システム管理者がハードウェア時計を変更した)
+				// 通常これは 1 秒以内の誤差として発生する
+				tick = tk64->LastTick;
+			}
+		}
+		tk64->LastTick = tick;
+
+		tick64 = (UINT64)tk64->RoundCount * (UINT64)4294967296LL + (UINT64)tick;
+
+		Lock(tk64->TickLock);
+		{
+			if (tk64->TickStart == 0)
+			{
+				tk64->TickStart = tick64;
+			}
+			tick64 = tk64->Tick = tick64 - tk64->TickStart + (UINT64)1;
+		}
+		Unlock(tk64->TickLock);
+#else	// OS_WIN32
+		tick64 = Win32FastTick64();
+		tick = (UINT)tick64;
+#endif	// OS_WIN32
+
+		if (create_first_entry)
+		{
+			ADJUST_TIME *t = ZeroMalloc(sizeof(ADJUST_TIME));
+			t->Tick = tick64;
+			t->Time = SystemTime64();
+			tk64->Tick64WithTime64 = tick64;
+			tk64->Time64 = t->Time;
+			Add(tk64->AdjustTime, t);
+
+			// 初期化完了を通知
+			NoticeThreadInit(thread);
+			create_first_entry = false;
+		}
+
+		// 時刻補正
+		n += tick_span;
+		if (n >= 1000 || first == false)
+		{
+			UINT64 now = SystemTime64();
+
+			if (now < tk64->Time64 ||
+				Diff64((now - tk64->Time64) + tk64->Tick64WithTime64, tick64) >= tick_span)
+			{
+				ADJUST_TIME *t = ZeroMalloc(sizeof(ADJUST_TIME));
+				LockList(tk64->AdjustTime);
+				{
+					t->Tick = tick64;
+					t->Time = now;
+					Add(tk64->AdjustTime, t);
+					Debug("Adjust Time: Tick = %I64u, Time = %I64u\n",
+						t->Tick, t->Time);
+
+					// 時計が狂っているシステムでメモリを無限に食わないように
+					if (LIST_NUM(tk64->AdjustTime) > MAX_ADJUST_TIME)
+					{
+						// 2 個目を削除する
+						ADJUST_TIME *t2 = LIST_DATA(tk64->AdjustTime, 1);
+
+						Delete(tk64->AdjustTime, t2);
+
+						Debug("NUM_ADJUST TIME: %u\n", LIST_NUM(tk64->AdjustTime));
+
+						Free(t2);
+					}
+				}
+				UnlockList(tk64->AdjustTime);
+				tk64->Time64 = now;
+				tk64->Tick64WithTime64 = tick64;
+			}
+			first = true;
+			n = 0;
+		}
+
+		if (tk64->Halt)
+		{
+			break;
+		}
+
+#ifdef	OS_WIN32
+		Wait(halt_tick_event, tick_span);
+#else	// OS_WIN32
+		SleepThread(tick_span);
+#endif	// OS_WIN32
+	}
+}
+
+// 2 つの 64 bit 整数の差の絶対値を取得
+UINT64 Diff64(UINT64 a, UINT64 b)
+{
+	if (a > b)
+	{
+		return a - b;
+	}
+	else
+	{
+		return b - a;
+	}
+}
+
+// Tick64 の初期化
+void InitTick64()
+{
+	if (tk64 != NULL)
+	{
+		// すでに初期化されている
+		return;
+	}
+
+	halt_tick_event = NewEvent();
+
+	// 構造体の初期化
+	tk64 = ZeroMalloc(sizeof(TICK64));
+	tk64->TickLock = NewLock();
+	tk64->AdjustTime = NewList(NULL);
+
+	// スレッドの作成
+	tk64->Thread = NewThread(Tick64Thread, NULL);
+	WaitThreadInit(tk64->Thread);
+}
+
+// Tick64 の解放
+void FreeTick64()
+{
+	UINT i;
+	if (tk64 == NULL)
+	{
+		// 初期化されていない
+		return;
+	}
+
+	// 終了処理
+	tk64->Halt = true;
+	Set(halt_tick_event);
+	WaitThread(tk64->Thread, INFINITE);
+	ReleaseThread(tk64->Thread);
+
+	// 解放処理
+	for (i = 0;i < LIST_NUM(tk64->AdjustTime);i++)
+	{
+		ADJUST_TIME *t = LIST_DATA(tk64->AdjustTime, i);
+		Free(t);
+	}
+	ReleaseList(tk64->AdjustTime);
+	DeleteLock(tk64->TickLock);
+	Free(tk64);
+	tk64 = NULL;
+
+	ReleaseEvent(halt_tick_event);
+	halt_tick_event = NULL;
+}
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tick64.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tick64.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tick64.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,127 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Tick64.h
+// Tick64.c のヘッダ
+
+#ifndef	TICK64_H
+#define	TICK64_H
+
+// 最大の補正リストエントリ数
+#define	MAX_ADJUST_TIME				5000
+
+// 補正リストエントリ
+struct ADJUST_TIME
+{
+	UINT64 Tick;
+	UINT64 Time;
+};
+
+// TICK64 構造体
+struct TICK64
+{
+	THREAD *Thread;
+	UINT64 Tick;
+	UINT64 TickStart;
+	UINT64 Time64;
+	UINT64 Tick64WithTime64;
+	UINT LastTick;
+	UINT RoundCount;
+	LOCK *TickLock;
+	volatile bool Halt;
+	LIST *AdjustTime;
+};
+
+// 定数
+#define	TICK64_SPAN			10		// 測定間隔 (通常は 10ms以下)
+#define	TICK64_SPAN_WIN32	1000	// Win32 での測定間隔
+#define	TICK64_ADJUST_SPAN	5000	// この値以上時計がずれたら補正する
+
+// 関数プロトタイプ
+void InitTick64();
+void FreeTick64();
+void Tick64Thread(THREAD *thread, void *param);
+UINT64 Tick64();
+UINT64 Diff64(UINT64 a, UINT64 b);
+UINT64 Tick64ToTime64(UINT64 tick);
+UINT64 TickToTime(UINT64 tick);
+UINT64 TickHighres64();
+
+#endif	// TICK64_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tracking.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tracking.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tracking.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,966 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Tracking.c
+// オブジェクト追跡モジュール
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// グローバル変数
+static LOCK *obj_lock;
+static LOCK *obj_id_lock;
+static UINT obj_id;
+static LOCK *cs_lock;
+static bool disable_tracking = false;
+static TRACKING_LIST **hashlist;
+
+static bool do_not_get_callstack;
+
+// 追跡を有効にする
+void TrackingEnable()
+{
+	disable_tracking = false;
+}
+
+// 追跡を無効にする
+void TrackingDisable()
+{
+	disable_tracking = true;
+}
+
+// 追跡が有効かどうか取得
+bool IsTrackingEnabled()
+{
+	return !disable_tracking;
+}
+
+// メモリデバッグメニュー
+void MemoryDebugMenu()
+{
+	char tmp[MAX_SIZE];
+	TOKEN_LIST *t;
+	char *cmd;
+	Print("Mayaqua Kernel Memory Debug Tools\n"
+		"Copyright (C) SoftEther Corporation. All Rights Reserved.\n\n");
+	g_memcheck = false;
+	while (true)
+	{
+		Print("debug>");
+		GetLine(tmp, sizeof(tmp));
+		t = ParseToken(tmp, " \t");
+		if (t->NumTokens == 0)
+		{
+			FreeToken(t);
+			DebugPrintAllObjects();
+			continue;
+		}
+		cmd = t->Token[0];
+		if (!StrCmpi(cmd, "?"))
+		{
+			DebugPrintCommandList();
+		}
+		else if (!StrCmpi(cmd, "a"))
+		{
+			DebugPrintAllObjects();
+		}
+		else if (!StrCmpi(cmd, "i"))
+		{
+			if (t->NumTokens == 1)
+			{
+				Print("Usage: i <obj_id>\n\n");
+			}
+			else
+			{
+				DebugPrintObjectInfo(ToInt(t->Token[1]));
+			}
+		}
+		else if (!StrCmpi(cmd, "q"))
+		{
+			break;
+		}
+		else if (ToInt(cmd) != 0)
+		{
+			DebugPrintObjectInfo(ToInt(t->Token[0]));
+		}
+		else
+		{
+			Print("Command Not Found,\n\n");
+		}
+		FreeToken(t);
+	}
+	FreeToken(t);
+	g_memcheck = true;
+}
+
+// オブジェクトを時間順にソートする
+int SortObjectView(void *p1, void *p2)
+{
+	TRACKING_OBJECT *o1, *o2;
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	o1 = *(TRACKING_OBJECT **)p1;
+	o2 = *(TRACKING_OBJECT **)p2;
+	if (o1 == NULL || o2 == NULL)
+	{
+		return 0;
+	}
+
+	if (o1->Id > o2->Id)
+	{
+		return 1;
+	}
+	else if (o1->Id == o2->Id)
+	{
+		return 0;
+	}
+	return -1;
+}
+
+// オブジェクト情報の表示
+void PrintObjectInfo(TRACKING_OBJECT *o)
+{
+	SYSTEMTIME t;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	UINT64ToSystem(&t, o->CreatedDate);
+	GetDateTimeStrMilli(tmp, sizeof(tmp), &t);
+
+	Print("    TRACKING_OBJECT ID: %u\n"
+		"  TRACKING_OBJECT TYPE: %s\n"
+		"      ADDRESS: 0x%p\n"
+		"  TRACKING_OBJECT SIZE: %u bytes\n"
+		" CREATED DATE: %s\n",
+		o->Id, o->Name, UINT64_TO_POINTER(o->Address), o->Size, tmp);
+
+	PrintCallStack(o->CallStack);
+}
+
+// オブジェクト情報を表示する
+void DebugPrintObjectInfo(UINT id)
+{
+	UINT i;
+	TRACKING_OBJECT *o;
+
+	// 検索
+	o = NULL;
+	LockTrackingList();
+	{
+		for (i = 0;i < TRACKING_NUM_ARRAY;i++)
+		{
+			if (hashlist[i] != NULL)
+			{
+				TRACKING_LIST *t = hashlist[i];
+
+				while (true)
+				{
+					if (t->Object->Id == id)
+					{
+						o = t->Object;
+						break;
+					}
+
+					if (t->Next == NULL)
+					{
+						break;
+					}
+
+					t = t->Next;
+				}
+
+				if (o != NULL)
+				{
+					break;
+				}
+			}
+		}
+	}
+	UnlockTrackingList();
+
+	if (o == NULL)
+	{
+		// ID が発見できなかった
+		Print("obj_id %u Not Found.\n\n", id);
+		return;
+	}
+
+	PrintObjectInfo(o);
+	Print("\n");
+}
+
+// オブジェクトのサマリーの表示
+void PrintObjectList(TRACKING_OBJECT *o)
+{
+	char tmp[MAX_SIZE];
+	SYSTEMTIME t;
+	UINT64ToSystem(&t, o->CreatedDate);
+	GetTimeStrMilli(tmp, sizeof(tmp), &t);
+	TrackGetObjSymbolInfo(o);
+	Print("%-4u - [%-6s] %s 0x%p size=%-5u %11s %u\n",
+		o->Id, o->Name, tmp, UINT64_TO_POINTER(o->Address), o->Size, o->FileName, o->LineNumber);
+}
+
+// すべてのオブジェクトの表示
+void DebugPrintAllObjects()
+{
+	UINT i;
+	LIST *view;
+
+	// リスト作成
+	view = NewListFast(SortObjectView);
+	LockTrackingList();
+	{
+		for (i = 0;i < TRACKING_NUM_ARRAY;i++)
+		{
+			if (hashlist[i] != NULL)
+			{
+				TRACKING_LIST *t = hashlist[i];
+
+				while (true)
+				{
+					Add(view, t->Object);
+
+					if (t->Next == NULL)
+					{
+						break;
+					}
+
+					t = t->Next;
+				}
+			}
+		}
+	}
+	UnlockTrackingList();
+
+	// ソート
+	Sort(view);
+
+	// 描画
+	for (i = 0;i < LIST_NUM(view);i++)
+	{
+		TRACKING_OBJECT *o = (TRACKING_OBJECT *)LIST_DATA(view, i);
+		PrintObjectList(o);
+	}
+
+	// リスト解放
+	ReleaseList(view);
+
+	Print("\n");
+}
+
+// コマンド一覧
+void DebugPrintCommandList()
+{
+	Print(
+		"a - All Objects\n"
+		"i - Object Information\n"
+		"? - Help\n"
+		"q - Quit\n\n"
+		);
+}
+
+// メモリの使用状態を表示する
+void PrintMemoryStatus()
+{
+	MEMORY_STATUS s;
+	GetMemoryStatus(&s);
+	Print("MEMORY STATUS:\n"
+		" NUM_OF_MEMORY_BLOCKS: %u\n"
+		" SIZE_OF_TOTAL_MEMORY: %u bytes\n",
+		s.MemoryBlocksNum, s.MemorySize);
+}
+
+// メモリの使用状態を取得する
+void GetMemoryStatus(MEMORY_STATUS *status)
+{
+	UINT i, num, size;
+	// 引数チェック
+	if (status == NULL)
+	{
+		return;
+	}
+
+	LockTrackingList();
+	{
+		size = num = 0;
+
+		for (i = 0;i < TRACKING_NUM_ARRAY;i++)
+		{
+			if (hashlist[i] != NULL)
+			{
+				TRACKING_LIST *t = hashlist[i];
+
+				while (true)
+				{
+					TRACKING_OBJECT *o = t->Object;
+
+					if (StrCmpi(o->Name, "MEM") == 0)
+					{
+						num++;
+						size += o->Size;
+					}
+
+					if (t->Next == NULL)
+					{
+						break;
+					}
+
+					t = t->Next;
+				}
+			}
+		}
+	}
+	UnlockTrackingList();
+
+	status->MemoryBlocksNum = num;
+	status->MemorySize = size;
+}
+
+// オブジェクトからシンボル情報を取得する
+void TrackGetObjSymbolInfo(TRACKING_OBJECT *o)
+{
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	if (!(o->LineNumber == 0 && o->FileName[0] == 0))
+	{
+		return;
+	}
+
+	if (o->CallStack != NULL)
+	{
+		GetCallStackSymbolInfo(o->CallStack);
+		if (StrLen(o->CallStack->filename) != 0 && o->CallStack->line != 0)
+		{
+			StrCpy(o->FileName, sizeof(o->FileName), o->CallStack->filename);
+			o->LineNumber = o->CallStack->line;
+		}
+	}
+}
+
+// 新しいオブジェクトを追跡リストに入れる
+void TrackNewObj(UINT64 addr, char *name, UINT size)
+{
+	TRACKING_OBJECT *o;
+	UINT new_id;
+	// 引数チェック
+	if (addr == 0 || name == NULL)
+	{
+		return;
+	}
+
+	if (IsMemCheck() == false)
+	{
+		// リリースモードでは追跡しない
+		return;
+	}
+
+	if (disable_tracking)
+	{
+		return;
+	}
+
+	// 新しい ID の生成
+	OSLock(obj_id_lock);
+	{
+		new_id = ++obj_id;
+	}
+	OSUnlock(obj_id_lock);
+
+	o = OSMemoryAlloc(sizeof(TRACKING_OBJECT));
+	o->Id = new_id;
+	o->Address = addr;
+	o->Name = name;
+	o->Size = size;
+	o->CreatedDate = LocalTime64();
+	o->CallStack = WalkDownCallStack(GetCallStack(), 2);
+
+	o->FileName[0] = 0;
+	o->LineNumber = 0;
+
+	LockTrackingList();
+	{
+		InsertTrackingList(o);
+	}
+	UnlockTrackingList();
+}
+
+// 追跡リストからオブジェクトを削除する
+void TrackDeleteObj(UINT64 addr)
+{
+	TRACKING_OBJECT *o;
+	// 引数チェック
+	if (addr == 0)
+	{
+		return;
+	}
+
+	if (IsMemCheck() == false)
+	{
+		// リリースモードでは追跡しない
+		return;
+	}
+
+	if (disable_tracking)
+	{
+		return;
+	}
+
+	LockTrackingList();
+	{
+		o = SearchTrackingList(addr);
+		if (o == NULL)
+		{
+			UnlockTrackingList();
+
+			if (IsDebug())
+			{
+				printf("TrackDeleteObj: 0x%x is not Object!!\n", (void *)addr);
+			}
+			return;
+		}
+		DeleteTrackingList(o, true);
+	}
+	UnlockTrackingList();
+}
+
+// 追跡しているオブジェクトのサイズを変更する
+void TrackChangeObjSize(UINT64 addr, UINT size, UINT64 new_addr)
+{
+	TRACKING_OBJECT *o;
+	// 引数チェック
+	if (addr == 0)
+	{
+		return;
+	}
+
+	if (IsMemCheck() == false)
+	{
+		// リリースモードでは追跡しない
+		return;
+	}
+
+	if (disable_tracking)
+	{
+		return;
+	}
+
+	LockTrackingList();
+	{
+		o = SearchTrackingList(addr);
+		if (o == NULL)
+		{
+			UnlockTrackingList();
+			return;
+		}
+
+		DeleteTrackingList(o, false);
+
+		o->Size = size;
+		o->Address = new_addr;
+
+		InsertTrackingList(o);
+	}
+	UnlockTrackingList();
+}
+
+// メモリアドレス比較関数
+int CompareTrackingObject(const void *p1, const void *p2)
+{
+	TRACKING_OBJECT *o1, *o2;
+	// 引数チェック
+	if (p1 == NULL || p2 == NULL)
+	{
+		return 0;
+	}
+	o1 = *(TRACKING_OBJECT **)p1;
+	o2 = *(TRACKING_OBJECT **)p2;
+	if (o1 == NULL || o2 == NULL)
+	{
+		return 0;
+	}
+
+	if (o1->Address > o2->Address)
+	{
+		return 1;
+	}
+	if (o1->Address == o2->Address)
+	{
+		return 0;
+	}
+	return -1;
+}
+
+// オブジェクトをトラッキングリストから検索
+TRACKING_OBJECT *SearchTrackingList(UINT64 Address)
+{
+	UINT i;
+	// 引数チェック
+	if (Address == 0)
+	{
+		return NULL;
+	}
+
+	i = TRACKING_HASH(Address);
+
+	if (hashlist[i] != NULL)
+	{
+		TRACKING_LIST *tt = hashlist[i];
+
+		while (true)
+		{
+			if (tt->Object->Address == Address)
+			{
+				return tt->Object;
+			}
+
+			tt = tt->Next;
+
+			if (tt == NULL)
+			{
+				break;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+// オブジェクトをトラッキングリストから削除
+void DeleteTrackingList(TRACKING_OBJECT *o, bool free_object_memory)
+{
+	UINT i;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	i = TRACKING_HASH(o->Address);
+
+	if (hashlist[i] != NULL)
+	{
+		TRACKING_LIST *ft = NULL;
+
+		if (hashlist[i]->Object == o)
+		{
+			ft = hashlist[i];
+			hashlist[i] = hashlist[i]->Next;
+		}
+		else
+		{
+			TRACKING_LIST *tt = hashlist[i];
+			TRACKING_LIST *prev = NULL;
+
+			while (true)
+			{
+				if (tt->Object == o)
+				{
+					prev->Next = tt->Next;
+					ft = tt;
+					break;
+				}
+
+				if (tt->Next == NULL)
+				{
+					break;
+				}
+
+				prev = tt;
+				tt = tt->Next;
+			}
+		}
+
+		if (ft != NULL)
+		{
+			OSMemoryFree(ft);
+
+			if (free_object_memory)
+			{
+				FreeCallStack(o->CallStack);
+				OSMemoryFree(o);
+			}
+		}
+	}
+}
+
+// オブジェクトをトラッキングリストに挿入
+void InsertTrackingList(TRACKING_OBJECT *o)
+{
+	UINT i;
+	TRACKING_LIST *t;
+	// 引数チェック
+	if (o == NULL)
+	{
+		return;
+	}
+
+	t = OSMemoryAlloc(sizeof(TRACKING_LIST));
+	t->Object = o;
+	t->Next = NULL;
+
+	i = TRACKING_HASH(o->Address);
+
+	if (hashlist[i] == NULL)
+	{
+		hashlist[i] = t;
+	}
+	else
+	{
+		TRACKING_LIST *tt = hashlist[i];
+		while (true)
+		{
+			if (tt->Next == NULL)
+			{
+				tt->Next = t;
+				break;
+			}
+
+			tt = tt->Next;
+		}
+	}
+}
+
+// トラッキングリストのロック
+void LockTrackingList()
+{
+	OSLock(obj_lock);
+}
+
+// トラッキングリストのロック解除
+void UnlockTrackingList()
+{
+	OSUnlock(obj_lock);
+}
+
+// トラッキングの初期化
+void InitTracking()
+{
+	UINT i;
+	CALLSTACK_DATA *s;
+
+	// ハッシュリスト初期化
+	hashlist = (TRACKING_LIST **)OSMemoryAlloc(sizeof(TRACKING_LIST *) * TRACKING_NUM_ARRAY);
+
+	for (i = 0;i < TRACKING_NUM_ARRAY;i++)
+	{
+		hashlist[i] = NULL;
+	}
+
+	obj_id = 0;
+
+	// ロック作成
+	obj_lock = OSNewLock();
+	obj_id_lock = OSNewLock();
+	cs_lock = OSNewLock();
+
+	s = GetCallStack();
+	if (s == NULL)
+	{
+		do_not_get_callstack = true;
+	}
+	else
+	{
+		do_not_get_callstack = false;
+		FreeCallStack(s);
+	}
+}
+
+// トラッキングの解放
+void FreeTracking()
+{
+	UINT i;
+	// ロック削除
+	OSDeleteLock(obj_lock);
+	OSDeleteLock(obj_id_lock);
+	OSDeleteLock(cs_lock);
+	cs_lock = NULL;
+	obj_id_lock = NULL;
+	obj_lock = NULL;
+
+	// すべての要素を解放
+	for (i = 0;i < TRACKING_NUM_ARRAY;i++)
+	{
+		if (hashlist[i] != NULL)
+		{
+			TRACKING_LIST *t = hashlist[i];
+
+			while (true)
+			{
+				TRACKING_LIST *t2 = t;
+				TRACKING_OBJECT *o = t->Object;
+
+				FreeCallStack(o->CallStack);
+				OSMemoryFree(o);
+
+				t = t->Next;
+
+				OSMemoryFree(t2);
+
+				if (t == NULL)
+				{
+					break;
+				}
+			}
+		}
+	}
+
+	// リスト解放
+	OSMemoryFree(hashlist);
+}
+
+// コールスタックを表示する
+void PrintCallStack(CALLSTACK_DATA *s)
+{
+	char tmp[MAX_SIZE * 2];
+
+	GetCallStackStr(tmp, sizeof(tmp), s);
+	Print("%s", tmp);
+}
+
+// コールスタックを文字列に変換する
+void GetCallStackStr(char *str, UINT size, CALLSTACK_DATA *s)
+{
+	char tmp[MAX_SIZE];
+	char tmp2[MAX_SIZE];
+	char tmp3[MAX_SIZE];
+	UINT num, i;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	if (s == NULL)
+	{
+		StrCpy(str, size, "(Unknown)\n");
+	}
+	else
+	{
+		num = 0;
+		str[0] = 0;
+		while (true)
+		{
+			if (s == NULL)
+			{
+				break;
+			}
+
+			GetCallStackSymbolInfo(s);
+
+			if (s->name == NULL)
+			{
+				Format(tmp, sizeof(tmp), "0x%p ---", UINT64_TO_POINTER(s->offset));
+			}
+			else
+			{
+				Format(tmp, sizeof(tmp), "0x%p %s() + 0x%02x",
+					(void *)s->offset, s->name, UINT64_TO_POINTER(s->disp));
+			}
+			for (i = 0;i < num;i++)
+			{
+				tmp2[i] = ' ';
+			}
+			tmp2[i] = '\0';
+			StrCpy(tmp3, sizeof(tmp3), tmp2);
+			StrCat(tmp3, sizeof(tmp3), tmp);
+			Format(tmp, sizeof(tmp), "%-55s %11s %u\n", tmp3, s->filename, s->line);
+			StrCat(str, size, tmp);
+			num++;
+			s = s->next;
+		}
+	}
+}
+
+// 現在のコールスタックの取得
+CALLSTACK_DATA *GetCallStack()
+{
+	CALLSTACK_DATA *s;
+	if (do_not_get_callstack)
+	{
+		// コールスタックは取得しない
+		return NULL;
+	}
+
+	OSLock(cs_lock);
+	{
+		// コールスタックの取得
+		s = OSGetCallStack();
+	}
+	OSUnlock(cs_lock);
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	// コールスタックを 3 つ分だけ下降する
+	s = WalkDownCallStack(s, 3);
+
+	return s;
+}
+
+// コールスタックのシンボル情報を取得
+bool GetCallStackSymbolInfo(CALLSTACK_DATA *s)
+{
+	bool ret;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	OSLock(cs_lock);
+	{
+		ret = OSGetCallStackSymbolInfo(s);
+	}
+	OSUnlock(cs_lock);
+
+	return ret;
+}
+
+// コールスタックを指定された数だけ下降する
+CALLSTACK_DATA *WalkDownCallStack(CALLSTACK_DATA *s, UINT num)
+{
+	CALLSTACK_DATA *cs, *tmp;
+	UINT i;
+	// 引数チェック
+	if (s == NULL)
+	{
+		return NULL;
+	}
+
+	cs = s;
+	i = 0;
+
+	while (true)
+	{
+		if (i >= num)
+		{
+			return cs;
+		}
+		i++;
+		tmp = cs;
+		cs = tmp->next;
+		OSMemoryFree(tmp->name);
+		OSMemoryFree(tmp);
+
+		if (cs == NULL)
+		{
+			return NULL;
+		}
+	}
+}
+
+// コールスタックの解放
+void FreeCallStack(CALLSTACK_DATA *s)
+{
+	// 引数チェック
+	if (s == NULL)
+	{
+		return;
+	}
+
+	while (true)
+	{
+		CALLSTACK_DATA *next = s->next;
+		OSMemoryFree(s->name);
+		OSMemoryFree(s);
+		if (next == NULL)
+		{
+			break;
+		}
+		s = next;
+	}
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tracking.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tracking.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Tracking.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,164 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Tracking.h
+// Tracking.c のヘッダ
+
+#ifndef	TRACKING_H
+#define	TRACKING_H
+
+// 配列の数
+#define	TRACKING_NUM_ARRAY	1048576
+
+// ポインタから配列番号をハッシュ
+#define	TRACKING_HASH(p)	(UINT)(((((UINT64)(p)) / (UINT64)(sizeof(void *))) % ((UINT64)TRACKING_NUM_ARRAY)))
+
+// コールスタック
+struct CALLSTACK_DATA
+{
+	bool symbol_cache;
+	UINT64 offset, disp;
+	char *name;
+	struct CALLSTACK_DATA *next;
+	char filename[MAX_PATH];
+	UINT line;
+};
+
+// オブジェクト
+struct TRACKING_OBJECT
+{
+	UINT Id;
+	char *Name;
+	UINT64 Address;
+	UINT Size;
+	UINT64 CreatedDate;
+	CALLSTACK_DATA *CallStack;
+	char FileName[MAX_PATH];
+	UINT LineNumber;
+};
+
+// メモリの使用状態
+struct MEMORY_STATUS
+{
+	UINT MemoryBlocksNum;
+	UINT MemorySize;
+};
+
+// トラッキングリスト
+struct TRACKING_LIST
+{
+	struct TRACKING_LIST *Next;
+	struct TRACKING_OBJECT *Object;
+};
+
+CALLSTACK_DATA *GetCallStack();
+bool GetCallStackSymbolInfo(CALLSTACK_DATA *s);
+void FreeCallStack(CALLSTACK_DATA *s);
+CALLSTACK_DATA *WalkDownCallStack(CALLSTACK_DATA *s, UINT num);
+void GetCallStackStr(char *str, UINT size, CALLSTACK_DATA *s);
+void PrintCallStack(CALLSTACK_DATA *s);
+void InitTracking();
+void FreeTracking();
+int CompareTrackingObject(const void *p1, const void *p2);
+void LockTrackingList();
+void UnlockTrackingList();
+void InsertTrackingList(TRACKING_OBJECT *o);
+void DeleteTrackingList(TRACKING_OBJECT *o, bool free_object_memory);
+TRACKING_OBJECT *SearchTrackingList(UINT64 Address);
+
+void TrackNewObj(UINT64 addr, char *name, UINT size);
+void TrackGetObjSymbolInfo(TRACKING_OBJECT *o);
+void TrackDeleteObj(UINT64 addr);
+void TrackChangeObjSize(UINT64 addr, UINT size, UINT64 new_addr);
+
+void GetMemoryStatus(MEMORY_STATUS *status);
+void PrintMemoryStatus();
+void MemoryDebugMenu();
+int SortObjectView(void *p1, void *p2);
+void DebugPrintAllObjects();
+void DebugPrintCommandList();
+void PrintObjectList(TRACKING_OBJECT *o);
+void PrintObjectInfo(TRACKING_OBJECT *o);
+void DebugPrintObjectInfo(UINT id);
+
+void TrackingEnable();
+void TrackingDisable();
+bool IsTrackingEnabled();
+
+#endif	// TRACKING_H
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/TunTap.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/TunTap.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/TunTap.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,308 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+#ifndef	TUNTAP_H
+#define	TUNTAP_H
+
+#ifdef	UNIX_LINUX
+
+// -----------------------------------------------------------------
+// Linux 用 tap ヘッダ
+// -----------------------------------------------------------------
+/*
+ *  Universal TUN/TAP device driver.
+ *  Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  $Id: if_tun.h,v 1.2 2001/10/31 15:27:57 arjanv Exp $
+ */
+
+#ifndef __IF_TUN_H
+#define __IF_TUN_H
+
+/* Uncomment to enable debugging */
+/* #define TUN_DEBUG 1 */
+
+
+
+/* Read queue size */
+#define TUN_READQ_SIZE  10
+
+/* TUN device flags */
+#define TUN_TUN_DEV     0x0001  
+#define TUN_TAP_DEV     0x0002
+#define TUN_TYPE_MASK   0x000f
+
+#define TUN_FASYNC      0x0010
+#define TUN_NOCHECKSUM  0x0020
+#define TUN_NO_PI       0x0040
+#define TUN_ONE_QUEUE   0x0080
+#define TUN_PERSIST     0x0100  
+
+/* Ioctl defines */
+#define TUNSETNOCSUM  _IOW('T', 200, int) 
+#define TUNSETDEBUG   _IOW('T', 201, int) 
+#define TUNSETIFF     _IOW('T', 202, int) 
+#define TUNSETPERSIST _IOW('T', 203, int) 
+#define TUNSETOWNER   _IOW('T', 204, int)
+
+/* TUNSETIFF ifr flags */
+#define IFF_TUN         0x0001
+#define IFF_TAP         0x0002
+#define IFF_NO_PI       0x1000
+#define IFF_ONE_QUEUE   0x2000
+
+struct tun_pi {
+        unsigned short flags;
+        unsigned short proto;
+};
+#define TUN_PKT_STRIP   0x0001
+
+#endif /* __IF_TUN_H */
+#else	// UNIX_LINUX
+
+#ifdef	UNIX_SOLARIS
+
+// -----------------------------------------------------------------
+// Solaris 用 tap ヘッダ
+// -----------------------------------------------------------------
+/*
+ *  Universal TUN/TAP device driver.
+ *
+ *  Multithreaded STREAMS tun pseudo device driver.
+ *
+ *  Copyright (C) 1999-2000 Maxim Krasnyansky <max_mk@yahoo.com>
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  $Id: if_tun.h,v 1.4 2000/05/01 12:23:27 maxk Exp $
+ */
+
+#ifndef _SYS_IF_TUN_H
+#define _SYS_IF_TUN_H
+
+#ifdef _KERNEL
+/* Uncomment to enable debuging */
+/* #define TUN_DEBUG 1 */
+
+#ifdef TUN_DEBUG
+#define DBG      cmn_err
+#else
+#define DBG( a... )
+#endif
+
+/* PPA structure, one per TUN iface */ 
+struct tunppa {
+  unsigned int id;              /* Iface number         */
+  queue_t *rq;                  /* Control Stream RQ    */
+  struct tunstr * p_str;        /* Protocol Streams     */
+}; 
+#define TUNMAXPPA       20
+
+/* Stream structure, one per Stream */
+struct tunstr {
+  struct tunstr *s_next;        /* next in streams list */
+  struct tunstr *p_next;        /* next in ppa list */
+  queue_t *rq;                  /* pointer to rq */
+
+  struct tunppa *ppa;           /* assigned PPA */
+  u_long flags;                 /* flags */
+  u_long state;                 /* DL state */
+  u_long sap;                   /* bound sap */
+  u_long minor;                 /* minor device number */
+};
+
+/* Flags */
+#define TUN_CONTROL     0x0001
+
+#define TUN_RAW         0x0100
+#define TUN_FAST        0x0200
+
+#define TUN_ALL_PHY     0x0010
+#define TUN_ALL_SAP     0x0020
+#define TUN_ALL_MUL     0x0040
+
+#define SNIFFER(a) ( (a & TUN_ALL_SAP) || (a & TUN_ALL_PHY) )
+
+struct tundladdr {
+  u_short sap;
+};
+#define TUN_ADDR_LEN    (sizeof(struct tundladdr))
+
+#define TUN_QUEUE       0
+#define TUN_DROP        1
+
+#endif /* _KERNEL */
+
+/* IOCTL defines */
+#define TUNNEWPPA       (('T'<<16) | 0x0001)
+#define TUNSETPPA       (('T'<<16) | 0x0002)
+
+#endif  /* _SYS_IF_TUN_H */
+
+#else	// UNIX_SOLARIS
+
+#ifdef	UNIX_BSD
+
+// -----------------------------------------------------------------
+// FreeBSD 用 tap ヘッダ
+// -----------------------------------------------------------------
+/*      $NetBSD: if_tun.h,v 1.5 1994/06/29 06:36:27 cgd Exp $   */
+
+/*
+ * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
+ * Nottingham University 1987.
+ *
+ * This source may be freely distributed, however I would be interested
+ * in any changes that are made.
+ *
+ * This driver takes packets off the IP i/f and hands them up to a
+ * user process to have its wicked way with. This driver has it's
+ * roots in a similar driver written by Phil Cockcroft (formerly) at
+ * UCL. This driver is based much more on read/write/select mode of
+ * operation though.
+ *
+ * $FreeBSD: src/sys/net/if_tun.h,v 1.17 2000/01/23 01:47:12 brian Exp $
+ */
+
+#ifndef _NET_IF_TUN_H_
+#define _NET_IF_TUN_H_
+
+/* Refer to if_tunvar.h for the softc stuff */
+
+/* Maximum transmit packet size (default) */
+#define TUNMTU          1500
+
+/* Maximum receive packet size (hard limit) */
+#define TUNMRU          16384
+
+struct tuninfo {
+        int     baudrate;               /* linespeed */
+        short   mtu;                    /* maximum transmission unit */
+        u_char  type;                   /* ethernet, tokenring, etc. */
+        u_char  dummy;                  /* place holder */
+};
+
+/* ioctl's for get/set debug */
+#define TUNSDEBUG       _IOW('t', 90, int)
+#define TUNGDEBUG       _IOR('t', 89, int)
+#define TUNSIFINFO      _IOW('t', 91, struct tuninfo)
+#define TUNGIFINFO      _IOR('t', 92, struct tuninfo)
+#define TUNSLMODE       _IOW('t', 93, int)
+#define TUNSIFMODE      _IOW('t', 94, int)
+#define TUNSIFPID       _IO('t', 95)
+#define TUNSIFHEAD      _IOW('t', 96, int)
+#define TUNGIFHEAD      _IOR('t', 97, int)
+
+#endif /* !_NET_IF_TUN_H_ */
+
+#else	// UNIX_BSD
+
+#ifdef	UNIX_MACOS
+
+// -----------------------------------------------------------------
+// MacOS 用 tap ヘッダ
+// -----------------------------------------------------------------
+
+#else	// UNIX_MACOS
+
+#endif	// UNIX_MACOS
+
+#endif	// UNIX_BSD
+
+#endif	// UNIX_SOLARIS
+
+#endif	// UNIX_LINUX
+
+#endif	// TUNTAP_H
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Unix.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Unix.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Unix.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,2438 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Unix.c
+// UNIX 依存コード
+
+#ifdef	UNIX
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+// MacOS X 用の struct statfs
+#ifdef	UNIX_MACOS
+typedef struct fsid { int32_t val[2]; } fsid_t;
+struct statfs {
+        short   f_otype;                /* TEMPORARY SHADOW COPY OF f_type */
+        short   f_oflags;               /* TEMPORARY SHADOW COPY OF f_flags */
+        long    f_bsize;                /* fundamental file system block size */
+        long    f_iosize;               /* optimal transfer block size */
+        long    f_blocks;               /* total data blocks in file system */
+        long    f_bfree;                /* free blocks in fs */
+        long    f_bavail;               /* free blocks avail to non-superuser */
+        long    f_files;                /* total file nodes in file system */
+        long    f_ffree;                /* free file nodes in fs */
+        fsid_t  f_fsid;                 /* file system id */
+        uid_t   f_owner;                /* user that mounted the filesystem */
+        short   f_reserved1;    /* spare for later */
+        short   f_type;                 /* type of filesystem */
+    long        f_flags;                /* copy of mount exported flags */
+        long    f_reserved2[2]; /* reserved for future use */
+        char    f_fstypename[15]; /* fs type name */
+        char    f_mntonname[90];  /* directory on which mounted */
+        char    f_mntfromname[90];/* mounted filesystem */
+};
+#endif	// UNIX_MACOS
+
+// Solaris 用の scandir() 関数
+#ifdef	UNIX_SOLARIS
+#define scandir local_scandir
+#define	alphasort local_alphasort
+
+/*******************************************
+ * Copyright Free の互換ルーチン (local_scandir)
+ * コピー元: http://www005.upp.so-net.ne.jp/yoga/compile.html
+ *******************************************/
+
+int local_scandir(const char *dir, struct dirent ***namelist,
+            int (*select)(const struct dirent *),
+            int (*compar)(const struct dirent **, const struct dirent **))
+{
+  DIR *d;
+  struct dirent *entry;
+  register int i=0;
+  size_t entrysize;
+
+  if ((d=opendir(dir)) == NULL)
+     return(-1);
+
+  *namelist=NULL;
+  while ((entry=readdir(d)) != NULL)
+  {
+    if (select == NULL || (select != NULL && (*select)(entry)))
+    {
+      *namelist=(struct dirent **)realloc((void *)(*namelist),
+                 (size_t)((i+1)*sizeof(struct dirent *)));
+	if (*namelist == NULL) return(-1);
+	entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
+	(*namelist)[i]=(struct dirent *)malloc(entrysize);
+	if ((*namelist)[i] == NULL) return(-1);
+	memcpy((*namelist)[i], entry, entrysize);
+	i++;
+    }
+  }
+  if (closedir(d)) return(-1);
+  if (i == 0) return(-1);
+  if (compar != NULL)
+    qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
+    
+  return(i);
+}
+
+int local_alphasort(const struct dirent **a, const struct dirent **b)
+{
+  return(strcmp((*a)->d_name, (*b)->d_name));
+}
+
+
+#endif	// UNIX_SOLARIS
+
+// UNIX 用スレッドデータ
+typedef struct UNIXTHREAD
+{
+	pthread_t thread;
+	bool finished;
+} UNIXTHREAD;
+
+// UNIX 用スレッド起動情報
+typedef struct UNIXTHREADSTARTUPINFO
+{
+	THREAD_PROC *thread_proc;
+	void *param;
+	THREAD *thread;
+} UNIXTHREADSTARTUPINFO;
+
+// UNIX 用スレッド関数プロトタイプ
+void *UnixDefaultThreadProc(void *param);
+
+// 現在のプロセス ID
+static pid_t current_process_id = 0;
+
+// UNIX 用ファイル I/O データ
+typedef struct UNIXIO
+{
+	int fd;
+	bool write_mode;
+} UNIXIO;
+
+// UNIX 用ロックファイルデータ
+typedef struct UNIXLOCKFILE
+{
+	char FileName[MAX_SIZE];
+	int fd;
+} UNIXLOCKFILE;
+
+// UNIX 用イベントデータ
+typedef struct UNIXEVENT
+{
+	pthread_mutex_t mutex;
+	pthread_cond_t cond;
+	bool signal;
+} UNIXEVENT;
+
+static pthread_mutex_t get_time_lock;
+static pthread_mutex_t malloc_lock;
+static bool high_process = false;
+
+static bool unix_svc_terminate = false;
+static int solaris_sleep_p1 = -1, solaris_sleep_p2 = -1;
+
+// ディスパッチテーブルの作成
+OS_DISPATCH_TABLE *UnixGetDispatchTable()
+{
+	static OS_DISPATCH_TABLE t =
+	{
+		UnixInit,
+		UnixFree,
+		UnixMemoryAlloc,
+		UnixMemoryReAlloc,
+		UnixMemoryFree,
+		UnixGetTick,
+		UnixGetSystemTime,
+		UnixInc32,
+		UnixDec32,
+		UnixSleep,
+		UnixNewLock,
+		UnixLock,
+		UnixUnlock,
+		UnixDeleteLock,
+		UnixInitEvent,
+		UnixSetEvent,
+		UnixResetEvent,
+		UnixWaitEvent,
+		UnixFreeEvent,
+		UnixWaitThread,
+		UnixFreeThread,
+		UnixInitThread,
+		UnixThreadId,
+		UnixFileOpen,
+		UnixFileOpenW,
+		UnixFileCreate,
+		UnixFileCreateW,
+		UnixFileWrite,
+		UnixFileRead,
+		UnixFileClose,
+		UnixFileFlush,
+		UnixFileSize,
+		UnixFileSeek,
+		UnixFileDelete,
+		UnixFileDeleteW,
+		UnixMakeDir,
+		UnixMakeDirW,
+		UnixDeleteDir,
+		UnixDeleteDirW,
+		UnixGetCallStack,
+		UnixGetCallStackSymbolInfo,
+		UnixFileRename,
+		UnixFileRenameW,
+		UnixRun,
+		UnixRunW,
+		UnixIsSupportedOs,
+		UnixGetOsInfo,
+		UnixAlert,
+		UnixAlertW,
+		UnixGetProductId,
+		UnixSetHighPriority,
+		UnixRestorePriority,
+		UnixNewSingleInstance,
+		UnixFreeSingleInstance,
+		UnixGetMemInfo,
+		UnixYield,
+	};
+
+	return &t;
+}
+
+// Solaris 用 Sleep の初期化
+void UnixInitSolarisSleep()
+{
+	char tmp[MAX_SIZE];
+
+	UnixNewPipe(&solaris_sleep_p1, &solaris_sleep_p2);
+	read(solaris_sleep_p1, tmp, sizeof(tmp));
+}
+
+// Solaris 用 Sleep の解放
+void UnixFreeSolarisSleep()
+{
+	UnixDeletePipe(solaris_sleep_p1, solaris_sleep_p2);
+	solaris_sleep_p1 = -1;
+	solaris_sleep_p2 = -1;
+}
+
+// Solaris 用 Sleep
+void UnixSolarisSleep(UINT msec)
+{
+	struct pollfd p;
+
+	memset(&p, 0, sizeof(p));
+	p.fd = solaris_sleep_p1;
+	p.events = POLLIN;
+
+	poll(&p, 1, msec == INFINITE ? -1 : (int)msec);
+}
+
+// ディスクの空き容量を取得する
+bool UnixGetDiskFreeW(wchar_t *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
+{
+	char *path_a = CopyUniToStr(path);
+	bool ret;
+
+	ret = UnixGetDiskFree(path_a, free_size, used_size, total_size);
+
+	Free(path_a);
+
+	return ret;
+}
+bool UnixGetDiskFree(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
+{
+	char tmp[MAX_PATH];
+	bool ret = false;
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	NormalizePath(tmp, sizeof(tmp), path);
+
+	while ((ret = UnixGetDiskFreeMain(tmp, free_size, used_size, total_size)) == false)
+	{
+		if (StrCmpi(tmp, "/") == 0)
+		{
+			break;
+		}
+
+		GetDirNameFromFilePath(tmp, sizeof(tmp), tmp);
+	}
+
+	return ret;
+}
+bool UnixGetDiskFreeMain(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
+{
+#ifndef	USE_STATVFS
+	struct statfs st;
+	char tmp[MAX_PATH];
+	UINT64 v1 = 0, v2 = 0;
+	bool ret = false;
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	NormalizePath(tmp, sizeof(tmp), path);
+
+	Zero(&st, sizeof(st));
+	if (statfs(tmp, &st) == 0)
+	{
+		v1 = (UINT64)st.f_bsize * (UINT64)st.f_bavail;
+		v2 = (UINT64)st.f_bsize * (UINT64)st.f_blocks;
+		ret = true;
+	}
+
+	if (free_size != NULL)
+	{
+		*free_size = v1;
+	}
+
+	if (total_size != NULL)
+	{
+		*total_size = v2;
+	}
+
+	if (used_size != NULL)
+	{
+		*used_size = v2 - v1;
+	}
+
+	return ret;
+#else	// USE_STATVFS
+	struct statvfs st;
+	char tmp[MAX_PATH];
+	UINT64 v1 = 0, v2 = 0;
+	bool ret = false;
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	NormalizePath(tmp, sizeof(tmp), path);
+
+	Zero(&st, sizeof(st));
+
+	if (statvfs(tmp, &st) == 0)
+	{
+		v1 = (UINT64)st.f_bsize * (UINT64)st.f_bavail;
+		v2 = (UINT64)st.f_bsize * (UINT64)st.f_blocks;
+		ret = true;
+	}
+
+	if (free_size != NULL)
+	{
+		*free_size = v1;
+	}
+
+	if (total_size != NULL)
+	{
+		*total_size = v2;
+	}
+
+	if (used_size != NULL)
+	{
+		*used_size = v2 - v1;
+	}
+
+	return ret;
+#endif	// USE_STATVFS
+}
+
+// ディレクトリ列挙
+DIRLIST *UnixEnumDirEx(char *dirname, COMPARE *compare)
+{
+	char tmp[MAX_PATH];
+	DIRLIST *d;
+	int n;
+	struct dirent **e;
+	LIST *o;
+	// 引数チェック
+	if (dirname == NULL)
+	{
+		return NULL;
+	}
+
+	o = NewListFast(compare);
+
+	NormalizePath(tmp, sizeof(tmp), dirname);
+
+	if (StrLen(tmp) >= 1 && tmp[StrLen(tmp) - 1] != '/')
+	{
+		StrCat(tmp, sizeof(tmp), "/");
+	}
+
+	e = NULL;
+	n = scandir(tmp, &e, 0, alphasort);
+
+	if (StrLen(tmp) >= 1 && tmp[StrLen(tmp) - 1] == '/')
+	{
+		tmp[StrLen(tmp) - 1] = 0;
+	}
+
+	if (n >= 0 && e != NULL)
+	{
+		UINT i;
+
+		for (i = 0;i < (UINT)n;i++)
+		{
+			char *filename = e[i]->d_name;
+
+			if (filename != NULL)
+			{
+				if (StrCmpi(filename, "..") != 0 && StrCmpi(filename, ".") != 0)
+				{
+					char fullpath[MAX_PATH];
+					struct stat st;
+					Format(fullpath, sizeof(fullpath), "%s/%s", tmp, filename);
+
+					Zero(&st, sizeof(st));
+
+					if (stat(fullpath, &st) == 0)
+					{
+						DIRENT *f = ZeroMalloc(sizeof(DIRENT));
+						SYSTEMTIME t;
+
+						f->Folder = S_ISDIR(st.st_mode) ? true : false;
+						f->FileName = CopyStr(filename);
+						f->FileNameW = CopyUtfToUni(f->FileName);
+
+						Zero(&t, sizeof(t));
+						TimeToSystem(&t, st.st_ctime);
+						f->CreateDate = LocalToSystem64(SystemToUINT64(&t));
+
+						Zero(&t, sizeof(t));
+						TimeToSystem(&t, st.st_mtime);
+						f->UpdateDate = LocalToSystem64(SystemToUINT64(&t));
+
+						if (f->Folder == false)
+						{
+							f->FileSize = st.st_size;
+						}
+
+						Add(o, f);
+					}
+				}
+			}
+
+			free(e[i]);
+		}
+
+		free(e);
+	}
+
+	Sort(o);
+
+	d = ZeroMalloc(sizeof(DIRLIST));
+	d->NumFiles = LIST_NUM(o);
+	d->File = ToArray(o);
+
+	ReleaseList(o);
+
+	return d;
+}
+DIRLIST *UnixEnumDirExW(wchar_t *dirname, COMPARE *compare)
+{
+	char *dirname_a = CopyUniToUtf(dirname);
+	DIRLIST *ret;
+
+	ret = UnixEnumDirEx(dirname_a, compare);
+
+	Free(dirname_a);
+
+	return ret;
+}
+
+// 指定したファイルの実行権限をチェックする
+bool UnixCheckExecAccess(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (access(name, X_OK) == 0)
+	{
+		return true;
+	}
+
+	return false;
+}
+bool UnixCheckExecAccessW(wchar_t *name)
+{
+	char *name_a;
+	bool ret;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	name_a = CopyUniToUtf(name);
+
+	ret = UnixCheckExecAccess(name_a);
+
+	Free(name_a);
+
+	return ret;
+}
+
+// スレッドの優先順位を最高にする
+void UnixSetThreadPriorityRealtime()
+{
+	struct sched_param p;
+	Zero(&p, sizeof(p));
+	p.sched_priority = 255;
+	pthread_setschedparam(pthread_self(), SCHED_RR, &p);
+}
+
+// スレッドの優先順位を低くする
+void UnixSetThreadPriorityLow()
+{
+	struct sched_param p;
+	Zero(&p, sizeof(p));
+	p.sched_priority = 32;
+	pthread_setschedparam(pthread_self(), SCHED_OTHER, &p);
+}
+
+// スレッドの優先順位を高くする
+void UnixSetThreadPriorityHigh()
+{
+	struct sched_param p;
+	Zero(&p, sizeof(p));
+	p.sched_priority = 127;
+	pthread_setschedparam(pthread_self(), SCHED_RR, &p);
+}
+
+// スレッドの優先順位をアイドルにする
+void UnixSetThreadPriorityIdle()
+{
+	struct sched_param p;
+	Zero(&p, sizeof(p));
+	p.sched_priority = 1;
+	pthread_setschedparam(pthread_self(), SCHED_OTHER, &p);
+}
+
+// スレッドの優先順位を標準に戻す
+void UnixRestoreThreadPriority()
+{
+	struct sched_param p;
+	Zero(&p, sizeof(p));
+	p.sched_priority = 64;
+	pthread_setschedparam(pthread_self(), SCHED_OTHER, &p);
+}
+
+// 現在のディレクトリの取得
+void UnixGetCurrentDir(char *dir, UINT size)
+{
+	// 引数チェック
+	if (dir == NULL)
+	{
+		return;
+	}
+
+	getcwd(dir, size);
+}
+void UnixGetCurrentDirW(wchar_t *dir, UINT size)
+{
+	char dir_a[MAX_PATH];
+
+	UnixGetCurrentDir(dir_a, sizeof(dir_a));
+
+	UtfToUni(dir, size, dir_a);
+}
+
+// イールド
+void UnixYield()
+{
+#ifdef UNIX_SOLARIS
+	UnixSolarisSleep(1);
+#else
+	sleep(1);
+#endif
+}
+
+// メモリ情報の取得
+void UnixGetMemInfo(MEMINFO *info)
+{
+	// 引数チェック
+	if (info == NULL)
+	{
+		return;
+	}
+
+	// 知らん！！
+	Zero(info, sizeof(MEMINFO));
+}
+
+// シングルインスタンスの解放
+void UnixFreeSingleInstance(void *data)
+{
+	UNIXLOCKFILE *o;
+	struct flock lock;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return;
+	}
+
+	o = (UNIXLOCKFILE *)data;
+
+	Zero(&lock, sizeof(lock));
+	lock.l_type = F_UNLCK;
+	lock.l_whence = SEEK_SET;
+
+	fcntl(o->fd, F_SETLK, &lock);
+	close(o->fd);
+
+	remove(o->FileName);
+
+	Free(data);
+}
+
+// シングルインスタンスの作成
+void *UnixNewSingleInstance(char *instance_name)
+{
+	UNIXLOCKFILE *ret;
+	char tmp[MAX_SIZE];
+	char name[MAX_SIZE];
+	char dir[MAX_PATH];
+	int fd;
+	struct flock lock;
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		GetExeName(tmp, sizeof(tmp));
+		HashInstanceName(tmp, sizeof(tmp), tmp);
+	}
+	else
+	{
+		StrCpy(tmp, sizeof(tmp), instance_name);
+	}
+
+	GetExeDir(dir, sizeof(dir));
+
+	// ファイル名の生成
+	Format(name, sizeof(name), "%s/.%s", dir, tmp);
+
+	fd = open(name, O_WRONLY);
+	if (fd == -1)
+	{
+		fd = creat(name, 0600);
+	}
+	if (fd == -1)
+	{
+		Format(tmp, sizeof(tmp), "Unable to create %s.", name);
+		Alert(tmp, NULL);
+		exit(0);
+		return NULL;
+	}
+
+	Zero(&lock, sizeof(lock));
+	lock.l_type = F_WRLCK;
+	lock.l_whence = SEEK_SET;
+
+	if (fcntl(fd, F_SETLK, &lock) == -1)
+	{
+		return NULL;
+	}
+	else
+	{
+		ret = ZeroMalloc(sizeof(UNIXLOCKFILE));
+		ret->fd = fd;
+		StrCpy(ret->FileName, sizeof(ret->FileName), name);
+		return (void *)ret;
+	}
+}
+
+// プロセスの優先順位を上げる
+void UnixSetHighPriority()
+{
+	if (high_process == false)
+	{
+		UINT pid = getpid();
+		UINT pgid = getpgid(pid);
+
+		high_process = true;
+		nice(-20);
+
+		setpriority(PRIO_PROCESS, pid, -20);
+		setpriority(PRIO_PGRP, pgid, -20);
+	}
+}
+
+// プロセスの優先順位を戻す
+void UnixRestorePriority()
+{
+	if (high_process != false)
+	{
+		high_process = false;
+		nice(20);
+	}
+}
+
+// プロダクト ID を取得する
+char *UnixGetProductId()
+{
+	return CopyStr("--");
+}
+
+// アラートを表示する
+void UnixAlertW(wchar_t *msg, wchar_t *caption)
+{
+	char *msg8 = CopyUniToUtf(msg);
+	char *caption8 = CopyUniToUtf(caption);
+
+	UnixAlert(msg8, caption8);
+
+	Free(msg8);
+	Free(caption8);
+}
+void UnixAlert(char *msg, char *caption)
+{
+	char *tag =
+		"-- Alert: %s --\n%s\n";
+	// 引数チェック
+	if (msg == NULL)
+	{
+		msg = "Alert";
+	}
+	if (caption == NULL)
+	{
+		caption = "SoftEther UT-VPN Kernel";
+	}
+
+	printf(tag, caption, msg);
+}
+
+// 現在の OS の情報を取得する
+void UnixGetOsInfo(OS_INFO *info)
+{
+	// 引数チェック
+	if (info == NULL)
+	{
+		return;
+	}
+
+	Zero(info, sizeof(OS_INFO));
+	info->OsType = OSTYPE_UNIX_UNKNOWN;
+
+#ifdef	UNIX_SOLARIS
+	info->OsType = OSTYPE_SOLARIS;
+#endif	// UNIX_SOLARIS
+
+#ifdef	UNIX_CYGWIN
+	info->OsType = OSTYPE_CYGWIN;
+#endif	// UNIX_CYGWIN
+
+#ifdef	UNIX_MACOS
+	info->OsType = OSTYPE_MACOS_X;
+#endif	// UNIX_MACOS
+
+#ifdef	UNIX_BSD
+	info->OsType = OSTYPE_BSD;
+#endif	// UNIX_BSD
+
+#ifdef	UNIX_LINUX
+	info->OsType = OSTYPE_LINUX;
+#endif	// UNIX_LINUX
+
+	info->OsServicePack = 0;
+
+	if (info->OsType != OSTYPE_LINUX)
+	{
+		info->OsSystemName = CopyStr("UNIX");
+		info->OsProductName = CopyStr("UNIX");
+	}
+	else
+	{
+		info->OsSystemName = CopyStr("Linux");
+		info->OsProductName = CopyStr("Linux");
+	}
+
+	if (info->OsType == OSTYPE_LINUX)
+	{
+		// Linux の場合 ディストリビューション名を取得する
+		BUF *b;
+		b = ReadDump("/etc/redhat-release");
+		if (b != NULL)
+		{
+			info->OsVersion = CfgReadNextLine(b);
+			info->OsVendorName = CopyStr("Red Hat, Inc.");
+			FreeBuf(b);
+		}
+		else
+		{
+			b = ReadDump("/etc/turbolinux-release");
+			if (b != NULL)
+			{
+				info->OsVersion = CfgReadNextLine(b);
+				info->OsVendorName = CopyStr("Turbolinux, Inc.");
+				FreeBuf(b);
+			}
+			else
+			{
+				info->OsVersion = CopyStr("Unknown Liunx Version");
+				info->OsVendorName = CopyStr("Unknown Vendor");
+			}
+		}
+
+		info->KernelName = CopyStr("Linux Kernel");
+
+		b = ReadDump("/proc/sys/kernel/osrelease");
+		if (b != NULL)
+		{
+			info->KernelVersion = CfgReadNextLine(b);
+			FreeBuf(b);
+		}
+		else
+		{
+			info->KernelVersion = CopyStr("Unknown Version");
+		}
+	}
+	else
+	{
+		// その他の場合
+		info->OsProductName = CopyStr(OsTypeToStr(info->OsType));
+		info->OsVersion = CopyStr("Unknown Version");
+		info->KernelName = CopyStr(OsTypeToStr(info->OsType));
+		info->KernelVersion = CopyStr("Unknown Version");
+	}
+}
+
+// 現在の OS が SoftEther UT-VPN Kernel によってサポートされているかどうか調べる
+bool UnixIsSupportedOs()
+{
+	// すべての起動可能な UNIX OS をサポートしている
+	return true;
+}
+
+// 指定したコマンドを実行する
+bool UnixRunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)
+{
+	char *filename8 = CopyUniToUtf(filename);
+	char *arg8 = CopyUniToUtf(arg);
+	bool ret = UnixRun(filename8, arg8, hide, wait);
+
+	Free(filename8);
+	Free(arg8);
+
+	return ret;
+}
+bool UnixRun(char *filename, char *arg, bool hide, bool wait)
+{
+	TOKEN_LIST *t;
+	UINT ret;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return false;
+	}
+	if (arg == NULL)
+	{
+		arg = "";
+	}
+
+	// 子プロセス作成
+	ret = fork();
+	if (ret == -1)
+	{
+		// 子プロセス作成失敗
+		return false;
+	}
+
+	if (ret == 0)
+	{
+		Print("", filename, arg);
+		// 子プロセス
+		if (hide)
+		{
+			// 標準入出力を閉じる
+			UnixCloseIO();
+		}
+
+		t = ParseToken(arg, " ");
+		if (t == NULL)
+		{
+			AbortExit();
+		}
+		else
+		{
+			char **args;
+			UINT num_args;
+			UINT i;
+			num_args = t->NumTokens + 2;
+			args = ZeroMalloc(sizeof(char *) * num_args);
+			args[0] = filename;
+			for (i = 1;i < num_args - 1;i++)
+			{
+				args[i] = t->Token[i - 1];
+			}
+			execvp(filename, args);
+			AbortExit();
+		}
+	}
+	else
+	{
+		// 親プロセス
+		pid_t pid = (pid_t)ret;
+
+		if (wait)
+		{
+			int status = 0;
+			// 子プロセスの終了を待機する
+			if (waitpid(pid, &status, 0) == -1)
+			{
+				return false;
+			}
+
+			if (WEXITSTATUS(status) == 0)
+			{
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+
+		return true;
+	}
+}
+
+// デーモンの初期化
+void UnixDaemon(bool debug_mode)
+{
+	UINT ret;
+
+	if (debug_mode)
+	{
+		// デバッグモード
+		signal(SIGHUP, SIG_IGN);
+		return;
+	}
+
+	ret = fork();
+
+	if (ret == -1)
+	{
+		// エラー
+		return;
+	}
+	else if (ret == 0)
+	{
+		// 子プロセス用に新しいセッションを作成する
+		setsid();
+
+		// 標準入出力をクローズする
+		UnixCloseIO();
+
+		// 不要なシグナルを停止する
+		signal(SIGHUP, SIG_IGN);
+	}
+	else
+	{
+		// 親プロセスを終了する
+		exit(0);
+	}
+}
+
+// 標準入出力をクローズする
+void UnixCloseIO()
+{
+	static bool close_io_first = false;
+
+	// 1 回しか実行できない
+	if (close_io_first)
+	{
+		return;
+	}
+	else
+	{
+		close(0);
+		close(1);
+		close(2);
+		open("/dev/null", O_RDWR);
+		dup2(0, 1);
+		dup2(0, 2);
+		close_io_first = false;
+	}
+}
+
+// ファイル名を変更する
+bool UnixFileRenameW(wchar_t *old_name, wchar_t *new_name)
+{
+	char *old_name8 = CopyUniToUtf(old_name);
+	char *new_name8 = CopyUniToUtf(new_name);
+	bool ret = UnixFileRename(old_name8, new_name8);
+
+	Free(old_name8);
+	Free(new_name8);
+
+	return ret;
+}
+bool UnixFileRename(char *old_name, char *new_name)
+{
+	// 引数チェック
+	if (old_name == NULL || new_name == NULL)
+	{
+		return false;
+	}
+
+	if (rename(old_name, new_name) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// コールスタックを取得する
+CALLSTACK_DATA *UnixGetCallStack()
+{
+	// Win32 以外ではサポートされていない
+	return NULL;
+}
+
+// コールスタックからシンボル情報を取得
+bool UnixGetCallStackSymbolInfo(CALLSTACK_DATA *s)
+{
+	// Win32 以外ではサポートされていない
+	return false;
+}
+
+// ディレクトリを削除する
+bool UnixDeleteDirW(wchar_t *name)
+{
+	char *name8 = CopyUniToUtf(name);
+	bool ret = UnixDeleteDir(name8);
+
+	Free(name8);
+
+	return ret;
+}
+bool UnixDeleteDir(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (rmdir(name) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ディレクトリを作成する
+bool UnixMakeDirW(wchar_t *name)
+{
+	char *name8 = CopyUniToUtf(name);
+	bool ret = UnixMakeDir(name8);
+
+	Free(name8);
+
+	return ret;
+}
+bool UnixMakeDir(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (mkdir(name, 0700) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ファイルを削除する
+bool UnixFileDeleteW(wchar_t *name)
+{
+	bool ret;
+	char *name8 = CopyUniToUtf(name);
+
+	ret = UnixFileDelete(name8);
+
+	Free(name8);
+
+	return ret;
+}
+bool UnixFileDelete(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (remove(name) != 0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ファイルをシークする
+bool UnixFileSeek(void *pData, UINT mode, int offset)
+{
+	UNIXIO *p;
+	UINT ret;
+	// 引数チェック
+	if (pData == NULL)
+	{
+		return 0;
+	}
+	if (mode != FILE_BEGIN && mode != FILE_END && mode != FILE_CURRENT)
+	{
+		return false;
+	}
+
+	p = (UNIXIO *)pData;
+
+	ret = lseek(p->fd, offset, mode);
+
+	if (ret == -1)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ファイルサイズを取得する
+UINT64 UnixFileSize(void *pData)
+{
+	struct stat st;
+	UNIXIO *p;
+	// 引数チェック
+	if (pData == NULL)
+	{
+		return 0;
+	}
+
+	p = (UNIXIO *)pData;
+
+	if (fstat(p->fd, &st) != 0)
+	{
+		return 0;
+	}
+
+	return (UINT64)st.st_size;
+}
+
+// ファイルに書き込む
+bool UnixFileWrite(void *pData, void *buf, UINT size)
+{
+	UNIXIO *p;
+	UINT ret;
+	// 引数チェック
+	if (pData == NULL || buf == NULL || size == 0)
+	{
+		return false;
+	}
+
+	p = (UNIXIO *)pData;
+
+	ret = write(p->fd, buf, size);
+	if (ret != size)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ファイルから読み込む
+bool UnixFileRead(void *pData, void *buf, UINT size)
+{
+	UNIXIO *p;
+	UINT ret;
+	// 引数チェック
+	if (pData == NULL || buf == NULL || size == 0)
+	{
+		return false;
+	}
+
+	p = (UNIXIO *)pData;
+
+	ret = read(p->fd, buf, size);
+	if (ret != size)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ファイルをフラッシュする
+void UnixFileFlush(void *pData)
+{
+	UNIXIO *p;
+	bool write_mode;
+	// 引数チェック
+	if (pData == NULL)
+	{
+		return;
+	}
+
+	p = (UNIXIO *)pData;
+
+	write_mode = p->write_mode;
+
+	if (write_mode)
+	{
+		fsync(p->fd);
+	}
+}
+
+// ファイルを閉じる
+void UnixFileClose(void *pData, bool no_flush)
+{
+	UNIXIO *p;
+	bool write_mode;
+	// 引数チェック
+	if (pData == NULL)
+	{
+		return;
+	}
+
+	p = (UNIXIO *)pData;
+
+	write_mode = p->write_mode;
+
+	if (write_mode && no_flush == false)
+	{
+		fsync(p->fd);
+	}
+
+	close(p->fd);
+
+	UnixMemoryFree(p);
+
+	if (write_mode)
+	{
+		//sync();
+	}
+}
+
+// ファイルを作成する
+void *UnixFileCreateW(wchar_t *name)
+{
+	void *ret;
+	char *name8 = CopyUniToUtf(name);
+
+	ret = UnixFileCreate(name8);
+
+	Free(name8);
+
+	return ret;
+}
+void *UnixFileCreate(char *name)
+{
+	UNIXIO *p;
+	int fd;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	fd = creat(name, 0600);
+	if (fd == -1)
+	{
+		return NULL;
+	}
+
+	// メモリ確保
+	p = UnixMemoryAlloc(sizeof(UNIXIO));
+	p->fd = fd;
+	p->write_mode = true;
+
+	return (void *)p;
+}
+
+// ファイルを開く
+void *UnixFileOpenW(wchar_t *name, bool write_mode, bool read_lock)
+{
+	char *name8 = CopyUniToUtf(name);
+	void *ret;
+
+	ret = UnixFileOpen(name8, write_mode, read_lock);
+
+	Free(name8);
+
+	return ret;
+}
+void *UnixFileOpen(char *name, bool write_mode, bool read_lock)
+{
+	UNIXIO *p;
+	int fd;
+	int mode;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	if (write_mode == false)
+	{
+		mode = O_RDONLY;
+	}
+	else
+	{
+		mode = O_RDWR;
+	}
+
+	// ファイルを開く
+	fd = open(name, mode);
+	if (fd == -1)
+	{
+		return NULL;
+	}
+
+	// メモリ確保
+	p = UnixMemoryAlloc(sizeof(UNIXIO));
+	p->fd = fd;
+	p->write_mode = write_mode;
+
+	return (void *)p;
+}
+
+// 現在のスレッド ID を返す
+UINT UnixThreadId()
+{
+	UINT ret;
+
+	ret = (UINT)pthread_self();
+
+	return ret;
+}
+
+// スレッド関数
+void *UnixDefaultThreadProc(void *param)
+{
+	UNIXTHREAD *ut;
+	UNIXTHREADSTARTUPINFO *info = (UNIXTHREADSTARTUPINFO *)param;
+	if (info == NULL)
+	{
+		return 0;
+	}
+
+	ut = (UNIXTHREAD *)info->thread->pData;
+
+	// スレッド関数の呼び出し
+	info->thread_proc(info->thread, info->param);
+
+	// 終了フラグを立てる
+	ut->finished = true;
+
+	// 参照の解放
+	ReleaseThread(info->thread);
+
+	UnixMemoryFree(info);
+
+	FreeOpenSSLThreadState();
+
+	return 0;
+}
+
+// スレッドの解放
+void UnixFreeThread(THREAD *t)
+{
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+
+	// メモリの解放
+	UnixMemoryFree(t->pData);
+}
+
+// スレッドの終了を待機
+bool UnixWaitThread(THREAD *t)
+{
+	UNIXTHREAD *ut;
+	void *retcode = NULL;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return false;
+	}
+	ut = (UNIXTHREAD *)t->pData;
+	if (ut == NULL)
+	{
+		return false;
+	}
+
+	pthread_join(ut->thread, &retcode);
+
+	return true;
+}
+
+// スレッドの初期化
+bool UnixInitThread(THREAD *t)
+{
+	UNIXTHREAD *ut;
+	UNIXTHREADSTARTUPINFO *info;
+	pthread_attr_t attr;
+	// 引数チェック
+	if (t == NULL || t->thread_proc == NULL)
+	{
+		return false;
+	}
+
+	// スレッドデータ作成
+	ut = UnixMemoryAlloc(sizeof(UNIXTHREAD));
+	Zero(ut, sizeof(UNIXTHREAD));
+
+	// 起動情報作成
+	info = UnixMemoryAlloc(sizeof(UNIXTHREADSTARTUPINFO));
+	Zero(info, sizeof(UNIXTHREADSTARTUPINFO));
+	info->param = t->param;
+	info->thread_proc = t->thread_proc;
+	info->thread = t;
+	AddRef(t->ref);
+
+	// スレッド作成
+	pthread_attr_init(&attr);
+	pthread_attr_setstacksize(&attr, UNIX_THREAD_STACK_SIZE);
+
+	t->pData = (void *)ut;
+
+	if (pthread_create(&ut->thread, &attr, UnixDefaultThreadProc, info) != 0)
+	{
+		// エラー発生
+		t->pData = NULL;
+		Release(t->ref);
+		UnixMemoryFree(ut);
+		UnixMemoryFree(info);
+		pthread_attr_destroy(&attr);
+		return false;
+	}
+
+	pthread_attr_destroy(&attr);
+
+	return true;
+}
+
+// イベントの解放
+void UnixFreeEvent(EVENT *event)
+{
+	UNIXEVENT *ue = (UNIXEVENT *)event->pData;
+	if (ue == NULL)
+	{
+		return;
+	}
+
+	pthread_cond_destroy(&ue->cond);
+	pthread_mutex_destroy(&ue->mutex);
+
+	UnixMemoryFree(ue);
+}
+
+// イベントの待機
+bool UnixWaitEvent(EVENT *event, UINT timeout)
+{
+	UNIXEVENT *ue = (UNIXEVENT *)event->pData;
+	struct timeval now;
+	struct timespec to;
+	bool ret;
+	if (ue == NULL)
+	{
+		return false;
+	}
+
+	pthread_mutex_lock(&ue->mutex);
+	gettimeofday(&now, NULL);
+	to.tv_sec = now.tv_sec + timeout / 1000;
+	to.tv_nsec = now.tv_usec * 1000 + (timeout % 1000) * 1000 * 1000;
+	if ((to.tv_nsec / 1000000000) >= 1)
+	{
+		to.tv_sec += to.tv_nsec / 1000000000;
+		to.tv_nsec = to.tv_nsec % 1000000000;
+	}
+
+	ret = true;
+
+	while (ue->signal == false)
+	{
+		if (timeout != INFINITE)
+		{
+			if (pthread_cond_timedwait(&ue->cond, &ue->mutex, &to))
+			{
+				ret = false;
+				break;
+			}
+		}
+		else
+		{
+			pthread_cond_wait(&ue->cond, &ue->mutex);
+		}
+	}
+	ue->signal = false;
+
+	pthread_mutex_unlock(&ue->mutex);
+
+	return ret;
+}
+
+// イベントのリセット
+void UnixResetEvent(EVENT *event)
+{
+	UNIXEVENT *ue = (UNIXEVENT *)event->pData;
+	if (ue == NULL)
+	{
+		return;
+	}
+
+	pthread_mutex_lock(&ue->mutex);
+	ue->signal = false;
+	pthread_cond_signal(&ue->cond);
+	pthread_mutex_unlock(&ue->mutex);
+}
+
+// イベントのセット
+void UnixSetEvent(EVENT *event)
+{
+	UNIXEVENT *ue = (UNIXEVENT *)event->pData;
+	if (ue == NULL)
+	{
+		return;
+	}
+
+	pthread_mutex_lock(&ue->mutex);
+	ue->signal = true;
+	pthread_cond_signal(&ue->cond);
+	pthread_mutex_unlock(&ue->mutex);
+}
+
+// イベントの初期化
+void UnixInitEvent(EVENT *event)
+{
+	UNIXEVENT *ue = UnixMemoryAlloc(sizeof(UNIXEVENT));
+
+	Zero(ue, sizeof(UNIXEVENT));
+
+	pthread_cond_init(&ue->cond, NULL);
+	pthread_mutex_init(&ue->mutex, NULL);
+	ue->signal = false;
+
+	event->pData = (void *)ue;
+}
+
+// ロックの削除
+void UnixDeleteLock(LOCK *lock)
+{
+	pthread_mutex_t *mutex;
+	// Ready フラグを安全に解除する
+	UnixLock(lock);
+	lock->Ready = false;
+	UnixUnlockEx(lock, true);
+
+	// mutex の削除
+	mutex = (pthread_mutex_t *)lock->pData;
+	pthread_mutex_destroy(mutex);
+
+	// メモリ解放
+	UnixMemoryFree(mutex);
+	UnixMemoryFree(lock);
+}
+
+// ロック解除
+void UnixUnlock(LOCK *lock)
+{
+	UnixUnlockEx(lock, false);
+}
+void UnixUnlockEx(LOCK *lock, bool inner)
+{
+	pthread_mutex_t *mutex;
+	if (lock->Ready == false && inner == false)
+	{
+		// 状態が不正
+		return;
+	}
+	mutex = (pthread_mutex_t *)lock->pData;
+
+	if ((--lock->locked_count) > 0)
+	{
+		return;
+	}
+
+	lock->thread_id = INFINITE;
+
+	pthread_mutex_unlock(mutex);
+
+	return;
+}
+
+// ロック
+bool UnixLock(LOCK *lock)
+{
+	pthread_mutex_t *mutex;
+	UINT thread_id = UnixThreadId();
+	if (lock->Ready == false)
+	{
+		// 状態が不正
+		return false;
+	}
+
+	if (lock->thread_id == thread_id)
+	{
+		lock->locked_count++;
+		return true;
+	}
+
+	mutex = (pthread_mutex_t *)lock->pData;
+
+	pthread_mutex_lock(mutex);
+
+	lock->thread_id = thread_id;
+	lock->locked_count++;
+
+	return true;
+}
+
+// 新しいロックの作成
+LOCK *UnixNewLock()
+{
+	pthread_mutex_t *mutex;
+	// メモリ確保
+	LOCK *lock = UnixMemoryAlloc(sizeof(LOCK));
+
+	// mutex 作成
+	mutex = UnixMemoryAlloc(sizeof(pthread_mutex_t));
+
+	// mutex 初期化
+	pthread_mutex_init(mutex, NULL);
+
+	lock->pData = (void *)mutex;
+	lock->Ready = true;
+
+	lock->thread_id = INFINITE;
+	lock->locked_count = 0;
+
+	return lock;
+}
+
+// スリープ
+void UnixSleep(UINT time)
+{
+	UINT sec = 0, millisec = 0;
+	// 引数チェック
+	if (time == 0)
+	{
+		return;
+	}
+
+	if (time == INFINITE)
+	{
+		// 無限に待機する
+		while (true)
+		{
+#ifdef UNIX_SOLARIS
+			UnixSolarisSleep(time);
+#else
+			sleep(1000000);
+#endif
+		}
+	}
+
+#ifdef UNIX_SOLARIS
+	UnixSolarisSleep(time);
+#else
+
+	// 桁あふれ防止
+	sec = time / 1000;
+	millisec = time % 1000;
+
+	if (sec != 0)
+	{
+		sleep(sec);
+	}
+	if (millisec != 0)
+	{
+		usleep(millisec * 1000);
+	}
+#endif
+}
+
+// デクリメント
+void UnixDec32(UINT *value)
+{
+	if (value != NULL)
+	{
+		(*value)--;
+	}
+}
+
+// インクリメント
+void UnixInc32(UINT *value)
+{
+	if (value != NULL)
+	{
+		(*value)++;
+	}
+}
+
+// システム時刻の取得
+void UnixGetSystemTime(SYSTEMTIME *system_time)
+{
+	time_t now = 0;
+	struct tm tm;
+	struct timeval tv;
+	struct timezone tz;
+	// 引数チェック
+	if (system_time == NULL)
+	{
+		return;
+	}
+
+	pthread_mutex_lock(&get_time_lock);
+
+	Zero(system_time, sizeof(SYSTEMTIME));
+	Zero(&tv, sizeof(tv));
+	Zero(&tz, sizeof(tz));
+
+	time(&now);
+
+	gmtime_r(&now, &tm);
+
+	TmToSystem(system_time, &tm);
+
+	gettimeofday(&tv, &tz);
+
+	system_time->wMilliseconds = tv.tv_usec / 1000;
+
+	pthread_mutex_unlock(&get_time_lock);
+}
+
+// システムタイマの取得 (64bit)
+UINT64 UnixGetTick64()
+{
+#if	defined(OS_WIN32) || defined(CLOCK_REALTIME) || defined(CLOCK_MONOTONIC) || defined(CLOCK_HIGHRES)
+
+	struct timespec t;
+	UINT64 ret;
+	static bool akirame = false;
+
+	if (akirame)
+	{
+		return TickRealtimeManual();
+	}
+
+	Zero(&t, sizeof(t));
+
+	// システムの起動時刻を取得する関数
+	// システムによって実装が異なるので注意
+#ifdef	CLOCK_HIGHRES
+	clock_gettime(CLOCK_HIGHRES, &t);
+#else	// CLOCK_HIGHRES
+#ifdef	CLOCK_MONOTONIC
+	clock_gettime(CLOCK_MONOTONIC, &t);
+#else	// CLOCK_MONOTONIC
+	clock_gettime(CLOCK_REALTIME, &t);
+#endif	// CLOCK_MONOTONIC
+#endif	// CLOCK_HIGHRES
+
+	ret = (UINT64)t.tv_sec * 1000LL + (UINT64)t.tv_nsec / 1000000LL;
+
+	if (akirame == false && ret == 0)
+	{
+		ret = TickRealtimeManual();
+		akirame = true;
+	}
+
+	return ret;
+
+#else
+
+	return TickRealtimeManual();
+
+#endif
+}
+
+// システムタイマの取得
+UINT UnixGetTick()
+{
+	return (UINT)UnixGetTick64();
+}
+
+// メモリの確保
+void *UnixMemoryAlloc(UINT size)
+{
+	void *r;
+	pthread_mutex_lock(&malloc_lock);
+	r = malloc(size);
+	pthread_mutex_unlock(&malloc_lock);
+	return r;
+}
+
+// メモリの再確保
+void *UnixMemoryReAlloc(void *addr, UINT size)
+{
+	void *r;
+	pthread_mutex_lock(&malloc_lock);
+	r = realloc(addr, size);
+	pthread_mutex_unlock(&malloc_lock);
+	return r;
+}
+
+// メモリの解放
+void UnixMemoryFree(void *addr)
+{
+	pthread_mutex_lock(&malloc_lock);
+	free(addr);
+	pthread_mutex_unlock(&malloc_lock);
+}
+
+// SIGCHLD ハンドラ
+void UnixSigChldHandler(int sig)
+{
+	// ゾンビプロセスの回収
+	while (waitpid(-1, NULL, WNOHANG) > 0);
+	signal(SIGCHLD, UnixSigChldHandler);
+}
+
+// UNIX 用ライブラリの初期化
+void UnixInit()
+{
+	UNIXIO *o;
+
+	UnixInitSolarisSleep();
+
+	// グローバルロック
+	pthread_mutex_init(&get_time_lock, NULL);
+	pthread_mutex_init(&malloc_lock, NULL);
+
+	// プロセス ID の取得
+	current_process_id = getpid();
+
+#ifdef	RLIMIT_CORE
+	UnixSetResourceLimit(RLIMIT_CORE, UNIX_MAX_MEMORY);
+#endif	// RLIMIT_CORE
+
+#ifdef	RLIMIT_DATA
+	UnixSetResourceLimit(RLIMIT_DATA, UNIX_MAX_MEMORY);
+#endif	// RLIMIT_DATA
+
+#ifdef	RLIMIT_NOFILE
+	UnixSetResourceLimit(RLIMIT_NOFILE, UNIX_MAX_FD);
+#endif	// RLIMIT_NOFILE
+
+#ifdef	RLIMIT_STACK
+//	UnixSetResourceLimit(RLIMIT_STACK, UNIX_MAX_MEMORY);
+#endif	// RLIMIT_STACK
+
+#ifdef	RLIMIT_RSS
+	UnixSetResourceLimit(RLIMIT_RSS, UNIX_MAX_MEMORY);
+#endif	// RLIMIT_RSS
+
+#ifdef	RLIMIT_LOCKS
+	UnixSetResourceLimit(RLIMIT_LOCKS, UNIX_MAX_LOCKS);
+#endif	// RLIMIT_LOCKS
+
+#ifdef	RLIMIT_MEMLOCK
+	UnixSetResourceLimit(RLIMIT_MEMLOCK, UNIX_MAX_MEMORY);
+#endif	// RLIMIT_MEMLOCK
+
+#ifdef	RLIMIT_NPROC
+	UnixSetResourceLimit(RLIMIT_NPROC, UNIX_MAX_CHILD_PROCESSES);
+#endif	// RLIMIT_NPROC
+
+	// proc ファイルシステムの threads-max に値を書き込む
+	o = UnixFileCreate("/proc/sys/kernel/threads-max");
+	if (o != NULL)
+	{
+		char tmp[128];
+		sprintf(tmp, "%u\n", UNIX_LINUX_MAX_THREADS);
+		UnixFileWrite(o, tmp, strlen(tmp));
+		UnixFileClose(o, false);
+	}
+
+	// 無視するシグナルを設定
+	signal(SIGPIPE, SIG_IGN);
+	signal(SIGALRM, SIG_IGN);
+
+#ifdef	UNIX_BSD
+	signal(64, SIG_IGN);
+#endif	// UNIX_BSD
+
+#ifdef	SIGXFSZ
+	signal(SIGXFSZ, SIG_IGN);
+#endif	// SIGXFSZ
+
+	// 子プロセス回収用シグナルハンドラの設定
+	signal(SIGCHLD, UnixSigChldHandler);
+}
+
+// UNIX 用ライブラリの解放
+void UnixFree()
+{
+	UnixFreeSolarisSleep();
+
+	current_process_id = 0;
+
+	pthread_mutex_destroy(&get_time_lock);
+}
+
+// 占有することができる資源の上限値を調整
+void UnixSetResourceLimit(UINT id, UINT value)
+{
+	struct rlimit t;
+	UINT hard_limit;
+
+	Zero(&t, sizeof(t));
+	getrlimit(id, &t);
+
+	hard_limit = t.rlim_max;
+
+	Zero(&t, sizeof(t));
+	t.rlim_cur = MIN(value, hard_limit);
+	t.rlim_max = hard_limit;
+	setrlimit(id, &t);
+
+	Zero(&t, sizeof(t));
+	t.rlim_cur = value;
+	t.rlim_max = value;
+	setrlimit(id, &t);
+}
+
+// PID ファイル名を生成する
+void UnixGenPidFileName(char *name, UINT size)
+{
+	char exe_name[MAX_PATH];
+	UCHAR hash[MD5_SIZE];
+	char tmp1[64];
+	char dir[MAX_PATH];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	GetExeDir(dir, sizeof(dir));
+
+	GetExeName(exe_name, sizeof(exe_name));
+	StrCat(exe_name, sizeof(exe_name), ":pid_hash");
+	StrUpper(exe_name);
+
+	Hash(hash, exe_name, StrLen(exe_name), false);
+	BinToStr(tmp1, sizeof(tmp1), hash, sizeof(hash));
+
+	Format(name, size, "%s/.pid_%s", dir, tmp1);
+}
+
+// PID ファイルを削除する
+void UnixDeletePidFile()
+{
+	char tmp[MAX_PATH];
+
+	UnixGenPidFileName(tmp, sizeof(tmp));
+
+	UnixFileDelete(tmp);
+}
+
+// PID ファイルに書き込む
+void UnixWritePidFile(UINT pid)
+{
+	char tmp[MAX_PATH];
+	char tmp2[64];
+	IO *o;
+
+	UnixGenPidFileName(tmp, sizeof(tmp));
+	Format(tmp2, sizeof(tmp2), "%u\n", pid);
+
+	o = FileCreate(tmp);
+	if (o != NULL)
+	{
+		FileWrite(o, tmp2, StrLen(tmp2));
+		FileClose(o);
+	}
+}
+
+// PID ファイルを読み込む
+UINT UnixReadPidFile()
+{
+	char tmp[MAX_PATH];
+	BUF *buf;
+
+	UnixGenPidFileName(tmp, sizeof(tmp));
+
+	buf = ReadDump(tmp);
+	if (buf == NULL)
+	{
+		return 0;
+	}
+
+	Zero(tmp, sizeof(tmp));
+	Copy(tmp, buf->Buf, MIN(buf->Size, sizeof(tmp)));
+	FreeBuf(buf);
+
+	return ToInt(tmp);
+}
+
+// サービスの開始
+void UnixStartService(char *name)
+{
+	char *svc_name, *svc_title;
+	char tmp[128];
+	INSTANCE *inst;
+	char exe[MAX_PATH];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	GetExeName(exe, sizeof(exe));
+
+	Format(tmp, sizeof(tmp), SVC_NAME, name);
+	svc_name = _SS(tmp);
+	Format(tmp, sizeof(tmp), SVC_TITLE, name);
+	svc_title = _SS(tmp);
+
+	// すでにサービスが起動していないかどうか調べる
+	inst = NewSingleInstance(NULL);
+	if (inst == NULL)
+	{
+		// すでにサービスが起動している
+		UniPrint(_UU("UNIX_SVC_ALREADY_START"), svc_title, svc_name);
+	}
+	else
+	{
+		int pid;
+		// サービスの起動を開始する
+		UniPrint(_UU("UNIX_SVC_STARTED"), svc_title);
+		FreeSingleInstance(inst);
+
+		// 子プロセスを作成する
+		pid = fork();
+		if (pid == -1)
+		{
+			UniPrint(_UU("UNIX_SVC_ERROR_FORK"), svc_title);
+		}
+		else
+		{
+			if (pid == 0)
+			{
+				// 子プロセス
+				char *param = UNIX_SVC_ARG_EXEC_SVC;
+				char **args;
+
+				// デーモン化する
+				setsid();
+				UnixCloseIO();
+				signal(SIGHUP, SIG_IGN);
+
+				// 引数を準備
+				args = ZeroMalloc(sizeof(char *) * 3);
+				args[0] = exe;
+				args[1] = param;
+				args[2] = NULL;
+
+				execvp(exe, args);
+				AbortExit();
+			}
+			else
+			{
+				// 子プロセス番号をファイルに書き込まない
+//				UnixWritePidFile(pid);
+			}
+		}
+	}
+}
+
+// サービスの停止
+void UnixStopService(char *name)
+{
+	char *svc_name, *svc_title;
+	char tmp[128];
+	INSTANCE *inst;
+	char exe[MAX_PATH];
+	UINT pid;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	GetExeName(exe, sizeof(exe));
+
+	Format(tmp, sizeof(tmp), SVC_NAME, name);
+	svc_name = _SS(tmp);
+	Format(tmp, sizeof(tmp), SVC_TITLE, name);
+	svc_title = _SS(tmp);
+
+	inst = NewSingleInstance(NULL);
+	pid = UnixReadPidFile();
+	if (inst != NULL || pid == 0)
+	{
+		// まだサービスが起動していない
+		UniPrint(_UU("UNIX_SVC_NOT_STARTED"), svc_title, svc_name);
+	}
+	else
+	{
+		int status;
+
+		// サービスを停止する
+		UniPrint(_UU("UNIX_SVC_STOPPING"), svc_title);
+
+		// プロセスを終了する
+		kill(pid, SIGTERM);
+		if (UnixWaitProcessEx(pid, UNIX_SERVICE_STOP_TIMEOUT_2))
+		{
+			UniPrint(_UU("UNIX_SVC_STOPPED"), svc_title);
+		}
+		else
+		{
+			UniPrint(_UU("UNIX_SVC_STOP_FAILED"), svc_title);
+		}
+	}
+
+	FreeSingleInstance(inst);
+}
+
+// プロセスへの停止シグナルのハンドラ
+void UnixSigTermHandler(int signum)
+{
+	if (signum == SIGTERM)
+	{
+		unix_svc_terminate = true;
+	}
+}
+
+// サービス停止用スレッド
+void UnixStopThread(THREAD *t, void *param)
+{
+	SERVICE_FUNCTION *stop = (SERVICE_FUNCTION *)param;
+	// 引数チェック
+	if (t == NULL || param == NULL)
+	{
+		return;
+	}
+
+	stop();
+}
+
+// サービスの内容の実行
+void UnixExecService(char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
+{
+	char *svc_name, *svc_title;
+	char tmp[128];
+	INSTANCE *inst;
+	UINT yobi_size = 1024 * 128;
+	void *yobi1, *yobi2;
+	// 引数チェック
+	if (start == NULL || stop == NULL || name == NULL)
+	{
+		return;
+	}
+
+	Format(tmp, sizeof(tmp), SVC_NAME, name);
+	svc_name = _SS(tmp);
+	Format(tmp, sizeof(tmp), SVC_TITLE, name);
+	svc_title = _SS(tmp);
+
+	inst = NewSingleInstance(NULL);
+	if (inst != NULL)
+	{
+		THREAD *t;
+
+		yobi1 = ZeroMalloc(yobi_size);
+		yobi2 = ZeroMalloc(yobi_size);
+
+		// 起動
+		UnixWritePidFile(getpid());
+
+		start();
+
+		// 起動完了 別のプロセスから SIGTERM が送られてくるのを待つ
+		signal(SIGTERM, &UnixSigTermHandler);
+		while (unix_svc_terminate == false)
+		{
+			pause();
+		}
+
+		// 停止
+		Free(yobi1);
+		t = NewThread(UnixStopThread, stop);
+		if (t == NULL || (WaitThread(t, UNIX_SERVICE_STOP_TIMEOUT_1) == false))
+		{
+			// 停止用スレッドの作成に失敗したか、タイムアウトした場合は
+			// 強制終了する
+			Free(yobi2);
+			FreeSingleInstance(inst);
+			UnixDeletePidFile();
+			_exit(0);
+		}
+		ReleaseThread(t);
+
+		// PID ファイルを削除
+		UnixDeletePidFile();
+
+		FreeSingleInstance(inst);
+
+		Free(yobi2);
+	}
+}
+
+// 指定した pid のプロセスが存在するかどうか取得する
+bool UnixIsProcess(UINT pid)
+{
+	if (getsid((pid_t)pid) == -1)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// 指定したプロセスの終了を待機する
+bool UnixWaitProcessEx(UINT pid,  UINT timeout)
+{
+	UINT64 start_tick = Tick64();
+	UINT64 end_tick = start_tick + (UINT64)timeout;
+	if (timeout == INFINITE)
+	{
+		end_tick = 0;
+	}
+	while (UnixIsProcess(pid))
+	{
+		if (end_tick != 0)
+		{
+			if (end_tick < Tick64())
+			{
+				return false;
+			}
+		}
+		SleepThread(100);
+	}
+	return true;
+}
+void UnixWaitProcess(UINT pid)
+{
+	UnixWaitProcessEx(pid, INFINITE);
+}
+
+// 起動方法の説明
+void UnixUsage(char *name)
+{
+	char *svc_name, *svc_title;
+	char tmp[128];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	Format(tmp, sizeof(tmp), SVC_NAME, name);
+	svc_name = _SS(tmp);
+	Format(tmp, sizeof(tmp), SVC_TITLE, name);
+	svc_title = _SS(tmp);
+
+	UniPrint(_UU("UNIX_SVC_HELP"), svc_title, svc_name, svc_name, svc_title, svc_name, svc_title);
+}
+
+// UNIX サービスのメイン関数
+UINT UnixService(int argc, char *argv[], char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
+{
+	// 引数チェック
+	if (name == NULL || start == NULL || stop == NULL)
+	{
+		return 0;
+	}
+
+	if (argc >= 2 && StrCmpi(argv[1], UNIX_SVC_ARG_EXEC_SVC) == 0)
+	{
+		UINT pid;
+		// 子プロセスを生成して開始する
+		// もし子プロセスが正しく終了しなかった場合は再起動する
+
+RESTART_PROCESS:
+		pid = fork();
+		if ((int)pid != -1)
+		{
+			if (pid == 0)
+			{
+				// メイン処理の実行
+				UnixServiceMain(argc, argv, name, start, stop);
+			}
+			else
+			{
+				int status = 0, ret;
+
+				// 子プロセスの終了を待機する
+				ret = waitpid(pid, &status, 0);
+
+				if (WIFEXITED(status) == 0)
+				{
+					// 異常終了した
+					UnixSleep(100);
+					goto RESTART_PROCESS;
+				}
+			}
+		}
+	}
+	else
+	{
+		// 通常に開始する
+		UnixServiceMain(argc, argv, name, start, stop);
+	}
+
+	return 0;
+}
+void UnixServiceMain(int argc, char *argv[], char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop)
+{
+	UINT mode = 0;
+	// Mayaqua の開始
+	InitMayaqua(false, false, argc, argv);
+
+	if (argc >= 2)
+	{
+		if (StrCmpi(argv[1], UNIX_SVC_ARG_START) == 0)
+		{
+			mode = UNIX_SVC_MODE_START;
+		}
+		if (StrCmpi(argv[1], UNIX_SVC_ARG_STOP) == 0)
+		{
+			mode = UNIX_SVC_MODE_STOP;
+		}
+		if (StrCmpi(argv[1], UNIX_SVC_ARG_EXEC_SVC) == 0)
+		{
+			mode = UNIX_SVC_MODE_EXEC_SVC;
+		}
+		if (StrCmpi(argv[1], UNIX_ARG_EXIT) == 0)
+		{
+			mode = UNIX_SVC_MODE_EXIT;
+		}
+	}
+
+	switch (mode)
+	{
+	case UNIX_SVC_MODE_EXIT:
+		break;
+
+	case UNIX_SVC_MODE_START:
+		UnixStartService(name);
+		break;
+
+	case UNIX_SVC_MODE_STOP:
+		UnixStopService(name);
+		break;
+
+	case UNIX_SVC_MODE_EXEC_SVC:
+		UnixExecService(name, start, stop);
+		break;
+
+	default:
+		UnixUsage(name);
+		break;
+	}
+
+	// Mayaquq の終了
+	FreeMayaqua();
+
+	return;
+}
+
+#endif	// UNIX
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Unix.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Unix.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Unix.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,219 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Unix.h
+// Unix.c のヘッダ
+
+#ifdef	OS_UNIX
+
+#ifndef	UNIX_H
+#define	UNIX_H
+
+// 定数
+#define	UNIX_THREAD_STACK_SIZE			(200 * 1000)	// スタックサイズ
+#define	UNIX_MAX_CHILD_PROCESSES		2000000			// 最大子プロセス数
+#define	UNIX_LINUX_MAX_THREADS			200000000		// 最大スレッド数
+#define	UNIX_MAX_LOCKS					65536			// 最大ロック数
+#define	UNIX_MAX_MEMORY					(2147483648UL)	// 最大メモリ容量
+#define	UNIX_MAX_FD						(655360)		// 最大 FD 数
+#define	MAXIMUM_WAIT_OBJECTS			64				// 最大 select 数
+
+#define	UNIX_SERVICE_STOP_TIMEOUT_1		(600 * 1000)	// サービス停止までのタイムアウト
+#define	UNIX_SERVICE_STOP_TIMEOUT_2		(900 * 1000)	// サービス停止までのタイムアウト (親プロセス)
+
+
+// サービス関係
+typedef void (SERVICE_FUNCTION)();
+
+#define	SVC_NAME					"SVC_%s_NAME"
+#define	SVC_TITLE					"SVC_%s_TITLE"
+
+#define	UNIX_SVC_ARG_START				"start"
+#define	UNIX_SVC_ARG_STOP				"stop"
+#define	UNIX_SVC_ARG_EXEC_SVC			"execsvc"
+#define	UNIX_ARG_EXIT					"exit"
+
+#define	UNIX_SVC_MODE_START				1
+#define	UNIX_SVC_MODE_STOP				2
+#define	UNIX_SVC_MODE_EXEC_SVC			3
+#define	UNIX_SVC_MODE_EXIT				4
+
+
+// 関数プロトタイプ
+OS_DISPATCH_TABLE *UnixGetDispatchTable();
+void UnixInit();
+void UnixFree();
+void *UnixMemoryAlloc(UINT size);
+void *UnixMemoryReAlloc(void *addr, UINT size);
+void UnixMemoryFree(void *addr);
+UINT UnixGetTick();
+void UnixGetSystemTime(SYSTEMTIME *system_time);
+void UnixInc32(UINT *value);
+void UnixDec32(UINT *value);
+void UnixSleep(UINT time);
+LOCK *UnixNewLock();
+bool UnixLock(LOCK *lock);
+void UnixUnlock(LOCK *lock);
+void UnixUnlockEx(LOCK *lock, bool inner);
+void UnixDeleteLock(LOCK *lock);
+void UnixInitEvent(EVENT *event);
+void UnixSetEvent(EVENT *event);
+void UnixResetEvent(EVENT *event);
+bool UnixWaitEvent(EVENT *event, UINT timeout);
+void UnixFreeEvent(EVENT *event);
+bool UnixWaitThread(THREAD *t);
+void UnixFreeThread(THREAD *t);
+bool UnixInitThread(THREAD *t);
+UINT UnixThreadId();
+void *UnixFileOpen(char *name, bool write_mode, bool read_lock);
+void *UnixFileOpenW(wchar_t *name, bool write_mode, bool read_lock);
+void *UnixFileCreate(char *name);
+void *UnixFileCreateW(wchar_t *name);
+bool UnixFileWrite(void *pData, void *buf, UINT size);
+bool UnixFileRead(void *pData, void *buf, UINT size);
+void UnixFileClose(void *pData, bool no_flush);
+void UnixFileFlush(void *pData);
+UINT64 UnixFileSize(void *pData);
+bool UnixFileSeek(void *pData, UINT mode, int offset);
+bool UnixFileDelete(char *name);
+bool UnixFileDeleteW(wchar_t *name);
+bool UnixMakeDir(char *name);
+bool UnixMakeDirW(wchar_t *name);
+bool UnixDeleteDir(char *name);
+bool UnixDeleteDirW(wchar_t *name);
+CALLSTACK_DATA *UnixGetCallStack();
+bool UnixGetCallStackSymbolInfo(CALLSTACK_DATA *s);
+bool UnixFileRename(char *old_name, char *new_name);
+bool UnixFileRenameW(wchar_t *old_name, wchar_t *new_name);
+bool UnixRun(char *filename, char *arg, bool hide, bool wait);
+bool UnixRunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait);
+bool UnixIsSupportedOs();
+void UnixGetOsInfo(OS_INFO *info);
+void UnixAlert(char *msg, char *caption);
+void UnixAlertW(wchar_t *msg, wchar_t *caption);
+char *UnixGetProductId();
+void UnixSetHighPriority();
+void UnixRestorePriority();
+void *UnixNewSingleInstance(char *instance_name);
+void UnixFreeSingleInstance(void *data);
+void UnixGetMemInfo(MEMINFO *info);
+void UnixYield();
+
+
+void UnixSetThreadPriorityRealtime();
+void UnixSetThreadPriorityLow();
+void UnixSetThreadPriorityHigh();
+void UnixSetThreadPriorityIdle();
+void UnixRestoreThreadPriority();
+void UnixSetResourceLimit(UINT id, UINT value);
+UINT64 UnixGetTick64();
+void UnixSigChldHandler(int sig);
+void UnixCloseIO();
+void UnixDaemon(bool debug_mode);
+void UnixGetCurrentDir(char *dir, UINT size);
+void UnixGetCurrentDirW(wchar_t *dir, UINT size);
+bool UnixCheckExecAccess(char *name);
+bool UnixCheckExecAccessW(wchar_t *name);
+DIRLIST *UnixEnumDirEx(char *dirname, COMPARE *compare);
+DIRLIST *UnixEnumDirExW(wchar_t *dirname, COMPARE *compare);
+bool UnixGetDiskFreeMain(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size);
+bool UnixGetDiskFree(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size);
+bool UnixGetDiskFreeW(wchar_t *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size);
+void UnixInitSolarisSleep();
+void UnixFreeSolarisSleep();
+void UnixSolarisSleep(UINT msec);
+
+UINT UnixService(int argc, char *argv[], char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop);
+void UnixServiceMain(int argc, char *argv[], char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop);
+void UnixGenPidFileName(char *name, UINT size);
+void UnixStartService(char *name);
+void UnixStopService(char *name);
+void UnixExecService(char *name, SERVICE_FUNCTION *start, SERVICE_FUNCTION *stop);
+void UnixUsage(char *name);
+void UnixWritePidFile(UINT pid);
+UINT UnixReadPidFile();
+bool UnixIsProcess(UINT pid);
+bool UnixWaitProcessEx(UINT pid, UINT timeout);
+void UnixWaitProcess(UINT pid);
+void UnixDeletePidFile();
+void UnixStopThread(THREAD *t, void *param);
+
+
+#endif	// UNIX_H
+
+#endif	// OS_UNIX
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Win32.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Win32.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Win32.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,3165 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Win32.c
+// Microsoft Windows 依存コード
+
+#ifdef	WIN32
+
+#define	_WIN32_WINNT		0x0502
+#define	WINVER				0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <Dbghelp.h>
+#include <commctrl.h>
+#include <process.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+
+static HANDLE heap_handle = NULL;
+static HANDLE hstdout = INVALID_HANDLE_VALUE;
+static HANDLE hstdin = INVALID_HANDLE_VALUE;
+
+// Win32 用スレッドデータ
+typedef struct WIN32THREAD
+{
+	HANDLE hThread;
+	DWORD thread_id;
+} WIN32THREAD;
+
+// Win32 用スレッド起動情報
+typedef struct WIN32THREADSTARTUPINFO
+{
+	THREAD_PROC *thread_proc;
+	void *param;
+	THREAD *thread;
+} WIN32THREADSTARTUPINFO;
+
+// Win32 用関数プロトタイプ
+DWORD CALLBACK Win32DefaultThreadProc(void *param);
+
+// 現在のプロセスハンドル
+static HANDLE hCurrentProcessHandle = NULL;
+static CRITICAL_SECTION fasttick_lock;
+static UINT64 start_tick = 0;
+static bool use_heap_api = false;
+static bool win32_is_nt = false;
+
+// Win32 用ファイル I/O データ
+typedef struct WIN32IO
+{
+	HANDLE hFile;
+	bool WriteMode;
+} WIN32IO;
+
+// Win32 用ミューテックスデータ
+typedef struct WIN32MUTEX
+{
+	HANDLE hMutex;
+} WIN32MUTEX;
+
+// ディスパッチテーブルの作成
+OS_DISPATCH_TABLE *Win32GetDispatchTable()
+{
+	static OS_DISPATCH_TABLE t =
+	{
+		Win32Init,
+		Win32Free,
+		Win32MemoryAlloc,
+		Win32MemoryReAlloc,
+		Win32MemoryFree,
+		Win32GetTick,
+		Win32GetSystemTime,
+		Win32Inc32,
+		Win32Dec32,
+		Win32Sleep,
+		Win32NewLock,
+		Win32Lock,
+		Win32Unlock,
+		Win32DeleteLock,
+		Win32InitEvent,
+		Win32SetEvent,
+		Win32ResetEvent,
+		Win32WaitEvent,
+		Win32FreeEvent,
+		Win32WaitThread,
+		Win32FreeThread,
+		Win32InitThread,
+		Win32ThreadId,
+		Win32FileOpen,
+		Win32FileOpenW,
+		Win32FileCreate,
+		Win32FileCreateW,
+		Win32FileWrite,
+		Win32FileRead,
+		Win32FileClose,
+		Win32FileFlush,
+		Win32FileSize,
+		Win32FileSeek,
+		Win32FileDelete,
+		Win32FileDeleteW,
+		Win32MakeDir,
+		Win32MakeDirW,
+		Win32DeleteDir,
+		Win32DeleteDirW,
+		Win32GetCallStack,
+		Win32GetCallStackSymbolInfo,
+		Win32FileRename,
+		Win32FileRenameW,
+		Win32Run,
+		Win32RunW,
+		Win32IsSupportedOs,
+		Win32GetOsInfo,
+		Win32Alert,
+		Win32AlertW,
+		Win32GetProductId,
+		Win32SetHighPriority,
+		Win32RestorePriority,
+		Win32NewSingleInstance,
+		Win32FreeSingleInstance,
+		Win32GetMemInfo,
+		Win32Yield,
+	};
+
+	return &t;
+}
+
+// 新しいスレッド用の初期化関数
+void Win32InitNewThread()
+{
+	static HINSTANCE hDll = NULL;
+	static bool (WINAPI *_SetThreadLocale)(LCID) = NULL;
+
+	if (hDll == NULL)
+	{
+		hDll = LoadLibrary("kernel32.dll");
+
+		_SetThreadLocale =
+			(bool (__stdcall *)(LCID))
+			GetProcAddress(hDll, "SetThreadLocale");
+	}
+
+	if (_SetThreadLocale != NULL)
+	{
+		_SetThreadLocale(LOCALE_USER_DEFAULT);
+	}
+}
+
+// フォルダの圧縮フラグを設定する
+bool Win32SetFolderCompressW(wchar_t *path, bool compressed)
+{
+	HANDLE h;
+	UINT retsize = 0;
+	USHORT flag;
+	wchar_t tmp[MAX_PATH];
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char *path_a = CopyUniToStr(path);
+		bool ret = Win32SetFolderCompress(path_a, compressed);
+
+		Free(path_a);
+
+		return ret;
+	}
+
+	InnerFilePathW(tmp, sizeof(tmp), path);
+
+	// フォルダを開く
+	h = CreateFileW(tmp, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		return false;
+	}
+
+	flag = compressed ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE;
+
+	if (DeviceIoControl(h, FSCTL_SET_COMPRESSION, &flag, sizeof(USHORT),
+		NULL, 0, &retsize, NULL) == false)
+	{
+		return false;
+	}
+
+	CloseHandle(h);
+
+	return true;
+}
+bool Win32SetFolderCompress(char *path, bool compressed)
+{
+	HANDLE h;
+	UINT retsize = 0;
+	USHORT flag;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	InnerFilePath(tmp, sizeof(tmp), path);
+
+	// フォルダを開く
+	h = CreateFile(tmp, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		return false;
+	}
+
+	flag = compressed ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE;
+
+	if (DeviceIoControl(h, FSCTL_SET_COMPRESSION, &flag, sizeof(USHORT),
+		NULL, 0, &retsize, NULL) == false)
+	{
+		return false;
+	}
+
+	CloseHandle(h);
+
+	return true;
+}
+
+// ディスクの空き容量を取得する
+bool Win32GetDiskFreeW(wchar_t *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
+{
+	wchar_t tmp[MAX_SIZE];
+	UINT count = 0;
+	UINT i, n, len;
+	ULARGE_INTEGER v1, v2, v3;
+	bool ret = false;
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		bool ret;
+		char *path_a = CopyUniToStr(path);
+
+		ret = Win32GetDiskFree(path_a, free_size, used_size, total_size);
+
+		Free(path_a);
+
+		return ret;
+	}
+
+	Zero(&v1, sizeof(v1));
+	Zero(&v2, sizeof(v2));
+	Zero(&v3, sizeof(v3));
+
+	NormalizePathW(tmp, sizeof(tmp), path);
+
+	// ディレクトリ名を取得
+	if (UniStartWith(path, L"\\\\"))
+	{
+		count = 4;
+	}
+	else
+	{
+		count = 1;
+	}
+
+	len = UniStrLen(tmp);
+	n = 0;
+	for (i = 0;i < len;i++)
+	{
+		if (tmp[i] == L'\\')
+		{
+			n++;
+			if (n >= count)
+			{
+				tmp[i + 1] = 0;
+				break;
+			}
+		}
+	}
+
+	if (GetDiskFreeSpaceExW(tmp, &v1, &v2, &v3))
+	{
+		ret = true;
+	}
+
+	if (free_size != NULL)
+	{
+		*free_size = v1.QuadPart;
+	}
+
+	if (total_size != NULL)
+	{
+		*total_size = v2.QuadPart;
+	}
+
+	if (used_size != NULL)
+	{
+		*used_size = v2.QuadPart - v1.QuadPart;
+	}
+
+	return ret;
+}
+bool Win32GetDiskFree(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size)
+{
+	char tmp[MAX_SIZE];
+	UINT count = 0;
+	UINT i, n, len;
+	ULARGE_INTEGER v1, v2, v3;
+	bool ret = false;
+	// 引数チェック
+	if (path == NULL)
+	{
+		return false;
+	}
+
+	Zero(&v1, sizeof(v1));
+	Zero(&v2, sizeof(v2));
+	Zero(&v3, sizeof(v3));
+
+	NormalizePath(tmp, sizeof(tmp), path);
+
+	// ディレクトリ名を取得
+	if (StartWith(path, "\\\\"))
+	{
+		count = 4;
+	}
+	else
+	{
+		count = 1;
+	}
+
+	len = StrLen(tmp);
+	n = 0;
+	for (i = 0;i < len;i++)
+	{
+		if (tmp[i] == '\\')
+		{
+			n++;
+			if (n >= count)
+			{
+				tmp[i + 1] = 0;
+				break;
+			}
+		}
+	}
+
+	if (GetDiskFreeSpaceEx(tmp, &v1, &v2, &v3))
+	{
+		ret = true;
+	}
+
+	if (free_size != NULL)
+	{
+		*free_size = v1.QuadPart;
+	}
+
+	if (total_size != NULL)
+	{
+		*total_size = v2.QuadPart;
+	}
+
+	if (used_size != NULL)
+	{
+		*used_size = v2.QuadPart - v1.QuadPart;
+	}
+
+	return ret;
+}
+
+// ディレクトリの列挙
+DIRLIST *Win32EnumDirEx(char *dirname, COMPARE *compare)
+{
+	DIRLIST *ret;
+	wchar_t *dirname_w = CopyStrToUni(dirname);
+
+	ret = Win32EnumDirExW(dirname_w, compare);
+
+	Free(dirname_w);
+
+	return ret;
+}
+DIRLIST *Win32EnumDirExW(wchar_t *dirname, COMPARE *compare)
+{
+	WIN32_FIND_DATAA data_a;
+	WIN32_FIND_DATAW data_w;
+	HANDLE h;
+	wchar_t tmp[MAX_PATH];
+	wchar_t tmp2[MAX_PATH];
+	wchar_t dirname2[MAX_PATH];
+	LIST *o;
+	DIRLIST *d;
+
+	UniStrCpy(tmp2, sizeof(tmp2), dirname);
+
+	if (UniStrLen(tmp2) >= 1 && tmp[UniStrLen(tmp2) - 1] == L'\\')
+	{
+		tmp2[UniStrLen(tmp2) - 1] = 0;
+	}
+
+	UniFormat(tmp, sizeof(tmp), L"%s\\*.*", tmp2);
+	NormalizePathW(tmp, sizeof(tmp), tmp);
+	NormalizePathW(dirname2, sizeof(dirname2), tmp2);
+
+	o = NewListFast(compare);
+
+	Zero(&data_a, sizeof(data_a));
+	Zero(&data_w, sizeof(data_w));
+
+	if (IsNt())
+	{
+		h = FindFirstFileW(tmp, &data_w);
+	}
+	else
+	{
+		char *tmp_a = CopyUniToStr(tmp);
+
+		h = FindFirstFileA(tmp_a, &data_a);
+
+		Free(tmp_a);
+	}
+
+	if (h != INVALID_HANDLE_VALUE)
+	{
+		bool b = true;
+
+		do
+		{
+			if (IsNt() == false)
+			{
+				Zero(&data_w, sizeof(data_w));
+				StrToUni(data_w.cFileName, sizeof(data_w.cFileName), data_a.cFileName);
+				data_w.dwFileAttributes = data_a.dwFileAttributes;
+				data_w.ftCreationTime = data_a.ftCreationTime;
+				data_w.ftLastWriteTime = data_a.ftLastWriteTime;
+				data_w.nFileSizeHigh = data_a.nFileSizeHigh;
+				data_w.nFileSizeLow = data_a.nFileSizeLow;
+			}
+
+			if (UniStrCmpi(data_w.cFileName, L"..") != 0 &&
+				UniStrCmpi(data_w.cFileName, L".") != 0)
+			{
+				DIRENT *f = ZeroMalloc(sizeof(DIRENT));
+				SYSTEMTIME t1, t2;
+				wchar_t fullpath[MAX_SIZE];
+				bool ok = false;
+
+				f->FileNameW = UniCopyStr(data_w.cFileName);
+				f->FileName = CopyUniToStr(f->FileNameW);
+				f->Folder = (data_w.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false;
+
+				CombinePathW(fullpath, sizeof(fullpath), dirname2, f->FileNameW);
+
+				// ファイル情報の取得を試行する
+				if (MsIsNt())
+				{
+					HANDLE h = CreateFileW(fullpath, 0,
+						FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+						NULL, OPEN_EXISTING, 0, NULL);
+
+					if (h != INVALID_HANDLE_VALUE)
+					{
+						BY_HANDLE_FILE_INFORMATION info;
+
+						Zero(&info, sizeof(info));
+
+						if (MsGetFileInformation(h, &info))
+						{
+							Zero(&t1, sizeof(t1));
+							Zero(&t2, sizeof(t2));
+							FileTimeToSystemTime(&info.ftCreationTime, &t1);
+							FileTimeToSystemTime(&info.ftLastWriteTime, &t2);
+							f->CreateDate = SystemToUINT64(&t1);
+							f->UpdateDate = SystemToUINT64(&t2);
+
+							if (f->Folder == false)
+							{
+								f->FileSize = ((UINT64)info.nFileSizeHigh * (UINT64)((UINT64)MAXDWORD + (UINT64)1)) + (UINT64)info.nFileSizeLow;
+							}
+
+							ok = true;
+						}
+
+						CloseHandle(h);
+					}
+				}
+
+				if (ok == false)
+				{
+					Zero(&t1, sizeof(t1));
+					Zero(&t2, sizeof(t2));
+					FileTimeToSystemTime(&data_w.ftCreationTime, &t1);
+					FileTimeToSystemTime(&data_w.ftLastWriteTime, &t2);
+					f->CreateDate = SystemToUINT64(&t1);
+					f->UpdateDate = SystemToUINT64(&t2);
+
+					if (f->Folder == false)
+					{
+						f->FileSize = ((UINT64)data_w.nFileSizeHigh * (UINT64)((UINT64)MAXDWORD + (UINT64)1)) + (UINT64)data_w.nFileSizeLow;
+					}
+				}
+
+				Add(o, f);
+			}
+
+			Zero(&data_w, sizeof(data_w));
+			Zero(&data_a, sizeof(data_a));
+
+			if (IsNt())
+			{
+				b = FindNextFileW(h, &data_w);
+			}
+			else
+			{
+				b = FindNextFileA(h, &data_a);
+			}
+		}
+		while (b);
+
+		FindClose(h);
+	}
+
+	Sort(o);
+
+	d = ZeroMalloc(sizeof(DIRLIST));
+	d->NumFiles = LIST_NUM(o);
+	d->File = ToArray(o);
+
+	ReleaseList(o);
+
+	return d;
+}
+
+// EXE ファイル名を取得
+void Win32GetExeNameW(wchar_t *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	if (IsNt() == false)
+	{
+		char name_a[MAX_PATH];
+
+		Win32GetExeName(name_a, sizeof(name_a));
+
+		StrToUni(name, size, name_a);
+
+		return;
+	}
+
+	UniStrCpy(name, size, L"");
+
+	GetModuleFileNameW(NULL, name, size);
+}
+void Win32GetExeName(char *name, UINT size)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	StrCpy(name, size, "");
+
+	GetModuleFileName(NULL, name, size);
+}
+
+// 現在のディレクトリの取得
+void Win32GetCurrentDirW(wchar_t *dir, UINT size)
+{
+	// 引数チェック
+	if (dir == NULL)
+	{
+		return;
+	}
+
+	if (IsNt() == false)
+	{
+		char dir_a[MAX_PATH];
+
+		Win32GetCurrentDir(dir_a, sizeof(dir_a));
+
+		StrToUni(dir, size, dir_a);
+
+		return;
+	}
+
+	GetCurrentDirectoryW(size, dir);
+}
+void Win32GetCurrentDir(char *dir, UINT size)
+{
+	// 引数チェック
+	if (dir == NULL)
+	{
+		return;
+	}
+
+	GetCurrentDirectory(size, dir);
+}
+
+// イールド
+void Win32Yield()
+{
+	Sleep(0);
+}
+
+// メモリ情報の取得
+void Win32GetMemInfo(MEMINFO *info)
+{
+	MEMORYSTATUS st;
+	// 引数チェック
+	if (info == NULL)
+	{
+		return;
+	}
+
+	Zero(info, sizeof(MEMINFO));
+	Zero(&st, sizeof(st));
+	st.dwLength = sizeof(st);
+
+	GlobalMemoryStatus(&st);
+
+	// 論理メモリ量
+	info->TotalMemory = (UINT64)st.dwTotalPageFile;
+	info->FreeMemory = (UINT64)st.dwAvailPageFile;
+	info->UsedMemory = info->TotalMemory - info->FreeMemory;
+
+	// 物理メモリ量
+	info->TotalPhys = (UINT64)st.dwTotalPhys;
+	info->FreePhys = (UINT64)st.dwAvailPhys;
+	info->UsedPhys = info->TotalPhys - info->FreePhys;
+}
+
+// シングルインスタンスの作成
+void *Win32NewSingleInstance(char *instance_name)
+{
+	WIN32MUTEX *ret;
+	char tmp[MAX_SIZE];
+	HANDLE hMutex;
+	// 引数チェック
+	if (instance_name == NULL)
+	{
+		char exe_path[MAX_PATH];
+		GetModuleFileName(NULL, exe_path, sizeof(exe_path));
+		HashInstanceName(tmp, sizeof(tmp), exe_path);
+		instance_name = tmp;
+	}
+
+	hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, instance_name);
+	if (hMutex != NULL)
+	{
+		CloseHandle(hMutex);
+		return NULL;
+	}
+
+	hMutex = CreateMutex(NULL, FALSE, instance_name);
+	if (hMutex == NULL)
+	{
+		CloseHandle(hMutex);
+		return NULL;
+	}
+
+	ret = Win32MemoryAlloc(sizeof(WIN32MUTEX));
+	ret->hMutex = hMutex;
+
+	return (void *)ret;
+}
+
+// シングルインスタンスの解放
+void Win32FreeSingleInstance(void *data)
+{
+	WIN32MUTEX *m;
+	// 引数チェック
+	if (data == NULL)
+	{
+		return;
+	}
+
+	m = (WIN32MUTEX *)data;
+	ReleaseMutex(m->hMutex);
+	CloseHandle(m->hMutex);
+
+	Win32MemoryFree(m);
+}
+
+// 優先順位を高くする
+void Win32SetHighPriority()
+{
+	SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+}
+
+// 優先順位を戻す
+void Win32RestorePriority()
+{
+	SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);
+}
+
+// ノード情報を取得
+char* Win32GetProductId()
+{
+	char *product_id;
+
+	return CopyStr("--");
+
+	// プロダクト ID
+	product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductId");
+	if (product_id == NULL)
+	{
+		product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", "ProductId");
+	}
+
+	return product_id;
+}
+
+// 現在サポートされている OS かどうか取得
+bool Win32IsSupportedOs()
+{
+	if (Win32GetOsType() == 0)
+	{
+		Win32Alert(
+			"SoftEther UT-VPN doesn't support this Windows Operating System.\n"
+			"SoftEther UT-VPN requires " SUPPORTED_WINDOWS_LIST ".\n\n"
+			"Please contact your system administrator.", NULL);
+		return false;
+	}
+
+	return true;
+}
+
+// アラートの表示
+void Win32AlertW(wchar_t *msg, wchar_t *caption)
+{
+	char *s;
+	// 引数チェック
+	if (msg == NULL)
+	{
+		msg = L"Alert";
+	}
+	if (caption == NULL)
+	{
+		caption = L"SoftEther UT-VPN Kernel";
+	}
+
+	s = GetCommandLineStr();
+
+	if (SearchStr(s, "win9x_uninstall", 0) == INFINITE && SearchStr(s, "win9x_install", 0) == INFINITE)
+	{
+		// Win9x サービスモードのアンインストール時には非表示とする
+		MessageBoxW(NULL, msg, caption, MB_SETFOREGROUND | MB_TOPMOST | MB_SERVICE_NOTIFICATION | MB_OK | MB_ICONEXCLAMATION);
+	}
+
+	Free(s);
+}
+void Win32Alert(char *msg, char *caption)
+{
+	char *s;
+	// 引数チェック
+	if (msg == NULL)
+	{
+		msg = "Alert";
+	}
+	if (caption == NULL)
+	{
+		caption = "SoftEther UT-VPN Kernel";
+	}
+
+	s = GetCommandLineStr();
+
+	if (SearchStr(s, "win9x_uninstall", 0) == INFINITE && SearchStr(s, "win9x_install", 0) == INFINITE)
+	{
+		// Win9x サービスモードのアンインストール時には非表示とする
+		MessageBox(NULL, msg, caption, MB_SETFOREGROUND | MB_TOPMOST | MB_SERVICE_NOTIFICATION | MB_OK | MB_ICONEXCLAMATION);
+	}
+
+	Free(s);
+}
+void Win32DebugAlert(char *msg)
+{
+	// 引数チェック
+	if (msg == NULL)
+	{
+		msg = "Alert";
+	}
+
+	MessageBox(NULL, msg, "Debug", MB_SETFOREGROUND | MB_TOPMOST | MB_SERVICE_NOTIFICATION | MB_OK | MB_ICONEXCLAMATION);
+}
+
+// OS 情報の取得
+void Win32GetOsInfo(OS_INFO *info)
+{
+	UINT type = Win32GetOsType();
+	OSVERSIONINFOEX os;
+	char tmp[MAX_SIZE];
+	// 引数チェック
+	if (info == NULL)
+	{
+		return;
+	}
+
+	Zero(&os, sizeof(os));
+	os.dwOSVersionInfoSize = sizeof(os);
+	GetVersionEx((LPOSVERSIONINFOA)&os);
+
+	info->OsType = Win32GetOsType();
+	info->OsServicePack = os.wServicePackMajor;
+	if (OS_IS_WINDOWS_NT(info->OsType))
+	{
+		char *s;
+		char *keyname = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
+		info->OsSystemName = CopyStr("Windows NT");
+		Format(tmp, sizeof(tmp), "Build %u", os.dwBuildNumber);
+		if (s = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "CurrentType"))
+		{
+			char str[MAX_SIZE];
+			Format(str, sizeof(str), ", %s", s);
+			StrCat(tmp, sizeof(tmp), str);
+			Free(s);
+		}
+		if (os.wServicePackMajor != 0)
+		{
+			char str[MAX_SIZE];
+			Format(str, sizeof(str), ", Service Pack %u", os.wServicePackMajor);
+			StrCat(tmp, sizeof(tmp), str);
+		}
+		if (s = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "BuildLab"))
+		{
+			char str[MAX_SIZE];
+			Format(str, sizeof(str), " (%s)", s);
+			StrCat(tmp, sizeof(tmp), str);
+			Free(s);
+		}
+		info->OsVersion = CopyStr(tmp);
+		info->KernelName = CopyStr("NTOS Kernel");
+		Format(tmp, sizeof(tmp), "Build %u", os.dwBuildNumber);
+		if (s = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "CurrentType"))
+		{
+			char str[MAX_SIZE];
+			Format(str, sizeof(str), " %s", s);
+			StrCat(tmp, sizeof(tmp), str);
+			Free(s);
+		}
+		info->KernelVersion = CopyStr(tmp);
+	}
+	else
+	{
+		OSVERSIONINFO os;
+		Zero(&os, sizeof(os));
+		os.dwOSVersionInfoSize = sizeof(os);
+		GetVersionEx(&os);
+		Format(tmp, sizeof(tmp), "Build %u %s", LOWORD(os.dwBuildNumber), os.szCSDVersion);
+		Trim(tmp);
+		info->OsVersion = CopyStr(tmp);
+		info->OsSystemName = CopyStr("Windows");
+		info->KernelName = CopyStr("Windows 9x Kernel");
+		info->KernelVersion = CopyStr(tmp);
+	}
+
+	info->OsProductName = CopyStr(OsTypeToStr(info->OsType));
+	info->OsVendorName = CopyStr("Microsoft Corporation");
+}
+
+// Windows NT かどうか取得
+bool Win32IsNt()
+{
+	OSVERSIONINFO os;
+	Zero(&os, sizeof(os));
+	os.dwOSVersionInfoSize = sizeof(os);
+
+	if (GetVersionEx(&os) == FALSE)
+	{
+		// 失敗?
+		return false;
+	}
+
+	if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
+	{
+		// NT
+		return true;
+	}
+
+	// 9x
+	return false;
+}
+
+// OS 種類の取得
+UINT Win32GetOsType()
+{
+	OSVERSIONINFO os;
+	Zero(&os, sizeof(os));
+	os.dwOSVersionInfoSize = sizeof(os);
+
+	if (GetVersionEx(&os) == FALSE)
+	{
+		// 失敗?
+		return 0;
+	}
+
+	if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
+	{
+		// Windows 9x 系
+		if (os.dwMajorVersion == 4)
+		{
+			if (os.dwMinorVersion == 0)
+			{
+				return OSTYPE_WINDOWS_95;
+			}
+			else if (os.dwMinorVersion == 10)
+			{
+				return OSTYPE_WINDOWS_98;
+			}
+			else if (os.dwMinorVersion == 90)
+			{
+				return OSTYPE_WINDOWS_ME;
+			}
+			else
+			{
+				return OSTYPE_WINDOWS_UNKNOWN;
+			}
+		}
+		else if (os.dwMajorVersion >= 5)
+		{
+			return OSTYPE_WINDOWS_UNKNOWN;
+		}
+	}
+	else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
+	{
+		UINT sp = Win32GetSpVer(os.szCSDVersion);
+		if (os.dwMajorVersion == 4)
+		{
+			if (sp < 6)
+			{
+				// SP6 以前
+				return 0;
+			}
+		}
+		if (os.dwMajorVersion < 4)
+		{
+			// NT 3.51 以前
+			return 0;
+		}
+		else
+		{
+			OSVERSIONINFOEX os;
+			Zero(&os, sizeof(os));
+			os.dwOSVersionInfoSize = sizeof(os);
+			GetVersionEx((LPOSVERSIONINFOA)&os);
+
+			if (os.dwMajorVersion == 4)
+			{
+				// Windows NT 4.0
+				if (os.wProductType == VER_NT_DOMAIN_CONTROLLER || os.wProductType == VER_NT_SERVER)
+				{
+					if ((os.wSuiteMask & VER_SUITE_TERMINAL) || (os.wSuiteMask & VER_SUITE_SINGLEUSERTS))
+					{
+						return OSTYPE_WINDOWS_NT_4_TERMINAL_SERVER;
+					}
+					if (os.wSuiteMask & VER_SUITE_ENTERPRISE)
+					{
+						return OSTYPE_WINDOWS_NT_4_SERVER_ENTERPRISE;
+					}
+					if (os.wSuiteMask & VER_SUITE_BACKOFFICE)
+					{
+						return OSTYPE_WINDOWS_NT_4_BACKOFFICE;
+					}
+					if ((os.wSuiteMask & VER_SUITE_SMALLBUSINESS) || (os.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED))
+					{
+						return OSTYPE_WINDOWS_NT_4_SMS;
+					}
+					else
+					{
+						return OSTYPE_WINDOWS_NT_4_SERVER;
+					}
+				}
+				else
+				{
+					return OSTYPE_WINDOWS_NT_4_WORKSTATION;
+				}
+			}
+			else if (os.dwMajorVersion == 5)
+			{
+				// Windows 2000, XP, Server 2003
+				if (os.dwMinorVersion == 0)
+				{
+					// Windows 2000
+					if (os.wProductType == VER_NT_DOMAIN_CONTROLLER || os.wProductType == VER_NT_SERVER)
+					{
+						// Server
+						if (os.wSuiteMask & VER_SUITE_DATACENTER)
+						{
+							return OSTYPE_WINDOWS_2000_DATACENTER_SERVER;
+						}
+						else if ((os.wSuiteMask & VER_SUITE_SMALLBUSINESS) || (os.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED))
+						{
+							return OSTYPE_WINDOWS_2000_SBS;
+						}
+						else if (os.wSuiteMask & VER_SUITE_BACKOFFICE)
+						{
+							return OSTYPE_WINDOWS_2000_BACKOFFICE;
+						}
+						else if (os.wSuiteMask & VER_SUITE_ENTERPRISE)
+						{
+							return OSTYPE_WINDOWS_2000_ADVANCED_SERVER;
+						}
+						else
+						{
+							return OSTYPE_WINDOWS_2000_SERVER;
+						}
+					}
+					else
+					{
+						// Client
+						return OSTYPE_WINDOWS_2000_PROFESSIONAL;
+					}
+				}
+				else if (os.dwMinorVersion == 1)
+				{
+					// Windows XP
+					if (os.wSuiteMask & VER_SUITE_PERSONAL)
+					{
+						return OSTYPE_WINDOWS_XP_HOME;
+					}
+					else
+					{
+						return OSTYPE_WINDOWS_XP_PROFESSIONAL;
+					}
+				}
+				else if (os.dwMinorVersion == 2)
+				{
+					// Windows Server 2003
+					if (os.wProductType == VER_NT_DOMAIN_CONTROLLER || os.wProductType == VER_NT_SERVER)
+					{
+						// Server
+						if (os.wSuiteMask & VER_SUITE_DATACENTER)
+						{
+							return OSTYPE_WINDOWS_2003_DATACENTER;
+						}
+						else if ((os.wSuiteMask & VER_SUITE_SMALLBUSINESS) || (os.wSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED))
+						{
+							return OSTYPE_WINDOWS_2003_SBS;
+						}
+						else if (os.wSuiteMask & VER_SUITE_BACKOFFICE)
+						{
+							return OSTYPE_WINDOWS_2003_BACKOFFICE;
+						}
+						else if (os.wSuiteMask & VER_SUITE_ENTERPRISE)
+						{
+							return OSTYPE_WINDOWS_2003_ENTERPRISE;
+						}
+						else if (os.wSuiteMask & VER_SUITE_BLADE)
+						{
+							return OSTYPE_WINDOWS_2003_WEB;
+						}
+						else
+						{
+							return OSTYPE_WINDOWS_2003_STANDARD;
+						}
+					}
+					else
+					{
+						// Client (Unknown XP?)
+						return OSTYPE_WINDOWS_XP_PROFESSIONAL;
+					}
+				}
+				else
+				{
+					// Windows Longhorn
+					if (os.wProductType == VER_NT_DOMAIN_CONTROLLER || os.wProductType == VER_NT_SERVER)
+					{
+						return OSTYPE_WINDOWS_LONGHORN_SERVER;
+					}
+					else
+					{
+						return OSTYPE_WINDOWS_LONGHORN_PROFESSIONAL;
+					}
+				}
+			}
+			else
+			{
+				if (os.dwMajorVersion == 6 && os.dwMinorVersion == 0)
+				{
+					// Windows Vista, Server 2008
+					if (os.wProductType == VER_NT_DOMAIN_CONTROLLER || os.wProductType == VER_NT_SERVER)
+					{
+						return OSTYPE_WINDOWS_LONGHORN_SERVER;
+					}
+					else
+					{
+						return OSTYPE_WINDOWS_LONGHORN_PROFESSIONAL;
+					}
+				}
+				else if (os.dwMajorVersion == 6 && os.dwMinorVersion == 1)
+				{
+					if (os.wProductType == VER_NT_WORKSTATION)
+					{
+						// Windows 7
+						return OSTYPE_WINDOWS_7;
+					}
+					else
+					{
+						// Windows Server 2008 R2
+						return OSTYPE_WINDOWS_SERVER_2008_R2;
+					}
+				}
+				else
+				{
+					if (os.wProductType == VER_NT_WORKSTATION)
+					{
+						// Windows 8
+						return OSTYPE_WINDOWS_8;
+					}
+					else
+					{
+						// Windows Server 8
+						return OSTYPE_WINDOWS_SERVER_2008_R2;
+					}
+				}
+			}
+		}
+	}
+
+	// 判別できない
+	return 0;
+}
+
+// 文字列から SP のバージョンを取得する
+UINT Win32GetSpVer(char *str)
+{
+	UINT ret, i;
+	TOKEN_LIST *t;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return 0;
+	}
+
+	t = ParseToken(str, NULL);
+	if (t == NULL)
+	{
+		return 0;
+	}
+
+	ret = 0;
+	for (i = 0;i < t->NumTokens;i++)
+	{
+		ret = ToInt(t->Token[i]);
+		if (ret != 0)
+		{
+			break;
+		}
+	}
+
+	FreeToken(t);
+
+	return ret;
+}
+
+// プロセスの強制終了
+bool Win32TerminateProcess(void *handle)
+{
+	HANDLE h;
+	// 引数チェック
+	if (handle == NULL)
+	{
+		return false;
+	}
+
+	h = (HANDLE)handle;
+
+	TerminateProcess(h, 0);
+
+	return true;
+}
+
+// プロセスを閉じる
+void Win32CloseProcess(void *handle)
+{
+	// 引数チェック
+	if (handle == NULL)
+	{
+		return;
+	}
+
+	CloseHandle((HANDLE)handle);
+}
+
+// 指定されたプロセスが生きているかどうかチェック
+bool Win32IsProcessAlive(void *handle)
+{
+	HANDLE h;
+	// 引数チェック
+	if (handle == NULL)
+	{
+		return false;
+	}
+
+	h = (HANDLE)handle;
+
+	if (WaitForSingleObject(h, 0) == WAIT_OBJECT_0)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// プロセスの終了を待機する
+bool Win32WaitProcess(void *h, UINT timeout)
+{
+	// 引数チェック
+	if (h == NULL)
+	{
+		return false;
+	}
+	if (timeout == 0)
+	{
+		timeout = INFINITE;
+	}
+
+	if (WaitForSingleObject((HANDLE)h, timeout) == WAIT_TIMEOUT)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// プロセスの起動 (ハンドルを返す)
+void *Win32RunExW(wchar_t *filename, wchar_t *arg, bool hide)
+{
+	return Win32RunEx2W(filename, arg, hide, NULL);
+}
+void *Win32RunEx2W(wchar_t *filename, wchar_t *arg, bool hide, UINT *process_id)
+{
+	return Win32RunEx3W(filename, arg, hide, process_id, false);
+}
+void *Win32RunEx3W(wchar_t *filename, wchar_t *arg, bool hide, UINT *process_id, bool disableWow)
+{
+	STARTUPINFOW info;
+	PROCESS_INFORMATION ret;
+	wchar_t cmdline[MAX_SIZE];
+	wchar_t name[MAX_PATH];
+	void *p;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	if (IsNt() == false)
+	{
+		char *filename_a = CopyUniToStr(filename);
+		char *arg_a = CopyUniToStr(arg);
+		void *ret = Win32RunEx(filename_a, arg_a, hide);
+
+		Free(filename_a);
+		Free(arg_a);
+
+		return ret;
+	}
+
+	UniStrCpy(name, sizeof(name), filename);
+	UniTrim(name);
+
+	if (UniSearchStr(name, L"\"", 0) == INFINITE)
+	{
+		if (arg == NULL)
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"%s", name);
+		}
+		else
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"%s %s", name, arg);
+		}
+	}
+	else
+	{
+		if (arg == NULL)
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"\"%s\"", name);
+		}
+		else
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"\"%s\" %s", name, arg);
+		}
+	}
+
+	Zero(&info, sizeof(info));
+	Zero(&ret, sizeof(ret));
+	info.cb = sizeof(info);
+	info.dwFlags = STARTF_USESHOWWINDOW;
+	info.wShowWindow = (hide == false ? SW_SHOWDEFAULT : SW_HIDE);
+
+	UniTrim(cmdline);
+
+	if (disableWow)
+	{
+		p = MsDisableWow64FileSystemRedirection();
+	}
+
+	if (CreateProcessW(NULL, cmdline, NULL, NULL, FALSE,
+		(hide == false ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW | CREATE_NEW_CONSOLE) | NORMAL_PRIORITY_CLASS,
+		NULL, NULL, &info, &ret) == FALSE)
+	{
+		if (disableWow)
+		{
+			MsRestoreWow64FileSystemRedirection(p);
+		}
+		return NULL;
+	}
+
+	if (disableWow)
+	{
+		MsRestoreWow64FileSystemRedirection(p);
+	}
+
+	if (process_id != NULL)
+	{
+		*process_id = ret.dwProcessId;
+	}
+
+	CloseHandle(ret.hThread);
+	return ret.hProcess;
+}
+void *Win32RunEx(char *filename, char *arg, bool hide)
+{
+	return Win32RunEx2(filename, arg, hide, NULL);
+}
+void *Win32RunEx2(char *filename, char *arg, bool hide, UINT *process_id)
+{
+	return Win32RunEx3(filename, arg, hide, process_id, false);
+}
+void *Win32RunEx3(char *filename, char *arg, bool hide, UINT *process_id, bool disableWow)
+{
+	STARTUPINFO info;
+	PROCESS_INFORMATION ret;
+	char cmdline[MAX_SIZE];
+	char name[MAX_PATH];
+	void *p = NULL;
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return NULL;
+	}
+
+	StrCpy(name, sizeof(name), filename);
+	Trim(name);
+
+	if (SearchStr(name, "\"", 0) == INFINITE)
+	{
+		if (arg == NULL)
+		{
+			Format(cmdline, sizeof(cmdline), "%s", name);
+		}
+		else
+		{
+			Format(cmdline, sizeof(cmdline), "%s %s", name, arg);
+		}
+	}
+	else
+	{
+		if (arg == NULL)
+		{
+			Format(cmdline, sizeof(cmdline), "\"%s\"", name);
+		}
+		else
+		{
+			Format(cmdline, sizeof(cmdline), "\"%s\" %s", name, arg);
+		}
+	}
+
+	Zero(&info, sizeof(info));
+	Zero(&ret, sizeof(ret));
+	info.cb = sizeof(info);
+	info.dwFlags = STARTF_USESHOWWINDOW;
+	info.wShowWindow = (hide == false ? SW_SHOWDEFAULT : SW_HIDE);
+
+	Trim(cmdline);
+
+	if (disableWow)
+	{
+		p = MsDisableWow64FileSystemRedirection();
+	}
+
+	if (CreateProcess(NULL, cmdline, NULL, NULL, FALSE,
+		(hide == false ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW | CREATE_NEW_CONSOLE) | NORMAL_PRIORITY_CLASS,
+		NULL, NULL, &info, &ret) == FALSE)
+	{
+		if (disableWow)
+		{
+			MsRestoreWow64FileSystemRedirection(p);
+		}
+		return NULL;
+	}
+	if (disableWow)
+	{
+		MsRestoreWow64FileSystemRedirection(p);
+	}
+
+	if (process_id != NULL)
+	{
+		*process_id = ret.dwProcessId;
+	}
+
+	CloseHandle(ret.hThread);
+	return ret.hProcess;
+}
+
+// プロセスの起動
+bool Win32RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait)
+{
+	STARTUPINFOW info;
+	PROCESS_INFORMATION ret;
+	wchar_t cmdline[MAX_SIZE];
+	wchar_t name[MAX_PATH];
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char *filename_a = CopyUniToStr(filename);
+		char *arg_a = CopyUniToStr(arg);
+		bool ret;
+
+		ret = Win32Run(filename_a, arg_a, hide, wait);
+
+		Free(filename_a);
+		Free(arg_a);
+
+		return ret;
+	}
+
+	UniStrCpy(name, sizeof(name), filename);
+	UniTrim(name);
+
+	if (UniSearchStr(name, L"\"", 0) == INFINITE)
+	{
+		if (arg == NULL)
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"%s", name);
+		}
+		else
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"%s %s", name, arg);
+		}
+	}
+	else
+	{
+		if (arg == NULL)
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"\"%s\"", name);
+		}
+		else
+		{
+			UniFormat(cmdline, sizeof(cmdline), L"\"%s\" %s", name, arg);
+		}
+	}
+
+	Zero(&info, sizeof(info));
+	Zero(&ret, sizeof(ret));
+	info.cb = sizeof(info);
+	info.dwFlags = STARTF_USESHOWWINDOW;
+	info.wShowWindow = (hide == false ? SW_SHOWDEFAULT : SW_HIDE);
+
+	UniTrim(cmdline);
+
+	if (CreateProcessW(NULL, cmdline, NULL, NULL, FALSE,
+		(hide == false ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW | CREATE_NEW_CONSOLE) | NORMAL_PRIORITY_CLASS,
+		NULL, NULL, &info, &ret) == FALSE)
+	{
+		return false;
+	}
+
+	if (wait)
+	{
+		WaitForSingleObject(ret.hProcess, INFINITE);
+	}
+
+	CloseHandle(ret.hThread);
+	CloseHandle(ret.hProcess);
+
+	return true;
+}
+bool Win32Run(char *filename, char *arg, bool hide, bool wait)
+{
+	STARTUPINFO info;
+	PROCESS_INFORMATION ret;
+	char cmdline[MAX_SIZE];
+	char name[MAX_PATH];
+	// 引数チェック
+	if (filename == NULL)
+	{
+		return false;
+	}
+
+	StrCpy(name, sizeof(name), filename);
+	Trim(name);
+
+	if (SearchStr(name, "\"", 0) == INFINITE)
+	{
+		if (arg == NULL)
+		{
+			Format(cmdline, sizeof(cmdline), "%s", name);
+		}
+		else
+		{
+			Format(cmdline, sizeof(cmdline), "%s %s", name, arg);
+		}
+	}
+	else
+	{
+		if (arg == NULL)
+		{
+			Format(cmdline, sizeof(cmdline), "\"%s\"", name);
+		}
+		else
+		{
+			Format(cmdline, sizeof(cmdline), "\"%s\" %s", name, arg);
+		}
+	}
+
+	Zero(&info, sizeof(info));
+	Zero(&ret, sizeof(ret));
+	info.cb = sizeof(info);
+	info.dwFlags = STARTF_USESHOWWINDOW;
+	info.wShowWindow = (hide == false ? SW_SHOWDEFAULT : SW_HIDE);
+
+	Trim(cmdline);
+
+	if (CreateProcess(NULL, cmdline, NULL, NULL, FALSE,
+		(hide == false ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW | CREATE_NEW_CONSOLE) | NORMAL_PRIORITY_CLASS,
+		NULL, NULL, &info, &ret) == FALSE)
+	{
+		return false;
+	}
+
+	if (wait)
+	{
+		WaitForSingleObject(ret.hProcess, INFINITE);
+	}
+
+	CloseHandle(ret.hThread);
+	CloseHandle(ret.hProcess);
+
+	return true;
+}
+
+// スレッド ID の取得
+UINT Win32ThreadId()
+{
+	return GetCurrentThreadId();
+}
+
+// ファイル名の変更
+bool Win32FileRenameW(wchar_t *old_name, wchar_t *new_name)
+{
+	// 引数チェック
+	if (old_name == NULL || new_name == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char *old_name_a = CopyUniToStr(old_name);
+		char *new_name_a = CopyUniToStr(new_name);
+		bool ret = Win32FileRename(old_name_a, new_name_a);
+
+		Free(old_name_a);
+		Free(new_name_a);
+
+		return ret;
+	}
+
+	// リネーム
+	if (MoveFileW(old_name, new_name) == FALSE)
+	{
+		return false;
+	}
+
+	return true;
+}
+bool Win32FileRename(char *old_name, char *new_name)
+{
+	// 引数チェック
+	if (old_name == NULL || new_name == NULL)
+	{
+		return false;
+	}
+
+	// リネーム
+	if (MoveFile(old_name, new_name) == FALSE)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// EXE ファイルが存在しているディレクトリ名を取得する
+void Win32GetExeDirW(wchar_t *name, UINT size)
+{
+	wchar_t exe_path[MAX_SIZE];
+	wchar_t exe_dir[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	if (IsNt() == false)
+	{
+		char name_a[MAX_PATH];
+
+		Win32GetExeDir(name_a, sizeof(name_a));
+
+		StrToUni(name, size, name_a);
+
+		return;
+	}
+
+	// EXE ファイル名を取得
+	GetModuleFileNameW(NULL, exe_path, sizeof(exe_path));
+
+	// ディレクトリ名を取得
+	Win32GetDirFromPathW(exe_dir, sizeof(exe_dir), exe_path);
+
+	UniStrCpy(name, size, exe_dir);
+}
+void Win32GetExeDir(char *name, UINT size)
+{
+	char exe_path[MAX_SIZE];
+	char exe_dir[MAX_SIZE];
+	// 引数チェック
+	if (name == NULL)
+	{
+		return;
+	}
+
+	// EXE ファイル名を取得
+	GetModuleFileName(NULL, exe_path, sizeof(exe_path));
+
+	// ディレクトリ名を取得
+	Win32GetDirFromPath(exe_dir, sizeof(exe_dir), exe_path);
+
+	StrCpy(name, size, exe_dir);
+}
+
+// 終端の \ を抜く
+void Win32NukuEnW(wchar_t *dst, UINT size, wchar_t *src)
+{
+	wchar_t str[MAX_SIZE];
+	int i;
+	if (src)
+	{
+		UniStrCpy(str, sizeof(str), src);
+	}
+	else
+	{
+		UniStrCpy(str, sizeof(str), dst);
+	}
+	i = UniStrLen(str);
+	if (str[i - 1] == L'\\')
+	{
+		str[i - 1] = 0;
+	}
+	UniStrCpy(dst, size, str);
+}
+void Win32NukuEn(char *dst, UINT size, char *src)
+{
+	char str[MAX_SIZE];
+	int i;
+	if (src)
+	{
+		StrCpy(str, sizeof(str), src);
+	}
+	else
+	{
+		StrCpy(str, sizeof(str), dst);
+	}
+	i = StrLen(str);
+	if (str[i - 1] == '\\')
+	{
+		str[i - 1] = 0;
+	}
+	StrCpy(dst, size, str);
+}
+
+// ディレクトリ名をパスから取得
+void Win32GetDirFromPathW(wchar_t *dst, UINT size, wchar_t *src)
+{
+	wchar_t str[MAX_SIZE];
+	int i,len;
+	wchar_t c;
+	wchar_t tmp[MAX_SIZE];
+	int wp;
+	if (src)
+	{
+		UniStrCpy(str, sizeof(str), src);
+	}
+	else
+	{
+		UniStrCpy(str, sizeof(str), dst);
+	}
+	Win32NukuEnW(str, sizeof(str), NULL);
+	wp = 0;
+	len = UniStrLen(str);
+	dst[0] = 0;
+	for (i = 0;i < len;i++)
+	{
+		c = str[i];
+		switch (c)
+		{
+		case L'\\':
+			tmp[wp] = 0;
+			wp = 0;
+			UniStrCat(dst, size, tmp);
+			UniStrCat(dst, size, L"\\");
+			break;
+		default:
+			tmp[wp] = c;
+			wp++;
+			break;
+		}
+	}
+	Win32NukuEnW(dst, size, NULL);
+}
+void Win32GetDirFromPath(char *dst, UINT size, char *src)
+{
+	char str[MAX_SIZE];
+	int i,len;
+	char c;
+	char tmp[MAX_SIZE];
+	int wp;
+	if (src)
+	{
+		StrCpy(str, sizeof(str), src);
+	}
+	else
+	{
+		StrCpy(str, sizeof(str), dst);
+	}
+	Win32NukuEn(str, sizeof(str), NULL);
+	wp = 0;
+	len = StrLen(str);
+	dst[0] = 0;
+	for (i = 0;i < len;i++)
+	{
+		c = str[i];
+		switch (c)
+		{
+		case '\\':
+			tmp[wp] = 0;
+			wp = 0;
+			StrCat(dst, size, tmp);
+			StrCat(dst, size, "\\");
+			break;
+		default:
+			tmp[wp] = c;
+			wp++;
+			break;
+		}
+	}
+	Win32NukuEn(dst, size, NULL);
+}
+
+// ディレクトリの削除
+bool Win32DeleteDirW(wchar_t *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char *name_a = CopyUniToStr(name);
+		bool ret = Win32DeleteDir(name_a);
+
+		Free(name_a);
+
+		return ret;
+	}
+
+	if (RemoveDirectoryW(name) == FALSE)
+	{
+		return false;
+	}
+	return true;
+}
+bool Win32DeleteDir(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (RemoveDirectory(name) == FALSE)
+	{
+		return false;
+	}
+	return true;
+}
+
+// ディレクトリの作成
+bool Win32MakeDirW(wchar_t *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		char *name_a = CopyUniToStr(name);
+		bool ret = Win32MakeDir(name_a);
+
+		Free(name_a);
+
+		return ret;
+	}
+
+	if (CreateDirectoryW(name, NULL) == FALSE)
+	{
+		return false;
+	}
+
+	return true;
+}
+bool Win32MakeDir(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (CreateDirectory(name, NULL) == FALSE)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ファイルの削除
+bool Win32FileDeleteW(wchar_t *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (IsNt() == false)
+	{
+		bool ret;
+		char *name_a = CopyUniToStr(name);
+
+		ret = Win32FileDelete(name_a);
+
+		Free(name_a);
+
+		return ret;
+	}
+
+	if (DeleteFileW(name) == FALSE)
+	{
+		return false;
+	}
+	return true;
+}
+bool Win32FileDelete(char *name)
+{
+	// 引数チェック
+	if (name == NULL)
+	{
+		return false;
+	}
+
+	if (DeleteFile(name) == FALSE)
+	{
+		return false;
+	}
+	return true;
+}
+
+// ファイルのシーク
+bool Win32FileSeek(void *pData, UINT mode, int offset)
+{
+	WIN32IO *p;
+	DWORD ret;
+	// 引数チェック
+	if (pData == NULL)
+	{
+		return false;
+	}
+	if (mode != FILE_BEGIN && mode != FILE_END && mode != FILE_CURRENT)
+	{
+		return false;
+	}
+
+	p = (WIN32IO *)pData;
+	ret = SetFilePointer(p->hFile, (LONG)offset, NULL, mode);
+	if (ret == INVALID_SET_FILE_POINTER || ret == ERROR_NEGATIVE_SEEK)
+	{
+		return false;
+	}
+	return true;
+}
+
+// ファイルサイズの取得
+UINT64 Win32FileSize(void *pData)
+{
+	WIN32IO *p;
+	UINT64 ret;
+	DWORD tmp;
+	// 引数チェック
+	if (pData == NULL)
+	{
+		return 0;
+	}
+
+	p = (WIN32IO *)pData;
+	tmp = 0;
+	ret = GetFileSize(p->hFile, &tmp);
+	if (ret == (DWORD)-1)
+	{
+		return 0;
+	}
+
+	if (tmp != 0)
+	{
+		ret += (UINT64)tmp * 4294967296ULL;
+	}
+
+	return ret;
+}
+
+// ファイルに書き込む
+bool Win32FileWrite(void *pData, void *buf, UINT size)
+{
+	WIN32IO *p;
+	DWORD write_size;
+	// 引数チェック
+	if (pData == NULL || buf == NULL || size == 0)
+	{
+		return false;
+	}
+
+	p = (WIN32IO *)pData;
+	if (WriteFile(p->hFile, buf, size, &write_size, NULL) == FALSE)
+	{
+		return false;
+	}
+
+	if (write_size != size)
+	{
+		return false;
+	}
+
+	return true;
+}
+
+// ファイルから読み込む
+bool Win32FileRead(void *pData, void *buf, UINT size)
+{
+	WIN32IO *p;
+	DWORD read_size;
+	// 引数チェック
+	if (pData == NULL || buf == NULL || size == 0)
+	{
+		return false;
+	}
+
+	p = (WIN32IO *)pData;
+	if (ReadFile(p->hFile, buf, size, &read_size, NULL) == FALSE)
+	{
+		return false;
+	}
+
+	if (read_size != size)
+	{
+		return false;
+	}
+	
+	return true;;
+}
+
+// ファイルを閉じる
+void Win32FileClose(void *pData, bool no_flush)
+{
+	WIN32IO *p;
+	// 引数チェック
+	if (pData == NULL)
+	{
+		return;
+	}
+
+	p = (WIN32IO *)pData;
+	if (p->WriteMode && no_flush == false)
+	{
+		FlushFileBuffers(p->hFile);
+	}
+	CloseHandle(p->hFile);
+	p->hFile = NULL;
+
+	// メモリ解放
+	Win32MemoryFree(p);
+}
+
+// ファイルをフラッシュする
+void Win32FileFlush(void *pData)
+{
+	WIN32IO *p;
+	// 引数チェック
+	if (pData == NULL)
+	{
+		return;
+	}
+
+	p = (WIN32IO *)pData;
+	if (p->WriteMode)
+	{
+		FlushFileBuffers(p->hFile);
+	}
+}
+
+// ファイルを開く
+void *Win32FileOpenW(wchar_t *name, bool write_mode, bool read_lock)
+{
+	WIN32IO *p;
+	HANDLE h;
+	DWORD lock_mode;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	if (IsNt() == false)
+	{
+		void *ret;
+		char *name_a = CopyUniToStr(name);
+
+		ret = Win32FileOpen(name_a, write_mode, read_lock);
+
+		Free(name_a);
+
+		return ret;
+	}
+
+	if (write_mode)
+	{
+		lock_mode = FILE_SHARE_READ;
+	}
+	else
+	{
+		if (read_lock == false)
+		{
+			lock_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+		}
+		else
+		{
+			lock_mode = FILE_SHARE_READ;
+		}
+	}
+
+	// ファイルを開く
+	h = CreateFileW(name,
+		(write_mode ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ),
+		lock_mode,
+		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		UINT ret = GetLastError();
+		// 失敗
+		return NULL;
+	}
+
+	// メモリ確保
+	p = Win32MemoryAlloc(sizeof(WIN32IO));
+	// ハンドル格納
+	p->hFile = h;
+
+	p->WriteMode = write_mode;
+
+	return (void *)p;
+}
+void *Win32FileOpen(char *name, bool write_mode, bool read_lock)
+{
+	WIN32IO *p;
+	HANDLE h;
+	DWORD lock_mode;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	if (write_mode)
+	{
+		lock_mode = FILE_SHARE_READ;
+	}
+	else
+	{
+		if (read_lock == false)
+		{
+			lock_mode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+		}
+		else
+		{
+			lock_mode = FILE_SHARE_READ;
+		}
+	}
+
+	// ファイルを開く
+	h = CreateFile(name,
+		(write_mode ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ),
+		lock_mode,
+		NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		UINT ret = GetLastError();
+		// 失敗
+		return NULL;
+	}
+
+	// メモリ確保
+	p = Win32MemoryAlloc(sizeof(WIN32IO));
+	// ハンドル格納
+	p->hFile = h;
+
+	p->WriteMode = write_mode;
+
+	return (void *)p;
+}
+
+// ファイルを作成する
+void *Win32FileCreateW(wchar_t *name)
+{
+	WIN32IO *p;
+	HANDLE h;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	if (IsNt() == false)
+	{
+		void *ret;
+		char *name_a = CopyUniToStr(name);
+
+		ret = Win32FileCreate(name_a);
+
+		Free(name_a);
+
+		return ret;
+	}
+
+	// ファイルを作成する
+	h = CreateFileW(name, GENERIC_READ | GENERIC_WRITE,
+		FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+		NULL);
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		h = CreateFileW(name, GENERIC_READ | GENERIC_WRITE,
+			FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN,
+			NULL);
+		if (h == INVALID_HANDLE_VALUE)
+		{
+			return NULL;
+		}
+	}
+
+	// メモリ確保
+	p = Win32MemoryAlloc(sizeof(WIN32IO));
+	// ハンドル格納
+	p->hFile = h;
+
+	p->WriteMode = true;
+
+	return (void *)p;
+}
+void *Win32FileCreate(char *name)
+{
+	WIN32IO *p;
+	HANDLE h;
+	// 引数チェック
+	if (name == NULL)
+	{
+		return NULL;
+	}
+
+	// ファイルを作成する
+	h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
+		FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
+		NULL);
+	if (h == INVALID_HANDLE_VALUE)
+	{
+		h = CreateFile(name, GENERIC_READ | GENERIC_WRITE,
+			FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN,
+			NULL);
+		if (h == INVALID_HANDLE_VALUE)
+		{
+			return NULL;
+		}
+	}
+
+	// メモリ確保
+	p = Win32MemoryAlloc(sizeof(WIN32IO));
+	// ハンドル格納
+	p->hFile = h;
+
+	p->WriteMode = true;
+
+	return (void *)p;
+}
+
+#define	SIZE_OF_CALLSTACK_SYM	10000
+#define	CALLSTACK_DEPTH			12
+
+// コールスタックの取得
+CALLSTACK_DATA *Win32GetCallStack()
+{
+#ifndef	WIN32_NO_DEBUG_HELP_DLL
+	DWORD current_eip32 = 0, current_esp32 = 0, current_ebp32 = 0;
+	UINT64 current_eip = 0, current_esp = 0, current_ebp = 0;
+	STACKFRAME64 sf;
+	CALLSTACK_DATA *cs = NULL, *s;
+
+#ifdef	CPU_64
+	CONTEXT context;
+#endif	// CPU_64
+
+	bool ret;
+	UINT depth = 0;
+
+#ifndef	CPU_64
+	// レジスタ取得 (32 bit)
+	__asm
+	{
+		mov current_esp32, esp
+		mov current_ebp32, ebp
+	};
+
+	current_eip32 = (DWORD)Win32GetCallStack;
+
+	current_eip = (UINT64)current_eip32;
+	current_esp = (UINT64)current_esp32;
+	current_ebp = (UINT64)current_ebp32;
+#else	// CPU_64
+	// レジスタ取得 (64 bit)
+	Zero(&context, sizeof(context));
+	context.ContextFlags = CONTEXT_FULL;
+	RtlCaptureContext(&context);
+#endif	// CPU_64
+
+	Zero(&sf, sizeof(sf));
+
+#ifndef	CPU_64
+	sf.AddrPC.Offset = current_eip;
+	sf.AddrStack.Offset = current_esp;
+	sf.AddrFrame.Offset = current_ebp;
+#else	// CPU_64
+	sf.AddrPC.Offset = context.Rip;
+	sf.AddrStack.Offset = context.Rsp;
+	sf.AddrFrame.Offset = context.Rsp;
+#endif	// CPU_64
+
+	sf.AddrPC.Mode = AddrModeFlat;
+	sf.AddrStack.Mode = AddrModeFlat;
+	sf.AddrFrame.Mode = AddrModeFlat;
+
+	while (true)
+	{
+		DWORD type = IMAGE_FILE_MACHINE_I386;
+
+#ifdef	CPU_64
+		type = IMAGE_FILE_MACHINE_AMD64;
+#endif	// CPU_64
+
+		if ((depth++) >= CALLSTACK_DEPTH)
+		{
+			break;
+		}
+
+#ifndef	CPU_64
+		ret = StackWalk64(type,
+			hCurrentProcessHandle,
+			GetCurrentThread(),
+			&sf,
+			NULL, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL);
+#else	// CPU_64
+		ret = StackWalk64(type,
+			hCurrentProcessHandle,
+			GetCurrentThread(),
+			&sf,
+			&context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL);
+#endif	// CPU_64
+		if (ret == false || sf.AddrFrame.Offset == 0)
+		{
+			break;
+		}
+
+		if (cs == NULL)
+		{
+			cs = OSMemoryAlloc(sizeof(CALLSTACK_DATA));
+			s = cs;
+		}
+		else
+		{
+			s->next = OSMemoryAlloc(sizeof(CALLSTACK_DATA));
+			s = s->next;
+		}
+		s->symbol_cache = false;
+		s->next = NULL;
+		s->offset = sf.AddrPC.Offset;
+		s->disp = 0;
+		s->name = NULL;
+		s->line = 0;
+		s->filename[0] = 0;
+	}
+
+	return cs;
+#else	// WIN32_NO_DEBUG_HELP_DLL
+	return NULL;
+#endif	// WIN32_NO_DEBUG_HELP_DLL
+}
+
+// コールスタックからシンボル情報を取得
+bool Win32GetCallStackSymbolInfo(CALLSTACK_DATA *s)
+{
+#ifdef	WIN32_NO_DEBUG_HELP_DLL
+	return false;
+#else	// WIN32_NO_DEBUG_HELP_DLL
+	UINT64 disp;
+	UINT disp32, len;
+	IMAGEHLP_SYMBOL64 *sym;
+	IMAGEHLP_LINE64 line;
+	char tmp[MAX_PATH];
+	// 引数チェック
+	if (s == NULL)
+	{
+		return false;
+	}
+
+	if (s->symbol_cache)
+	{
+		return true;
+	}
+
+	sym = OSMemoryAlloc(SIZE_OF_CALLSTACK_SYM);
+	sym->SizeOfStruct = SIZE_OF_CALLSTACK_SYM;
+	sym->MaxNameLength = SIZE_OF_CALLSTACK_SYM - sizeof(IMAGEHLP_SYMBOL64);
+
+	if (SymGetSymFromAddr64(hCurrentProcessHandle, s->offset, &disp, sym))
+	{
+		s->disp = disp;
+		s->name = OSMemoryAlloc((UINT)strlen(sym->Name) + 1);
+		lstrcpy(s->name, sym->Name);
+	}
+	else
+	{
+		s->disp = 0;
+		s->name = NULL;
+	}
+
+	Zero(&line, sizeof(line));
+	line.SizeOfStruct = sizeof(line);
+	if (SymGetLineFromAddr64(hCurrentProcessHandle, s->offset, &disp32, &line))
+	{
+		disp = (UINT64)disp32;
+		s->line = line.LineNumber;
+		lstrcpy(s->filename, line.FileName);
+		Win32GetDirFromPath(tmp, sizeof(tmp), s->filename);
+		len = lstrlen(tmp);
+		lstrcpy(tmp, &s->filename[len + 1]);
+		lstrcpy(s->filename, tmp);
+	}
+	else
+	{
+		s->line = 0;
+		s->filename[0] = 0;
+	}
+
+	OSMemoryFree(sym);
+
+	s->symbol_cache = true;
+
+	return true;
+#endif	// WIN32_NO_DEBUG_HELP_DLL
+}
+
+// デフォルトの Win32 スレッド
+DWORD CALLBACK Win32DefaultThreadProc(void *param)
+{
+	WIN32THREADSTARTUPINFO *info = (WIN32THREADSTARTUPINFO *)param;
+	// 引数チェック
+	if (info == NULL)
+	{
+		return 0;
+	}
+
+	Win32InitNewThread();
+
+	// スレッド関数の呼び出し
+	info->thread_proc(info->thread, info->param);
+
+	// 参照の解放
+	ReleaseThread(info->thread);
+
+	Win32MemoryFree(info);
+
+	FreeOpenSSLThreadState();
+
+	_endthreadex(0);
+	return 0;
+}
+
+// スレッドの終了を待機
+bool Win32WaitThread(THREAD *t)
+{
+	WIN32THREAD *w;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return false;
+	}
+	w = (WIN32THREAD *)t->pData;
+	if (w == NULL)
+	{
+		return false;
+	}
+
+	// スレッドイベントを待機する
+	if (WaitForSingleObject(w->hThread, INFINITE) == WAIT_OBJECT_0)
+	{
+		// スレッドがシグナル状態になった
+		return true;
+	}
+
+	// 待機失敗 (タイムアウト等)
+	return false;
+}
+
+// スレッドの解放
+void Win32FreeThread(THREAD *t)
+{
+	WIN32THREAD *w;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return;
+	}
+	w = (WIN32THREAD *)t->pData;
+	if (w == NULL)
+	{
+		return;
+	}
+
+	// ハンドルを閉じる
+	CloseHandle(w->hThread);
+
+	// メモリ解放
+	Win32MemoryFree(t->pData);
+	t->pData = NULL;
+}
+
+// スレッドの初期化
+bool Win32InitThread(THREAD *t)
+{
+	WIN32THREAD *w;
+	HANDLE hThread;
+	DWORD thread_id;
+	WIN32THREADSTARTUPINFO *info;
+	// 引数チェック
+	if (t == NULL)
+	{
+		return false;
+	}
+	if (t->thread_proc == NULL)
+	{
+		return false;
+	}
+
+	// スレッドデータ生成
+	w = Win32MemoryAlloc(sizeof(WIN32THREAD));
+
+	// 起動情報生成
+	info = Win32MemoryAlloc(sizeof(WIN32THREADSTARTUPINFO));
+	info->param = t->param;
+	info->thread_proc = t->thread_proc;
+	info->thread = t;
+	AddRef(t->ref);
+
+	// スレッド作成
+	t->pData = w;
+	hThread = (HANDLE)_beginthreadex(NULL, 0, Win32DefaultThreadProc, info, 0, &thread_id);
+	if (hThread == NULL)
+	{
+		// スレッド作成失敗
+		t->pData = NULL;
+		Release(t->ref);
+		Win32MemoryFree(info);
+		Win32MemoryFree(w);
+		return false;
+	}
+
+	// スレッド情報の保存
+	w->hThread = hThread;
+	w->thread_id = thread_id;
+
+	return true;
+}
+
+// Win32 用ライブラリの初期化
+void Win32Init()
+{
+	INITCOMMONCONTROLSEX c;
+	OSVERSIONINFO os;
+
+	// Windows NT かどうか取得する
+	Zero(&os, sizeof(os));
+	os.dwOSVersionInfoSize = sizeof(os);
+	GetVersionEx(&os);
+
+	if (os.dwPlatformId == VER_PLATFORM_WIN32_NT)
+	{
+		// NT 系
+		win32_is_nt = true;
+	}
+	else
+	{
+		// 9x 系
+		win32_is_nt = false;
+	}
+
+	// stdout を開く
+	if (hstdout == INVALID_HANDLE_VALUE)
+	{
+		hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
+	}
+
+	// stdin を開く
+	if (hstdin == INVALID_HANDLE_VALUE)
+	{
+		hstdin = GetStdHandle(STD_INPUT_HANDLE);
+	}
+
+	Win32InitNewThread();
+
+	CoInitialize(NULL);
+
+	InitializeCriticalSection(&fasttick_lock);
+
+#ifdef	WIN32_USE_HEAP_API_FOR_MEMORY
+	use_heap_api = true;
+#else	// WIN32_USE_HEAP_API_FOR_MEMORY
+	use_heap_api = false;
+#endif	// WIN32_USE_HEAP_API_FOR_MEMORY
+
+	if (MayaquaIsDotNetMode())
+	{
+		// .NET API 内からヒープ関係の API を呼び出すとクラッシュする
+		use_heap_api = false;
+	}
+
+	if (IsNt() == false)
+	{
+		// Win9x ではヒープ関係の API は使用しない
+		use_heap_api = false;
+	}
+
+	if (use_heap_api)
+	{
+		heap_handle = HeapCreate(0, 0, 0);
+	}
+
+	// プロセス擬似ハンドルの取得
+	hCurrentProcessHandle = GetCurrentProcess();
+
+	// カレントディレクトリの初期化
+	// Win32InitCurrentDir(); /* 行わない */
+
+	// シンボルハンドラの初期化
+	if (IsMemCheck())
+	{
+#ifndef	WIN32_NO_DEBUG_HELP_DLL
+		SymInitialize(hCurrentProcessHandle, NULL, TRUE);
+#endif	// WIN32_NO_DEBUG_HELP_DLL
+	}
+
+	// Common Control の初期化
+	Zero(&c, sizeof(INITCOMMONCONTROLSEX));
+	c.dwSize = sizeof(INITCOMMONCONTROLSEX);
+	c.dwICC = ICC_ANIMATE_CLASS | ICC_BAR_CLASSES | ICC_COOL_CLASSES |
+		ICC_DATE_CLASSES | ICC_HOTKEY_CLASS | ICC_INTERNET_CLASSES |
+		ICC_LISTVIEW_CLASSES | ICC_NATIVEFNTCTL_CLASS |
+		ICC_PAGESCROLLER_CLASS | ICC_PROGRESS_CLASS |
+		ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES | ICC_UPDOWN_CLASS | ICC_USEREX_CLASSES |
+		ICC_WIN95_CLASSES;
+	InitCommonControlsEx(&c);
+}
+
+// Win32 用ライブラリの解放
+void Win32Free()
+{
+	// シンボルハンドラを閉じる
+	if (IsMemCheck())
+	{
+#ifndef	WIN32_NO_DEBUG_HELP_DLL
+		SymCleanup(hCurrentProcessHandle);
+#endif	// WIN32_NO_DEBUG_HELP_DLL
+	}
+
+	if (use_heap_api)
+	{
+		HeapDestroy(heap_handle);
+		heap_handle = NULL;
+	}
+
+	CoUninitialize();
+
+	DeleteCriticalSection(&fasttick_lock);
+}
+
+// メモリ確保
+void *Win32MemoryAlloc(UINT size)
+{
+	if (use_heap_api)
+	{
+		return HeapAlloc(heap_handle, 0, size);
+	}
+	else
+	{
+		return malloc(size);
+	}
+}
+
+// メモリ再確保
+void *Win32MemoryReAlloc(void *addr, UINT size)
+{
+	if (use_heap_api)
+	{
+		return HeapReAlloc(heap_handle, 0, addr, size);
+	}
+	else
+	{
+		return realloc(addr, size);
+	}
+}
+
+// メモリ確報
+void Win32MemoryFree(void *addr)
+{
+	if (use_heap_api)
+	{
+		HeapFree(heap_handle, 0, addr);
+	}
+	else
+	{
+		free(addr);
+	}
+}
+
+// システムタイマの取得
+UINT Win32GetTick()
+{
+	return (UINT)timeGetTime();
+}
+
+// システム時刻の取得
+void Win32GetSystemTime(SYSTEMTIME *system_time)
+{
+	// システム時刻の取得
+	GetSystemTime(system_time);
+}
+
+// 32bit 整数のインクリメント
+void Win32Inc32(UINT *value)
+{
+	InterlockedIncrement(value);
+}
+
+// 32bit 整数のデクリメント
+void Win32Dec32(UINT *value)
+{
+	InterlockedDecrement(value);
+}
+
+// スレッドの休止
+void Win32Sleep(UINT time)
+{
+	Sleep(time);
+}
+
+// ロックの作成
+LOCK *Win32NewLock()
+{
+	// メモリ確保
+	LOCK *lock = Win32MemoryAlloc(sizeof(LOCK));
+
+	// クリティカルセクション確保
+	CRITICAL_SECTION *critical_section = Win32MemoryAlloc(sizeof(CRITICAL_SECTION));
+
+	if (lock == NULL || critical_section == NULL)
+	{
+		Win32MemoryFree(lock);
+		Win32MemoryFree(critical_section);
+		return NULL;
+	}
+
+	// クリティカルセクション初期化
+	InitializeCriticalSection(critical_section);
+
+	lock->pData = (void *)critical_section;
+	lock->Ready = true;
+
+	return lock;
+}
+
+// ロック
+bool Win32Lock(LOCK *lock)
+{
+	CRITICAL_SECTION *critical_section;
+	if (lock->Ready == false)
+	{
+		// 状態が不正
+		return false;
+	}
+
+	// クリティカルセクションに入る
+	critical_section = (CRITICAL_SECTION *)lock->pData;
+	EnterCriticalSection(critical_section);
+
+	return true;
+}
+
+// ロック解除
+void Win32Unlock(LOCK *lock)
+{
+	Win32UnlockEx(lock, false);
+}
+void Win32UnlockEx(LOCK *lock, bool inner)
+{
+	CRITICAL_SECTION *critical_section;
+	if (lock->Ready == false && inner == false)
+	{
+		// 状態が不正
+		return;
+	}
+
+	// クリティカルセクションから出る
+	critical_section = (CRITICAL_SECTION *)lock->pData;
+	LeaveCriticalSection(critical_section);
+}
+
+// ロックの削除
+void Win32DeleteLock(LOCK *lock)
+{
+	CRITICAL_SECTION *critical_section;
+	// Ready フラグを安全に解除する
+	Win32Lock(lock);
+	lock->Ready = false;
+	Win32UnlockEx(lock, true);
+
+	// クリティカルセクションの削除
+	critical_section = (CRITICAL_SECTION *)lock->pData;
+	DeleteCriticalSection(critical_section);
+
+	// メモリ解放
+	Win32MemoryFree(critical_section);
+	Win32MemoryFree(lock);
+}
+
+// イベントの初期化
+void Win32InitEvent(EVENT *event)
+{
+	// 自動リセットイベントの作成
+	HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+
+	event->pData = hEvent;
+}
+
+// イベントのセット
+void Win32SetEvent(EVENT *event)
+{
+	HANDLE hEvent = (HANDLE)event->pData;
+	if (hEvent == NULL)
+	{
+		return;
+	}
+
+	SetEvent(hEvent);
+}
+
+// イベントのリセット
+void Win32ResetEvent(EVENT *event)
+{
+	HANDLE hEvent = (HANDLE)event->pData;
+	if (hEvent == NULL)
+	{
+		return;
+	}
+
+	ResetEvent(hEvent);
+}
+
+// イベントを待機する
+bool Win32WaitEvent(EVENT *event, UINT timeout)
+{
+	HANDLE hEvent = (HANDLE)event->pData;
+	UINT ret;
+	if (hEvent == NULL)
+	{
+		return false;
+	}
+
+	// オブジェクトを待機
+	ret = WaitForSingleObject(hEvent, timeout);
+	if (ret == WAIT_TIMEOUT)
+	{
+		// タイムアウト
+		return false;
+	}
+	else
+	{
+		// シグナル状態
+		return true;
+	}
+}
+
+// イベントの解放
+void Win32FreeEvent(EVENT *event)
+{
+	HANDLE hEvent = (HANDLE)event->pData;
+	if (hEvent == NULL)
+	{
+		return;
+	}
+
+	CloseHandle(hEvent);
+}
+
+// Win32 専用の高速な 64 bit Tick 取得関数
+UINT64 Win32FastTick64()
+{
+	static UINT last_tick = 0;
+	static UINT counter = 0;
+	UINT64 ret;
+	UINT tick;
+
+	EnterCriticalSection(&fasttick_lock);
+
+	// 現在の tick 値を取得する
+	tick = Win32GetTick();
+
+	if (last_tick > tick)
+	{
+		// 前回取得した tick 値のほうが今回取得した値よりも大きい場合
+		// カウンタが 1 回りしたと考えることができる
+
+		counter++;
+	}
+
+	last_tick = tick;
+
+	ret = (UINT64)tick + (UINT64)counter * 4294967296ULL;
+
+	LeaveCriticalSection(&fasttick_lock);
+
+	if (start_tick == 0)
+	{
+		start_tick = ret;
+		ret = 0;
+	}
+	else
+	{
+		ret -= start_tick;
+	}
+
+	return ret + 1;
+}
+
+// 文字列をコンソールから読み込む
+bool Win32InputW(wchar_t *str, UINT size)
+{
+	bool ret = false;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return false;
+	}
+	if (size == 0)
+	{
+		size = 0x7fffffff;
+	}
+
+	if (str == NULL || size <= sizeof(wchar_t))
+	{
+		if (str != NULL)
+		{
+			Zero(str, size);
+		}
+
+		return Win32InputFromFileW(NULL, 0);
+	}
+
+	if (IsNt())
+	{
+		DWORD read_size = 0;
+
+		if (ReadConsoleW(hstdin, str, (size - sizeof(wchar_t)), &read_size, NULL))
+		{
+			str[read_size] = 0;
+
+			UniTrimCrlf(str);
+
+			ret = true;
+		}
+		else
+		{
+			ret = Win32InputFromFileW(str, size);
+		}
+	}
+	else
+	{
+		DWORD read_size = 0;
+		UINT a_size = size / sizeof(wchar_t) + 16;
+		char *a;
+
+		a = ZeroMalloc(a_size);
+
+		if (ReadConsoleA(hstdin, a, a_size - 1, &read_size, NULL))
+		{
+			a[read_size] = 0;
+
+			StrToUni(str, size, a);
+
+			UniTrimCrlf(str);
+
+			ret = true;
+		}
+		else
+		{
+			ret = Win32InputFromFileW(str, size);
+		}
+
+		Free(a);
+	}
+
+	return ret;
+}
+// 1 行を標準入力から取得
+bool Win32InputFromFileW(wchar_t *str, UINT size)
+{
+	char *a;
+	if (str == NULL)
+	{
+		wchar_t tmp[MAX_SIZE];
+		Win32InputFromFileW(tmp, sizeof(tmp));
+		return false;
+	}
+
+	a = Win32InputFromFileLineA();
+	if (a == NULL)
+	{
+		UniStrCpy(str, size, L"");
+		return false;
+	}
+
+	UtfToUni(str, size, a);
+
+	UniTrimCrlf(str);
+
+	Free(a);
+
+	return true;
+}
+char *Win32InputFromFileLineA()
+{
+	BUF *b = NewBuf();
+	char zero = 0;
+	char *ret = NULL;
+	bool ok = true;
+
+	while (true)
+	{
+		char c;
+		UINT read_size = 0;
+
+		if (ReadFile(hstdin, &c, 1, &read_size, NULL) == false)
+		{
+			ok = false;
+			break;
+		}
+		if (read_size != 1)
+		{
+			ok = false;
+			break;
+		}
+
+		WriteBuf(b, &c, 1);
+
+		if (c == 10)
+		{
+			break;
+		}
+	}
+
+	WriteBuf(b, &zero, 1);
+
+	if (ok)
+	{
+		ret = CopyStr(b->Buf);
+	}
+
+	FreeBuf(b);
+
+	return ret;
+}
+
+// 文字列をコンソールにプリントする
+void Win32PrintW(wchar_t *str)
+{
+	DWORD write_size = 0;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	if (IsNt())
+	{
+		if (WriteConsoleW(hstdout, str, UniStrLen(str), &write_size, NULL) == false)
+		{
+			Win32PrintToFileW(str);
+		}
+	}
+	else
+	{
+		char *ansi_str = CopyUniToStr(str);
+
+		if (WriteConsoleA(hstdout, ansi_str, StrLen(ansi_str), &write_size, NULL) == false)
+		{
+			Win32PrintToFileW(str);
+		}
+
+		Free(ansi_str);
+	}
+}
+void Win32PrintToFileW(wchar_t *str)
+{
+	char *utf;
+	DWORD size = 0;
+	// 引数チェック
+	if (str == NULL)
+	{
+		return;
+	}
+
+	utf = CopyUniToUtf(str);
+
+	WriteFile(hstdout, utf, StrLen(utf), &size, NULL);
+
+	Free(utf);
+}
+
+
+#endif	// WIN32
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Win32.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Win32.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/Win32.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,190 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// Win32.h
+// Win32.c のヘッダ
+
+#ifdef	OS_WIN32
+
+#ifndef	WIN32_H
+#define	WIN32_H
+
+// 関数プロトタイプ
+OS_DISPATCH_TABLE *Win32GetDispatchTable();
+
+void Win32Init();
+void Win32Free();
+void *Win32MemoryAlloc(UINT size);
+void *Win32MemoryReAlloc(void *addr, UINT size);
+void Win32MemoryFree(void *addr);
+UINT Win32GetTick();
+void Win32GetSystemTime(SYSTEMTIME *system_time);
+void Win32Inc32(UINT *value);
+void Win32Dec32(UINT *value);
+void Win32Sleep(UINT time);
+LOCK *Win32NewLock();
+bool Win32Lock(LOCK *lock);
+void Win32Unlock(LOCK *lock);
+void Win32DeleteLock(LOCK *lock);
+void Win32InitEvent(EVENT *event);
+void Win32SetEvent(EVENT *event);
+void Win32ResetEvent(EVENT *event);
+bool Win32WaitEvent(EVENT *event, UINT timeout);
+void Win32FreeEvent(EVENT *event);
+bool Win32WaitThread(THREAD *t);
+void Win32FreeThread(THREAD *t);
+bool Win32InitThread(THREAD *t);
+UINT Win32ThreadId();
+void *Win32FileOpen(char *name, bool write_mode, bool read_lock);
+void *Win32FileOpenW(wchar_t *name, bool write_mode, bool read_lock);
+void *Win32FileCreate(char *name);
+void *Win32FileCreateW(wchar_t *name);
+bool Win32FileWrite(void *pData, void *buf, UINT size);
+bool Win32FileRead(void *pData, void *buf, UINT size);
+void Win32FileClose(void *pData, bool no_flush);
+void Win32FileFlush(void *pData);
+UINT64 Win32FileSize(void *pData);
+bool Win32FileSeek(void *pData, UINT mode, int offset);
+bool Win32FileDelete(char *name);
+bool Win32FileDeleteW(wchar_t *name);
+bool Win32MakeDir(char *name);
+bool Win32MakeDirW(wchar_t *name);
+bool Win32DeleteDir(char *name);
+bool Win32DeleteDirW(wchar_t *name);
+CALLSTACK_DATA *Win32GetCallStack();
+bool Win32GetCallStackSymbolInfo(CALLSTACK_DATA *s);
+bool Win32FileRename(char *old_name, char *new_name);
+bool Win32FileRenameW(wchar_t *old_name, wchar_t *new_name);
+bool Win32Run(char *filename, char *arg, bool hide, bool wait);
+bool Win32RunW(wchar_t *filename, wchar_t *arg, bool hide, bool wait);
+void *Win32RunEx(char *filename, char *arg, bool hide);
+void *Win32RunEx2(char *filename, char *arg, bool hide, UINT *process_id);
+void *Win32RunEx3(char *filename, char *arg, bool hide, UINT *process_id, bool disableWow);
+void *Win32RunExW(wchar_t *filename, wchar_t *arg, bool hide);
+void *Win32RunEx2W(wchar_t *filename, wchar_t *arg, bool hide, UINT *process_id);
+void *Win32RunEx3W(wchar_t *filename, wchar_t *arg, bool hide, UINT *process_id, bool disableWow);
+bool Win32WaitProcess(void *h, UINT timeout);
+bool Win32IsProcessAlive(void *handle);
+bool Win32TerminateProcess(void *handle);
+void Win32CloseProcess(void *handle);
+bool Win32IsSupportedOs();
+void Win32GetOsInfo(OS_INFO *info);
+void Win32Alert(char *msg, char *caption);
+void Win32AlertW(wchar_t *msg, wchar_t *caption);
+void Win32DebugAlert(char *msg);
+char* Win32GetProductId();
+void Win32SetHighPriority();
+void Win32RestorePriority();
+void *Win32NewSingleInstance(char *instance_name);
+void Win32FreeSingleInstance(void *data);
+void Win32GetMemInfo(MEMINFO *info);
+void Win32Yield();
+
+void Win32UnlockEx(LOCK *lock, bool inner);
+UINT Win32GetOsType();
+UINT Win32GetSpVer(char *str);
+UINT Win32GetOsSpVer();
+void Win32NukuEn(char *dst, UINT size, char *src);
+void Win32NukuEnW(wchar_t *dst, UINT size, wchar_t *src);
+void Win32GetDirFromPath(char *dst, UINT size, char *src);
+void Win32GetDirFromPathW(wchar_t *dst, UINT size, wchar_t *src);
+void Win32GetExeDir(char *name, UINT size);
+void Win32GetExeDirW(wchar_t *name, UINT size);
+void Win32GetCurrentDir(char *dir, UINT size);
+void Win32GetCurrentDirW(wchar_t *dir, UINT size);
+void Win32GetExeName(char *name, UINT size);
+void Win32GetExeNameW(wchar_t *name, UINT size);
+DIRLIST *Win32EnumDirEx(char *dirname, COMPARE *compare);
+DIRLIST *Win32EnumDirExW(wchar_t *dirname, COMPARE *compare);
+bool Win32GetDiskFreeW(wchar_t *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size);
+bool Win32GetDiskFree(char *path, UINT64 *free_size, UINT64 *used_size, UINT64 *total_size);
+bool Win32SetFolderCompress(char *path, bool compressed);
+bool Win32SetFolderCompressW(wchar_t *path, bool compressed);
+UINT64 Win32FastTick64();
+void Win32InitNewThread();
+bool Win32IsNt();
+bool Win32InputW(wchar_t *str, UINT size);
+bool Win32InputFromFileW(wchar_t *str, UINT size);
+char *Win32InputFromFileLineA();
+void Win32PrintW(wchar_t *str);
+void Win32PrintToFileW(wchar_t *str);
+
+#endif	// WIN32_H
+
+#endif	// OS_WIN32
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/cryptoki.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/cryptoki.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/cryptoki.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,66 @@
+/* cryptoki.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the 
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* This is a sample file containing the top level include directives
+ * for building Win32 Cryptoki libraries and applications.
+ */
+
+#ifndef ___CRYPTOKI_H_INC___
+#define ___CRYPTOKI_H_INC___
+
+#pragma pack(push, cryptoki, 1)
+
+/* Specifies that the function is a DLL entry point. */
+#define CK_IMPORT_SPEC __declspec(dllimport)
+
+/* Define CRYPTOKI_EXPORTS during the build of cryptoki libraries. Do
+ * not define it in applications.
+ */
+#ifdef CRYPTOKI_EXPORTS
+/* Specified that the function is an exported DLL entry point. */
+#define CK_EXPORT_SPEC __declspec(dllexport) 
+#else
+#define CK_EXPORT_SPEC CK_IMPORT_SPEC 
+#endif
+
+/* Ensures the calling convention for Win32 builds */
+#define CK_CALL_SPEC __cdecl
+
+#define CK_PTR *
+
+#define CK_DEFINE_FUNCTION(returnType, name) \
+  returnType CK_EXPORT_SPEC CK_CALL_SPEC name
+
+#define CK_DECLARE_FUNCTION(returnType, name) \
+  returnType CK_EXPORT_SPEC CK_CALL_SPEC name
+
+#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+  returnType CK_IMPORT_SPEC (CK_CALL_SPEC CK_PTR name)
+
+#define CK_CALLBACK_FUNCTION(returnType, name) \
+  returnType (CK_CALL_SPEC CK_PTR name)
+
+#ifndef NULL_PTR
+#define NULL_PTR 0
+#endif
+
+#include "pkcs11.h"
+
+#pragma pack(pop, cryptoki)
+
+#endif /* ___CRYPTOKI_H_INC___ */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/aes.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/aes.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/aes.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,127 @@
+/* crypto/aes/aes.h -*- mode:C; c-file-style: "eay" -*- */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ */
+
+#ifndef HEADER_AES_H
+#define HEADER_AES_H
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_NO_AES
+#error AES is disabled.
+#endif
+
+#define AES_ENCRYPT	1
+#define AES_DECRYPT	0
+
+/* Because array size can't be a const in C, the following two are macros.
+   Both sizes are in bytes. */
+#define AES_MAXNR 14
+#define AES_BLOCK_SIZE 16
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* This should be a hidden type, but EVP requires that the size be known */
+struct aes_key_st {
+#ifdef AES_LONG
+    unsigned long rd_key[4 *(AES_MAXNR + 1)];
+#else
+    unsigned int rd_key[4 *(AES_MAXNR + 1)];
+#endif
+    int rounds;
+};
+typedef struct aes_key_st AES_KEY;
+
+const char *AES_options(void);
+
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
+	AES_KEY *key);
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
+	AES_KEY *key);
+
+void AES_encrypt(const unsigned char *in, unsigned char *out,
+	const AES_KEY *key);
+void AES_decrypt(const unsigned char *in, unsigned char *out,
+	const AES_KEY *key);
+
+void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,
+	const AES_KEY *key, const int enc);
+void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
+	const unsigned long length, const AES_KEY *key,
+	unsigned char *ivec, const int enc);
+void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
+	const unsigned long length, const AES_KEY *key,
+	unsigned char *ivec, int *num, const int enc);
+void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
+	const unsigned long length, const AES_KEY *key,
+	unsigned char *ivec, int *num, const int enc);
+void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
+	const unsigned long length, const AES_KEY *key,
+	unsigned char *ivec, int *num, const int enc);
+void AES_cfbr_encrypt_block(const unsigned char *in,unsigned char *out,
+			    const int nbits,const AES_KEY *key,
+			    unsigned char *ivec,const int enc);
+void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out,
+	const unsigned long length, const AES_KEY *key,
+	unsigned char *ivec, int *num);
+void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out,
+	const unsigned long length, const AES_KEY *key,
+	unsigned char ivec[AES_BLOCK_SIZE],
+	unsigned char ecount_buf[AES_BLOCK_SIZE],
+	unsigned int *num);
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* !HEADER_AES_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1230 @@
+/* crypto/asn1/asn1.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_ASN1_H
+#define HEADER_ASN1_H
+
+#include <time.h>
+#include <openssl/e_os2.h>
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/stack.h>
+#include <openssl/safestack.h>
+
+#include <openssl/symhacks.h>
+
+#include <openssl/ossl_typ.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#endif
+
+#ifdef OPENSSL_BUILD_SHLIBCRYPTO
+# undef OPENSSL_EXTERN
+# define OPENSSL_EXTERN OPENSSL_EXPORT
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define V_ASN1_UNIVERSAL		0x00
+#define	V_ASN1_APPLICATION		0x40
+#define V_ASN1_CONTEXT_SPECIFIC		0x80
+#define V_ASN1_PRIVATE			0xc0
+
+#define V_ASN1_CONSTRUCTED		0x20
+#define V_ASN1_PRIMITIVE_TAG		0x1f
+#define V_ASN1_PRIMATIVE_TAG		0x1f
+
+#define V_ASN1_APP_CHOOSE		-2	/* let the recipient choose */
+#define V_ASN1_OTHER			-3	/* used in ASN1_TYPE */
+#define V_ASN1_ANY			-4	/* used in ASN1 template code */
+
+#define V_ASN1_NEG			0x100	/* negative flag */
+
+#define V_ASN1_UNDEF			-1
+#define V_ASN1_EOC			0
+#define V_ASN1_BOOLEAN			1	/**/
+#define V_ASN1_INTEGER			2
+#define V_ASN1_NEG_INTEGER		(2 | V_ASN1_NEG)
+#define V_ASN1_BIT_STRING		3
+#define V_ASN1_OCTET_STRING		4
+#define V_ASN1_NULL			5
+#define V_ASN1_OBJECT			6
+#define V_ASN1_OBJECT_DESCRIPTOR	7
+#define V_ASN1_EXTERNAL			8
+#define V_ASN1_REAL			9
+#define V_ASN1_ENUMERATED		10
+#define V_ASN1_NEG_ENUMERATED		(10 | V_ASN1_NEG)
+#define V_ASN1_UTF8STRING		12
+#define V_ASN1_SEQUENCE			16
+#define V_ASN1_SET			17
+#define V_ASN1_NUMERICSTRING		18	/**/
+#define V_ASN1_PRINTABLESTRING		19
+#define V_ASN1_T61STRING		20
+#define V_ASN1_TELETEXSTRING		20	/* alias */
+#define V_ASN1_VIDEOTEXSTRING		21	/**/
+#define V_ASN1_IA5STRING		22
+#define V_ASN1_UTCTIME			23
+#define V_ASN1_GENERALIZEDTIME		24	/**/
+#define V_ASN1_GRAPHICSTRING		25	/**/
+#define V_ASN1_ISO64STRING		26	/**/
+#define V_ASN1_VISIBLESTRING		26	/* alias */
+#define V_ASN1_GENERALSTRING		27	/**/
+#define V_ASN1_UNIVERSALSTRING		28	/**/
+#define V_ASN1_BMPSTRING		30
+
+/* For use with d2i_ASN1_type_bytes() */
+#define B_ASN1_NUMERICSTRING	0x0001
+#define B_ASN1_PRINTABLESTRING	0x0002
+#define B_ASN1_T61STRING	0x0004
+#define B_ASN1_TELETEXSTRING	0x0004
+#define B_ASN1_VIDEOTEXSTRING	0x0008
+#define B_ASN1_IA5STRING	0x0010
+#define B_ASN1_GRAPHICSTRING	0x0020
+#define B_ASN1_ISO64STRING	0x0040
+#define B_ASN1_VISIBLESTRING	0x0040
+#define B_ASN1_GENERALSTRING	0x0080
+#define B_ASN1_UNIVERSALSTRING	0x0100
+#define B_ASN1_OCTET_STRING	0x0200
+#define B_ASN1_BIT_STRING	0x0400
+#define B_ASN1_BMPSTRING	0x0800
+#define B_ASN1_UNKNOWN		0x1000
+#define B_ASN1_UTF8STRING	0x2000
+#define B_ASN1_UTCTIME		0x4000
+#define B_ASN1_GENERALIZEDTIME	0x8000
+
+/* For use with ASN1_mbstring_copy() */
+#define MBSTRING_FLAG		0x1000
+#define MBSTRING_UTF8		(MBSTRING_FLAG)
+#define MBSTRING_ASC		(MBSTRING_FLAG|1)
+#define MBSTRING_BMP		(MBSTRING_FLAG|2)
+#define MBSTRING_UNIV		(MBSTRING_FLAG|4)
+
+struct X509_algor_st;
+
+#define DECLARE_ASN1_SET_OF(type) /* filled in by mkstack.pl */
+#define IMPLEMENT_ASN1_SET_OF(type) /* nothing, no longer needed */
+
+/* We MUST make sure that, except for constness, asn1_ctx_st and
+   asn1_const_ctx are exactly the same.  Fortunately, as soon as
+   the old ASN1 parsing macros are gone, we can throw this away
+   as well... */
+typedef struct asn1_ctx_st
+	{
+	unsigned char *p;/* work char pointer */
+	int eos;	/* end of sequence read for indefinite encoding */
+	int error;	/* error code to use when returning an error */
+	int inf;	/* constructed if 0x20, indefinite is 0x21 */
+	int tag;	/* tag from last 'get object' */
+	int xclass;	/* class from last 'get object' */
+	long slen;	/* length of last 'get object' */
+	unsigned char *max; /* largest value of p allowed */
+	unsigned char *q;/* temporary variable */
+	unsigned char **pp;/* variable */
+	int line;	/* used in error processing */
+	} ASN1_CTX;
+
+typedef struct asn1_const_ctx_st
+	{
+	const unsigned char *p;/* work char pointer */
+	int eos;	/* end of sequence read for indefinite encoding */
+	int error;	/* error code to use when returning an error */
+	int inf;	/* constructed if 0x20, indefinite is 0x21 */
+	int tag;	/* tag from last 'get object' */
+	int xclass;	/* class from last 'get object' */
+	long slen;	/* length of last 'get object' */
+	const unsigned char *max; /* largest value of p allowed */
+	const unsigned char *q;/* temporary variable */
+	const unsigned char **pp;/* variable */
+	int line;	/* used in error processing */
+	} ASN1_const_CTX;
+
+/* These are used internally in the ASN1_OBJECT to keep track of
+ * whether the names and data need to be free()ed */
+#define ASN1_OBJECT_FLAG_DYNAMIC	 0x01	/* internal use */
+#define ASN1_OBJECT_FLAG_CRITICAL	 0x02	/* critical x509v3 object id */
+#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04	/* internal use */
+#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 	 0x08	/* internal use */
+typedef struct asn1_object_st
+	{
+	const char *sn,*ln;
+	int nid;
+	int length;
+	unsigned char *data;
+	int flags;	/* Should we free this one */
+	} ASN1_OBJECT;
+
+#define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */
+/* This indicates that the ASN1_STRING is not a real value but just a place
+ * holder for the location where indefinite length constructed data should
+ * be inserted in the memory buffer 
+ */
+#define ASN1_STRING_FLAG_NDEF 0x010 
+/* This is the base type that holds just about everything :-) */
+typedef struct asn1_string_st
+	{
+	int length;
+	int type;
+	unsigned char *data;
+	/* The value of the following field depends on the type being
+	 * held.  It is mostly being used for BIT_STRING so if the
+	 * input data has a non-zero 'unused bits' value, it will be
+	 * handled correctly */
+	long flags;
+	} ASN1_STRING;
+
+/* ASN1_ENCODING structure: this is used to save the received
+ * encoding of an ASN1 type. This is useful to get round
+ * problems with invalid encodings which can break signatures.
+ */
+
+typedef struct ASN1_ENCODING_st
+	{
+	unsigned char *enc;	/* DER encoding */
+	long len;		/* Length of encoding */
+	int modified;		 /* set to 1 if 'enc' is invalid */
+	} ASN1_ENCODING;
+
+/* Used with ASN1 LONG type: if a long is set to this it is omitted */
+#define ASN1_LONG_UNDEF	0x7fffffffL
+
+#define STABLE_FLAGS_MALLOC	0x01
+#define STABLE_NO_MASK		0x02
+#define DIRSTRING_TYPE	\
+ (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING)
+#define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING)
+
+typedef struct asn1_string_table_st {
+	int nid;
+	long minsize;
+	long maxsize;
+	unsigned long mask;
+	unsigned long flags;
+} ASN1_STRING_TABLE;
+
+DECLARE_STACK_OF(ASN1_STRING_TABLE)
+
+/* size limits: this stuff is taken straight from RFC2459 */
+
+#define ub_name				32768
+#define ub_common_name			64
+#define ub_locality_name		128
+#define ub_state_name			128
+#define ub_organization_name		64
+#define ub_organization_unit_name	64
+#define ub_title			64
+#define ub_email_address		128
+
+/* Declarations for template structures: for full definitions
+ * see asn1t.h
+ */
+typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE;
+typedef struct ASN1_ITEM_st ASN1_ITEM;
+typedef struct ASN1_TLC_st ASN1_TLC;
+/* This is just an opaque pointer */
+typedef struct ASN1_VALUE_st ASN1_VALUE;
+
+/* Declare ASN1 functions: the implement macro in in asn1t.h */
+
+#define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type)
+
+#define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \
+	DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type)
+
+#define DECLARE_ASN1_FUNCTIONS_name(type, name) \
+	DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
+	DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name)
+
+#define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \
+	DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
+	DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name)
+
+#define	DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \
+	type *d2i_##name(type **a, const unsigned char **in, long len); \
+	int i2d_##name(type *a, unsigned char **out); \
+	DECLARE_ASN1_ITEM(itname)
+
+#define	DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \
+	type *d2i_##name(type **a, const unsigned char **in, long len); \
+	int i2d_##name(const type *a, unsigned char **out); \
+	DECLARE_ASN1_ITEM(name)
+
+#define	DECLARE_ASN1_NDEF_FUNCTION(name) \
+	int i2d_##name##_NDEF(name *a, unsigned char **out);
+
+#define DECLARE_ASN1_FUNCTIONS_const(name) \
+	name *name##_new(void); \
+	void name##_free(name *a);
+
+#define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \
+	type *name##_new(void); \
+	void name##_free(type *a);
+
+#define D2I_OF(type) type *(*)(type **,const unsigned char **,long)
+#define I2D_OF(type) int (*)(type *,unsigned char **)
+#define I2D_OF_const(type) int (*)(const type *,unsigned char **)
+
+#define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **,const unsigned char **,long)
+#define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(type *,unsigned char **)
+#define TYPEDEF_D2I2D_OF(type) TYPEDEF_D2I_OF(type); TYPEDEF_I2D_OF(type)
+
+TYPEDEF_D2I2D_OF(void);
+
+/* The following macros and typedefs allow an ASN1_ITEM
+ * to be embedded in a structure and referenced. Since
+ * the ASN1_ITEM pointers need to be globally accessible
+ * (possibly from shared libraries) they may exist in
+ * different forms. On platforms that support it the
+ * ASN1_ITEM structure itself will be globally exported.
+ * Other platforms will export a function that returns
+ * an ASN1_ITEM pointer.
+ *
+ * To handle both cases transparently the macros below
+ * should be used instead of hard coding an ASN1_ITEM
+ * pointer in a structure.
+ *
+ * The structure will look like this:
+ *
+ * typedef struct SOMETHING_st {
+ *      ...
+ *      ASN1_ITEM_EXP *iptr;
+ *      ...
+ * } SOMETHING; 
+ *
+ * It would be initialised as e.g.:
+ *
+ * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...};
+ *
+ * and the actual pointer extracted with:
+ *
+ * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr);
+ *
+ * Finally an ASN1_ITEM pointer can be extracted from an
+ * appropriate reference with: ASN1_ITEM_rptr(X509). This
+ * would be used when a function takes an ASN1_ITEM * argument.
+ *
+ */
+
+#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
+
+/* ASN1_ITEM pointer exported type */
+typedef const ASN1_ITEM ASN1_ITEM_EXP;
+
+/* Macro to obtain ASN1_ITEM pointer from exported type */
+#define ASN1_ITEM_ptr(iptr) (iptr)
+
+/* Macro to include ASN1_ITEM pointer from base type */
+#define ASN1_ITEM_ref(iptr) (&(iptr##_it))
+
+#define ASN1_ITEM_rptr(ref) (&(ref##_it))
+
+#define DECLARE_ASN1_ITEM(name) \
+	OPENSSL_EXTERN const ASN1_ITEM name##_it;
+
+#else
+
+/* Platforms that can't easily handle shared global variables are declared
+ * as functions returning ASN1_ITEM pointers.
+ */
+
+/* ASN1_ITEM pointer exported type */
+typedef const ASN1_ITEM * ASN1_ITEM_EXP(void);
+
+/* Macro to obtain ASN1_ITEM pointer from exported type */
+#define ASN1_ITEM_ptr(iptr) (iptr())
+
+/* Macro to include ASN1_ITEM pointer from base type */
+#define ASN1_ITEM_ref(iptr) (iptr##_it)
+
+#define ASN1_ITEM_rptr(ref) (ref##_it())
+
+#define DECLARE_ASN1_ITEM(name) \
+	const ASN1_ITEM * name##_it(void);
+
+#endif
+
+/* Parameters used by ASN1_STRING_print_ex() */
+
+/* These determine which characters to escape:
+ * RFC2253 special characters, control characters and
+ * MSB set characters
+ */
+
+#define ASN1_STRFLGS_ESC_2253		1
+#define ASN1_STRFLGS_ESC_CTRL		2
+#define ASN1_STRFLGS_ESC_MSB		4
+
+
+/* This flag determines how we do escaping: normally
+ * RC2253 backslash only, set this to use backslash and
+ * quote.
+ */
+
+#define ASN1_STRFLGS_ESC_QUOTE		8
+
+
+/* These three flags are internal use only. */
+
+/* Character is a valid PrintableString character */
+#define CHARTYPE_PRINTABLESTRING	0x10
+/* Character needs escaping if it is the first character */
+#define CHARTYPE_FIRST_ESC_2253		0x20
+/* Character needs escaping if it is the last character */
+#define CHARTYPE_LAST_ESC_2253		0x40
+
+/* NB the internal flags are safely reused below by flags
+ * handled at the top level.
+ */
+
+/* If this is set we convert all character strings
+ * to UTF8 first 
+ */
+
+#define ASN1_STRFLGS_UTF8_CONVERT	0x10
+
+/* If this is set we don't attempt to interpret content:
+ * just assume all strings are 1 byte per character. This
+ * will produce some pretty odd looking output!
+ */
+
+#define ASN1_STRFLGS_IGNORE_TYPE	0x20
+
+/* If this is set we include the string type in the output */
+#define ASN1_STRFLGS_SHOW_TYPE		0x40
+
+/* This determines which strings to display and which to
+ * 'dump' (hex dump of content octets or DER encoding). We can
+ * only dump non character strings or everything. If we
+ * don't dump 'unknown' they are interpreted as character
+ * strings with 1 octet per character and are subject to
+ * the usual escaping options.
+ */
+
+#define ASN1_STRFLGS_DUMP_ALL		0x80
+#define ASN1_STRFLGS_DUMP_UNKNOWN	0x100
+
+/* These determine what 'dumping' does, we can dump the
+ * content octets or the DER encoding: both use the
+ * RFC2253 #XXXXX notation.
+ */
+
+#define ASN1_STRFLGS_DUMP_DER		0x200
+
+/* All the string flags consistent with RFC2253,
+ * escaping control characters isn't essential in
+ * RFC2253 but it is advisable anyway.
+ */
+
+#define ASN1_STRFLGS_RFC2253	(ASN1_STRFLGS_ESC_2253 | \
+				ASN1_STRFLGS_ESC_CTRL | \
+				ASN1_STRFLGS_ESC_MSB | \
+				ASN1_STRFLGS_UTF8_CONVERT | \
+				ASN1_STRFLGS_DUMP_UNKNOWN | \
+				ASN1_STRFLGS_DUMP_DER)
+
+DECLARE_STACK_OF(ASN1_INTEGER)
+DECLARE_ASN1_SET_OF(ASN1_INTEGER)
+
+DECLARE_STACK_OF(ASN1_GENERALSTRING)
+
+typedef struct asn1_type_st
+	{
+	int type;
+	union	{
+		char *ptr;
+		ASN1_BOOLEAN		boolean;
+		ASN1_STRING *		asn1_string;
+		ASN1_OBJECT *		object;
+		ASN1_INTEGER *		integer;
+		ASN1_ENUMERATED *	enumerated;
+		ASN1_BIT_STRING *	bit_string;
+		ASN1_OCTET_STRING *	octet_string;
+		ASN1_PRINTABLESTRING *	printablestring;
+		ASN1_T61STRING *	t61string;
+		ASN1_IA5STRING *	ia5string;
+		ASN1_GENERALSTRING *	generalstring;
+		ASN1_BMPSTRING *	bmpstring;
+		ASN1_UNIVERSALSTRING *	universalstring;
+		ASN1_UTCTIME *		utctime;
+		ASN1_GENERALIZEDTIME *	generalizedtime;
+		ASN1_VISIBLESTRING *	visiblestring;
+		ASN1_UTF8STRING *	utf8string;
+		/* set and sequence are left complete and still
+		 * contain the set or sequence bytes */
+		ASN1_STRING *		set;
+		ASN1_STRING *		sequence;
+		} value;
+	} ASN1_TYPE;
+
+DECLARE_STACK_OF(ASN1_TYPE)
+DECLARE_ASN1_SET_OF(ASN1_TYPE)
+
+typedef struct asn1_method_st
+	{
+	i2d_of_void *i2d;
+	d2i_of_void *d2i;
+	void *(*create)(void);
+	void (*destroy)(void *);
+	} ASN1_METHOD;
+
+/* This is used when parsing some Netscape objects */
+typedef struct asn1_header_st
+	{
+	ASN1_OCTET_STRING *header;
+	void *data;
+	ASN1_METHOD *meth;
+	} ASN1_HEADER;
+
+/* This is used to contain a list of bit names */
+typedef struct BIT_STRING_BITNAME_st {
+	int bitnum;
+	const char *lname;
+	const char *sname;
+} BIT_STRING_BITNAME;
+
+
+#define M_ASN1_STRING_length(x)	((x)->length)
+#define M_ASN1_STRING_length_set(x, n)	((x)->length = (n))
+#define M_ASN1_STRING_type(x)	((x)->type)
+#define M_ASN1_STRING_data(x)	((x)->data)
+
+/* Macros for string operations */
+#define M_ASN1_BIT_STRING_new()	(ASN1_BIT_STRING *)\
+		ASN1_STRING_type_new(V_ASN1_BIT_STRING)
+#define M_ASN1_BIT_STRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_BIT_STRING_dup(a) (ASN1_BIT_STRING *)\
+		ASN1_STRING_dup((ASN1_STRING *)a)
+#define M_ASN1_BIT_STRING_cmp(a,b) ASN1_STRING_cmp(\
+		(ASN1_STRING *)a,(ASN1_STRING *)b)
+#define M_ASN1_BIT_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c)
+
+#define M_ASN1_INTEGER_new()	(ASN1_INTEGER *)\
+		ASN1_STRING_type_new(V_ASN1_INTEGER)
+#define M_ASN1_INTEGER_free(a)		ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_INTEGER_dup(a) (ASN1_INTEGER *)ASN1_STRING_dup((ASN1_STRING *)a)
+#define M_ASN1_INTEGER_cmp(a,b)	ASN1_STRING_cmp(\
+		(ASN1_STRING *)a,(ASN1_STRING *)b)
+
+#define M_ASN1_ENUMERATED_new()	(ASN1_ENUMERATED *)\
+		ASN1_STRING_type_new(V_ASN1_ENUMERATED)
+#define M_ASN1_ENUMERATED_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_ENUMERATED_dup(a) (ASN1_ENUMERATED *)ASN1_STRING_dup((ASN1_STRING *)a)
+#define M_ASN1_ENUMERATED_cmp(a,b)	ASN1_STRING_cmp(\
+		(ASN1_STRING *)a,(ASN1_STRING *)b)
+
+#define M_ASN1_OCTET_STRING_new()	(ASN1_OCTET_STRING *)\
+		ASN1_STRING_type_new(V_ASN1_OCTET_STRING)
+#define M_ASN1_OCTET_STRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_OCTET_STRING_dup(a) (ASN1_OCTET_STRING *)\
+		ASN1_STRING_dup((ASN1_STRING *)a)
+#define M_ASN1_OCTET_STRING_cmp(a,b) ASN1_STRING_cmp(\
+		(ASN1_STRING *)a,(ASN1_STRING *)b)
+#define M_ASN1_OCTET_STRING_set(a,b,c)	ASN1_STRING_set((ASN1_STRING *)a,b,c)
+#define M_ASN1_OCTET_STRING_print(a,b)	ASN1_STRING_print(a,(ASN1_STRING *)b)
+#define M_i2d_ASN1_OCTET_STRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,\
+		V_ASN1_UNIVERSAL)
+
+#define B_ASN1_TIME \
+			B_ASN1_UTCTIME | \
+			B_ASN1_GENERALIZEDTIME
+
+#define B_ASN1_PRINTABLE \
+			B_ASN1_PRINTABLESTRING| \
+			B_ASN1_T61STRING| \
+			B_ASN1_IA5STRING| \
+			B_ASN1_BIT_STRING| \
+			B_ASN1_UNIVERSALSTRING|\
+			B_ASN1_BMPSTRING|\
+			B_ASN1_UTF8STRING|\
+			B_ASN1_UNKNOWN
+
+#define B_ASN1_DIRECTORYSTRING \
+			B_ASN1_PRINTABLESTRING| \
+			B_ASN1_TELETEXSTRING|\
+			B_ASN1_BMPSTRING|\
+			B_ASN1_UNIVERSALSTRING|\
+			B_ASN1_UTF8STRING
+
+#define B_ASN1_DISPLAYTEXT \
+			B_ASN1_IA5STRING| \
+			B_ASN1_VISIBLESTRING| \
+			B_ASN1_BMPSTRING|\
+			B_ASN1_UTF8STRING
+
+#define M_ASN1_PRINTABLE_new()	ASN1_STRING_type_new(V_ASN1_T61STRING)
+#define M_ASN1_PRINTABLE_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
+		pp,a->type,V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_PRINTABLE(a,pp,l) \
+		d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
+			B_ASN1_PRINTABLE)
+
+#define M_DIRECTORYSTRING_new() ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING)
+#define M_DIRECTORYSTRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
+						pp,a->type,V_ASN1_UNIVERSAL)
+#define M_d2i_DIRECTORYSTRING(a,pp,l) \
+		d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
+			B_ASN1_DIRECTORYSTRING)
+
+#define M_DISPLAYTEXT_new() ASN1_STRING_type_new(V_ASN1_VISIBLESTRING)
+#define M_DISPLAYTEXT_free(a) ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\
+						pp,a->type,V_ASN1_UNIVERSAL)
+#define M_d2i_DISPLAYTEXT(a,pp,l) \
+		d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \
+			B_ASN1_DISPLAYTEXT)
+
+#define M_ASN1_PRINTABLESTRING_new() (ASN1_PRINTABLESTRING *)\
+		ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING)
+#define M_ASN1_PRINTABLESTRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_PRINTABLESTRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,\
+		V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) \
+		(ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes\
+		((ASN1_STRING **)a,pp,l,B_ASN1_PRINTABLESTRING)
+
+#define M_ASN1_T61STRING_new()	(ASN1_T61STRING *)\
+		ASN1_STRING_type_new(V_ASN1_T61STRING)
+#define M_ASN1_T61STRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_T61STRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_T61STRING,\
+		V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_T61STRING(a,pp,l) \
+		(ASN1_T61STRING *)d2i_ASN1_type_bytes\
+		((ASN1_STRING **)a,pp,l,B_ASN1_T61STRING)
+
+#define M_ASN1_IA5STRING_new()	(ASN1_IA5STRING *)\
+		ASN1_STRING_type_new(V_ASN1_IA5STRING)
+#define M_ASN1_IA5STRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_IA5STRING_dup(a)	\
+			(ASN1_IA5STRING *)ASN1_STRING_dup((ASN1_STRING *)a)
+#define M_i2d_ASN1_IA5STRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_IA5STRING,\
+			V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_IA5STRING(a,pp,l) \
+		(ASN1_IA5STRING *)d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l,\
+			B_ASN1_IA5STRING)
+
+#define M_ASN1_UTCTIME_new()	(ASN1_UTCTIME *)\
+		ASN1_STRING_type_new(V_ASN1_UTCTIME)
+#define M_ASN1_UTCTIME_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_UTCTIME_dup(a) (ASN1_UTCTIME *)ASN1_STRING_dup((ASN1_STRING *)a)
+
+#define M_ASN1_GENERALIZEDTIME_new()	(ASN1_GENERALIZEDTIME *)\
+		ASN1_STRING_type_new(V_ASN1_GENERALIZEDTIME)
+#define M_ASN1_GENERALIZEDTIME_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_GENERALIZEDTIME_dup(a) (ASN1_GENERALIZEDTIME *)ASN1_STRING_dup(\
+	(ASN1_STRING *)a)
+
+#define M_ASN1_TIME_new()	(ASN1_TIME *)\
+		ASN1_STRING_type_new(V_ASN1_UTCTIME)
+#define M_ASN1_TIME_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_ASN1_TIME_dup(a) (ASN1_TIME *)ASN1_STRING_dup((ASN1_STRING *)a)
+
+#define M_ASN1_GENERALSTRING_new()	(ASN1_GENERALSTRING *)\
+		ASN1_STRING_type_new(V_ASN1_GENERALSTRING)
+#define M_ASN1_GENERALSTRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_GENERALSTRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,\
+			V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_GENERALSTRING(a,pp,l) \
+		(ASN1_GENERALSTRING *)d2i_ASN1_type_bytes\
+		((ASN1_STRING **)a,pp,l,B_ASN1_GENERALSTRING)
+
+#define M_ASN1_UNIVERSALSTRING_new()	(ASN1_UNIVERSALSTRING *)\
+		ASN1_STRING_type_new(V_ASN1_UNIVERSALSTRING)
+#define M_ASN1_UNIVERSALSTRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,\
+			V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) \
+		(ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes\
+		((ASN1_STRING **)a,pp,l,B_ASN1_UNIVERSALSTRING)
+
+#define M_ASN1_BMPSTRING_new()	(ASN1_BMPSTRING *)\
+		ASN1_STRING_type_new(V_ASN1_BMPSTRING)
+#define M_ASN1_BMPSTRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_BMPSTRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,\
+			V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_BMPSTRING(a,pp,l) \
+		(ASN1_BMPSTRING *)d2i_ASN1_type_bytes\
+		((ASN1_STRING **)a,pp,l,B_ASN1_BMPSTRING)
+
+#define M_ASN1_VISIBLESTRING_new()	(ASN1_VISIBLESTRING *)\
+		ASN1_STRING_type_new(V_ASN1_VISIBLESTRING)
+#define M_ASN1_VISIBLESTRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_VISIBLESTRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,\
+			V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) \
+		(ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes\
+		((ASN1_STRING **)a,pp,l,B_ASN1_VISIBLESTRING)
+
+#define M_ASN1_UTF8STRING_new()	(ASN1_UTF8STRING *)\
+		ASN1_STRING_type_new(V_ASN1_UTF8STRING)
+#define M_ASN1_UTF8STRING_free(a)	ASN1_STRING_free((ASN1_STRING *)a)
+#define M_i2d_ASN1_UTF8STRING(a,pp) \
+		i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,\
+			V_ASN1_UNIVERSAL)
+#define M_d2i_ASN1_UTF8STRING(a,pp,l) \
+		(ASN1_UTF8STRING *)d2i_ASN1_type_bytes\
+		((ASN1_STRING **)a,pp,l,B_ASN1_UTF8STRING)
+
+  /* for the is_set parameter to i2d_ASN1_SET */
+#define IS_SEQUENCE	0
+#define IS_SET		1
+
+DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE)
+
+int ASN1_TYPE_get(ASN1_TYPE *a);
+void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value);
+
+ASN1_OBJECT *	ASN1_OBJECT_new(void );
+void		ASN1_OBJECT_free(ASN1_OBJECT *a);
+int		i2d_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char **pp);
+ASN1_OBJECT *	c2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp,
+			long length);
+ASN1_OBJECT *	d2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp,
+			long length);
+
+DECLARE_ASN1_ITEM(ASN1_OBJECT)
+
+DECLARE_STACK_OF(ASN1_OBJECT)
+DECLARE_ASN1_SET_OF(ASN1_OBJECT)
+
+ASN1_STRING *	ASN1_STRING_new(void);
+void		ASN1_STRING_free(ASN1_STRING *a);
+ASN1_STRING *	ASN1_STRING_dup(ASN1_STRING *a);
+ASN1_STRING *	ASN1_STRING_type_new(int type );
+int 		ASN1_STRING_cmp(ASN1_STRING *a, ASN1_STRING *b);
+  /* Since this is used to store all sorts of things, via macros, for now, make
+     its data void * */
+int 		ASN1_STRING_set(ASN1_STRING *str, const void *data, int len);
+int ASN1_STRING_length(ASN1_STRING *x);
+void ASN1_STRING_length_set(ASN1_STRING *x, int n);
+int ASN1_STRING_type(ASN1_STRING *x);
+unsigned char * ASN1_STRING_data(ASN1_STRING *x);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING)
+int		i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp);
+ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,const unsigned char **pp,
+			long length);
+int		ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d,
+			int length );
+int		ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value);
+int		ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n);
+
+#ifndef OPENSSL_NO_BIO
+int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs,
+				BIT_STRING_BITNAME *tbl, int indent);
+#endif
+int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl);
+int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value,
+				BIT_STRING_BITNAME *tbl);
+
+int		i2d_ASN1_BOOLEAN(int a,unsigned char **pp);
+int 		d2i_ASN1_BOOLEAN(int *a,const unsigned char **pp,long length);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER)
+int		i2c_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp);
+ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,const unsigned char **pp,
+			long length);
+ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a,const unsigned char **pp,
+			long length);
+ASN1_INTEGER *	ASN1_INTEGER_dup(ASN1_INTEGER *x);
+int ASN1_INTEGER_cmp(ASN1_INTEGER *x, ASN1_INTEGER *y);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED)
+
+int ASN1_UTCTIME_check(ASN1_UTCTIME *a);
+ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s,time_t t);
+int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str);
+int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t);
+#if 0
+time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s);
+#endif
+
+int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *a);
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,time_t t);
+int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING)
+ASN1_OCTET_STRING *	ASN1_OCTET_STRING_dup(ASN1_OCTET_STRING *a);
+int 	ASN1_OCTET_STRING_cmp(ASN1_OCTET_STRING *a, ASN1_OCTET_STRING *b);
+int 	ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, int len);
+
+DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_NULL)
+DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING)
+
+int UTF8_getc(const unsigned char *str, int len, unsigned long *val);
+int UTF8_putc(unsigned char *str, int len, unsigned long value);
+
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE)
+
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING)
+DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT)
+DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING)
+DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME)
+DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME)
+DECLARE_ASN1_FUNCTIONS(ASN1_TIME)
+
+DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF)
+
+ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s,time_t t);
+int ASN1_TIME_check(ASN1_TIME *t);
+ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out);
+
+int i2d_ASN1_SET(STACK *a, unsigned char **pp,
+		 i2d_of_void *i2d, int ex_tag, int ex_class, int is_set);
+STACK *	d2i_ASN1_SET(STACK **a, const unsigned char **pp, long length,
+		     d2i_of_void *d2i, void (*free_func)(void *),
+		     int ex_tag, int ex_class);
+
+#ifndef OPENSSL_NO_BIO
+int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a);
+int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size);
+int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a);
+int a2i_ASN1_ENUMERATED(BIO *bp,ASN1_ENUMERATED *bs,char *buf,int size);
+int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a);
+int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size);
+int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type);
+#endif
+int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a);
+
+int a2d_ASN1_OBJECT(unsigned char *out,int olen, const char *buf, int num);
+ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len,
+	const char *sn, const char *ln);
+
+int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
+long ASN1_INTEGER_get(ASN1_INTEGER *a);
+ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *bn, ASN1_INTEGER *ai);
+BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *ai,BIGNUM *bn);
+
+int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v);
+long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a);
+ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai);
+BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai,BIGNUM *bn);
+
+/* General */
+/* given a string, return the correct type, max is the maximum length */
+int ASN1_PRINTABLE_type(const unsigned char *s, int max);
+
+int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass);
+ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp,
+	long length, int Ptag, int Pclass);
+unsigned long ASN1_tag2bit(int tag);
+/* type is one or more of the B_ASN1_ values. */
+ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a,const unsigned char **pp,
+		long length,int type);
+
+/* PARSING */
+int asn1_Finish(ASN1_CTX *c);
+int asn1_const_Finish(ASN1_const_CTX *c);
+
+/* SPECIALS */
+int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag,
+	int *pclass, long omax);
+int ASN1_check_infinite_end(unsigned char **p,long len);
+int ASN1_const_check_infinite_end(const unsigned char **p,long len);
+void ASN1_put_object(unsigned char **pp, int constructed, int length,
+	int tag, int xclass);
+int ASN1_put_eoc(unsigned char **pp);
+int ASN1_object_size(int constructed, int length, int tag);
+
+/* Used to implement other functions */
+void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, char *x);
+#define ASN1_dup_of(type,i2d,d2i,x) \
+	((type *(*)(I2D_OF(type),D2I_OF(type),type *))openssl_fcast(ASN1_dup))(i2d,d2i,x)
+#define ASN1_dup_of_const(type,i2d,d2i,x) \
+	((type *(*)(I2D_OF_const(type),D2I_OF(type),type *))openssl_fcast(ASN1_dup))(i2d,d2i,x)
+
+void *ASN1_item_dup(const ASN1_ITEM *it, void *x);
+
+#ifndef OPENSSL_NO_FP_API
+void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x);
+#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \
+	((type *(*)(type *(*)(void),D2I_OF(type),FILE *,type **))openssl_fcast(ASN1_d2i_fp))(xnew,d2i,in,x)
+void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x);
+int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x);
+#define ASN1_i2d_fp_of(type,i2d,out,x) \
+	((int (*)(I2D_OF(type),FILE *,type *))openssl_fcast(ASN1_i2d_fp))(i2d,out,x)
+#define ASN1_i2d_fp_of_const(type,i2d,out,x) \
+	((int (*)(I2D_OF_const(type),FILE *,type *))openssl_fcast(ASN1_i2d_fp))(i2d,out,x)
+int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x);
+int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags);
+#endif
+
+int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in);
+
+#ifndef OPENSSL_NO_BIO
+void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x);
+#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \
+	((type *(*)(type *(*)(void),D2I_OF(type),BIO *,type **))openssl_fcast(ASN1_d2i_bio))(xnew,d2i,in,x)
+void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x);
+int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, unsigned char *x);
+#define ASN1_i2d_bio_of(type,i2d,out,x) \
+	((int (*)(I2D_OF(type),BIO *,type *))openssl_fcast(ASN1_i2d_bio))(i2d,out,x)
+#define ASN1_i2d_bio_of_const(type,i2d,out,x) \
+	((int (*)(I2D_OF_const(type),BIO *,const type *))openssl_fcast(ASN1_i2d_bio))(i2d,out,x)
+int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x);
+int ASN1_UTCTIME_print(BIO *fp,ASN1_UTCTIME *a);
+int ASN1_GENERALIZEDTIME_print(BIO *fp,ASN1_GENERALIZEDTIME *a);
+int ASN1_TIME_print(BIO *fp,ASN1_TIME *a);
+int ASN1_STRING_print(BIO *bp,ASN1_STRING *v);
+int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags);
+int ASN1_parse(BIO *bp,const unsigned char *pp,long len,int indent);
+int ASN1_parse_dump(BIO *bp,const unsigned char *pp,long len,int indent,int dump);
+#endif
+const char *ASN1_tag2str(int tag);
+
+/* Used to load and write netscape format cert/key */
+int i2d_ASN1_HEADER(ASN1_HEADER *a,unsigned char **pp);
+ASN1_HEADER *d2i_ASN1_HEADER(ASN1_HEADER **a,const unsigned char **pp, long length);
+ASN1_HEADER *ASN1_HEADER_new(void );
+void ASN1_HEADER_free(ASN1_HEADER *a);
+
+int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s);
+
+/* Not used that much at this point, except for the first two */
+ASN1_METHOD *X509_asn1_meth(void);
+ASN1_METHOD *RSAPrivateKey_asn1_meth(void);
+ASN1_METHOD *ASN1_IA5STRING_asn1_meth(void);
+ASN1_METHOD *ASN1_BIT_STRING_asn1_meth(void);
+
+int ASN1_TYPE_set_octetstring(ASN1_TYPE *a,
+	unsigned char *data, int len);
+int ASN1_TYPE_get_octetstring(ASN1_TYPE *a,
+	unsigned char *data, int max_len);
+int ASN1_TYPE_set_int_octetstring(ASN1_TYPE *a, long num,
+	unsigned char *data, int len);
+int ASN1_TYPE_get_int_octetstring(ASN1_TYPE *a,long *num,
+	unsigned char *data, int max_len);
+
+STACK *ASN1_seq_unpack(const unsigned char *buf, int len,
+		       d2i_of_void *d2i, void (*free_func)(void *));
+unsigned char *ASN1_seq_pack(STACK *safes, i2d_of_void *i2d,
+			     unsigned char **buf, int *len );
+void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i);
+void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it);
+ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d,
+			      ASN1_OCTET_STRING **oct);
+#define ASN1_pack_string_of(type,obj,i2d,oct) \
+	((ASN1_STRING *(*)(type *,I2D_OF(type),ASN1_OCTET_STRING **))openssl_fcast(ASN1_pack_string))(obj,i2d,oct)
+ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct);
+
+void ASN1_STRING_set_default_mask(unsigned long mask);
+int ASN1_STRING_set_default_mask_asc(char *p);
+unsigned long ASN1_STRING_get_default_mask(void);
+int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len,
+					int inform, unsigned long mask);
+int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len,
+					int inform, unsigned long mask, 
+					long minsize, long maxsize);
+
+ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, 
+		const unsigned char *in, int inlen, int inform, int nid);
+ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid);
+int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long);
+void ASN1_STRING_TABLE_cleanup(void);
+
+/* ASN1 template functions */
+
+/* Old API compatible functions */
+ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it);
+void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it);
+ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it);
+int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
+int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it);
+
+void ASN1_add_oid_module(void);
+
+ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf);
+ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf);
+	
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_ASN1_strings(void);
+
+/* Error codes for the ASN1 functions. */
+
+/* Function codes. */
+#define ASN1_F_A2D_ASN1_OBJECT				 100
+#define ASN1_F_A2I_ASN1_ENUMERATED			 101
+#define ASN1_F_A2I_ASN1_INTEGER				 102
+#define ASN1_F_A2I_ASN1_STRING				 103
+#define ASN1_F_APPEND_EXP				 176
+#define ASN1_F_ASN1_BIT_STRING_SET_BIT			 183
+#define ASN1_F_ASN1_CB					 177
+#define ASN1_F_ASN1_CHECK_TLEN				 104
+#define ASN1_F_ASN1_COLLATE_PRIMITIVE			 105
+#define ASN1_F_ASN1_COLLECT				 106
+#define ASN1_F_ASN1_D2I_EX_PRIMITIVE			 108
+#define ASN1_F_ASN1_D2I_FP				 109
+#define ASN1_F_ASN1_D2I_READ_BIO			 107
+#define ASN1_F_ASN1_DIGEST				 184
+#define ASN1_F_ASN1_DO_ADB				 110
+#define ASN1_F_ASN1_DUP					 111
+#define ASN1_F_ASN1_ENUMERATED_SET			 112
+#define ASN1_F_ASN1_ENUMERATED_TO_BN			 113
+#define ASN1_F_ASN1_EX_C2I				 204
+#define ASN1_F_ASN1_FIND_END				 190
+#define ASN1_F_ASN1_GENERALIZEDTIME_SET			 185
+#define ASN1_F_ASN1_GENERATE_V3				 178
+#define ASN1_F_ASN1_GET_OBJECT				 114
+#define ASN1_F_ASN1_HEADER_NEW				 115
+#define ASN1_F_ASN1_I2D_BIO				 116
+#define ASN1_F_ASN1_I2D_FP				 117
+#define ASN1_F_ASN1_INTEGER_SET				 118
+#define ASN1_F_ASN1_INTEGER_TO_BN			 119
+#define ASN1_F_ASN1_ITEM_D2I_FP				 190
+#define ASN1_F_ASN1_ITEM_DUP				 191
+#define ASN1_F_ASN1_ITEM_EX_COMBINE_NEW			 121
+#define ASN1_F_ASN1_ITEM_EX_D2I				 120
+#define ASN1_F_ASN1_ITEM_I2D_BIO			 192
+#define ASN1_F_ASN1_ITEM_I2D_FP				 193
+#define ASN1_F_ASN1_ITEM_PACK				 198
+#define ASN1_F_ASN1_ITEM_SIGN				 195
+#define ASN1_F_ASN1_ITEM_UNPACK				 199
+#define ASN1_F_ASN1_ITEM_VERIFY				 197
+#define ASN1_F_ASN1_MBSTRING_NCOPY			 122
+#define ASN1_F_ASN1_OBJECT_NEW				 123
+#define ASN1_F_ASN1_PACK_STRING				 124
+#define ASN1_F_ASN1_PKCS5_PBE_SET			 125
+#define ASN1_F_ASN1_SEQ_PACK				 126
+#define ASN1_F_ASN1_SEQ_UNPACK				 127
+#define ASN1_F_ASN1_SIGN				 128
+#define ASN1_F_ASN1_STR2TYPE				 179
+#define ASN1_F_ASN1_STRING_SET				 186
+#define ASN1_F_ASN1_STRING_TABLE_ADD			 129
+#define ASN1_F_ASN1_STRING_TYPE_NEW			 130
+#define ASN1_F_ASN1_TEMPLATE_EX_D2I			 132
+#define ASN1_F_ASN1_TEMPLATE_NEW			 133
+#define ASN1_F_ASN1_TEMPLATE_NOEXP_D2I			 131
+#define ASN1_F_ASN1_TIME_SET				 175
+#define ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING		 134
+#define ASN1_F_ASN1_TYPE_GET_OCTETSTRING		 135
+#define ASN1_F_ASN1_UNPACK_STRING			 136
+#define ASN1_F_ASN1_UTCTIME_SET				 187
+#define ASN1_F_ASN1_VERIFY				 137
+#define ASN1_F_BITSTR_CB				 180
+#define ASN1_F_BN_TO_ASN1_ENUMERATED			 138
+#define ASN1_F_BN_TO_ASN1_INTEGER			 139
+#define ASN1_F_C2I_ASN1_BIT_STRING			 189
+#define ASN1_F_C2I_ASN1_INTEGER				 194
+#define ASN1_F_C2I_ASN1_OBJECT				 196
+#define ASN1_F_COLLECT_DATA				 140
+#define ASN1_F_D2I_ASN1_BIT_STRING			 141
+#define ASN1_F_D2I_ASN1_BOOLEAN				 142
+#define ASN1_F_D2I_ASN1_BYTES				 143
+#define ASN1_F_D2I_ASN1_GENERALIZEDTIME			 144
+#define ASN1_F_D2I_ASN1_HEADER				 145
+#define ASN1_F_D2I_ASN1_INTEGER				 146
+#define ASN1_F_D2I_ASN1_OBJECT				 147
+#define ASN1_F_D2I_ASN1_SET				 148
+#define ASN1_F_D2I_ASN1_TYPE_BYTES			 149
+#define ASN1_F_D2I_ASN1_UINTEGER			 150
+#define ASN1_F_D2I_ASN1_UTCTIME				 151
+#define ASN1_F_D2I_NETSCAPE_RSA				 152
+#define ASN1_F_D2I_NETSCAPE_RSA_2			 153
+#define ASN1_F_D2I_PRIVATEKEY				 154
+#define ASN1_F_D2I_PUBLICKEY				 155
+#define ASN1_F_D2I_RSA_NET				 200
+#define ASN1_F_D2I_RSA_NET_2				 201
+#define ASN1_F_D2I_X509					 156
+#define ASN1_F_D2I_X509_CINF				 157
+#define ASN1_F_D2I_X509_PKEY				 159
+#define ASN1_F_I2D_ASN1_SET				 188
+#define ASN1_F_I2D_ASN1_TIME				 160
+#define ASN1_F_I2D_DSA_PUBKEY				 161
+#define ASN1_F_I2D_EC_PUBKEY				 181
+#define ASN1_F_I2D_PRIVATEKEY				 163
+#define ASN1_F_I2D_PUBLICKEY				 164
+#define ASN1_F_I2D_RSA_NET				 162
+#define ASN1_F_I2D_RSA_PUBKEY				 165
+#define ASN1_F_LONG_C2I					 166
+#define ASN1_F_OID_MODULE_INIT				 174
+#define ASN1_F_PARSE_TAGGING				 182
+#define ASN1_F_PKCS5_PBE2_SET				 167
+#define ASN1_F_PKCS5_PBE_SET				 202
+#define ASN1_F_X509_CINF_NEW				 168
+#define ASN1_F_X509_CRL_ADD0_REVOKED			 169
+#define ASN1_F_X509_INFO_NEW				 170
+#define ASN1_F_X509_NAME_ENCODE				 203
+#define ASN1_F_X509_NAME_EX_D2I				 158
+#define ASN1_F_X509_NAME_EX_NEW				 171
+#define ASN1_F_X509_NEW					 172
+#define ASN1_F_X509_PKEY_NEW				 173
+
+/* Reason codes. */
+#define ASN1_R_ADDING_OBJECT				 171
+#define ASN1_R_AUX_ERROR				 100
+#define ASN1_R_BAD_CLASS				 101
+#define ASN1_R_BAD_OBJECT_HEADER			 102
+#define ASN1_R_BAD_PASSWORD_READ			 103
+#define ASN1_R_BAD_TAG					 104
+#define ASN1_R_BN_LIB					 105
+#define ASN1_R_BOOLEAN_IS_WRONG_LENGTH			 106
+#define ASN1_R_BUFFER_TOO_SMALL				 107
+#define ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER		 108
+#define ASN1_R_DATA_IS_WRONG				 109
+#define ASN1_R_DECODE_ERROR				 110
+#define ASN1_R_DECODING_ERROR				 111
+#define ASN1_R_DEPTH_EXCEEDED				 174
+#define ASN1_R_ENCODE_ERROR				 112
+#define ASN1_R_ERROR_GETTING_TIME			 173
+#define ASN1_R_ERROR_LOADING_SECTION			 172
+#define ASN1_R_ERROR_PARSING_SET_ELEMENT		 113
+#define ASN1_R_ERROR_SETTING_CIPHER_PARAMS		 114
+#define ASN1_R_EXPECTING_AN_INTEGER			 115
+#define ASN1_R_EXPECTING_AN_OBJECT			 116
+#define ASN1_R_EXPECTING_A_BOOLEAN			 117
+#define ASN1_R_EXPECTING_A_TIME				 118
+#define ASN1_R_EXPLICIT_LENGTH_MISMATCH			 119
+#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED		 120
+#define ASN1_R_FIELD_MISSING				 121
+#define ASN1_R_FIRST_NUM_TOO_LARGE			 122
+#define ASN1_R_HEADER_TOO_LONG				 123
+#define ASN1_R_ILLEGAL_BITSTRING_FORMAT			 175
+#define ASN1_R_ILLEGAL_BOOLEAN				 176
+#define ASN1_R_ILLEGAL_CHARACTERS			 124
+#define ASN1_R_ILLEGAL_FORMAT				 177
+#define ASN1_R_ILLEGAL_HEX				 178
+#define ASN1_R_ILLEGAL_IMPLICIT_TAG			 179
+#define ASN1_R_ILLEGAL_INTEGER				 180
+#define ASN1_R_ILLEGAL_NESTED_TAGGING			 181
+#define ASN1_R_ILLEGAL_NULL				 125
+#define ASN1_R_ILLEGAL_NULL_VALUE			 182
+#define ASN1_R_ILLEGAL_OBJECT				 183
+#define ASN1_R_ILLEGAL_OPTIONAL_ANY			 126
+#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE		 170
+#define ASN1_R_ILLEGAL_TAGGED_ANY			 127
+#define ASN1_R_ILLEGAL_TIME_VALUE			 184
+#define ASN1_R_INTEGER_NOT_ASCII_FORMAT			 185
+#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG		 128
+#define ASN1_R_INVALID_BMPSTRING_LENGTH			 129
+#define ASN1_R_INVALID_DIGIT				 130
+#define ASN1_R_INVALID_MODIFIER				 186
+#define ASN1_R_INVALID_NUMBER				 187
+#define ASN1_R_INVALID_SEPARATOR			 131
+#define ASN1_R_INVALID_TIME_FORMAT			 132
+#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH		 133
+#define ASN1_R_INVALID_UTF8STRING			 134
+#define ASN1_R_IV_TOO_LARGE				 135
+#define ASN1_R_LENGTH_ERROR				 136
+#define ASN1_R_LIST_ERROR				 188
+#define ASN1_R_MISSING_EOC				 137
+#define ASN1_R_MISSING_SECOND_NUMBER			 138
+#define ASN1_R_MISSING_VALUE				 189
+#define ASN1_R_MSTRING_NOT_UNIVERSAL			 139
+#define ASN1_R_MSTRING_WRONG_TAG			 140
+#define ASN1_R_NESTED_ASN1_STRING			 197
+#define ASN1_R_NON_HEX_CHARACTERS			 141
+#define ASN1_R_NOT_ASCII_FORMAT				 190
+#define ASN1_R_NOT_ENOUGH_DATA				 142
+#define ASN1_R_NO_MATCHING_CHOICE_TYPE			 143
+#define ASN1_R_NULL_IS_WRONG_LENGTH			 144
+#define ASN1_R_OBJECT_NOT_ASCII_FORMAT			 191
+#define ASN1_R_ODD_NUMBER_OF_CHARS			 145
+#define ASN1_R_PRIVATE_KEY_HEADER_MISSING		 146
+#define ASN1_R_SECOND_NUMBER_TOO_LARGE			 147
+#define ASN1_R_SEQUENCE_LENGTH_MISMATCH			 148
+#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED			 149
+#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG		 192
+#define ASN1_R_SHORT_LINE				 150
+#define ASN1_R_STRING_TOO_LONG				 151
+#define ASN1_R_STRING_TOO_SHORT				 152
+#define ASN1_R_TAG_VALUE_TOO_HIGH			 153
+#define ASN1_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 154
+#define ASN1_R_TIME_NOT_ASCII_FORMAT			 193
+#define ASN1_R_TOO_LONG					 155
+#define ASN1_R_TYPE_NOT_CONSTRUCTED			 156
+#define ASN1_R_UNABLE_TO_DECODE_RSA_KEY			 157
+#define ASN1_R_UNABLE_TO_DECODE_RSA_PRIVATE_KEY		 158
+#define ASN1_R_UNEXPECTED_EOC				 159
+#define ASN1_R_UNKNOWN_FORMAT				 160
+#define ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM		 161
+#define ASN1_R_UNKNOWN_OBJECT_TYPE			 162
+#define ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE			 163
+#define ASN1_R_UNKNOWN_TAG				 194
+#define ASN1_R_UNKOWN_FORMAT				 195
+#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE		 164
+#define ASN1_R_UNSUPPORTED_CIPHER			 165
+#define ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM		 166
+#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE		 167
+#define ASN1_R_UNSUPPORTED_TYPE				 196
+#define ASN1_R_WRONG_TAG				 168
+#define ASN1_R_WRONG_TYPE				 169
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1_mac.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1_mac.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1_mac.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,571 @@
+/* crypto/asn1/asn1_mac.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_ASN1_MAC_H
+#define HEADER_ASN1_MAC_H
+
+#include <openssl/asn1.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifndef ASN1_MAC_ERR_LIB
+#define ASN1_MAC_ERR_LIB	ERR_LIB_ASN1
+#endif 
+
+#define ASN1_MAC_H_err(f,r,line) \
+	ERR_PUT_error(ASN1_MAC_ERR_LIB,(f),(r),__FILE__,(line))
+
+#define M_ASN1_D2I_vars(a,type,func) \
+	ASN1_const_CTX c; \
+	type ret=NULL; \
+	\
+	c.pp=(const unsigned char **)pp; \
+	c.q= *(const unsigned char **)pp; \
+	c.error=ERR_R_NESTED_ASN1_ERROR; \
+	if ((a == NULL) || ((*a) == NULL)) \
+		{ if ((ret=(type)func()) == NULL) \
+			{ c.line=__LINE__; goto err; } } \
+	else	ret=(*a);
+
+#define M_ASN1_D2I_Init() \
+	c.p= *(const unsigned char **)pp; \
+	c.max=(length == 0)?0:(c.p+length);
+
+#define M_ASN1_D2I_Finish_2(a) \
+	if (!asn1_const_Finish(&c)) \
+		{ c.line=__LINE__; goto err; } \
+	*(const unsigned char **)pp=c.p; \
+	if (a != NULL) (*a)=ret; \
+	return(ret);
+
+#define M_ASN1_D2I_Finish(a,func,e) \
+	M_ASN1_D2I_Finish_2(a); \
+err:\
+	ASN1_MAC_H_err((e),c.error,c.line); \
+	asn1_add_error(*(const unsigned char **)pp,(int)(c.q- *pp)); \
+	if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \
+	return(NULL)
+
+#define M_ASN1_D2I_start_sequence() \
+	if (!asn1_GetSequence(&c,&length)) \
+		{ c.line=__LINE__; goto err; }
+/* Begin reading ASN1 without a surrounding sequence */
+#define M_ASN1_D2I_begin() \
+	c.slen = length;
+
+/* End reading ASN1 with no check on length */
+#define M_ASN1_D2I_Finish_nolen(a, func, e) \
+	*pp=c.p; \
+	if (a != NULL) (*a)=ret; \
+	return(ret); \
+err:\
+	ASN1_MAC_H_err((e),c.error,c.line); \
+	asn1_add_error(*pp,(int)(c.q- *pp)); \
+	if ((ret != NULL) && ((a == NULL) || (*a != ret))) func(ret); \
+	return(NULL)
+
+#define M_ASN1_D2I_end_sequence() \
+	(((c.inf&1) == 0)?(c.slen <= 0): \
+		(c.eos=ASN1_const_check_infinite_end(&c.p,c.slen)))
+
+/* Don't use this with d2i_ASN1_BOOLEAN() */
+#define M_ASN1_D2I_get(b, func) \
+	c.q=c.p; \
+	if (func(&(b),&c.p,c.slen) == NULL) \
+		{c.line=__LINE__; goto err; } \
+	c.slen-=(c.p-c.q);
+
+/* Don't use this with d2i_ASN1_BOOLEAN() */
+#define M_ASN1_D2I_get_x(type,b,func) \
+	c.q=c.p; \
+	if (((D2I_OF(type))func)(&(b),&c.p,c.slen) == NULL) \
+		{c.line=__LINE__; goto err; } \
+	c.slen-=(c.p-c.q);
+
+/* use this instead () */
+#define M_ASN1_D2I_get_int(b,func) \
+	c.q=c.p; \
+	if (func(&(b),&c.p,c.slen) < 0) \
+		{c.line=__LINE__; goto err; } \
+	c.slen-=(c.p-c.q);
+
+#define M_ASN1_D2I_get_opt(b,func,type) \
+	if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) \
+		== (V_ASN1_UNIVERSAL|(type)))) \
+		{ \
+		M_ASN1_D2I_get(b,func); \
+		}
+
+#define M_ASN1_D2I_get_imp(b,func, type) \
+	M_ASN1_next=(_tmp& V_ASN1_CONSTRUCTED)|type; \
+	c.q=c.p; \
+	if (func(&(b),&c.p,c.slen) == NULL) \
+		{c.line=__LINE__; M_ASN1_next_prev = _tmp; goto err; } \
+	c.slen-=(c.p-c.q);\
+	M_ASN1_next_prev=_tmp;
+
+#define M_ASN1_D2I_get_IMP_opt(b,func,tag,type) \
+	if ((c.slen != 0) && ((M_ASN1_next & (~V_ASN1_CONSTRUCTED)) == \
+		(V_ASN1_CONTEXT_SPECIFIC|(tag)))) \
+		{ \
+		unsigned char _tmp = M_ASN1_next; \
+		M_ASN1_D2I_get_imp(b,func, type);\
+		}
+
+#define M_ASN1_D2I_get_set(r,func,free_func) \
+		M_ASN1_D2I_get_imp_set(r,func,free_func, \
+			V_ASN1_SET,V_ASN1_UNIVERSAL);
+
+#define M_ASN1_D2I_get_set_type(type,r,func,free_func) \
+		M_ASN1_D2I_get_imp_set_type(type,r,func,free_func, \
+			V_ASN1_SET,V_ASN1_UNIVERSAL);
+
+#define M_ASN1_D2I_get_set_opt(r,func,free_func) \
+	if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
+		V_ASN1_CONSTRUCTED|V_ASN1_SET)))\
+		{ M_ASN1_D2I_get_set(r,func,free_func); }
+
+#define M_ASN1_D2I_get_set_opt_type(type,r,func,free_func) \
+	if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
+		V_ASN1_CONSTRUCTED|V_ASN1_SET)))\
+		{ M_ASN1_D2I_get_set_type(type,r,func,free_func); }
+
+#define M_ASN1_I2D_len_SET_opt(a,f) \
+	if ((a != NULL) && (sk_num(a) != 0)) \
+		M_ASN1_I2D_len_SET(a,f);
+
+#define M_ASN1_I2D_put_SET_opt(a,f) \
+	if ((a != NULL) && (sk_num(a) != 0)) \
+		M_ASN1_I2D_put_SET(a,f);
+
+#define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \
+	if ((a != NULL) && (sk_num(a) != 0)) \
+		M_ASN1_I2D_put_SEQUENCE(a,f);
+
+#define M_ASN1_I2D_put_SEQUENCE_opt_type(type,a,f) \
+	if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+		M_ASN1_I2D_put_SEQUENCE_type(type,a,f);
+
+#define M_ASN1_D2I_get_IMP_set_opt(b,func,free_func,tag) \
+	if ((c.slen != 0) && \
+		(M_ASN1_next == \
+		(V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\
+		{ \
+		M_ASN1_D2I_get_imp_set(b,func,free_func,\
+			tag,V_ASN1_CONTEXT_SPECIFIC); \
+		}
+
+#define M_ASN1_D2I_get_IMP_set_opt_type(type,b,func,free_func,tag) \
+	if ((c.slen != 0) && \
+		(M_ASN1_next == \
+		(V_ASN1_CONTEXT_SPECIFIC|V_ASN1_CONSTRUCTED|(tag))))\
+		{ \
+		M_ASN1_D2I_get_imp_set_type(type,b,func,free_func,\
+			tag,V_ASN1_CONTEXT_SPECIFIC); \
+		}
+
+#define M_ASN1_D2I_get_seq(r,func,free_func) \
+		M_ASN1_D2I_get_imp_set(r,func,free_func,\
+			V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL);
+
+#define M_ASN1_D2I_get_seq_type(type,r,func,free_func) \
+		M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\
+					    V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL)
+
+#define M_ASN1_D2I_get_seq_opt(r,func,free_func) \
+	if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
+		V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\
+		{ M_ASN1_D2I_get_seq(r,func,free_func); }
+
+#define M_ASN1_D2I_get_seq_opt_type(type,r,func,free_func) \
+	if ((c.slen != 0) && (M_ASN1_next == (V_ASN1_UNIVERSAL| \
+		V_ASN1_CONSTRUCTED|V_ASN1_SEQUENCE)))\
+		{ M_ASN1_D2I_get_seq_type(type,r,func,free_func); }
+
+#define M_ASN1_D2I_get_IMP_set(r,func,free_func,x) \
+		M_ASN1_D2I_get_imp_set(r,func,free_func,\
+			x,V_ASN1_CONTEXT_SPECIFIC);
+
+#define M_ASN1_D2I_get_IMP_set_type(type,r,func,free_func,x) \
+		M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,\
+			x,V_ASN1_CONTEXT_SPECIFIC);
+
+#define M_ASN1_D2I_get_imp_set(r,func,free_func,a,b) \
+	c.q=c.p; \
+	if (d2i_ASN1_SET(&(r),&c.p,c.slen,(char *(*)())func,\
+		(void (*)())free_func,a,b) == NULL) \
+		{ c.line=__LINE__; goto err; } \
+	c.slen-=(c.p-c.q);
+
+#define M_ASN1_D2I_get_imp_set_type(type,r,func,free_func,a,b) \
+	c.q=c.p; \
+	if (d2i_ASN1_SET_OF_##type(&(r),&c.p,c.slen,func,\
+				   free_func,a,b) == NULL) \
+		{ c.line=__LINE__; goto err; } \
+	c.slen-=(c.p-c.q);
+
+#define M_ASN1_D2I_get_set_strings(r,func,a,b) \
+	c.q=c.p; \
+	if (d2i_ASN1_STRING_SET(&(r),&c.p,c.slen,a,b) == NULL) \
+		{ c.line=__LINE__; goto err; } \
+	c.slen-=(c.p-c.q);
+
+#define M_ASN1_D2I_get_EXP_opt(r,func,tag) \
+	if ((c.slen != 0L) && (M_ASN1_next == \
+		(V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
+		{ \
+		int Tinf,Ttag,Tclass; \
+		long Tlen; \
+		\
+		c.q=c.p; \
+		Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
+		if (Tinf & 0x80) \
+			{ c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
+			c.line=__LINE__; goto err; } \
+		if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
+					Tlen = c.slen - (c.p - c.q) - 2; \
+		if (func(&(r),&c.p,Tlen) == NULL) \
+			{ c.line=__LINE__; goto err; } \
+		if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
+			Tlen = c.slen - (c.p - c.q); \
+			if(!ASN1_const_check_infinite_end(&c.p, Tlen)) \
+				{ c.error=ERR_R_MISSING_ASN1_EOS; \
+				c.line=__LINE__; goto err; } \
+		}\
+		c.slen-=(c.p-c.q); \
+		}
+
+#define M_ASN1_D2I_get_EXP_set_opt(r,func,free_func,tag,b) \
+	if ((c.slen != 0) && (M_ASN1_next == \
+		(V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
+		{ \
+		int Tinf,Ttag,Tclass; \
+		long Tlen; \
+		\
+		c.q=c.p; \
+		Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
+		if (Tinf & 0x80) \
+			{ c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
+			c.line=__LINE__; goto err; } \
+		if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
+					Tlen = c.slen - (c.p - c.q) - 2; \
+		if (d2i_ASN1_SET(&(r),&c.p,Tlen,(char *(*)())func, \
+			(void (*)())free_func, \
+			b,V_ASN1_UNIVERSAL) == NULL) \
+			{ c.line=__LINE__; goto err; } \
+		if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
+			Tlen = c.slen - (c.p - c.q); \
+			if(!ASN1_check_infinite_end(&c.p, Tlen)) \
+				{ c.error=ERR_R_MISSING_ASN1_EOS; \
+				c.line=__LINE__; goto err; } \
+		}\
+		c.slen-=(c.p-c.q); \
+		}
+
+#define M_ASN1_D2I_get_EXP_set_opt_type(type,r,func,free_func,tag,b) \
+	if ((c.slen != 0) && (M_ASN1_next == \
+		(V_ASN1_CONSTRUCTED|V_ASN1_CONTEXT_SPECIFIC|tag))) \
+		{ \
+		int Tinf,Ttag,Tclass; \
+		long Tlen; \
+		\
+		c.q=c.p; \
+		Tinf=ASN1_get_object(&c.p,&Tlen,&Ttag,&Tclass,c.slen); \
+		if (Tinf & 0x80) \
+			{ c.error=ERR_R_BAD_ASN1_OBJECT_HEADER; \
+			c.line=__LINE__; goto err; } \
+		if (Tinf == (V_ASN1_CONSTRUCTED+1)) \
+					Tlen = c.slen - (c.p - c.q) - 2; \
+		if (d2i_ASN1_SET_OF_##type(&(r),&c.p,Tlen,func, \
+			free_func,b,V_ASN1_UNIVERSAL) == NULL) \
+			{ c.line=__LINE__; goto err; } \
+		if (Tinf == (V_ASN1_CONSTRUCTED+1)) { \
+			Tlen = c.slen - (c.p - c.q); \
+			if(!ASN1_check_infinite_end(&c.p, Tlen)) \
+				{ c.error=ERR_R_MISSING_ASN1_EOS; \
+				c.line=__LINE__; goto err; } \
+		}\
+		c.slen-=(c.p-c.q); \
+		}
+
+/* New macros */
+#define M_ASN1_New_Malloc(ret,type) \
+	if ((ret=(type *)OPENSSL_malloc(sizeof(type))) == NULL) \
+		{ c.line=__LINE__; goto err2; }
+
+#define M_ASN1_New(arg,func) \
+	if (((arg)=func()) == NULL) return(NULL)
+
+#define M_ASN1_New_Error(a) \
+/*	err:	ASN1_MAC_H_err((a),ERR_R_NESTED_ASN1_ERROR,c.line); \
+		return(NULL);*/ \
+	err2:	ASN1_MAC_H_err((a),ERR_R_MALLOC_FAILURE,c.line); \
+		return(NULL)
+
+
+/* BIG UGLY WARNING!  This is so damn ugly I wanna puke.  Unfortunately,
+   some macros that use ASN1_const_CTX still insist on writing in the input
+   stream.  ARGH!  ARGH!  ARGH!  Let's get rid of this macro package.
+   Please?						-- Richard Levitte */
+#define M_ASN1_next		(*((unsigned char *)(c.p)))
+#define M_ASN1_next_prev	(*((unsigned char *)(c.q)))
+
+/*************************************************/
+
+#define M_ASN1_I2D_vars(a)	int r=0,ret=0; \
+				unsigned char *p; \
+				if (a == NULL) return(0)
+
+/* Length Macros */
+#define M_ASN1_I2D_len(a,f)	ret+=f(a,NULL)
+#define M_ASN1_I2D_len_IMP_opt(a,f)	if (a != NULL) M_ASN1_I2D_len(a,f)
+
+#define M_ASN1_I2D_len_SET(a,f) \
+		ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET);
+
+#define M_ASN1_I2D_len_SET_type(type,a,f) \
+		ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SET, \
+					    V_ASN1_UNIVERSAL,IS_SET);
+
+#define M_ASN1_I2D_len_SEQUENCE(a,f) \
+		ret+=i2d_ASN1_SET(a,NULL,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \
+				  IS_SEQUENCE);
+
+#define M_ASN1_I2D_len_SEQUENCE_type(type,a,f) \
+		ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,V_ASN1_SEQUENCE, \
+					    V_ASN1_UNIVERSAL,IS_SEQUENCE)
+
+#define M_ASN1_I2D_len_SEQUENCE_opt(a,f) \
+		if ((a != NULL) && (sk_num(a) != 0)) \
+			M_ASN1_I2D_len_SEQUENCE(a,f);
+
+#define M_ASN1_I2D_len_SEQUENCE_opt_type(type,a,f) \
+		if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+			M_ASN1_I2D_len_SEQUENCE_type(type,a,f);
+
+#define M_ASN1_I2D_len_IMP_SET(a,f,x) \
+		ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET);
+
+#define M_ASN1_I2D_len_IMP_SET_type(type,a,f,x) \
+		ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
+					    V_ASN1_CONTEXT_SPECIFIC,IS_SET);
+
+#define M_ASN1_I2D_len_IMP_SET_opt(a,f,x) \
+		if ((a != NULL) && (sk_num(a) != 0)) \
+			ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+					  IS_SET);
+
+#define M_ASN1_I2D_len_IMP_SET_opt_type(type,a,f,x) \
+		if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+			ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
+					       V_ASN1_CONTEXT_SPECIFIC,IS_SET);
+
+#define M_ASN1_I2D_len_IMP_SEQUENCE(a,f,x) \
+		ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+				  IS_SEQUENCE);
+
+#define M_ASN1_I2D_len_IMP_SEQUENCE_opt(a,f,x) \
+		if ((a != NULL) && (sk_num(a) != 0)) \
+			ret+=i2d_ASN1_SET(a,NULL,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+					  IS_SEQUENCE);
+
+#define M_ASN1_I2D_len_IMP_SEQUENCE_opt_type(type,a,f,x) \
+		if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+			ret+=i2d_ASN1_SET_OF_##type(a,NULL,f,x, \
+						    V_ASN1_CONTEXT_SPECIFIC, \
+						    IS_SEQUENCE);
+
+#define M_ASN1_I2D_len_EXP_opt(a,f,mtag,v) \
+		if (a != NULL)\
+			{ \
+			v=f(a,NULL); \
+			ret+=ASN1_object_size(1,v,mtag); \
+			}
+
+#define M_ASN1_I2D_len_EXP_SET_opt(a,f,mtag,tag,v) \
+		if ((a != NULL) && (sk_num(a) != 0))\
+			{ \
+			v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL,IS_SET); \
+			ret+=ASN1_object_size(1,v,mtag); \
+			}
+
+#define M_ASN1_I2D_len_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \
+		if ((a != NULL) && (sk_num(a) != 0))\
+			{ \
+			v=i2d_ASN1_SET(a,NULL,f,tag,V_ASN1_UNIVERSAL, \
+				       IS_SEQUENCE); \
+			ret+=ASN1_object_size(1,v,mtag); \
+			}
+
+#define M_ASN1_I2D_len_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \
+		if ((a != NULL) && (sk_##type##_num(a) != 0))\
+			{ \
+			v=i2d_ASN1_SET_OF_##type(a,NULL,f,tag, \
+						 V_ASN1_UNIVERSAL, \
+						 IS_SEQUENCE); \
+			ret+=ASN1_object_size(1,v,mtag); \
+			}
+
+/* Put Macros */
+#define M_ASN1_I2D_put(a,f)	f(a,&p)
+
+#define M_ASN1_I2D_put_IMP_opt(a,f,t)	\
+		if (a != NULL) \
+			{ \
+			unsigned char *q=p; \
+			f(a,&p); \
+			*q=(V_ASN1_CONTEXT_SPECIFIC|t|(*q&V_ASN1_CONSTRUCTED));\
+			}
+
+#define M_ASN1_I2D_put_SET(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SET,\
+			V_ASN1_UNIVERSAL,IS_SET)
+#define M_ASN1_I2D_put_SET_type(type,a,f) \
+     i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SET,V_ASN1_UNIVERSAL,IS_SET)
+#define M_ASN1_I2D_put_IMP_SET(a,f,x) i2d_ASN1_SET(a,&p,f,x,\
+			V_ASN1_CONTEXT_SPECIFIC,IS_SET)
+#define M_ASN1_I2D_put_IMP_SET_type(type,a,f,x) \
+     i2d_ASN1_SET_OF_##type(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC,IS_SET)
+#define M_ASN1_I2D_put_IMP_SEQUENCE(a,f,x) i2d_ASN1_SET(a,&p,f,x,\
+			V_ASN1_CONTEXT_SPECIFIC,IS_SEQUENCE)
+
+#define M_ASN1_I2D_put_SEQUENCE(a,f) i2d_ASN1_SET(a,&p,f,V_ASN1_SEQUENCE,\
+					     V_ASN1_UNIVERSAL,IS_SEQUENCE)
+
+#define M_ASN1_I2D_put_SEQUENCE_type(type,a,f) \
+     i2d_ASN1_SET_OF_##type(a,&p,f,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL, \
+			    IS_SEQUENCE)
+
+#define M_ASN1_I2D_put_SEQUENCE_opt(a,f) \
+		if ((a != NULL) && (sk_num(a) != 0)) \
+			M_ASN1_I2D_put_SEQUENCE(a,f);
+
+#define M_ASN1_I2D_put_IMP_SET_opt(a,f,x) \
+		if ((a != NULL) && (sk_num(a) != 0)) \
+			{ i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+				       IS_SET); }
+
+#define M_ASN1_I2D_put_IMP_SET_opt_type(type,a,f,x) \
+		if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+			{ i2d_ASN1_SET_OF_##type(a,&p,f,x, \
+						 V_ASN1_CONTEXT_SPECIFIC, \
+						 IS_SET); }
+
+#define M_ASN1_I2D_put_IMP_SEQUENCE_opt(a,f,x) \
+		if ((a != NULL) && (sk_num(a) != 0)) \
+			{ i2d_ASN1_SET(a,&p,f,x,V_ASN1_CONTEXT_SPECIFIC, \
+				       IS_SEQUENCE); }
+
+#define M_ASN1_I2D_put_IMP_SEQUENCE_opt_type(type,a,f,x) \
+		if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+			{ i2d_ASN1_SET_OF_##type(a,&p,f,x, \
+						 V_ASN1_CONTEXT_SPECIFIC, \
+						 IS_SEQUENCE); }
+
+#define M_ASN1_I2D_put_EXP_opt(a,f,tag,v) \
+		if (a != NULL) \
+			{ \
+			ASN1_put_object(&p,1,v,tag,V_ASN1_CONTEXT_SPECIFIC); \
+			f(a,&p); \
+			}
+
+#define M_ASN1_I2D_put_EXP_SET_opt(a,f,mtag,tag,v) \
+		if ((a != NULL) && (sk_num(a) != 0)) \
+			{ \
+			ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
+			i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SET); \
+			}
+
+#define M_ASN1_I2D_put_EXP_SEQUENCE_opt(a,f,mtag,tag,v) \
+		if ((a != NULL) && (sk_num(a) != 0)) \
+			{ \
+			ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
+			i2d_ASN1_SET(a,&p,f,tag,V_ASN1_UNIVERSAL,IS_SEQUENCE); \
+			}
+
+#define M_ASN1_I2D_put_EXP_SEQUENCE_opt_type(type,a,f,mtag,tag,v) \
+		if ((a != NULL) && (sk_##type##_num(a) != 0)) \
+			{ \
+			ASN1_put_object(&p,1,v,mtag,V_ASN1_CONTEXT_SPECIFIC); \
+			i2d_ASN1_SET_OF_##type(a,&p,f,tag,V_ASN1_UNIVERSAL, \
+					       IS_SEQUENCE); \
+			}
+
+#define M_ASN1_I2D_seq_total() \
+		r=ASN1_object_size(1,ret,V_ASN1_SEQUENCE); \
+		if (pp == NULL) return(r); \
+		p= *pp; \
+		ASN1_put_object(&p,1,ret,V_ASN1_SEQUENCE,V_ASN1_UNIVERSAL)
+
+#define M_ASN1_I2D_INF_seq_start(tag,ctx) \
+		*(p++)=(V_ASN1_CONSTRUCTED|(tag)|(ctx)); \
+		*(p++)=0x80
+
+#define M_ASN1_I2D_INF_seq_end() *(p++)=0x00; *(p++)=0x00
+
+#define M_ASN1_I2D_finish()	*pp=p; \
+				return(r);
+
+int asn1_GetSequence(ASN1_const_CTX *c, long *length);
+void asn1_add_error(const unsigned char *address,int offset);
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1t.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1t.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/asn1t.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,886 @@
+/* asn1t.h */
+/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#ifndef HEADER_ASN1T_H
+#define HEADER_ASN1T_H
+
+#include <stddef.h>
+#include <openssl/e_os2.h>
+#include <openssl/asn1.h>
+
+#ifdef OPENSSL_BUILD_SHLIBCRYPTO
+# undef OPENSSL_EXTERN
+# define OPENSSL_EXTERN OPENSSL_EXPORT
+#endif
+
+/* ASN1 template defines, structures and functions */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
+
+/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
+#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr))
+
+
+/* Macros for start and end of ASN1_ITEM definition */
+
+#define ASN1_ITEM_start(itname) \
+	OPENSSL_GLOBAL const ASN1_ITEM itname##_it = {
+
+#define ASN1_ITEM_end(itname) \
+		};
+
+#else
+
+/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */
+#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr()))
+
+
+/* Macros for start and end of ASN1_ITEM definition */
+
+#define ASN1_ITEM_start(itname) \
+	const ASN1_ITEM * itname##_it(void) \
+	{ \
+		static const ASN1_ITEM local_it = { \
+
+#define ASN1_ITEM_end(itname) \
+		}; \
+	return &local_it; \
+	}
+
+#endif
+
+
+/* Macros to aid ASN1 template writing */
+
+#define ASN1_ITEM_TEMPLATE(tname) \
+	static const ASN1_TEMPLATE tname##_item_tt 
+
+#define ASN1_ITEM_TEMPLATE_END(tname) \
+	;\
+	ASN1_ITEM_start(tname) \
+		ASN1_ITYPE_PRIMITIVE,\
+		-1,\
+		&tname##_item_tt,\
+		0,\
+		NULL,\
+		0,\
+		#tname \
+	ASN1_ITEM_end(tname)
+
+
+/* This is a ASN1 type which just embeds a template */
+ 
+/* This pair helps declare a SEQUENCE. We can do:
+ *
+ * 	ASN1_SEQUENCE(stname) = {
+ * 		... SEQUENCE components ...
+ * 	} ASN1_SEQUENCE_END(stname)
+ *
+ * 	This will produce an ASN1_ITEM called stname_it
+ *	for a structure called stname.
+ *
+ * 	If you want the same structure but a different
+ *	name then use:
+ *
+ * 	ASN1_SEQUENCE(itname) = {
+ * 		... SEQUENCE components ...
+ * 	} ASN1_SEQUENCE_END_name(stname, itname)
+ *
+ *	This will create an item called itname_it using
+ *	a structure called stname.
+ */
+
+#define ASN1_SEQUENCE(tname) \
+	static const ASN1_TEMPLATE tname##_seq_tt[] 
+
+#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname)
+
+#define ASN1_SEQUENCE_END_name(stname, tname) \
+	;\
+	ASN1_ITEM_start(tname) \
+		ASN1_ITYPE_SEQUENCE,\
+		V_ASN1_SEQUENCE,\
+		tname##_seq_tt,\
+		sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
+		NULL,\
+		sizeof(stname),\
+		#stname \
+	ASN1_ITEM_end(tname)
+
+#define ASN1_NDEF_SEQUENCE(tname) \
+	ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_cb(tname, cb) \
+	static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
+	ASN1_SEQUENCE(tname)
+
+#define ASN1_BROKEN_SEQUENCE(tname) \
+	static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0, 0}; \
+	ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_ref(tname, cb, lck) \
+	static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), lck, cb, 0}; \
+	ASN1_SEQUENCE(tname)
+
+#define ASN1_SEQUENCE_enc(tname, enc, cb) \
+	static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, 0, cb, offsetof(tname, enc)}; \
+	ASN1_SEQUENCE(tname)
+
+#define ASN1_NDEF_SEQUENCE_END(tname) \
+	;\
+	ASN1_ITEM_start(tname) \
+		ASN1_ITYPE_NDEF_SEQUENCE,\
+		V_ASN1_SEQUENCE,\
+		tname##_seq_tt,\
+		sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
+		NULL,\
+		sizeof(tname),\
+		#tname \
+	ASN1_ITEM_end(tname)
+
+#define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname)
+
+#define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
+
+#define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname)
+
+#define ASN1_SEQUENCE_END_ref(stname, tname) \
+	;\
+	ASN1_ITEM_start(tname) \
+		ASN1_ITYPE_SEQUENCE,\
+		V_ASN1_SEQUENCE,\
+		tname##_seq_tt,\
+		sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\
+		&tname##_aux,\
+		sizeof(stname),\
+		#stname \
+	ASN1_ITEM_end(tname)
+
+
+/* This pair helps declare a CHOICE type. We can do:
+ *
+ * 	ASN1_CHOICE(chname) = {
+ * 		... CHOICE options ...
+ * 	ASN1_CHOICE_END(chname)
+ *
+ * 	This will produce an ASN1_ITEM called chname_it
+ *	for a structure called chname. The structure
+ *	definition must look like this:
+ *	typedef struct {
+ *		int type;
+ *		union {
+ *			ASN1_SOMETHING *opt1;
+ *			ASN1_SOMEOTHER *opt2;
+ *		} value;
+ *	} chname;
+ *	
+ *	the name of the selector must be 'type'.
+ * 	to use an alternative selector name use the
+ *      ASN1_CHOICE_END_selector() version.
+ */
+
+#define ASN1_CHOICE(tname) \
+	static const ASN1_TEMPLATE tname##_ch_tt[] 
+
+#define ASN1_CHOICE_cb(tname, cb) \
+	static const ASN1_AUX tname##_aux = {NULL, 0, 0, 0, cb, 0}; \
+	ASN1_CHOICE(tname)
+
+#define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname)
+
+#define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type)
+
+#define ASN1_CHOICE_END_selector(stname, tname, selname) \
+	;\
+	ASN1_ITEM_start(tname) \
+		ASN1_ITYPE_CHOICE,\
+		offsetof(stname,selname) ,\
+		tname##_ch_tt,\
+		sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\
+		NULL,\
+		sizeof(stname),\
+		#stname \
+	ASN1_ITEM_end(tname)
+
+#define ASN1_CHOICE_END_cb(stname, tname, selname) \
+	;\
+	ASN1_ITEM_start(tname) \
+		ASN1_ITYPE_CHOICE,\
+		offsetof(stname,selname) ,\
+		tname##_ch_tt,\
+		sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\
+		&tname##_aux,\
+		sizeof(stname),\
+		#stname \
+	ASN1_ITEM_end(tname)
+
+/* This helps with the template wrapper form of ASN1_ITEM */
+
+#define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \
+	(flags), (tag), 0,\
+	#name, ASN1_ITEM_ref(type) }
+
+/* These help with SEQUENCE or CHOICE components */
+
+/* used to declare other types */
+
+#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \
+	(flags), (tag), offsetof(stname, field),\
+	#field, ASN1_ITEM_ref(type) }
+
+/* used when the structure is combined with the parent */
+
+#define ASN1_EX_COMBINE(flags, tag, type) { \
+	(flags)|ASN1_TFLG_COMBINE, (tag), 0, NULL, ASN1_ITEM_ref(type) }
+
+/* implicit and explicit helper macros */
+
+#define ASN1_IMP_EX(stname, field, type, tag, ex) \
+		ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type)
+
+#define ASN1_EXP_EX(stname, field, type, tag, ex) \
+		ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type)
+
+/* Any defined by macros: the field used is in the table itself */
+
+#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
+#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) }
+#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) }
+#else
+#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, tblname##_adb }
+#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, tblname##_adb }
+#endif
+/* Plain simple type */
+#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type)
+
+/* OPTIONAL simple type */
+#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+
+/* IMPLICIT tagged simple type */
+#define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0)
+
+/* IMPLICIT tagged OPTIONAL simple type */
+#define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
+
+/* Same as above but EXPLICIT */
+
+#define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0)
+#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL)
+
+/* SEQUENCE OF type */
+#define ASN1_SEQUENCE_OF(stname, field, type) \
+		ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type)
+
+/* OPTIONAL SEQUENCE OF */
+#define ASN1_SEQUENCE_OF_OPT(stname, field, type) \
+		ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+
+/* Same as above but for SET OF */
+
+#define ASN1_SET_OF(stname, field, type) \
+		ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type)
+
+#define ASN1_SET_OF_OPT(stname, field, type) \
+		ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type)
+
+/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */
+
+#define ASN1_IMP_SET_OF(stname, field, type, tag) \
+			ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
+
+#define ASN1_EXP_SET_OF(stname, field, type, tag) \
+			ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF)
+
+#define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \
+			ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL)
+
+#define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \
+			ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL)
+
+#define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \
+			ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
+
+#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \
+			ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
+
+#define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \
+			ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF)
+
+#define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \
+			ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL)
+
+/* EXPLICIT OPTIONAL using indefinite length constructed form */
+#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \
+			ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF)
+
+/* Macros for the ASN1_ADB structure */
+
+#define ASN1_ADB(name) \
+	static const ASN1_ADB_TABLE name##_adbtbl[] 
+
+#ifndef OPENSSL_EXPORT_VAR_AS_FUNCTION
+
+#define ASN1_ADB_END(name, flags, field, app_table, def, none) \
+	;\
+	static const ASN1_ADB name##_adb = {\
+		flags,\
+		offsetof(name, field),\
+		app_table,\
+		name##_adbtbl,\
+		sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\
+		def,\
+		none\
+	}
+
+#else
+
+#define ASN1_ADB_END(name, flags, field, app_table, def, none) \
+	;\
+	static const ASN1_ITEM *name##_adb(void) \
+	{ \
+	static const ASN1_ADB internal_adb = \
+		{\
+		flags,\
+		offsetof(name, field),\
+		app_table,\
+		name##_adbtbl,\
+		sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\
+		def,\
+		none\
+		}; \
+		return (const ASN1_ITEM *) &internal_adb; \
+	} \
+	void dummy_function(void)
+
+#endif
+
+#define ADB_ENTRY(val, template) {val, template}
+
+#define ASN1_ADB_TEMPLATE(name) \
+	static const ASN1_TEMPLATE name##_tt 
+
+/* This is the ASN1 template structure that defines
+ * a wrapper round the actual type. It determines the
+ * actual position of the field in the value structure,
+ * various flags such as OPTIONAL and the field name.
+ */
+
+struct ASN1_TEMPLATE_st {
+unsigned long flags;		/* Various flags */
+long tag;			/* tag, not used if no tagging */
+unsigned long offset;		/* Offset of this field in structure */
+#ifndef NO_ASN1_FIELD_NAMES
+const char *field_name;		/* Field name */
+#endif
+ASN1_ITEM_EXP *item;		/* Relevant ASN1_ITEM or ASN1_ADB */
+};
+
+/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */
+
+#define ASN1_TEMPLATE_item(t) (t->item_ptr)
+#define ASN1_TEMPLATE_adb(t) (t->item_ptr)
+
+typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE;
+typedef struct ASN1_ADB_st ASN1_ADB;
+
+struct ASN1_ADB_st {
+	unsigned long flags;	/* Various flags */
+	unsigned long offset;	/* Offset of selector field */
+	STACK_OF(ASN1_ADB_TABLE) **app_items; /* Application defined items */
+	const ASN1_ADB_TABLE *tbl;	/* Table of possible types */
+	long tblcount;		/* Number of entries in tbl */
+	const ASN1_TEMPLATE *default_tt;  /* Type to use if no match */
+	const ASN1_TEMPLATE *null_tt;  /* Type to use if selector is NULL */
+};
+
+struct ASN1_ADB_TABLE_st {
+	long value;		/* NID for an object or value for an int */
+	const ASN1_TEMPLATE tt;		/* item for this value */
+};
+
+/* template flags */
+
+/* Field is optional */
+#define ASN1_TFLG_OPTIONAL	(0x1)
+
+/* Field is a SET OF */
+#define ASN1_TFLG_SET_OF	(0x1 << 1)
+
+/* Field is a SEQUENCE OF */
+#define ASN1_TFLG_SEQUENCE_OF	(0x2 << 1)
+
+/* Special case: this refers to a SET OF that
+ * will be sorted into DER order when encoded *and*
+ * the corresponding STACK will be modified to match
+ * the new order.
+ */
+#define ASN1_TFLG_SET_ORDER	(0x3 << 1)
+
+/* Mask for SET OF or SEQUENCE OF */
+#define ASN1_TFLG_SK_MASK	(0x3 << 1)
+
+/* These flags mean the tag should be taken from the
+ * tag field. If EXPLICIT then the underlying type
+ * is used for the inner tag.
+ */
+
+/* IMPLICIT tagging */
+#define ASN1_TFLG_IMPTAG	(0x1 << 3)
+
+
+/* EXPLICIT tagging, inner tag from underlying type */
+#define ASN1_TFLG_EXPTAG	(0x2 << 3)
+
+#define ASN1_TFLG_TAG_MASK	(0x3 << 3)
+
+/* context specific IMPLICIT */
+#define ASN1_TFLG_IMPLICIT	ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT
+
+/* context specific EXPLICIT */
+#define ASN1_TFLG_EXPLICIT	ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT
+
+/* If tagging is in force these determine the
+ * type of tag to use. Otherwise the tag is
+ * determined by the underlying type. These 
+ * values reflect the actual octet format.
+ */
+
+/* Universal tag */ 
+#define ASN1_TFLG_UNIVERSAL	(0x0<<6)
+/* Application tag */ 
+#define ASN1_TFLG_APPLICATION	(0x1<<6)
+/* Context specific tag */ 
+#define ASN1_TFLG_CONTEXT	(0x2<<6)
+/* Private tag */ 
+#define ASN1_TFLG_PRIVATE	(0x3<<6)
+
+#define ASN1_TFLG_TAG_CLASS	(0x3<<6)
+
+/* These are for ANY DEFINED BY type. In this case
+ * the 'item' field points to an ASN1_ADB structure
+ * which contains a table of values to decode the
+ * relevant type
+ */
+
+#define ASN1_TFLG_ADB_MASK	(0x3<<8)
+
+#define ASN1_TFLG_ADB_OID	(0x1<<8)
+
+#define ASN1_TFLG_ADB_INT	(0x1<<9)
+
+/* This flag means a parent structure is passed
+ * instead of the field: this is useful is a
+ * SEQUENCE is being combined with a CHOICE for
+ * example. Since this means the structure and
+ * item name will differ we need to use the
+ * ASN1_CHOICE_END_name() macro for example.
+ */
+
+#define ASN1_TFLG_COMBINE	(0x1<<10)
+
+/* This flag when present in a SEQUENCE OF, SET OF
+ * or EXPLICIT causes indefinite length constructed
+ * encoding to be used if required.
+ */
+
+#define ASN1_TFLG_NDEF		(0x1<<11)
+
+/* This is the actual ASN1 item itself */
+
+struct ASN1_ITEM_st {
+char itype;			/* The item type, primitive, SEQUENCE, CHOICE or extern */
+long utype;			/* underlying type */
+const ASN1_TEMPLATE *templates;	/* If SEQUENCE or CHOICE this contains the contents */
+long tcount;			/* Number of templates if SEQUENCE or CHOICE */
+const void *funcs;		/* functions that handle this type */
+long size;			/* Structure size (usually)*/
+#ifndef NO_ASN1_FIELD_NAMES
+const char *sname;		/* Structure name */
+#endif
+};
+
+/* These are values for the itype field and
+ * determine how the type is interpreted.
+ *
+ * For PRIMITIVE types the underlying type
+ * determines the behaviour if items is NULL.
+ *
+ * Otherwise templates must contain a single 
+ * template and the type is treated in the
+ * same way as the type specified in the template.
+ *
+ * For SEQUENCE types the templates field points
+ * to the members, the size field is the
+ * structure size.
+ *
+ * For CHOICE types the templates field points
+ * to each possible member (typically a union)
+ * and the 'size' field is the offset of the
+ * selector.
+ *
+ * The 'funcs' field is used for application
+ * specific functions. 
+ *
+ * For COMPAT types the funcs field gives a
+ * set of functions that handle this type, this
+ * supports the old d2i, i2d convention.
+ *
+ * The EXTERN type uses a new style d2i/i2d.
+ * The new style should be used where possible
+ * because it avoids things like the d2i IMPLICIT
+ * hack.
+ *
+ * MSTRING is a multiple string type, it is used
+ * for a CHOICE of character strings where the
+ * actual strings all occupy an ASN1_STRING
+ * structure. In this case the 'utype' field
+ * has a special meaning, it is used as a mask
+ * of acceptable types using the B_ASN1 constants.
+ *
+ * NDEF_SEQUENCE is the same as SEQUENCE except
+ * that it will use indefinite length constructed
+ * encoding if requested.
+ *
+ */
+
+#define ASN1_ITYPE_PRIMITIVE		0x0
+
+#define ASN1_ITYPE_SEQUENCE		0x1
+
+#define ASN1_ITYPE_CHOICE		0x2
+
+#define ASN1_ITYPE_COMPAT		0x3
+
+#define ASN1_ITYPE_EXTERN		0x4
+
+#define ASN1_ITYPE_MSTRING		0x5
+
+#define ASN1_ITYPE_NDEF_SEQUENCE	0x6
+
+/* Cache for ASN1 tag and length, so we
+ * don't keep re-reading it for things
+ * like CHOICE
+ */
+
+struct ASN1_TLC_st{
+	char valid;	/* Values below are valid */
+	int ret;	/* return value */
+	long plen;	/* length */
+	int ptag;	/* class value */
+	int pclass;	/* class value */
+	int hdrlen;	/* header length */
+};
+
+/* Typedefs for ASN1 function pointers */
+
+typedef ASN1_VALUE * ASN1_new_func(void);
+typedef void ASN1_free_func(ASN1_VALUE *a);
+typedef ASN1_VALUE * ASN1_d2i_func(ASN1_VALUE **a, const unsigned char ** in, long length);
+typedef int ASN1_i2d_func(ASN1_VALUE * a, unsigned char **in);
+
+typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it,
+					int tag, int aclass, char opt, ASN1_TLC *ctx);
+
+typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass);
+typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it);
+typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it);
+
+typedef struct ASN1_COMPAT_FUNCS_st {
+	ASN1_new_func *asn1_new;
+	ASN1_free_func *asn1_free;
+	ASN1_d2i_func *asn1_d2i;
+	ASN1_i2d_func *asn1_i2d;
+} ASN1_COMPAT_FUNCS;
+
+typedef struct ASN1_EXTERN_FUNCS_st {
+	void *app_data;
+	ASN1_ex_new_func *asn1_ex_new;
+	ASN1_ex_free_func *asn1_ex_free;
+	ASN1_ex_free_func *asn1_ex_clear;
+	ASN1_ex_d2i *asn1_ex_d2i;
+	ASN1_ex_i2d *asn1_ex_i2d;
+} ASN1_EXTERN_FUNCS;
+
+typedef struct ASN1_PRIMITIVE_FUNCS_st {
+	void *app_data;
+	unsigned long flags;
+	ASN1_ex_new_func *prim_new;
+	ASN1_ex_free_func *prim_free;
+	ASN1_ex_free_func *prim_clear;
+	ASN1_primitive_c2i *prim_c2i;
+	ASN1_primitive_i2c *prim_i2c;
+} ASN1_PRIMITIVE_FUNCS;
+
+/* This is the ASN1_AUX structure: it handles various
+ * miscellaneous requirements. For example the use of
+ * reference counts and an informational callback.
+ *
+ * The "informational callback" is called at various
+ * points during the ASN1 encoding and decoding. It can
+ * be used to provide minor customisation of the structures
+ * used. This is most useful where the supplied routines
+ * *almost* do the right thing but need some extra help
+ * at a few points. If the callback returns zero then
+ * it is assumed a fatal error has occurred and the 
+ * main operation should be abandoned.
+ *
+ * If major changes in the default behaviour are required
+ * then an external type is more appropriate.
+ */
+
+typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it);
+
+typedef struct ASN1_AUX_st {
+	void *app_data;
+	int flags;
+	int ref_offset;		/* Offset of reference value */
+	int ref_lock;		/* Lock type to use */
+	ASN1_aux_cb *asn1_cb;
+	int enc_offset;		/* Offset of ASN1_ENCODING structure */
+} ASN1_AUX;
+
+/* Flags in ASN1_AUX */
+
+/* Use a reference count */
+#define ASN1_AFLG_REFCOUNT	1
+/* Save the encoding of structure (useful for signatures) */
+#define ASN1_AFLG_ENCODING	2
+/* The Sequence length is invalid */
+#define ASN1_AFLG_BROKEN	4
+
+/* operation values for asn1_cb */
+
+#define ASN1_OP_NEW_PRE		0
+#define ASN1_OP_NEW_POST	1
+#define ASN1_OP_FREE_PRE	2
+#define ASN1_OP_FREE_POST	3
+#define ASN1_OP_D2I_PRE		4
+#define ASN1_OP_D2I_POST	5
+#define ASN1_OP_I2D_PRE		6
+#define ASN1_OP_I2D_POST	7
+
+/* Macro to implement a primitive type */
+#define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0)
+#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \
+				ASN1_ITEM_start(itname) \
+					ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \
+				ASN1_ITEM_end(itname)
+
+/* Macro to implement a multi string type */
+#define IMPLEMENT_ASN1_MSTRING(itname, mask) \
+				ASN1_ITEM_start(itname) \
+					ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \
+				ASN1_ITEM_end(itname)
+
+/* Macro to implement an ASN1_ITEM in terms of old style funcs */
+
+#define IMPLEMENT_COMPAT_ASN1(sname) IMPLEMENT_COMPAT_ASN1_type(sname, V_ASN1_SEQUENCE)
+
+#define IMPLEMENT_COMPAT_ASN1_type(sname, tag) \
+	static const ASN1_COMPAT_FUNCS sname##_ff = { \
+		(ASN1_new_func *)sname##_new, \
+		(ASN1_free_func *)sname##_free, \
+		(ASN1_d2i_func *)d2i_##sname, \
+		(ASN1_i2d_func *)i2d_##sname, \
+	}; \
+	ASN1_ITEM_start(sname) \
+		ASN1_ITYPE_COMPAT, \
+		tag, \
+		NULL, \
+		0, \
+		&sname##_ff, \
+		0, \
+		#sname \
+	ASN1_ITEM_end(sname)
+
+#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \
+	ASN1_ITEM_start(sname) \
+		ASN1_ITYPE_EXTERN, \
+		tag, \
+		NULL, \
+		0, \
+		&fptrs, \
+		0, \
+		#sname \
+	ASN1_ITEM_end(sname)
+
+/* Macro to implement standard functions in terms of ASN1_ITEM structures */
+
+#define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname)
+
+#define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname)
+
+#define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \
+			IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname)
+
+#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \
+		IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname)
+
+#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \
+	stname *fname##_new(void) \
+	{ \
+		return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \
+	} \
+	void fname##_free(stname *a) \
+	{ \
+		ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \
+	}
+
+#define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \
+	IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
+	IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
+
+#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \
+	stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
+	{ \
+		return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
+	} \
+	int i2d_##fname(stname *a, unsigned char **out) \
+	{ \
+		return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
+	} 
+
+#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \
+	int i2d_##stname##_NDEF(stname *a, unsigned char **out) \
+	{ \
+		return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\
+	} 
+
+/* This includes evil casts to remove const: they will go away when full
+ * ASN1 constification is done.
+ */
+#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
+	stname *d2i_##fname(stname **a, const unsigned char **in, long len) \
+	{ \
+		return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\
+	} \
+	int i2d_##fname(const stname *a, unsigned char **out) \
+	{ \
+		return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\
+	} 
+
+#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \
+	stname * stname##_dup(stname *x) \
+        { \
+        return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \
+        }
+
+#define IMPLEMENT_ASN1_FUNCTIONS_const(name) \
+		IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name)
+
+#define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \
+	IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \
+	IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname)
+
+/* external definitions for primitive types */
+
+DECLARE_ASN1_ITEM(ASN1_BOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_TBOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_FBOOLEAN)
+DECLARE_ASN1_ITEM(ASN1_SEQUENCE)
+DECLARE_ASN1_ITEM(CBIGNUM)
+DECLARE_ASN1_ITEM(BIGNUM)
+DECLARE_ASN1_ITEM(LONG)
+DECLARE_ASN1_ITEM(ZLONG)
+
+DECLARE_STACK_OF(ASN1_VALUE)
+
+/* Functions used internally by the ASN1 code */
+
+int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
+void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
+int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
+int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt);
+int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it,
+				int tag, int aclass, char opt, ASN1_TLC *ctx);
+
+int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass);
+int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt);
+void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+
+int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it);
+int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it);
+
+int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it);
+int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it);
+
+ASN1_VALUE ** asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt);
+
+const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, int nullerr);
+
+int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it);
+
+void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it);
+void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it);
+int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, const ASN1_ITEM *it);
+int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, const ASN1_ITEM *it);
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/bio.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/bio.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/bio.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,767 @@
+/* crypto/bio/bio.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_BIO_H
+#define HEADER_BIO_H
+
+#include <openssl/e_os2.h>
+
+#ifndef OPENSSL_NO_FP_API
+# include <stdio.h>
+#endif
+#include <stdarg.h>
+
+#include <openssl/crypto.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* These are the 'types' of BIOs */
+#define BIO_TYPE_NONE		0
+#define BIO_TYPE_MEM		(1|0x0400)
+#define BIO_TYPE_FILE		(2|0x0400)
+
+#define BIO_TYPE_FD		(4|0x0400|0x0100)
+#define BIO_TYPE_SOCKET		(5|0x0400|0x0100)
+#define BIO_TYPE_NULL		(6|0x0400)
+#define BIO_TYPE_SSL		(7|0x0200)
+#define BIO_TYPE_MD		(8|0x0200)		/* passive filter */
+#define BIO_TYPE_BUFFER		(9|0x0200)		/* filter */
+#define BIO_TYPE_CIPHER		(10|0x0200)		/* filter */
+#define BIO_TYPE_BASE64		(11|0x0200)		/* filter */
+#define BIO_TYPE_CONNECT	(12|0x0400|0x0100)	/* socket - connect */
+#define BIO_TYPE_ACCEPT		(13|0x0400|0x0100)	/* socket for accept */
+#define BIO_TYPE_PROXY_CLIENT	(14|0x0200)		/* client proxy BIO */
+#define BIO_TYPE_PROXY_SERVER	(15|0x0200)		/* server proxy BIO */
+#define BIO_TYPE_NBIO_TEST	(16|0x0200)		/* server proxy BIO */
+#define BIO_TYPE_NULL_FILTER	(17|0x0200)
+#define BIO_TYPE_BER		(18|0x0200)		/* BER -> bin filter */
+#define BIO_TYPE_BIO		(19|0x0400)		/* (half a) BIO pair */
+#define BIO_TYPE_LINEBUFFER	(20|0x0200)		/* filter */
+#define BIO_TYPE_DGRAM		(21|0x0400|0x0100)
+
+#define BIO_TYPE_DESCRIPTOR	0x0100	/* socket, fd, connect or accept */
+#define BIO_TYPE_FILTER		0x0200
+#define BIO_TYPE_SOURCE_SINK	0x0400
+
+/* BIO_FILENAME_READ|BIO_CLOSE to open or close on free.
+ * BIO_set_fp(in,stdin,BIO_NOCLOSE); */
+#define BIO_NOCLOSE		0x00
+#define BIO_CLOSE		0x01
+
+/* These are used in the following macros and are passed to
+ * BIO_ctrl() */
+#define BIO_CTRL_RESET		1  /* opt - rewind/zero etc */
+#define BIO_CTRL_EOF		2  /* opt - are we at the eof */
+#define BIO_CTRL_INFO		3  /* opt - extra tit-bits */
+#define BIO_CTRL_SET		4  /* man - set the 'IO' type */
+#define BIO_CTRL_GET		5  /* man - get the 'IO' type */
+#define BIO_CTRL_PUSH		6  /* opt - internal, used to signify change */
+#define BIO_CTRL_POP		7  /* opt - internal, used to signify change */
+#define BIO_CTRL_GET_CLOSE	8  /* man - set the 'close' on free */
+#define BIO_CTRL_SET_CLOSE	9  /* man - set the 'close' on free */
+#define BIO_CTRL_PENDING	10  /* opt - is their more data buffered */
+#define BIO_CTRL_FLUSH		11  /* opt - 'flush' buffered output */
+#define BIO_CTRL_DUP		12  /* man - extra stuff for 'duped' BIO */
+#define BIO_CTRL_WPENDING	13  /* opt - number of bytes still to write */
+/* callback is int cb(BIO *bio,state,ret); */
+#define BIO_CTRL_SET_CALLBACK	14  /* opt - set callback function */
+#define BIO_CTRL_GET_CALLBACK	15  /* opt - set callback function */
+
+#define BIO_CTRL_SET_FILENAME	30	/* BIO_s_file special */
+
+/* dgram BIO stuff */
+#define BIO_CTRL_DGRAM_CONNECT       31  /* BIO dgram special */
+#define BIO_CTRL_DGRAM_SET_CONNECTED 32  /* allow for an externally
+										  * connected socket to be
+										  * passed in */ 
+#define BIO_CTRL_DGRAM_SET_RECV_TIMEOUT 33 /* setsockopt, essentially */
+#define BIO_CTRL_DGRAM_GET_RECV_TIMEOUT 34 /* getsockopt, essentially */
+#define BIO_CTRL_DGRAM_SET_SEND_TIMEOUT 35 /* setsockopt, essentially */
+#define BIO_CTRL_DGRAM_GET_SEND_TIMEOUT 36 /* getsockopt, essentially */
+
+#define BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP 37 /* flag whether the last */
+#define BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP 38 /* I/O operation tiemd out */
+					
+/* #ifdef IP_MTU_DISCOVER */
+#define BIO_CTRL_DGRAM_MTU_DISCOVER       39 /* set DF bit on egress packets */
+/* #endif */
+
+#define BIO_CTRL_DGRAM_QUERY_MTU          40 /* as kernel for current MTU */
+#define BIO_CTRL_DGRAM_GET_MTU            41 /* get cached value for MTU */
+#define BIO_CTRL_DGRAM_SET_MTU            42 /* set cached value for
+											  * MTU. want to use this
+                                              * if asking the kernel
+                                              * fails */
+
+#define BIO_CTRL_DGRAM_MTU_EXCEEDED       43 /* check whether the MTU
+											  * was exceed in the
+											  * previous write
+											  * operation */
+
+#define BIO_CTRL_DGRAM_SET_PEER           44 /* Destination for the data */
+
+
+/* modifiers */
+#define BIO_FP_READ		0x02
+#define BIO_FP_WRITE		0x04
+#define BIO_FP_APPEND		0x08
+#define BIO_FP_TEXT		0x10
+
+#define BIO_FLAGS_READ		0x01
+#define BIO_FLAGS_WRITE		0x02
+#define BIO_FLAGS_IO_SPECIAL	0x04
+#define BIO_FLAGS_RWS (BIO_FLAGS_READ|BIO_FLAGS_WRITE|BIO_FLAGS_IO_SPECIAL)
+#define BIO_FLAGS_SHOULD_RETRY	0x08
+#ifndef	BIO_FLAGS_UPLINK
+/* "UPLINK" flag denotes file descriptors provided by application.
+   It defaults to 0, as most platforms don't require UPLINK interface. */
+#define	BIO_FLAGS_UPLINK	0
+#endif
+
+/* Used in BIO_gethostbyname() */
+#define BIO_GHBN_CTRL_HITS		1
+#define BIO_GHBN_CTRL_MISSES		2
+#define BIO_GHBN_CTRL_CACHE_SIZE	3
+#define BIO_GHBN_CTRL_GET_ENTRY		4
+#define BIO_GHBN_CTRL_FLUSH		5
+
+/* Mostly used in the SSL BIO */
+/* Not used anymore
+ * #define BIO_FLAGS_PROTOCOL_DELAYED_READ 0x10
+ * #define BIO_FLAGS_PROTOCOL_DELAYED_WRITE 0x20
+ * #define BIO_FLAGS_PROTOCOL_STARTUP	0x40
+ */
+
+#define BIO_FLAGS_BASE64_NO_NL	0x100
+
+/* This is used with memory BIOs: it means we shouldn't free up or change the
+ * data in any way.
+ */
+#define BIO_FLAGS_MEM_RDONLY	0x200
+
+#define BIO_set_flags(b,f) ((b)->flags|=(f))
+#define BIO_get_flags(b) ((b)->flags)
+#define BIO_set_retry_special(b) \
+		((b)->flags|=(BIO_FLAGS_IO_SPECIAL|BIO_FLAGS_SHOULD_RETRY))
+#define BIO_set_retry_read(b) \
+		((b)->flags|=(BIO_FLAGS_READ|BIO_FLAGS_SHOULD_RETRY))
+#define BIO_set_retry_write(b) \
+		((b)->flags|=(BIO_FLAGS_WRITE|BIO_FLAGS_SHOULD_RETRY))
+
+/* These are normally used internally in BIOs */
+#define BIO_clear_flags(b,f) ((b)->flags&= ~(f))
+#define BIO_clear_retry_flags(b) \
+		((b)->flags&= ~(BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
+#define BIO_get_retry_flags(b) \
+		((b)->flags&(BIO_FLAGS_RWS|BIO_FLAGS_SHOULD_RETRY))
+
+/* These should be used by the application to tell why we should retry */
+#define BIO_should_read(a)		((a)->flags & BIO_FLAGS_READ)
+#define BIO_should_write(a)		((a)->flags & BIO_FLAGS_WRITE)
+#define BIO_should_io_special(a)	((a)->flags & BIO_FLAGS_IO_SPECIAL)
+#define BIO_retry_type(a)		((a)->flags & BIO_FLAGS_RWS)
+#define BIO_should_retry(a)		((a)->flags & BIO_FLAGS_SHOULD_RETRY)
+
+/* The next three are used in conjunction with the
+ * BIO_should_io_special() condition.  After this returns true,
+ * BIO *BIO_get_retry_BIO(BIO *bio, int *reason); will walk the BIO 
+ * stack and return the 'reason' for the special and the offending BIO.
+ * Given a BIO, BIO_get_retry_reason(bio) will return the code. */
+/* Returned from the SSL bio when the certificate retrieval code had an error */
+#define BIO_RR_SSL_X509_LOOKUP		0x01
+/* Returned from the connect BIO when a connect would have blocked */
+#define BIO_RR_CONNECT			0x02
+/* Returned from the accept BIO when an accept would have blocked */
+#define BIO_RR_ACCEPT			0x03
+
+/* These are passed by the BIO callback */
+#define BIO_CB_FREE	0x01
+#define BIO_CB_READ	0x02
+#define BIO_CB_WRITE	0x03
+#define BIO_CB_PUTS	0x04
+#define BIO_CB_GETS	0x05
+#define BIO_CB_CTRL	0x06
+
+/* The callback is called before and after the underling operation,
+ * The BIO_CB_RETURN flag indicates if it is after the call */
+#define BIO_CB_RETURN	0x80
+#define BIO_CB_return(a) ((a)|BIO_CB_RETURN))
+#define BIO_cb_pre(a)	(!((a)&BIO_CB_RETURN))
+#define BIO_cb_post(a)	((a)&BIO_CB_RETURN)
+
+#define BIO_set_callback(b,cb)		((b)->callback=(cb))
+#define BIO_set_callback_arg(b,arg)	((b)->cb_arg=(char *)(arg))
+#define BIO_get_callback_arg(b)		((b)->cb_arg)
+#define BIO_get_callback(b)		((b)->callback)
+#define BIO_method_name(b)		((b)->method->name)
+#define BIO_method_type(b)		((b)->method->type)
+
+typedef struct bio_st BIO;
+
+typedef void bio_info_cb(struct bio_st *, int, const char *, int, long, long);
+
+#ifndef OPENSSL_SYS_WIN16
+typedef struct bio_method_st
+	{
+	int type;
+	const char *name;
+	int (*bwrite)(BIO *, const char *, int);
+	int (*bread)(BIO *, char *, int);
+	int (*bputs)(BIO *, const char *);
+	int (*bgets)(BIO *, char *, int);
+	long (*ctrl)(BIO *, int, long, void *);
+	int (*create)(BIO *);
+	int (*destroy)(BIO *);
+        long (*callback_ctrl)(BIO *, int, bio_info_cb *);
+	} BIO_METHOD;
+#else
+typedef struct bio_method_st
+	{
+	int type;
+	const char *name;
+	int (_far *bwrite)();
+	int (_far *bread)();
+	int (_far *bputs)();
+	int (_far *bgets)();
+	long (_far *ctrl)();
+	int (_far *create)();
+	int (_far *destroy)();
+	long (_far *callback_ctrl)();
+	} BIO_METHOD;
+#endif
+
+struct bio_st
+	{
+	BIO_METHOD *method;
+	/* bio, mode, argp, argi, argl, ret */
+	long (*callback)(struct bio_st *,int,const char *,int, long,long);
+	char *cb_arg; /* first argument for the callback */
+
+	int init;
+	int shutdown;
+	int flags;	/* extra storage */
+	int retry_reason;
+	int num;
+	void *ptr;
+	struct bio_st *next_bio;	/* used by filter BIOs */
+	struct bio_st *prev_bio;	/* used by filter BIOs */
+	int references;
+	unsigned long num_read;
+	unsigned long num_write;
+
+	CRYPTO_EX_DATA ex_data;
+	};
+
+DECLARE_STACK_OF(BIO)
+
+typedef struct bio_f_buffer_ctx_struct
+	{
+	/* BIO *bio; */ /* this is now in the BIO struct */
+	int ibuf_size;	/* how big is the input buffer */
+	int obuf_size;	/* how big is the output buffer */
+
+	char *ibuf;		/* the char array */
+	int ibuf_len;		/* how many bytes are in it */
+	int ibuf_off;		/* write/read offset */
+
+	char *obuf;		/* the char array */
+	int obuf_len;		/* how many bytes are in it */
+	int obuf_off;		/* write/read offset */
+	} BIO_F_BUFFER_CTX;
+
+/* connect BIO stuff */
+#define BIO_CONN_S_BEFORE		1
+#define BIO_CONN_S_GET_IP		2
+#define BIO_CONN_S_GET_PORT		3
+#define BIO_CONN_S_CREATE_SOCKET	4
+#define BIO_CONN_S_CONNECT		5
+#define BIO_CONN_S_OK			6
+#define BIO_CONN_S_BLOCKED_CONNECT	7
+#define BIO_CONN_S_NBIO			8
+/*#define BIO_CONN_get_param_hostname	BIO_ctrl */
+
+#define BIO_C_SET_CONNECT			100
+#define BIO_C_DO_STATE_MACHINE			101
+#define BIO_C_SET_NBIO				102
+#define BIO_C_SET_PROXY_PARAM			103
+#define BIO_C_SET_FD				104
+#define BIO_C_GET_FD				105
+#define BIO_C_SET_FILE_PTR			106
+#define BIO_C_GET_FILE_PTR			107
+#define BIO_C_SET_FILENAME			108
+#define BIO_C_SET_SSL				109
+#define BIO_C_GET_SSL				110
+#define BIO_C_SET_MD				111
+#define BIO_C_GET_MD				112
+#define BIO_C_GET_CIPHER_STATUS			113
+#define BIO_C_SET_BUF_MEM			114
+#define BIO_C_GET_BUF_MEM_PTR			115
+#define BIO_C_GET_BUFF_NUM_LINES		116
+#define BIO_C_SET_BUFF_SIZE			117
+#define BIO_C_SET_ACCEPT			118
+#define BIO_C_SSL_MODE				119
+#define BIO_C_GET_MD_CTX			120
+#define BIO_C_GET_PROXY_PARAM			121
+#define BIO_C_SET_BUFF_READ_DATA		122 /* data to read first */
+#define BIO_C_GET_CONNECT			123
+#define BIO_C_GET_ACCEPT			124
+#define BIO_C_SET_SSL_RENEGOTIATE_BYTES		125
+#define BIO_C_GET_SSL_NUM_RENEGOTIATES		126
+#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT	127
+#define BIO_C_FILE_SEEK				128
+#define BIO_C_GET_CIPHER_CTX			129
+#define BIO_C_SET_BUF_MEM_EOF_RETURN		130/*return end of input value*/
+#define BIO_C_SET_BIND_MODE			131
+#define BIO_C_GET_BIND_MODE			132
+#define BIO_C_FILE_TELL				133
+#define BIO_C_GET_SOCKS				134
+#define BIO_C_SET_SOCKS				135
+
+#define BIO_C_SET_WRITE_BUF_SIZE		136/* for BIO_s_bio */
+#define BIO_C_GET_WRITE_BUF_SIZE		137
+#define BIO_C_MAKE_BIO_PAIR			138
+#define BIO_C_DESTROY_BIO_PAIR			139
+#define BIO_C_GET_WRITE_GUARANTEE		140
+#define BIO_C_GET_READ_REQUEST			141
+#define BIO_C_SHUTDOWN_WR			142
+#define BIO_C_NREAD0				143
+#define BIO_C_NREAD				144
+#define BIO_C_NWRITE0				145
+#define BIO_C_NWRITE				146
+#define BIO_C_RESET_READ_REQUEST		147
+
+
+#define BIO_set_app_data(s,arg)		BIO_set_ex_data(s,0,arg)
+#define BIO_get_app_data(s)		BIO_get_ex_data(s,0)
+
+/* BIO_s_connect() and BIO_s_socks4a_connect() */
+#define BIO_set_conn_hostname(b,name) BIO_ctrl(b,BIO_C_SET_CONNECT,0,(char *)name)
+#define BIO_set_conn_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,1,(char *)port)
+#define BIO_set_conn_ip(b,ip)	  BIO_ctrl(b,BIO_C_SET_CONNECT,2,(char *)ip)
+#define BIO_set_conn_int_port(b,port) BIO_ctrl(b,BIO_C_SET_CONNECT,3,(char *)port)
+#define BIO_get_conn_hostname(b)  BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,0)
+#define BIO_get_conn_port(b)      BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,1)
+#define BIO_get_conn_ip(b) 		 BIO_ptr_ctrl(b,BIO_C_GET_CONNECT,2)
+#define BIO_get_conn_int_port(b) BIO_int_ctrl(b,BIO_C_GET_CONNECT,3)
+
+
+#define BIO_set_nbio(b,n)	BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL)
+
+/* BIO_s_accept_socket() */
+#define BIO_set_accept_port(b,name) BIO_ctrl(b,BIO_C_SET_ACCEPT,0,(char *)name)
+#define BIO_get_accept_port(b)	BIO_ptr_ctrl(b,BIO_C_GET_ACCEPT,0)
+/* #define BIO_set_nbio(b,n)	BIO_ctrl(b,BIO_C_SET_NBIO,(n),NULL) */
+#define BIO_set_nbio_accept(b,n) BIO_ctrl(b,BIO_C_SET_ACCEPT,1,(n)?"a":NULL)
+#define BIO_set_accept_bios(b,bio) BIO_ctrl(b,BIO_C_SET_ACCEPT,2,(char *)bio)
+
+#define BIO_BIND_NORMAL			0
+#define BIO_BIND_REUSEADDR_IF_UNUSED	1
+#define BIO_BIND_REUSEADDR		2
+#define BIO_set_bind_mode(b,mode) BIO_ctrl(b,BIO_C_SET_BIND_MODE,mode,NULL)
+#define BIO_get_bind_mode(b,mode) BIO_ctrl(b,BIO_C_GET_BIND_MODE,0,NULL)
+
+#define BIO_do_connect(b)	BIO_do_handshake(b)
+#define BIO_do_accept(b)	BIO_do_handshake(b)
+#define BIO_do_handshake(b)	BIO_ctrl(b,BIO_C_DO_STATE_MACHINE,0,NULL)
+
+/* BIO_s_proxy_client() */
+#define BIO_set_url(b,url)	BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,0,(char *)(url))
+#define BIO_set_proxies(b,p)	BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,1,(char *)(p))
+/* BIO_set_nbio(b,n) */
+#define BIO_set_filter_bio(b,s) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,2,(char *)(s))
+/* BIO *BIO_get_filter_bio(BIO *bio); */
+#define BIO_set_proxy_cb(b,cb) BIO_callback_ctrl(b,BIO_C_SET_PROXY_PARAM,3,(void *(*cb)()))
+#define BIO_set_proxy_header(b,sk) BIO_ctrl(b,BIO_C_SET_PROXY_PARAM,4,(char *)sk)
+#define BIO_set_no_connect_return(b,bool) BIO_int_ctrl(b,BIO_C_SET_PROXY_PARAM,5,bool)
+
+#define BIO_get_proxy_header(b,skp) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,0,(char *)skp)
+#define BIO_get_proxies(b,pxy_p) BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,1,(char *)(pxy_p))
+#define BIO_get_url(b,url)	BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,2,(char *)(url))
+#define BIO_get_no_connect_return(b)	BIO_ctrl(b,BIO_C_GET_PROXY_PARAM,5,NULL)
+
+#define BIO_set_fd(b,fd,c)	BIO_int_ctrl(b,BIO_C_SET_FD,c,fd)
+#define BIO_get_fd(b,c)		BIO_ctrl(b,BIO_C_GET_FD,0,(char *)c)
+
+#define BIO_set_fp(b,fp,c)	BIO_ctrl(b,BIO_C_SET_FILE_PTR,c,(char *)fp)
+#define BIO_get_fp(b,fpp)	BIO_ctrl(b,BIO_C_GET_FILE_PTR,0,(char *)fpp)
+
+#define BIO_seek(b,ofs)	(int)BIO_ctrl(b,BIO_C_FILE_SEEK,ofs,NULL)
+#define BIO_tell(b)	(int)BIO_ctrl(b,BIO_C_FILE_TELL,0,NULL)
+
+/* name is cast to lose const, but might be better to route through a function
+   so we can do it safely */
+#ifdef CONST_STRICT
+/* If you are wondering why this isn't defined, its because CONST_STRICT is
+ * purely a compile-time kludge to allow const to be checked.
+ */
+int BIO_read_filename(BIO *b,const char *name);
+#else
+#define BIO_read_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \
+		BIO_CLOSE|BIO_FP_READ,(char *)name)
+#endif
+#define BIO_write_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \
+		BIO_CLOSE|BIO_FP_WRITE,name)
+#define BIO_append_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \
+		BIO_CLOSE|BIO_FP_APPEND,name)
+#define BIO_rw_filename(b,name) BIO_ctrl(b,BIO_C_SET_FILENAME, \
+		BIO_CLOSE|BIO_FP_READ|BIO_FP_WRITE,name)
+
+/* WARNING WARNING, this ups the reference count on the read bio of the
+ * SSL structure.  This is because the ssl read BIO is now pointed to by
+ * the next_bio field in the bio.  So when you free the BIO, make sure
+ * you are doing a BIO_free_all() to catch the underlying BIO. */
+#define BIO_set_ssl(b,ssl,c)	BIO_ctrl(b,BIO_C_SET_SSL,c,(char *)ssl)
+#define BIO_get_ssl(b,sslp)	BIO_ctrl(b,BIO_C_GET_SSL,0,(char *)sslp)
+#define BIO_set_ssl_mode(b,client)	BIO_ctrl(b,BIO_C_SSL_MODE,client,NULL)
+#define BIO_set_ssl_renegotiate_bytes(b,num) \
+	BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_BYTES,num,NULL);
+#define BIO_get_num_renegotiates(b) \
+	BIO_ctrl(b,BIO_C_GET_SSL_NUM_RENEGOTIATES,0,NULL);
+#define BIO_set_ssl_renegotiate_timeout(b,seconds) \
+	BIO_ctrl(b,BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT,seconds,NULL);
+
+/* defined in evp.h */
+/* #define BIO_set_md(b,md)	BIO_ctrl(b,BIO_C_SET_MD,1,(char *)md) */
+
+#define BIO_get_mem_data(b,pp)	BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp)
+#define BIO_set_mem_buf(b,bm,c)	BIO_ctrl(b,BIO_C_SET_BUF_MEM,c,(char *)bm)
+#define BIO_get_mem_ptr(b,pp)	BIO_ctrl(b,BIO_C_GET_BUF_MEM_PTR,0,(char *)pp)
+#define BIO_set_mem_eof_return(b,v) \
+				BIO_ctrl(b,BIO_C_SET_BUF_MEM_EOF_RETURN,v,NULL)
+
+/* For the BIO_f_buffer() type */
+#define BIO_get_buffer_num_lines(b)	BIO_ctrl(b,BIO_C_GET_BUFF_NUM_LINES,0,NULL)
+#define BIO_set_buffer_size(b,size)	BIO_ctrl(b,BIO_C_SET_BUFF_SIZE,size,NULL)
+#define BIO_set_read_buffer_size(b,size) BIO_int_ctrl(b,BIO_C_SET_BUFF_SIZE,size,0)
+#define BIO_set_write_buffer_size(b,size) BIO_int_ctrl(b,BIO_C_SET_BUFF_SIZE,size,1)
+#define BIO_set_buffer_read_data(b,buf,num) BIO_ctrl(b,BIO_C_SET_BUFF_READ_DATA,num,buf)
+
+/* Don't use the next one unless you know what you are doing :-) */
+#define BIO_dup_state(b,ret)	BIO_ctrl(b,BIO_CTRL_DUP,0,(char *)(ret))
+
+#define BIO_reset(b)		(int)BIO_ctrl(b,BIO_CTRL_RESET,0,NULL)
+#define BIO_eof(b)		(int)BIO_ctrl(b,BIO_CTRL_EOF,0,NULL)
+#define BIO_set_close(b,c)	(int)BIO_ctrl(b,BIO_CTRL_SET_CLOSE,(c),NULL)
+#define BIO_get_close(b)	(int)BIO_ctrl(b,BIO_CTRL_GET_CLOSE,0,NULL)
+#define BIO_pending(b)		(int)BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
+#define BIO_wpending(b)		(int)BIO_ctrl(b,BIO_CTRL_WPENDING,0,NULL)
+/* ...pending macros have inappropriate return type */
+size_t BIO_ctrl_pending(BIO *b);
+size_t BIO_ctrl_wpending(BIO *b);
+#define BIO_flush(b)		(int)BIO_ctrl(b,BIO_CTRL_FLUSH,0,NULL)
+#define BIO_get_info_callback(b,cbp) (int)BIO_ctrl(b,BIO_CTRL_GET_CALLBACK,0, \
+						   cbp)
+#define BIO_set_info_callback(b,cb) (int)BIO_callback_ctrl(b,BIO_CTRL_SET_CALLBACK,cb)
+
+/* For the BIO_f_buffer() type */
+#define BIO_buffer_get_num_lines(b) BIO_ctrl(b,BIO_CTRL_GET,0,NULL)
+
+/* For BIO_s_bio() */
+#define BIO_set_write_buf_size(b,size) (int)BIO_ctrl(b,BIO_C_SET_WRITE_BUF_SIZE,size,NULL)
+#define BIO_get_write_buf_size(b,size) (size_t)BIO_ctrl(b,BIO_C_GET_WRITE_BUF_SIZE,size,NULL)
+#define BIO_make_bio_pair(b1,b2)   (int)BIO_ctrl(b1,BIO_C_MAKE_BIO_PAIR,0,b2)
+#define BIO_destroy_bio_pair(b)    (int)BIO_ctrl(b,BIO_C_DESTROY_BIO_PAIR,0,NULL)
+#define BIO_shutdown_wr(b) (int)BIO_ctrl(b, BIO_C_SHUTDOWN_WR, 0, NULL)
+/* macros with inappropriate type -- but ...pending macros use int too: */
+#define BIO_get_write_guarantee(b) (int)BIO_ctrl(b,BIO_C_GET_WRITE_GUARANTEE,0,NULL)
+#define BIO_get_read_request(b)    (int)BIO_ctrl(b,BIO_C_GET_READ_REQUEST,0,NULL)
+size_t BIO_ctrl_get_write_guarantee(BIO *b);
+size_t BIO_ctrl_get_read_request(BIO *b);
+int BIO_ctrl_reset_read_request(BIO *b);
+
+/* ctrl macros for dgram */
+#define BIO_ctrl_dgram_connect(b,peer)  \
+                     (int)BIO_ctrl(b,BIO_CTRL_DGRAM_CONNECT,0, (char *)peer)
+#define BIO_ctrl_set_connected(b, state, peer) \
+         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_CONNECTED, state, (char *)peer)
+#define BIO_dgram_recv_timedout(b) \
+         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP, 0, NULL)
+#define BIO_dgram_send_timedout(b) \
+         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP, 0, NULL)
+#define BIO_dgram_set_peer(b,peer) \
+         (int)BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, (char *)peer)
+
+/* These two aren't currently implemented */
+/* int BIO_get_ex_num(BIO *bio); */
+/* void BIO_set_ex_free_func(BIO *bio,int idx,void (*cb)()); */
+int BIO_set_ex_data(BIO *bio,int idx,void *data);
+void *BIO_get_ex_data(BIO *bio,int idx);
+int BIO_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+unsigned long BIO_number_read(BIO *bio);
+unsigned long BIO_number_written(BIO *bio);
+
+# ifndef OPENSSL_NO_FP_API
+#  if defined(OPENSSL_SYS_WIN16) && defined(_WINDLL)
+BIO_METHOD *BIO_s_file_internal(void);
+BIO *BIO_new_file_internal(char *filename, char *mode);
+BIO *BIO_new_fp_internal(FILE *stream, int close_flag);
+#    define BIO_s_file	BIO_s_file_internal
+#    define BIO_new_file	BIO_new_file_internal
+#    define BIO_new_fp	BIO_new_fp_internal
+#  else /* FP_API */
+BIO_METHOD *BIO_s_file(void );
+BIO *BIO_new_file(const char *filename, const char *mode);
+BIO *BIO_new_fp(FILE *stream, int close_flag);
+#    define BIO_s_file_internal		BIO_s_file
+#    define BIO_new_file_internal	BIO_new_file
+#    define BIO_new_fp_internal		BIO_s_file
+#  endif /* FP_API */
+# endif
+BIO *	BIO_new(BIO_METHOD *type);
+int	BIO_set(BIO *a,BIO_METHOD *type);
+int	BIO_free(BIO *a);
+void	BIO_vfree(BIO *a);
+int	BIO_read(BIO *b, void *data, int len);
+int	BIO_gets(BIO *bp,char *buf, int size);
+int	BIO_write(BIO *b, const void *data, int len);
+int	BIO_puts(BIO *bp,const char *buf);
+int	BIO_indent(BIO *b,int indent,int max);
+long	BIO_ctrl(BIO *bp,int cmd,long larg,void *parg);
+long BIO_callback_ctrl(BIO *b, int cmd, void (*fp)(struct bio_st *, int, const char *, int, long, long));
+char *	BIO_ptr_ctrl(BIO *bp,int cmd,long larg);
+long	BIO_int_ctrl(BIO *bp,int cmd,long larg,int iarg);
+BIO *	BIO_push(BIO *b,BIO *append);
+BIO *	BIO_pop(BIO *b);
+void	BIO_free_all(BIO *a);
+BIO *	BIO_find_type(BIO *b,int bio_type);
+BIO *	BIO_next(BIO *b);
+BIO *	BIO_get_retry_BIO(BIO *bio, int *reason);
+int	BIO_get_retry_reason(BIO *bio);
+BIO *	BIO_dup_chain(BIO *in);
+
+int BIO_nread0(BIO *bio, char **buf);
+int BIO_nread(BIO *bio, char **buf, int num);
+int BIO_nwrite0(BIO *bio, char **buf);
+int BIO_nwrite(BIO *bio, char **buf, int num);
+
+#ifndef OPENSSL_SYS_WIN16
+long BIO_debug_callback(BIO *bio,int cmd,const char *argp,int argi,
+	long argl,long ret);
+#else
+long _far _loadds BIO_debug_callback(BIO *bio,int cmd,const char *argp,int argi,
+	long argl,long ret);
+#endif
+
+BIO_METHOD *BIO_s_mem(void);
+BIO *BIO_new_mem_buf(void *buf, int len);
+BIO_METHOD *BIO_s_socket(void);
+BIO_METHOD *BIO_s_connect(void);
+BIO_METHOD *BIO_s_accept(void);
+BIO_METHOD *BIO_s_fd(void);
+#ifndef OPENSSL_SYS_OS2
+BIO_METHOD *BIO_s_log(void);
+#endif
+BIO_METHOD *BIO_s_bio(void);
+BIO_METHOD *BIO_s_null(void);
+BIO_METHOD *BIO_f_null(void);
+BIO_METHOD *BIO_f_buffer(void);
+#ifdef OPENSSL_SYS_VMS
+BIO_METHOD *BIO_f_linebuffer(void);
+#endif
+BIO_METHOD *BIO_f_nbio_test(void);
+#ifndef OPENSSL_NO_DGRAM
+BIO_METHOD *BIO_s_datagram(void);
+#endif
+
+/* BIO_METHOD *BIO_f_ber(void); */
+
+int BIO_sock_should_retry(int i);
+int BIO_sock_non_fatal_error(int error);
+int BIO_dgram_non_fatal_error(int error);
+
+int BIO_fd_should_retry(int i);
+int BIO_fd_non_fatal_error(int error);
+int BIO_dump_cb(int (*cb)(const void *data, size_t len, void *u),
+		void *u, const char *s, int len);
+int BIO_dump_indent_cb(int (*cb)(const void *data, size_t len, void *u),
+		       void *u, const char *s, int len, int indent);
+int BIO_dump(BIO *b,const char *bytes,int len);
+int BIO_dump_indent(BIO *b,const char *bytes,int len,int indent);
+#ifndef OPENSSL_NO_FP_API
+int BIO_dump_fp(FILE *fp, const char *s, int len);
+int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent);
+#endif
+struct hostent *BIO_gethostbyname(const char *name);
+/* We might want a thread-safe interface too:
+ * struct hostent *BIO_gethostbyname_r(const char *name,
+ *     struct hostent *result, void *buffer, size_t buflen);
+ * or something similar (caller allocates a struct hostent,
+ * pointed to by "result", and additional buffer space for the various
+ * substructures; if the buffer does not suffice, NULL is returned
+ * and an appropriate error code is set).
+ */
+int BIO_sock_error(int sock);
+int BIO_socket_ioctl(int fd, long type, void *arg);
+int BIO_socket_nbio(int fd,int mode);
+int BIO_get_port(const char *str, unsigned short *port_ptr);
+int BIO_get_host_ip(const char *str, unsigned char *ip);
+int BIO_get_accept_socket(char *host_port,int mode);
+int BIO_accept(int sock,char **ip_port);
+int BIO_sock_init(void );
+void BIO_sock_cleanup(void);
+int BIO_set_tcp_ndelay(int sock,int turn_on);
+
+BIO *BIO_new_socket(int sock, int close_flag);
+BIO *BIO_new_dgram(int fd, int close_flag);
+BIO *BIO_new_fd(int fd, int close_flag);
+BIO *BIO_new_connect(char *host_port);
+BIO *BIO_new_accept(char *host_port);
+
+int BIO_new_bio_pair(BIO **bio1, size_t writebuf1,
+	BIO **bio2, size_t writebuf2);
+/* If successful, returns 1 and in *bio1, *bio2 two BIO pair endpoints.
+ * Otherwise returns 0 and sets *bio1 and *bio2 to NULL.
+ * Size 0 uses default value.
+ */
+
+void BIO_copy_next_retry(BIO *b);
+
+/*long BIO_ghbn_ctrl(int cmd,int iarg,char *parg);*/
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+int BIO_printf(BIO *bio, const char *format, ...)
+	__attribute__((__format__(__printf__,2,3)));
+int BIO_vprintf(BIO *bio, const char *format, va_list args)
+	__attribute__((__format__(__printf__,2,0)));
+int BIO_snprintf(char *buf, size_t n, const char *format, ...)
+	__attribute__((__format__(__printf__,3,4)));
+int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
+	__attribute__((__format__(__printf__,3,0)));
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_BIO_strings(void);
+
+/* Error codes for the BIO functions. */
+
+/* Function codes. */
+#define BIO_F_ACPT_STATE				 100
+#define BIO_F_BIO_ACCEPT				 101
+#define BIO_F_BIO_BER_GET_HEADER			 102
+#define BIO_F_BIO_CALLBACK_CTRL				 131
+#define BIO_F_BIO_CTRL					 103
+#define BIO_F_BIO_GETHOSTBYNAME				 120
+#define BIO_F_BIO_GETS					 104
+#define BIO_F_BIO_GET_ACCEPT_SOCKET			 105
+#define BIO_F_BIO_GET_HOST_IP				 106
+#define BIO_F_BIO_GET_PORT				 107
+#define BIO_F_BIO_MAKE_PAIR				 121
+#define BIO_F_BIO_NEW					 108
+#define BIO_F_BIO_NEW_FILE				 109
+#define BIO_F_BIO_NEW_MEM_BUF				 126
+#define BIO_F_BIO_NREAD					 123
+#define BIO_F_BIO_NREAD0				 124
+#define BIO_F_BIO_NWRITE				 125
+#define BIO_F_BIO_NWRITE0				 122
+#define BIO_F_BIO_PUTS					 110
+#define BIO_F_BIO_READ					 111
+#define BIO_F_BIO_SOCK_INIT				 112
+#define BIO_F_BIO_WRITE					 113
+#define BIO_F_BUFFER_CTRL				 114
+#define BIO_F_CONN_CTRL					 127
+#define BIO_F_CONN_STATE				 115
+#define BIO_F_FILE_CTRL					 116
+#define BIO_F_FILE_READ					 130
+#define BIO_F_LINEBUFFER_CTRL				 129
+#define BIO_F_MEM_READ					 128
+#define BIO_F_MEM_WRITE					 117
+#define BIO_F_SSL_NEW					 118
+#define BIO_F_WSASTARTUP				 119
+
+/* Reason codes. */
+#define BIO_R_ACCEPT_ERROR				 100
+#define BIO_R_BAD_FOPEN_MODE				 101
+#define BIO_R_BAD_HOSTNAME_LOOKUP			 102
+#define BIO_R_BROKEN_PIPE				 124
+#define BIO_R_CONNECT_ERROR				 103
+#define BIO_R_EOF_ON_MEMORY_BIO				 127
+#define BIO_R_ERROR_SETTING_NBIO			 104
+#define BIO_R_ERROR_SETTING_NBIO_ON_ACCEPTED_SOCKET	 105
+#define BIO_R_ERROR_SETTING_NBIO_ON_ACCEPT_SOCKET	 106
+#define BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET		 107
+#define BIO_R_INVALID_ARGUMENT				 125
+#define BIO_R_INVALID_IP_ADDRESS			 108
+#define BIO_R_IN_USE					 123
+#define BIO_R_KEEPALIVE					 109
+#define BIO_R_NBIO_CONNECT_ERROR			 110
+#define BIO_R_NO_ACCEPT_PORT_SPECIFIED			 111
+#define BIO_R_NO_HOSTNAME_SPECIFIED			 112
+#define BIO_R_NO_PORT_DEFINED				 113
+#define BIO_R_NO_PORT_SPECIFIED				 114
+#define BIO_R_NO_SUCH_FILE				 128
+#define BIO_R_NULL_PARAMETER				 115
+#define BIO_R_TAG_MISMATCH				 116
+#define BIO_R_UNABLE_TO_BIND_SOCKET			 117
+#define BIO_R_UNABLE_TO_CREATE_SOCKET			 118
+#define BIO_R_UNABLE_TO_LISTEN_SOCKET			 119
+#define BIO_R_UNINITIALIZED				 120
+#define BIO_R_UNSUPPORTED_METHOD			 121
+#define BIO_R_WRITE_TO_READ_ONLY_BIO			 126
+#define BIO_R_WSASTARTUP				 122
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/blowfish.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/blowfish.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/blowfish.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,127 @@
+/* crypto/bf/blowfish.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_BLOWFISH_H
+#define HEADER_BLOWFISH_H
+
+#include <openssl/e_os2.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_NO_BF
+#error BF is disabled.
+#endif
+
+#define BF_ENCRYPT	1
+#define BF_DECRYPT	0
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! BF_LONG has to be at least 32 bits wide. If it's wider, then !
+ * ! BF_LONG_LOG2 has to be defined along.                        !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__)
+#define BF_LONG unsigned long
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
+#define BF_LONG unsigned long
+#define BF_LONG_LOG2 3
+/*
+ * _CRAY note. I could declare short, but I have no idea what impact
+ * does it have on performance on none-T3E machines. I could declare
+ * int, but at least on C90 sizeof(int) can be chosen at compile time.
+ * So I've chosen long...
+ *					<appro@fy.chalmers.se>
+ */
+#else
+#define BF_LONG unsigned int
+#endif
+
+#define BF_ROUNDS	16
+#define BF_BLOCK	8
+
+typedef struct bf_key_st
+	{
+	BF_LONG P[BF_ROUNDS+2];
+	BF_LONG S[4*256];
+	} BF_KEY;
+
+ 
+void BF_set_key(BF_KEY *key, int len, const unsigned char *data);
+
+void BF_encrypt(BF_LONG *data,const BF_KEY *key);
+void BF_decrypt(BF_LONG *data,const BF_KEY *key);
+
+void BF_ecb_encrypt(const unsigned char *in, unsigned char *out,
+	const BF_KEY *key, int enc);
+void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
+	const BF_KEY *schedule, unsigned char *ivec, int enc);
+void BF_cfb64_encrypt(const unsigned char *in, unsigned char *out, long length,
+	const BF_KEY *schedule, unsigned char *ivec, int *num, int enc);
+void BF_ofb64_encrypt(const unsigned char *in, unsigned char *out, long length,
+	const BF_KEY *schedule, unsigned char *ivec, int *num);
+const char *BF_options(void);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/bn.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/bn.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/bn.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,807 @@
+/* crypto/bn/bn.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by 
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the Eric Young open source
+ * license provided above.
+ *
+ * The binary polynomial arithmetic software is originally written by 
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
+ *
+ */
+
+#ifndef HEADER_BN_H
+#define HEADER_BN_H
+
+#include <openssl/e_os2.h>
+#ifndef OPENSSL_NO_FP_API
+#include <stdio.h> /* FILE */
+#endif
+#include <openssl/ossl_typ.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* These preprocessor symbols control various aspects of the bignum headers and
+ * library code. They're not defined by any "normal" configuration, as they are
+ * intended for development and testing purposes. NB: defining all three can be
+ * useful for debugging application code as well as openssl itself.
+ *
+ * BN_DEBUG - turn on various debugging alterations to the bignum code
+ * BN_DEBUG_RAND - uses random poisoning of unused words to trip up
+ * mismanagement of bignum internals. You must also define BN_DEBUG.
+ */
+/* #define BN_DEBUG */
+/* #define BN_DEBUG_RAND */
+
+#define BN_MUL_COMBA
+#define BN_SQR_COMBA
+#define BN_RECURSION
+
+/* This next option uses the C libraries (2 word)/(1 word) function.
+ * If it is not defined, I use my C version (which is slower).
+ * The reason for this flag is that when the particular C compiler
+ * library routine is used, and the library is linked with a different
+ * compiler, the library is missing.  This mostly happens when the
+ * library is built with gcc and then linked using normal cc.  This would
+ * be a common occurrence because gcc normally produces code that is
+ * 2 times faster than system compilers for the big number stuff.
+ * For machines with only one compiler (or shared libraries), this should
+ * be on.  Again this in only really a problem on machines
+ * using "long long's", are 32bit, and are not using my assembler code. */
+#if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) || \
+    defined(OPENSSL_SYS_WIN32) || defined(linux)
+# ifndef BN_DIV2W
+#  define BN_DIV2W
+# endif
+#endif
+
+/* assuming long is 64bit - this is the DEC Alpha
+ * unsigned long long is only 64 bits :-(, don't define
+ * BN_LLONG for the DEC Alpha */
+#ifdef SIXTY_FOUR_BIT_LONG
+#define BN_ULLONG	unsigned long long
+#define BN_ULONG	unsigned long
+#define BN_LONG		long
+#define BN_BITS		128
+#define BN_BYTES	8
+#define BN_BITS2	64
+#define BN_BITS4	32
+#define BN_MASK		(0xffffffffffffffffffffffffffffffffLL)
+#define BN_MASK2	(0xffffffffffffffffL)
+#define BN_MASK2l	(0xffffffffL)
+#define BN_MASK2h	(0xffffffff00000000L)
+#define BN_MASK2h1	(0xffffffff80000000L)
+#define BN_TBIT		(0x8000000000000000L)
+#define BN_DEC_CONV	(10000000000000000000UL)
+#define BN_DEC_FMT1	"%lu"
+#define BN_DEC_FMT2	"%019lu"
+#define BN_DEC_NUM	19
+#endif
+
+/* This is where the long long data type is 64 bits, but long is 32.
+ * For machines where there are 64bit registers, this is the mode to use.
+ * IRIX, on R4000 and above should use this mode, along with the relevant
+ * assembler code :-).  Do NOT define BN_LLONG.
+ */
+#ifdef SIXTY_FOUR_BIT
+#undef BN_LLONG
+#undef BN_ULLONG
+#define BN_ULONG	unsigned long long
+#define BN_LONG		long long
+#define BN_BITS		128
+#define BN_BYTES	8
+#define BN_BITS2	64
+#define BN_BITS4	32
+#define BN_MASK2	(0xffffffffffffffffLL)
+#define BN_MASK2l	(0xffffffffL)
+#define BN_MASK2h	(0xffffffff00000000LL)
+#define BN_MASK2h1	(0xffffffff80000000LL)
+#define BN_TBIT		(0x8000000000000000LL)
+#define BN_DEC_CONV	(10000000000000000000ULL)
+#define BN_DEC_FMT1	"%llu"
+#define BN_DEC_FMT2	"%019llu"
+#define BN_DEC_NUM	19
+#endif
+
+#ifdef THIRTY_TWO_BIT
+#ifdef BN_LLONG
+# if defined(OPENSSL_SYS_WIN32) && !defined(__GNUC__)
+#  define BN_ULLONG	unsigned __int64
+# else
+#  define BN_ULLONG	unsigned long long
+# endif
+#endif
+#define BN_ULONG	unsigned long
+#define BN_LONG		long
+#define BN_BITS		64
+#define BN_BYTES	4
+#define BN_BITS2	32
+#define BN_BITS4	16
+#ifdef OPENSSL_SYS_WIN32
+/* VC++ doesn't like the LL suffix */
+#define BN_MASK		(0xffffffffffffffffL)
+#else
+#define BN_MASK		(0xffffffffffffffffLL)
+#endif
+#define BN_MASK2	(0xffffffffL)
+#define BN_MASK2l	(0xffff)
+#define BN_MASK2h1	(0xffff8000L)
+#define BN_MASK2h	(0xffff0000L)
+#define BN_TBIT		(0x80000000L)
+#define BN_DEC_CONV	(1000000000L)
+#define BN_DEC_FMT1	"%lu"
+#define BN_DEC_FMT2	"%09lu"
+#define BN_DEC_NUM	9
+#endif
+
+#ifdef SIXTEEN_BIT
+#ifndef BN_DIV2W
+#define BN_DIV2W
+#endif
+#define BN_ULLONG	unsigned long
+#define BN_ULONG	unsigned short
+#define BN_LONG		short
+#define BN_BITS		32
+#define BN_BYTES	2
+#define BN_BITS2	16
+#define BN_BITS4	8
+#define BN_MASK		(0xffffffff)
+#define BN_MASK2	(0xffff)
+#define BN_MASK2l	(0xff)
+#define BN_MASK2h1	(0xff80)
+#define BN_MASK2h	(0xff00)
+#define BN_TBIT		(0x8000)
+#define BN_DEC_CONV	(100000)
+#define BN_DEC_FMT1	"%u"
+#define BN_DEC_FMT2	"%05u"
+#define BN_DEC_NUM	5
+#endif
+
+#ifdef EIGHT_BIT
+#ifndef BN_DIV2W
+#define BN_DIV2W
+#endif
+#define BN_ULLONG	unsigned short
+#define BN_ULONG	unsigned char
+#define BN_LONG		char
+#define BN_BITS		16
+#define BN_BYTES	1
+#define BN_BITS2	8
+#define BN_BITS4	4
+#define BN_MASK		(0xffff)
+#define BN_MASK2	(0xff)
+#define BN_MASK2l	(0xf)
+#define BN_MASK2h1	(0xf8)
+#define BN_MASK2h	(0xf0)
+#define BN_TBIT		(0x80)
+#define BN_DEC_CONV	(100)
+#define BN_DEC_FMT1	"%u"
+#define BN_DEC_FMT2	"%02u"
+#define BN_DEC_NUM	2
+#endif
+
+#define BN_DEFAULT_BITS	1280
+
+#define BN_FLG_MALLOCED		0x01
+#define BN_FLG_STATIC_DATA	0x02
+#define BN_FLG_EXP_CONSTTIME	0x04 /* avoid leaking exponent information through timings
+                            	      * (BN_mod_exp_mont() will call BN_mod_exp_mont_consttime) */
+#ifndef OPENSSL_NO_DEPRECATED
+#define BN_FLG_FREE		0x8000	/* used for debuging */
+#endif
+#define BN_set_flags(b,n)	((b)->flags|=(n))
+#define BN_get_flags(b,n)	((b)->flags&(n))
+
+/* get a clone of a BIGNUM with changed flags, for *temporary* use only
+ * (the two BIGNUMs cannot not be used in parallel!) */
+#define BN_with_flags(dest,b,n)  ((dest)->d=(b)->d, \
+                                  (dest)->top=(b)->top, \
+                                  (dest)->dmax=(b)->dmax, \
+                                  (dest)->neg=(b)->neg, \
+                                  (dest)->flags=(((dest)->flags & BN_FLG_MALLOCED) \
+                                                 |  ((b)->flags & ~BN_FLG_MALLOCED) \
+                                                 |  BN_FLG_STATIC_DATA \
+                                                 |  (n)))
+
+/* Already declared in ossl_typ.h */
+#if 0
+typedef struct bignum_st BIGNUM;
+/* Used for temp variables (declaration hidden in bn_lcl.h) */
+typedef struct bignum_ctx BN_CTX;
+typedef struct bn_blinding_st BN_BLINDING;
+typedef struct bn_mont_ctx_st BN_MONT_CTX;
+typedef struct bn_recp_ctx_st BN_RECP_CTX;
+typedef struct bn_gencb_st BN_GENCB;
+#endif
+
+struct bignum_st
+	{
+	BN_ULONG *d;	/* Pointer to an array of 'BN_BITS2' bit chunks. */
+	int top;	/* Index of last used d +1. */
+	/* The next are internal book keeping for bn_expand. */
+	int dmax;	/* Size of the d array. */
+	int neg;	/* one if the number is negative */
+	int flags;
+	};
+
+/* Used for montgomery multiplication */
+struct bn_mont_ctx_st
+	{
+	int ri;        /* number of bits in R */
+	BIGNUM RR;     /* used to convert to montgomery form */
+	BIGNUM N;      /* The modulus */
+	BIGNUM Ni;     /* R*(1/R mod N) - N*Ni = 1
+	                * (Ni is only stored for bignum algorithm) */
+	BN_ULONG n0;   /* least significant word of Ni */
+	int flags;
+	};
+
+/* Used for reciprocal division/mod functions
+ * It cannot be shared between threads
+ */
+struct bn_recp_ctx_st
+	{
+	BIGNUM N;	/* the divisor */
+	BIGNUM Nr;	/* the reciprocal */
+	int num_bits;
+	int shift;
+	int flags;
+	};
+
+/* Used for slow "generation" functions. */
+struct bn_gencb_st
+	{
+	unsigned int ver;	/* To handle binary (in)compatibility */
+	void *arg;		/* callback-specific data */
+	union
+		{
+		/* if(ver==1) - handles old style callbacks */
+		void (*cb_1)(int, int, void *);
+		/* if(ver==2) - new callback style */
+		int (*cb_2)(int, int, BN_GENCB *);
+		} cb;
+	};
+/* Wrapper function to make using BN_GENCB easier,  */
+int BN_GENCB_call(BN_GENCB *cb, int a, int b);
+/* Macro to populate a BN_GENCB structure with an "old"-style callback */
+#define BN_GENCB_set_old(gencb, callback, cb_arg) { \
+		BN_GENCB *tmp_gencb = (gencb); \
+		tmp_gencb->ver = 1; \
+		tmp_gencb->arg = (cb_arg); \
+		tmp_gencb->cb.cb_1 = (callback); }
+/* Macro to populate a BN_GENCB structure with a "new"-style callback */
+#define BN_GENCB_set(gencb, callback, cb_arg) { \
+		BN_GENCB *tmp_gencb = (gencb); \
+		tmp_gencb->ver = 2; \
+		tmp_gencb->arg = (cb_arg); \
+		tmp_gencb->cb.cb_2 = (callback); }
+
+#define BN_prime_checks 0 /* default: select number of iterations
+			     based on the size of the number */
+
+/* number of Miller-Rabin iterations for an error rate  of less than 2^-80
+ * for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook
+ * of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996];
+ * original paper: Damgaard, Landrock, Pomerance: Average case error estimates
+ * for the strong probable prime test. -- Math. Comp. 61 (1993) 177-194) */
+#define BN_prime_checks_for_size(b) ((b) >= 1300 ?  2 : \
+                                (b) >=  850 ?  3 : \
+                                (b) >=  650 ?  4 : \
+                                (b) >=  550 ?  5 : \
+                                (b) >=  450 ?  6 : \
+                                (b) >=  400 ?  7 : \
+                                (b) >=  350 ?  8 : \
+                                (b) >=  300 ?  9 : \
+                                (b) >=  250 ? 12 : \
+                                (b) >=  200 ? 15 : \
+                                (b) >=  150 ? 18 : \
+                                /* b >= 100 */ 27)
+
+#define BN_num_bytes(a)	((BN_num_bits(a)+7)/8)
+
+/* Note that BN_abs_is_word didn't work reliably for w == 0 until 0.9.8 */
+#define BN_abs_is_word(a,w) ((((a)->top == 1) && ((a)->d[0] == (BN_ULONG)(w))) || \
+				(((w) == 0) && ((a)->top == 0)))
+#define BN_is_zero(a)       ((a)->top == 0)
+#define BN_is_one(a)        (BN_abs_is_word((a),1) && !(a)->neg)
+#define BN_is_word(a,w)     (BN_abs_is_word((a),(w)) && (!(w) || !(a)->neg))
+#define BN_is_odd(a)	    (((a)->top > 0) && ((a)->d[0] & 1))
+
+#define BN_one(a)	(BN_set_word((a),1))
+#define BN_zero_ex(a) \
+	do { \
+		BIGNUM *_tmp_bn = (a); \
+		_tmp_bn->top = 0; \
+		_tmp_bn->neg = 0; \
+	} while(0)
+#ifdef OPENSSL_NO_DEPRECATED
+#define BN_zero(a)	BN_zero_ex(a)
+#else
+#define BN_zero(a)	(BN_set_word((a),0))
+#endif
+
+const BIGNUM *BN_value_one(void);
+char *	BN_options(void);
+BN_CTX *BN_CTX_new(void);
+#ifndef OPENSSL_NO_DEPRECATED
+void	BN_CTX_init(BN_CTX *c);
+#endif
+void	BN_CTX_free(BN_CTX *c);
+void	BN_CTX_start(BN_CTX *ctx);
+BIGNUM *BN_CTX_get(BN_CTX *ctx);
+void	BN_CTX_end(BN_CTX *ctx);
+int     BN_rand(BIGNUM *rnd, int bits, int top,int bottom);
+int     BN_pseudo_rand(BIGNUM *rnd, int bits, int top,int bottom);
+int	BN_rand_range(BIGNUM *rnd, BIGNUM *range);
+int	BN_pseudo_rand_range(BIGNUM *rnd, BIGNUM *range);
+int	BN_num_bits(const BIGNUM *a);
+int	BN_num_bits_word(BN_ULONG);
+BIGNUM *BN_new(void);
+void	BN_init(BIGNUM *);
+void	BN_clear_free(BIGNUM *a);
+BIGNUM *BN_copy(BIGNUM *a, const BIGNUM *b);
+void	BN_swap(BIGNUM *a, BIGNUM *b);
+BIGNUM *BN_bin2bn(const unsigned char *s,int len,BIGNUM *ret);
+int	BN_bn2bin(const BIGNUM *a, unsigned char *to);
+BIGNUM *BN_mpi2bn(const unsigned char *s,int len,BIGNUM *ret);
+int	BN_bn2mpi(const BIGNUM *a, unsigned char *to);
+int	BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int	BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int	BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int	BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b);
+int	BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
+int	BN_sqr(BIGNUM *r, const BIGNUM *a,BN_CTX *ctx);
+/* BN_set_negative(): sets sign of a bignum */
+void	BN_set_negative(BIGNUM *b, int n);
+/* BN_get_negative():  returns 1 if the bignum is < 0 and 0 otherwise */
+#define BN_is_negative(a) ((a)->neg != 0)
+
+int	BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
+	BN_CTX *ctx);
+#define BN_mod(rem,m,d,ctx) BN_div(NULL,(rem),(m),(d),(ctx))
+int	BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx);
+int	BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+int	BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m);
+int	BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, BN_CTX *ctx);
+int	BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m);
+int	BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+	const BIGNUM *m, BN_CTX *ctx);
+int	BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+int	BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx);
+int	BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m);
+int	BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m, BN_CTX *ctx);
+int	BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m);
+
+BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w);
+BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w);
+int	BN_mul_word(BIGNUM *a, BN_ULONG w);
+int	BN_add_word(BIGNUM *a, BN_ULONG w);
+int	BN_sub_word(BIGNUM *a, BN_ULONG w);
+int	BN_set_word(BIGNUM *a, BN_ULONG w);
+BN_ULONG BN_get_word(const BIGNUM *a);
+
+int	BN_cmp(const BIGNUM *a, const BIGNUM *b);
+void	BN_free(BIGNUM *a);
+int	BN_is_bit_set(const BIGNUM *a, int n);
+int	BN_lshift(BIGNUM *r, const BIGNUM *a, int n);
+int	BN_lshift1(BIGNUM *r, const BIGNUM *a);
+int	BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,BN_CTX *ctx);
+
+int	BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	const BIGNUM *m,BN_CTX *ctx);
+int	BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
+	const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont);
+int	BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p,
+	const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx);
+int	BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, const BIGNUM *p1,
+	const BIGNUM *a2, const BIGNUM *p2,const BIGNUM *m,
+	BN_CTX *ctx,BN_MONT_CTX *m_ctx);
+int	BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	const BIGNUM *m,BN_CTX *ctx);
+
+int	BN_mask_bits(BIGNUM *a,int n);
+#ifndef OPENSSL_NO_FP_API
+int	BN_print_fp(FILE *fp, const BIGNUM *a);
+#endif
+#ifdef HEADER_BIO_H
+int	BN_print(BIO *fp, const BIGNUM *a);
+#else
+int	BN_print(void *fp, const BIGNUM *a);
+#endif
+int	BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx);
+int	BN_rshift(BIGNUM *r, const BIGNUM *a, int n);
+int	BN_rshift1(BIGNUM *r, const BIGNUM *a);
+void	BN_clear(BIGNUM *a);
+BIGNUM *BN_dup(const BIGNUM *a);
+int	BN_ucmp(const BIGNUM *a, const BIGNUM *b);
+int	BN_set_bit(BIGNUM *a, int n);
+int	BN_clear_bit(BIGNUM *a, int n);
+char *	BN_bn2hex(const BIGNUM *a);
+char *	BN_bn2dec(const BIGNUM *a);
+int 	BN_hex2bn(BIGNUM **a, const char *str);
+int 	BN_dec2bn(BIGNUM **a, const char *str);
+int	BN_gcd(BIGNUM *r,const BIGNUM *a,const BIGNUM *b,BN_CTX *ctx);
+int	BN_kronecker(const BIGNUM *a,const BIGNUM *b,BN_CTX *ctx); /* returns -2 for error */
+BIGNUM *BN_mod_inverse(BIGNUM *ret,
+	const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
+BIGNUM *BN_mod_sqrt(BIGNUM *ret,
+	const BIGNUM *a, const BIGNUM *n,BN_CTX *ctx);
+
+/* Deprecated versions */
+#ifndef OPENSSL_NO_DEPRECATED
+BIGNUM *BN_generate_prime(BIGNUM *ret,int bits,int safe,
+	const BIGNUM *add, const BIGNUM *rem,
+	void (*callback)(int,int,void *),void *cb_arg);
+int	BN_is_prime(const BIGNUM *p,int nchecks,
+	void (*callback)(int,int,void *),
+	BN_CTX *ctx,void *cb_arg);
+int	BN_is_prime_fasttest(const BIGNUM *p,int nchecks,
+	void (*callback)(int,int,void *),BN_CTX *ctx,void *cb_arg,
+	int do_trial_division);
+#endif /* !defined(OPENSSL_NO_DEPRECATED) */
+
+/* Newer versions */
+int	BN_generate_prime_ex(BIGNUM *ret,int bits,int safe, const BIGNUM *add,
+		const BIGNUM *rem, BN_GENCB *cb);
+int	BN_is_prime_ex(const BIGNUM *p,int nchecks, BN_CTX *ctx, BN_GENCB *cb);
+int	BN_is_prime_fasttest_ex(const BIGNUM *p,int nchecks, BN_CTX *ctx,
+		int do_trial_division, BN_GENCB *cb);
+
+BN_MONT_CTX *BN_MONT_CTX_new(void );
+void BN_MONT_CTX_init(BN_MONT_CTX *ctx);
+int BN_mod_mul_montgomery(BIGNUM *r,const BIGNUM *a,const BIGNUM *b,
+	BN_MONT_CTX *mont, BN_CTX *ctx);
+#define BN_to_montgomery(r,a,mont,ctx)	BN_mod_mul_montgomery(\
+	(r),(a),&((mont)->RR),(mont),(ctx))
+int BN_from_montgomery(BIGNUM *r,const BIGNUM *a,
+	BN_MONT_CTX *mont, BN_CTX *ctx);
+void BN_MONT_CTX_free(BN_MONT_CTX *mont);
+int BN_MONT_CTX_set(BN_MONT_CTX *mont,const BIGNUM *mod,BN_CTX *ctx);
+BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to,BN_MONT_CTX *from);
+BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, int lock,
+					const BIGNUM *mod, BN_CTX *ctx);
+
+/* BN_BLINDING flags */
+#define	BN_BLINDING_NO_UPDATE	0x00000001
+#define	BN_BLINDING_NO_RECREATE	0x00000002
+
+BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod);
+void BN_BLINDING_free(BN_BLINDING *b);
+int BN_BLINDING_update(BN_BLINDING *b,BN_CTX *ctx);
+int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx);
+int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *);
+int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *);
+unsigned long BN_BLINDING_get_thread_id(const BN_BLINDING *);
+void BN_BLINDING_set_thread_id(BN_BLINDING *, unsigned long);
+unsigned long BN_BLINDING_get_flags(const BN_BLINDING *);
+void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long);
+BN_BLINDING *BN_BLINDING_create_param(BN_BLINDING *b,
+	const BIGNUM *e, BIGNUM *m, BN_CTX *ctx,
+	int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+			  const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx),
+	BN_MONT_CTX *m_ctx);
+
+#ifndef OPENSSL_NO_DEPRECATED
+void BN_set_params(int mul,int high,int low,int mont);
+int BN_get_params(int which); /* 0, mul, 1 high, 2 low, 3 mont */
+#endif
+
+void	BN_RECP_CTX_init(BN_RECP_CTX *recp);
+BN_RECP_CTX *BN_RECP_CTX_new(void);
+void	BN_RECP_CTX_free(BN_RECP_CTX *recp);
+int	BN_RECP_CTX_set(BN_RECP_CTX *recp,const BIGNUM *rdiv,BN_CTX *ctx);
+int	BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y,
+	BN_RECP_CTX *recp,BN_CTX *ctx);
+int	BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	const BIGNUM *m, BN_CTX *ctx);
+int	BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m,
+	BN_RECP_CTX *recp, BN_CTX *ctx);
+
+/* Functions for arithmetic over binary polynomials represented by BIGNUMs. 
+ *
+ * The BIGNUM::neg property of BIGNUMs representing binary polynomials is
+ * ignored.
+ *
+ * Note that input arguments are not const so that their bit arrays can
+ * be expanded to the appropriate size if needed.
+ */
+
+int	BN_GF2m_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); /*r = a + b*/
+#define BN_GF2m_sub(r, a, b) BN_GF2m_add(r, a, b)
+int	BN_GF2m_mod(BIGNUM *r, const BIGNUM *a, const BIGNUM *p); /*r=a mod p*/
+int	BN_GF2m_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+	const BIGNUM *p, BN_CTX *ctx); /* r = (a * b) mod p */
+int	BN_GF2m_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	BN_CTX *ctx); /* r = (a * a) mod p */
+int	BN_GF2m_mod_inv(BIGNUM *r, const BIGNUM *b, const BIGNUM *p,
+	BN_CTX *ctx); /* r = (1 / b) mod p */
+int	BN_GF2m_mod_div(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+	const BIGNUM *p, BN_CTX *ctx); /* r = (a / b) mod p */
+int	BN_GF2m_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+	const BIGNUM *p, BN_CTX *ctx); /* r = (a ^ b) mod p */
+int	BN_GF2m_mod_sqrt(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	BN_CTX *ctx); /* r = sqrt(a) mod p */
+int	BN_GF2m_mod_solve_quad(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+	BN_CTX *ctx); /* r^2 + r = a mod p */
+#define BN_GF2m_cmp(a, b) BN_ucmp((a), (b))
+/* Some functions allow for representation of the irreducible polynomials
+ * as an unsigned int[], say p.  The irreducible f(t) is then of the form:
+ *     t^p[0] + t^p[1] + ... + t^p[k]
+ * where m = p[0] > p[1] > ... > p[k] = 0.
+ */
+int	BN_GF2m_mod_arr(BIGNUM *r, const BIGNUM *a, const unsigned int p[]);
+	/* r = a mod p */
+int	BN_GF2m_mod_mul_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+	const unsigned int p[], BN_CTX *ctx); /* r = (a * b) mod p */
+int	BN_GF2m_mod_sqr_arr(BIGNUM *r, const BIGNUM *a, const unsigned int p[],
+	BN_CTX *ctx); /* r = (a * a) mod p */
+int	BN_GF2m_mod_inv_arr(BIGNUM *r, const BIGNUM *b, const unsigned int p[],
+	BN_CTX *ctx); /* r = (1 / b) mod p */
+int	BN_GF2m_mod_div_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+	const unsigned int p[], BN_CTX *ctx); /* r = (a / b) mod p */
+int	BN_GF2m_mod_exp_arr(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
+	const unsigned int p[], BN_CTX *ctx); /* r = (a ^ b) mod p */
+int	BN_GF2m_mod_sqrt_arr(BIGNUM *r, const BIGNUM *a,
+	const unsigned int p[], BN_CTX *ctx); /* r = sqrt(a) mod p */
+int	BN_GF2m_mod_solve_quad_arr(BIGNUM *r, const BIGNUM *a,
+	const unsigned int p[], BN_CTX *ctx); /* r^2 + r = a mod p */
+int	BN_GF2m_poly2arr(const BIGNUM *a, unsigned int p[], int max);
+int	BN_GF2m_arr2poly(const unsigned int p[], BIGNUM *a);
+
+/* faster mod functions for the 'NIST primes' 
+ * 0 <= a < p^2 */
+int BN_nist_mod_192(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+int BN_nist_mod_224(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+int BN_nist_mod_256(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+int BN_nist_mod_384(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+int BN_nist_mod_521(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx);
+
+const BIGNUM *BN_get0_nist_prime_192(void);
+const BIGNUM *BN_get0_nist_prime_224(void);
+const BIGNUM *BN_get0_nist_prime_256(void);
+const BIGNUM *BN_get0_nist_prime_384(void);
+const BIGNUM *BN_get0_nist_prime_521(void);
+
+/* library internal functions */
+
+#define bn_expand(a,bits) ((((((bits+BN_BITS2-1))/BN_BITS2)) <= (a)->dmax)?\
+	(a):bn_expand2((a),(bits+BN_BITS2-1)/BN_BITS2))
+#define bn_wexpand(a,words) (((words) <= (a)->dmax)?(a):bn_expand2((a),(words)))
+BIGNUM *bn_expand2(BIGNUM *a, int words);
+#ifndef OPENSSL_NO_DEPRECATED
+BIGNUM *bn_dup_expand(const BIGNUM *a, int words); /* unused */
+#endif
+
+/* Bignum consistency macros
+ * There is one "API" macro, bn_fix_top(), for stripping leading zeroes from
+ * bignum data after direct manipulations on the data. There is also an
+ * "internal" macro, bn_check_top(), for verifying that there are no leading
+ * zeroes. Unfortunately, some auditing is required due to the fact that
+ * bn_fix_top() has become an overabused duct-tape because bignum data is
+ * occasionally passed around in an inconsistent state. So the following
+ * changes have been made to sort this out;
+ * - bn_fix_top()s implementation has been moved to bn_correct_top()
+ * - if BN_DEBUG isn't defined, bn_fix_top() maps to bn_correct_top(), and
+ *   bn_check_top() is as before.
+ * - if BN_DEBUG *is* defined;
+ *   - bn_check_top() tries to pollute unused words even if the bignum 'top' is
+ *     consistent. (ed: only if BN_DEBUG_RAND is defined)
+ *   - bn_fix_top() maps to bn_check_top() rather than "fixing" anything.
+ * The idea is to have debug builds flag up inconsistent bignums when they
+ * occur. If that occurs in a bn_fix_top(), we examine the code in question; if
+ * the use of bn_fix_top() was appropriate (ie. it follows directly after code
+ * that manipulates the bignum) it is converted to bn_correct_top(), and if it
+ * was not appropriate, we convert it permanently to bn_check_top() and track
+ * down the cause of the bug. Eventually, no internal code should be using the
+ * bn_fix_top() macro. External applications and libraries should try this with
+ * their own code too, both in terms of building against the openssl headers
+ * with BN_DEBUG defined *and* linking with a version of OpenSSL built with it
+ * defined. This not only improves external code, it provides more test
+ * coverage for openssl's own code.
+ */
+
+#ifdef BN_DEBUG
+
+/* We only need assert() when debugging */
+#include <assert.h>
+
+#ifdef BN_DEBUG_RAND
+/* To avoid "make update" cvs wars due to BN_DEBUG, use some tricks */
+#ifndef RAND_pseudo_bytes
+int RAND_pseudo_bytes(unsigned char *buf,int num);
+#define BN_DEBUG_TRIX
+#endif
+#define bn_pollute(a) \
+	do { \
+		const BIGNUM *_bnum1 = (a); \
+		if(_bnum1->top < _bnum1->dmax) { \
+			unsigned char _tmp_char; \
+			/* We cast away const without the compiler knowing, any \
+			 * *genuinely* constant variables that aren't mutable \
+			 * wouldn't be constructed with top!=dmax. */ \
+			BN_ULONG *_not_const; \
+			memcpy(&_not_const, &_bnum1->d, sizeof(BN_ULONG*)); \
+			RAND_pseudo_bytes(&_tmp_char, 1); \
+			memset((unsigned char *)(_not_const + _bnum1->top), _tmp_char, \
+				(_bnum1->dmax - _bnum1->top) * sizeof(BN_ULONG)); \
+		} \
+	} while(0)
+#ifdef BN_DEBUG_TRIX
+#undef RAND_pseudo_bytes
+#endif
+#else
+#define bn_pollute(a)
+#endif
+#define bn_check_top(a) \
+	do { \
+		const BIGNUM *_bnum2 = (a); \
+		assert((_bnum2->top == 0) || \
+				(_bnum2->d[_bnum2->top - 1] != 0)); \
+		bn_pollute(_bnum2); \
+	} while(0)
+
+#define bn_fix_top(a)		bn_check_top(a)
+
+#else /* !BN_DEBUG */
+
+#define bn_pollute(a)
+#define bn_check_top(a)
+#define bn_fix_top(a)		bn_correct_top(a)
+
+#endif
+
+#define bn_correct_top(a) \
+        { \
+        BN_ULONG *ftl; \
+	if ((a)->top > 0) \
+		{ \
+		for (ftl= &((a)->d[(a)->top-1]); (a)->top > 0; (a)->top--) \
+		if (*(ftl--)) break; \
+		} \
+	bn_pollute(a); \
+	}
+
+BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
+BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w);
+void     bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num);
+BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d);
+BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
+BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num);
+
+int BN_bntest_rand(BIGNUM *rnd, int bits, int top,int bottom);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_BN_strings(void);
+
+/* Error codes for the BN functions. */
+
+/* Function codes. */
+#define BN_F_BNRAND					 127
+#define BN_F_BN_BLINDING_CONVERT_EX			 100
+#define BN_F_BN_BLINDING_CREATE_PARAM			 128
+#define BN_F_BN_BLINDING_INVERT_EX			 101
+#define BN_F_BN_BLINDING_NEW				 102
+#define BN_F_BN_BLINDING_UPDATE				 103
+#define BN_F_BN_BN2DEC					 104
+#define BN_F_BN_BN2HEX					 105
+#define BN_F_BN_CTX_GET					 116
+#define BN_F_BN_CTX_NEW					 106
+#define BN_F_BN_CTX_START				 129
+#define BN_F_BN_DIV					 107
+#define BN_F_BN_DIV_RECP				 130
+#define BN_F_BN_EXP					 123
+#define BN_F_BN_EXPAND2					 108
+#define BN_F_BN_EXPAND_INTERNAL				 120
+#define BN_F_BN_GF2M_MOD				 131
+#define BN_F_BN_GF2M_MOD_EXP				 132
+#define BN_F_BN_GF2M_MOD_MUL				 133
+#define BN_F_BN_GF2M_MOD_SOLVE_QUAD			 134
+#define BN_F_BN_GF2M_MOD_SOLVE_QUAD_ARR			 135
+#define BN_F_BN_GF2M_MOD_SQR				 136
+#define BN_F_BN_GF2M_MOD_SQRT				 137
+#define BN_F_BN_MOD_EXP2_MONT				 118
+#define BN_F_BN_MOD_EXP_MONT				 109
+#define BN_F_BN_MOD_EXP_MONT_CONSTTIME			 124
+#define BN_F_BN_MOD_EXP_MONT_WORD			 117
+#define BN_F_BN_MOD_EXP_RECP				 125
+#define BN_F_BN_MOD_EXP_SIMPLE				 126
+#define BN_F_BN_MOD_INVERSE				 110
+#define BN_F_BN_MOD_LSHIFT_QUICK			 119
+#define BN_F_BN_MOD_MUL_RECIPROCAL			 111
+#define BN_F_BN_MOD_SQRT				 121
+#define BN_F_BN_MPI2BN					 112
+#define BN_F_BN_NEW					 113
+#define BN_F_BN_RAND					 114
+#define BN_F_BN_RAND_RANGE				 122
+#define BN_F_BN_USUB					 115
+
+/* Reason codes. */
+#define BN_R_ARG2_LT_ARG3				 100
+#define BN_R_BAD_RECIPROCAL				 101
+#define BN_R_BIGNUM_TOO_LONG				 114
+#define BN_R_CALLED_WITH_EVEN_MODULUS			 102
+#define BN_R_DIV_BY_ZERO				 103
+#define BN_R_ENCODING_ERROR				 104
+#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA		 105
+#define BN_R_INPUT_NOT_REDUCED				 110
+#define BN_R_INVALID_LENGTH				 106
+#define BN_R_INVALID_RANGE				 115
+#define BN_R_NOT_A_SQUARE				 111
+#define BN_R_NOT_INITIALIZED				 107
+#define BN_R_NO_INVERSE					 108
+#define BN_R_NO_SOLUTION				 116
+#define BN_R_P_IS_NOT_PRIME				 112
+#define BN_R_TOO_MANY_ITERATIONS			 113
+#define BN_R_TOO_MANY_TEMPORARY_VARIABLES		 109
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/buffer.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/buffer.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/buffer.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,118 @@
+/* crypto/buffer/buffer.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_BUFFER_H
+#define HEADER_BUFFER_H
+
+#include <openssl/ossl_typ.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+#if !defined(NO_SYS_TYPES_H)
+#include <sys/types.h>
+#endif
+
+/* Already declared in ossl_typ.h */
+/* typedef struct buf_mem_st BUF_MEM; */
+
+struct buf_mem_st
+	{
+	int length;	/* current number of bytes */
+	char *data;
+	int max;	/* size of buffer */
+	};
+
+BUF_MEM *BUF_MEM_new(void);
+void	BUF_MEM_free(BUF_MEM *a);
+int	BUF_MEM_grow(BUF_MEM *str, int len);
+int	BUF_MEM_grow_clean(BUF_MEM *str, int len);
+char *	BUF_strdup(const char *str);
+char *	BUF_strndup(const char *str, size_t siz);
+void *	BUF_memdup(const void *data, size_t siz);
+
+/* safe string functions */
+size_t BUF_strlcpy(char *dst,const char *src,size_t siz);
+size_t BUF_strlcat(char *dst,const char *src,size_t siz);
+
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_BUF_strings(void);
+
+/* Error codes for the BUF functions. */
+
+/* Function codes. */
+#define BUF_F_BUF_MEMDUP				 103
+#define BUF_F_BUF_MEM_GROW				 100
+#define BUF_F_BUF_MEM_GROW_CLEAN			 105
+#define BUF_F_BUF_MEM_NEW				 101
+#define BUF_F_BUF_STRDUP				 102
+#define BUF_F_BUF_STRNDUP				 104
+
+/* Reason codes. */
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/cast.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/cast.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/cast.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,105 @@
+/* crypto/cast/cast.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_CAST_H
+#define HEADER_CAST_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_NO_CAST
+#error CAST is disabled.
+#endif
+
+#define CAST_ENCRYPT	1
+#define CAST_DECRYPT	0
+
+#define CAST_LONG unsigned long
+
+#define CAST_BLOCK	8
+#define CAST_KEY_LENGTH	16
+
+typedef struct cast_key_st
+	{
+	CAST_LONG data[32];
+	int short_key;	/* Use reduced rounds for short key */
+	} CAST_KEY;
+
+ 
+void CAST_set_key(CAST_KEY *key, int len, const unsigned char *data);
+void CAST_ecb_encrypt(const unsigned char *in,unsigned char *out,CAST_KEY *key,
+		      int enc);
+void CAST_encrypt(CAST_LONG *data,CAST_KEY *key);
+void CAST_decrypt(CAST_LONG *data,CAST_KEY *key);
+void CAST_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
+		      CAST_KEY *ks, unsigned char *iv, int enc);
+void CAST_cfb64_encrypt(const unsigned char *in, unsigned char *out,
+			long length, CAST_KEY *schedule, unsigned char *ivec,
+			int *num, int enc);
+void CAST_ofb64_encrypt(const unsigned char *in, unsigned char *out, 
+			long length, CAST_KEY *schedule, unsigned char *ivec,
+			int *num);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/comp.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/comp.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/comp.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,66 @@
+
+#ifndef HEADER_COMP_H
+#define HEADER_COMP_H
+
+#include <openssl/crypto.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct comp_ctx_st COMP_CTX;
+
+typedef struct comp_method_st
+	{
+	int type;		/* NID for compression library */
+	const char *name;	/* A text string to identify the library */
+	int (*init)(COMP_CTX *ctx);
+	void (*finish)(COMP_CTX *ctx);
+	int (*compress)(COMP_CTX *ctx,
+			unsigned char *out, unsigned int olen,
+			unsigned char *in, unsigned int ilen);
+	int (*expand)(COMP_CTX *ctx,
+		      unsigned char *out, unsigned int olen,
+		      unsigned char *in, unsigned int ilen);
+	/* The following two do NOTHING, but are kept for backward compatibility */
+	long (*ctrl)(void);
+	long (*callback_ctrl)(void);
+	} COMP_METHOD;
+
+struct comp_ctx_st
+	{
+	COMP_METHOD *meth;
+	unsigned long compress_in;
+	unsigned long compress_out;
+	unsigned long expand_in;
+	unsigned long expand_out;
+
+	CRYPTO_EX_DATA	ex_data;
+	};
+
+
+COMP_CTX *COMP_CTX_new(COMP_METHOD *meth);
+void COMP_CTX_free(COMP_CTX *ctx);
+int COMP_compress_block(COMP_CTX *ctx, unsigned char *out, int olen,
+	unsigned char *in, int ilen);
+int COMP_expand_block(COMP_CTX *ctx, unsigned char *out, int olen,
+	unsigned char *in, int ilen);
+COMP_METHOD *COMP_rle(void );
+COMP_METHOD *COMP_zlib(void );
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_COMP_strings(void);
+
+/* Error codes for the COMP functions. */
+
+/* Function codes. */
+
+/* Reason codes. */
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/conf.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/conf.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/conf.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,253 @@
+/* crypto/conf/conf.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef  HEADER_CONF_H
+#define HEADER_CONF_H
+
+#include <openssl/bio.h>
+#include <openssl/lhash.h>
+#include <openssl/stack.h>
+#include <openssl/safestack.h>
+#include <openssl/e_os2.h>
+
+#include <openssl/ossl_typ.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct
+	{
+	char *section;
+	char *name;
+	char *value;
+	} CONF_VALUE;
+
+DECLARE_STACK_OF(CONF_VALUE)
+DECLARE_STACK_OF(CONF_MODULE)
+DECLARE_STACK_OF(CONF_IMODULE)
+
+struct conf_st;
+struct conf_method_st;
+typedef struct conf_method_st CONF_METHOD;
+
+struct conf_method_st
+	{
+	const char *name;
+	CONF *(*create)(CONF_METHOD *meth);
+	int (*init)(CONF *conf);
+	int (*destroy)(CONF *conf);
+	int (*destroy_data)(CONF *conf);
+	int (*load_bio)(CONF *conf, BIO *bp, long *eline);
+	int (*dump)(const CONF *conf, BIO *bp);
+	int (*is_number)(const CONF *conf, char c);
+	int (*to_int)(const CONF *conf, char c);
+	int (*load)(CONF *conf, const char *name, long *eline);
+	};
+
+/* Module definitions */
+
+typedef struct conf_imodule_st CONF_IMODULE;
+typedef struct conf_module_st CONF_MODULE;
+
+/* DSO module function typedefs */
+typedef int conf_init_func(CONF_IMODULE *md, const CONF *cnf);
+typedef void conf_finish_func(CONF_IMODULE *md);
+
+#define	CONF_MFLAGS_IGNORE_ERRORS	0x1
+#define CONF_MFLAGS_IGNORE_RETURN_CODES	0x2
+#define CONF_MFLAGS_SILENT		0x4
+#define CONF_MFLAGS_NO_DSO		0x8
+#define CONF_MFLAGS_IGNORE_MISSING_FILE	0x10
+
+int CONF_set_default_method(CONF_METHOD *meth);
+void CONF_set_nconf(CONF *conf,LHASH *hash);
+LHASH *CONF_load(LHASH *conf,const char *file,long *eline);
+#ifndef OPENSSL_NO_FP_API
+LHASH *CONF_load_fp(LHASH *conf, FILE *fp,long *eline);
+#endif
+LHASH *CONF_load_bio(LHASH *conf, BIO *bp,long *eline);
+STACK_OF(CONF_VALUE) *CONF_get_section(LHASH *conf,const char *section);
+char *CONF_get_string(LHASH *conf,const char *group,const char *name);
+long CONF_get_number(LHASH *conf,const char *group,const char *name);
+void CONF_free(LHASH *conf);
+int CONF_dump_fp(LHASH *conf, FILE *out);
+int CONF_dump_bio(LHASH *conf, BIO *out);
+
+void OPENSSL_config(const char *config_name);
+void OPENSSL_no_config(void);
+
+/* New conf code.  The semantics are different from the functions above.
+   If that wasn't the case, the above functions would have been replaced */
+
+struct conf_st
+	{
+	CONF_METHOD *meth;
+	void *meth_data;
+	LHASH *data;
+	};
+
+CONF *NCONF_new(CONF_METHOD *meth);
+CONF_METHOD *NCONF_default(void);
+CONF_METHOD *NCONF_WIN32(void);
+#if 0 /* Just to give you an idea of what I have in mind */
+CONF_METHOD *NCONF_XML(void);
+#endif
+void NCONF_free(CONF *conf);
+void NCONF_free_data(CONF *conf);
+
+int NCONF_load(CONF *conf,const char *file,long *eline);
+#ifndef OPENSSL_NO_FP_API
+int NCONF_load_fp(CONF *conf, FILE *fp,long *eline);
+#endif
+int NCONF_load_bio(CONF *conf, BIO *bp,long *eline);
+STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf,const char *section);
+char *NCONF_get_string(const CONF *conf,const char *group,const char *name);
+int NCONF_get_number_e(const CONF *conf,const char *group,const char *name,
+		       long *result);
+int NCONF_dump_fp(const CONF *conf, FILE *out);
+int NCONF_dump_bio(const CONF *conf, BIO *out);
+
+#if 0 /* The following function has no error checking,
+	 and should therefore be avoided */
+long NCONF_get_number(CONF *conf,char *group,char *name);
+#else
+#define NCONF_get_number(c,g,n,r) NCONF_get_number_e(c,g,n,r)
+#endif
+  
+/* Module functions */
+
+int CONF_modules_load(const CONF *cnf, const char *appname,
+		      unsigned long flags);
+int CONF_modules_load_file(const char *filename, const char *appname,
+			   unsigned long flags);
+void CONF_modules_unload(int all);
+void CONF_modules_finish(void);
+void CONF_modules_free(void);
+int CONF_module_add(const char *name, conf_init_func *ifunc,
+		    conf_finish_func *ffunc);
+
+const char *CONF_imodule_get_name(const CONF_IMODULE *md);
+const char *CONF_imodule_get_value(const CONF_IMODULE *md);
+void *CONF_imodule_get_usr_data(const CONF_IMODULE *md);
+void CONF_imodule_set_usr_data(CONF_IMODULE *md, void *usr_data);
+CONF_MODULE *CONF_imodule_get_module(const CONF_IMODULE *md);
+unsigned long CONF_imodule_get_flags(const CONF_IMODULE *md);
+void CONF_imodule_set_flags(CONF_IMODULE *md, unsigned long flags);
+void *CONF_module_get_usr_data(CONF_MODULE *pmod);
+void CONF_module_set_usr_data(CONF_MODULE *pmod, void *usr_data);
+
+char *CONF_get1_default_config_file(void);
+
+int CONF_parse_list(const char *list, int sep, int nospc,
+	int (*list_cb)(const char *elem, int len, void *usr), void *arg);
+
+void OPENSSL_load_builtin_modules(void);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_CONF_strings(void);
+
+/* Error codes for the CONF functions. */
+
+/* Function codes. */
+#define CONF_F_CONF_DUMP_FP				 104
+#define CONF_F_CONF_LOAD				 100
+#define CONF_F_CONF_LOAD_BIO				 102
+#define CONF_F_CONF_LOAD_FP				 103
+#define CONF_F_CONF_MODULES_LOAD			 116
+#define CONF_F_DEF_LOAD					 120
+#define CONF_F_DEF_LOAD_BIO				 121
+#define CONF_F_MODULE_INIT				 115
+#define CONF_F_MODULE_LOAD_DSO				 117
+#define CONF_F_MODULE_RUN				 118
+#define CONF_F_NCONF_DUMP_BIO				 105
+#define CONF_F_NCONF_DUMP_FP				 106
+#define CONF_F_NCONF_GET_NUMBER				 107
+#define CONF_F_NCONF_GET_NUMBER_E			 112
+#define CONF_F_NCONF_GET_SECTION			 108
+#define CONF_F_NCONF_GET_STRING				 109
+#define CONF_F_NCONF_LOAD				 113
+#define CONF_F_NCONF_LOAD_BIO				 110
+#define CONF_F_NCONF_LOAD_FP				 114
+#define CONF_F_NCONF_NEW				 111
+#define CONF_F_STR_COPY					 101
+
+/* Reason codes. */
+#define CONF_R_ERROR_LOADING_DSO			 110
+#define CONF_R_MISSING_CLOSE_SQUARE_BRACKET		 100
+#define CONF_R_MISSING_EQUAL_SIGN			 101
+#define CONF_R_MISSING_FINISH_FUNCTION			 111
+#define CONF_R_MISSING_INIT_FUNCTION			 112
+#define CONF_R_MODULE_INITIALIZATION_ERROR		 109
+#define CONF_R_NO_CLOSE_BRACE				 102
+#define CONF_R_NO_CONF					 105
+#define CONF_R_NO_CONF_OR_ENVIRONMENT_VARIABLE		 106
+#define CONF_R_NO_SECTION				 107
+#define CONF_R_NO_SUCH_FILE				 114
+#define CONF_R_NO_VALUE					 108
+#define CONF_R_UNABLE_TO_CREATE_NEW_SECTION		 103
+#define CONF_R_UNKNOWN_MODULE_NAME			 113
+#define CONF_R_VARIABLE_HAS_NO_VALUE			 104
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/conf_api.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/conf_api.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/conf_api.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,89 @@
+/* conf_api.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef  HEADER_CONF_API_H
+#define HEADER_CONF_API_H
+
+#include <openssl/lhash.h>
+#include <openssl/conf.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Up until OpenSSL 0.9.5a, this was new_section */
+CONF_VALUE *_CONF_new_section(CONF *conf, const char *section);
+/* Up until OpenSSL 0.9.5a, this was get_section */
+CONF_VALUE *_CONF_get_section(const CONF *conf, const char *section);
+/* Up until OpenSSL 0.9.5a, this was CONF_get_section */
+STACK_OF(CONF_VALUE) *_CONF_get_section_values(const CONF *conf,
+					       const char *section);
+
+int _CONF_add_string(CONF *conf, CONF_VALUE *section, CONF_VALUE *value);
+char *_CONF_get_string(const CONF *conf, const char *section,
+		       const char *name);
+long _CONF_get_number(const CONF *conf, const char *section, const char *name);
+
+int _CONF_new_data(CONF *conf);
+void _CONF_free_data(CONF *conf);
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/crypto.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/crypto.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/crypto.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,550 @@
+/* crypto/crypto.h */
+/* ====================================================================
+ * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECDH support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#ifndef HEADER_CRYPTO_H
+#define HEADER_CRYPTO_H
+
+#include <stdlib.h>
+
+#include <openssl/e_os2.h>
+
+#ifndef OPENSSL_NO_FP_API
+#include <stdio.h>
+#endif
+
+#include <openssl/stack.h>
+#include <openssl/safestack.h>
+#include <openssl/opensslv.h>
+#include <openssl/ossl_typ.h>
+
+#ifdef CHARSET_EBCDIC
+#include <openssl/ebcdic.h>
+#endif
+
+/* Resolve problems on some operating systems with symbol names that clash
+   one way or another */
+#include <openssl/symhacks.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Backward compatibility to SSLeay */
+/* This is more to be used to check the correct DLL is being used
+ * in the MS world. */
+#define SSLEAY_VERSION_NUMBER	OPENSSL_VERSION_NUMBER
+#define SSLEAY_VERSION		0
+/* #define SSLEAY_OPTIONS	1 no longer supported */
+#define SSLEAY_CFLAGS		2
+#define SSLEAY_BUILT_ON		3
+#define SSLEAY_PLATFORM		4
+#define SSLEAY_DIR		5
+
+/* Already declared in ossl_typ.h */
+#if 0
+typedef struct crypto_ex_data_st CRYPTO_EX_DATA;
+/* Called when a new object is created */
+typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+					int idx, long argl, void *argp);
+/* Called when an object is free()ed */
+typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+					int idx, long argl, void *argp);
+/* Called when we need to dup an object */
+typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d, 
+					int idx, long argl, void *argp);
+#endif
+
+/* A generic structure to pass assorted data in a expandable way */
+typedef struct openssl_item_st
+	{
+	int code;
+	void *value;		/* Not used for flag attributes */
+	size_t value_size;	/* Max size of value for output, length for input */
+	size_t *value_length;	/* Returned length of value for output */
+	} OPENSSL_ITEM;
+
+
+/* When changing the CRYPTO_LOCK_* list, be sure to maintin the text lock
+ * names in cryptlib.c
+ */
+
+#define	CRYPTO_LOCK_ERR			1
+#define	CRYPTO_LOCK_EX_DATA		2
+#define	CRYPTO_LOCK_X509		3
+#define	CRYPTO_LOCK_X509_INFO		4
+#define	CRYPTO_LOCK_X509_PKEY		5
+#define CRYPTO_LOCK_X509_CRL		6
+#define CRYPTO_LOCK_X509_REQ		7
+#define CRYPTO_LOCK_DSA			8
+#define CRYPTO_LOCK_RSA			9
+#define CRYPTO_LOCK_EVP_PKEY		10
+#define CRYPTO_LOCK_X509_STORE		11
+#define CRYPTO_LOCK_SSL_CTX		12
+#define CRYPTO_LOCK_SSL_CERT		13
+#define CRYPTO_LOCK_SSL_SESSION		14
+#define CRYPTO_LOCK_SSL_SESS_CERT	15
+#define CRYPTO_LOCK_SSL			16
+#define CRYPTO_LOCK_SSL_METHOD		17
+#define CRYPTO_LOCK_RAND		18
+#define CRYPTO_LOCK_RAND2		19
+#define CRYPTO_LOCK_MALLOC		20
+#define CRYPTO_LOCK_BIO			21
+#define CRYPTO_LOCK_GETHOSTBYNAME	22
+#define CRYPTO_LOCK_GETSERVBYNAME	23
+#define CRYPTO_LOCK_READDIR		24
+#define CRYPTO_LOCK_RSA_BLINDING	25
+#define CRYPTO_LOCK_DH			26
+#define CRYPTO_LOCK_MALLOC2		27
+#define CRYPTO_LOCK_DSO			28
+#define CRYPTO_LOCK_DYNLOCK		29
+#define CRYPTO_LOCK_ENGINE		30
+#define CRYPTO_LOCK_UI			31
+#define CRYPTO_LOCK_ECDSA               32
+#define CRYPTO_LOCK_EC			33
+#define CRYPTO_LOCK_ECDH		34
+#define CRYPTO_LOCK_BN  		35
+#define CRYPTO_LOCK_EC_PRE_COMP		36
+#define CRYPTO_LOCK_STORE		37
+#define CRYPTO_LOCK_COMP		38
+#define CRYPTO_NUM_LOCKS		39
+
+#define CRYPTO_LOCK		1
+#define CRYPTO_UNLOCK		2
+#define CRYPTO_READ		4
+#define CRYPTO_WRITE		8
+
+#ifndef OPENSSL_NO_LOCKING
+#ifndef CRYPTO_w_lock
+#define CRYPTO_w_lock(type)	\
+	CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,__FILE__,__LINE__)
+#define CRYPTO_w_unlock(type)	\
+	CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,__FILE__,__LINE__)
+#define CRYPTO_r_lock(type)	\
+	CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,__FILE__,__LINE__)
+#define CRYPTO_r_unlock(type)	\
+	CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,__FILE__,__LINE__)
+#define CRYPTO_add(addr,amount,type)	\
+	CRYPTO_add_lock(addr,amount,type,__FILE__,__LINE__)
+#endif
+#else
+#define CRYPTO_w_lock(a)
+#define CRYPTO_w_unlock(a)
+#define CRYPTO_r_lock(a)
+#define CRYPTO_r_unlock(a)
+#define CRYPTO_add(a,b,c)	((*(a))+=(b))
+#endif
+
+/* Some applications as well as some parts of OpenSSL need to allocate
+   and deallocate locks in a dynamic fashion.  The following typedef
+   makes this possible in a type-safe manner.  */
+/* struct CRYPTO_dynlock_value has to be defined by the application. */
+typedef struct
+	{
+	int references;
+	struct CRYPTO_dynlock_value *data;
+	} CRYPTO_dynlock;
+
+
+/* The following can be used to detect memory leaks in the SSLeay library.
+ * It used, it turns on malloc checking */
+
+#define CRYPTO_MEM_CHECK_OFF	0x0	/* an enume */
+#define CRYPTO_MEM_CHECK_ON	0x1	/* a bit */
+#define CRYPTO_MEM_CHECK_ENABLE	0x2	/* a bit */
+#define CRYPTO_MEM_CHECK_DISABLE 0x3	/* an enume */
+
+/* The following are bit values to turn on or off options connected to the
+ * malloc checking functionality */
+
+/* Adds time to the memory checking information */
+#define V_CRYPTO_MDEBUG_TIME	0x1 /* a bit */
+/* Adds thread number to the memory checking information */
+#define V_CRYPTO_MDEBUG_THREAD	0x2 /* a bit */
+
+#define V_CRYPTO_MDEBUG_ALL (V_CRYPTO_MDEBUG_TIME | V_CRYPTO_MDEBUG_THREAD)
+
+
+/* predec of the BIO type */
+typedef struct bio_st BIO_dummy;
+
+struct crypto_ex_data_st
+	{
+	STACK *sk;
+	int dummy; /* gcc is screwing up this data structure :-( */
+	};
+
+/* This stuff is basically class callback functions
+ * The current classes are SSL_CTX, SSL, SSL_SESSION, and a few more */
+
+typedef struct crypto_ex_data_func_st
+	{
+	long argl;	/* Arbitary long */
+	void *argp;	/* Arbitary void * */
+	CRYPTO_EX_new *new_func;
+	CRYPTO_EX_free *free_func;
+	CRYPTO_EX_dup *dup_func;
+	} CRYPTO_EX_DATA_FUNCS;
+
+DECLARE_STACK_OF(CRYPTO_EX_DATA_FUNCS)
+
+/* Per class, we have a STACK of CRYPTO_EX_DATA_FUNCS for each CRYPTO_EX_DATA
+ * entry.
+ */
+
+#define CRYPTO_EX_INDEX_BIO		0
+#define CRYPTO_EX_INDEX_SSL		1
+#define CRYPTO_EX_INDEX_SSL_CTX		2
+#define CRYPTO_EX_INDEX_SSL_SESSION	3
+#define CRYPTO_EX_INDEX_X509_STORE	4
+#define CRYPTO_EX_INDEX_X509_STORE_CTX	5
+#define CRYPTO_EX_INDEX_RSA		6
+#define CRYPTO_EX_INDEX_DSA		7
+#define CRYPTO_EX_INDEX_DH		8
+#define CRYPTO_EX_INDEX_ENGINE		9
+#define CRYPTO_EX_INDEX_X509		10
+#define CRYPTO_EX_INDEX_UI		11
+#define CRYPTO_EX_INDEX_ECDSA		12
+#define CRYPTO_EX_INDEX_ECDH		13
+#define CRYPTO_EX_INDEX_COMP		14
+#define CRYPTO_EX_INDEX_STORE		15
+
+/* Dynamically assigned indexes start from this value (don't use directly, use
+ * via CRYPTO_ex_data_new_class). */
+#define CRYPTO_EX_INDEX_USER		100
+
+
+/* This is the default callbacks, but we can have others as well:
+ * this is needed in Win32 where the application malloc and the
+ * library malloc may not be the same.
+ */
+#define CRYPTO_malloc_init()	CRYPTO_set_mem_functions(\
+	malloc, realloc, free)
+
+#if defined CRYPTO_MDEBUG_ALL || defined CRYPTO_MDEBUG_TIME || defined CRYPTO_MDEBUG_THREAD
+# ifndef CRYPTO_MDEBUG /* avoid duplicate #define */
+#  define CRYPTO_MDEBUG
+# endif
+#endif
+
+/* Set standard debugging functions (not done by default
+ * unless CRYPTO_MDEBUG is defined) */
+#define CRYPTO_malloc_debug_init()	do {\
+	CRYPTO_set_mem_debug_functions(\
+		CRYPTO_dbg_malloc,\
+		CRYPTO_dbg_realloc,\
+		CRYPTO_dbg_free,\
+		CRYPTO_dbg_set_options,\
+		CRYPTO_dbg_get_options);\
+	} while(0)
+
+int CRYPTO_mem_ctrl(int mode);
+int CRYPTO_is_mem_check_on(void);
+
+/* for applications */
+#define MemCheck_start() CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON)
+#define MemCheck_stop()	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_OFF)
+
+/* for library-internal use */
+#define MemCheck_on()	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ENABLE)
+#define MemCheck_off()	CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_DISABLE)
+#define is_MemCheck_on() CRYPTO_is_mem_check_on()
+
+#define OPENSSL_malloc(num)	CRYPTO_malloc((int)num,__FILE__,__LINE__)
+#define OPENSSL_realloc(addr,num) \
+	CRYPTO_realloc((char *)addr,(int)num,__FILE__,__LINE__)
+#define OPENSSL_realloc_clean(addr,old_num,num) \
+	CRYPTO_realloc_clean(addr,old_num,num,__FILE__,__LINE__)
+#define OPENSSL_remalloc(addr,num) \
+	CRYPTO_remalloc((char **)addr,(int)num,__FILE__,__LINE__)
+#define OPENSSL_freeFunc	CRYPTO_free
+#define OPENSSL_free(addr)	CRYPTO_free(addr)
+
+#define OPENSSL_malloc_locked(num) \
+	CRYPTO_malloc_locked((int)num,__FILE__,__LINE__)
+#define OPENSSL_free_locked(addr) CRYPTO_free_locked(addr)
+
+
+const char *SSLeay_version(int type);
+unsigned long SSLeay(void);
+
+int OPENSSL_issetugid(void);
+
+/* An opaque type representing an implementation of "ex_data" support */
+typedef struct st_CRYPTO_EX_DATA_IMPL	CRYPTO_EX_DATA_IMPL;
+/* Return an opaque pointer to the current "ex_data" implementation */
+const CRYPTO_EX_DATA_IMPL *CRYPTO_get_ex_data_implementation(void);
+/* Sets the "ex_data" implementation to be used (if it's not too late) */
+int CRYPTO_set_ex_data_implementation(const CRYPTO_EX_DATA_IMPL *i);
+/* Get a new "ex_data" class, and return the corresponding "class_index" */
+int CRYPTO_ex_data_new_class(void);
+/* Within a given class, get/register a new index */
+int CRYPTO_get_ex_new_index(int class_index, long argl, void *argp,
+		CRYPTO_EX_new *new_func, CRYPTO_EX_dup *dup_func,
+		CRYPTO_EX_free *free_func);
+/* Initialise/duplicate/free CRYPTO_EX_DATA variables corresponding to a given
+ * class (invokes whatever per-class callbacks are applicable) */
+int CRYPTO_new_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad);
+int CRYPTO_dup_ex_data(int class_index, CRYPTO_EX_DATA *to,
+		CRYPTO_EX_DATA *from);
+void CRYPTO_free_ex_data(int class_index, void *obj, CRYPTO_EX_DATA *ad);
+/* Get/set data in a CRYPTO_EX_DATA variable corresponding to a particular index
+ * (relative to the class type involved) */
+int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int idx, void *val);
+void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad,int idx);
+/* This function cleans up all "ex_data" state. It mustn't be called under
+ * potential race-conditions. */
+void CRYPTO_cleanup_all_ex_data(void);
+
+int CRYPTO_get_new_lockid(char *name);
+
+int CRYPTO_num_locks(void); /* return CRYPTO_NUM_LOCKS (shared libs!) */
+void CRYPTO_lock(int mode, int type,const char *file,int line);
+void CRYPTO_set_locking_callback(void (*func)(int mode,int type,
+					      const char *file,int line));
+void (*CRYPTO_get_locking_callback(void))(int mode,int type,const char *file,
+		int line);
+void CRYPTO_set_add_lock_callback(int (*func)(int *num,int mount,int type,
+					      const char *file, int line));
+int (*CRYPTO_get_add_lock_callback(void))(int *num,int mount,int type,
+					  const char *file,int line);
+void CRYPTO_set_id_callback(unsigned long (*func)(void));
+unsigned long (*CRYPTO_get_id_callback(void))(void);
+unsigned long CRYPTO_thread_id(void);
+const char *CRYPTO_get_lock_name(int type);
+int CRYPTO_add_lock(int *pointer,int amount,int type, const char *file,
+		    int line);
+
+int CRYPTO_get_new_dynlockid(void);
+void CRYPTO_destroy_dynlockid(int i);
+struct CRYPTO_dynlock_value *CRYPTO_get_dynlock_value(int i);
+void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *(*dyn_create_function)(const char *file, int line));
+void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line));
+void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *l, const char *file, int line));
+struct CRYPTO_dynlock_value *(*CRYPTO_get_dynlock_create_callback(void))(const char *file,int line);
+void (*CRYPTO_get_dynlock_lock_callback(void))(int mode, struct CRYPTO_dynlock_value *l, const char *file,int line);
+void (*CRYPTO_get_dynlock_destroy_callback(void))(struct CRYPTO_dynlock_value *l, const char *file,int line);
+
+/* CRYPTO_set_mem_functions includes CRYPTO_set_locked_mem_functions --
+ * call the latter last if you need different functions */
+int CRYPTO_set_mem_functions(void *(*m)(size_t),void *(*r)(void *,size_t), void (*f)(void *));
+int CRYPTO_set_locked_mem_functions(void *(*m)(size_t), void (*free_func)(void *));
+int CRYPTO_set_mem_ex_functions(void *(*m)(size_t,const char *,int),
+                                void *(*r)(void *,size_t,const char *,int),
+                                void (*f)(void *));
+int CRYPTO_set_locked_mem_ex_functions(void *(*m)(size_t,const char *,int),
+                                       void (*free_func)(void *));
+int CRYPTO_set_mem_debug_functions(void (*m)(void *,int,const char *,int,int),
+				   void (*r)(void *,void *,int,const char *,int,int),
+				   void (*f)(void *,int),
+				   void (*so)(long),
+				   long (*go)(void));
+void CRYPTO_get_mem_functions(void *(**m)(size_t),void *(**r)(void *, size_t), void (**f)(void *));
+void CRYPTO_get_locked_mem_functions(void *(**m)(size_t), void (**f)(void *));
+void CRYPTO_get_mem_ex_functions(void *(**m)(size_t,const char *,int),
+                                 void *(**r)(void *, size_t,const char *,int),
+                                 void (**f)(void *));
+void CRYPTO_get_locked_mem_ex_functions(void *(**m)(size_t,const char *,int),
+                                        void (**f)(void *));
+void CRYPTO_get_mem_debug_functions(void (**m)(void *,int,const char *,int,int),
+				    void (**r)(void *,void *,int,const char *,int,int),
+				    void (**f)(void *,int),
+				    void (**so)(long),
+				    long (**go)(void));
+
+void *CRYPTO_malloc_locked(int num, const char *file, int line);
+void CRYPTO_free_locked(void *);
+void *CRYPTO_malloc(int num, const char *file, int line);
+void CRYPTO_free(void *);
+void *CRYPTO_realloc(void *addr,int num, const char *file, int line);
+void *CRYPTO_realloc_clean(void *addr,int old_num,int num,const char *file,
+			   int line);
+void *CRYPTO_remalloc(void *addr,int num, const char *file, int line);
+
+void OPENSSL_cleanse(void *ptr, size_t len);
+
+void CRYPTO_set_mem_debug_options(long bits);
+long CRYPTO_get_mem_debug_options(void);
+
+#define CRYPTO_push_info(info) \
+        CRYPTO_push_info_(info, __FILE__, __LINE__);
+int CRYPTO_push_info_(const char *info, const char *file, int line);
+int CRYPTO_pop_info(void);
+int CRYPTO_remove_all_info(void);
+
+
+/* Default debugging functions (enabled by CRYPTO_malloc_debug_init() macro;
+ * used as default in CRYPTO_MDEBUG compilations): */
+/* The last argument has the following significance:
+ *
+ * 0:	called before the actual memory allocation has taken place
+ * 1:	called after the actual memory allocation has taken place
+ */
+void CRYPTO_dbg_malloc(void *addr,int num,const char *file,int line,int before_p);
+void CRYPTO_dbg_realloc(void *addr1,void *addr2,int num,const char *file,int line,int before_p);
+void CRYPTO_dbg_free(void *addr,int before_p);
+/* Tell the debugging code about options.  By default, the following values
+ * apply:
+ *
+ * 0:                           Clear all options.
+ * V_CRYPTO_MDEBUG_TIME (1):    Set the "Show Time" option.
+ * V_CRYPTO_MDEBUG_THREAD (2):  Set the "Show Thread Number" option.
+ * V_CRYPTO_MDEBUG_ALL (3):     1 + 2
+ */
+void CRYPTO_dbg_set_options(long bits);
+long CRYPTO_dbg_get_options(void);
+
+
+#ifndef OPENSSL_NO_FP_API
+void CRYPTO_mem_leaks_fp(FILE *);
+#endif
+void CRYPTO_mem_leaks(struct bio_st *bio);
+/* unsigned long order, char *file, int line, int num_bytes, char *addr */
+typedef void *CRYPTO_MEM_LEAK_CB(unsigned long, const char *, int, int, void *);
+void CRYPTO_mem_leaks_cb(CRYPTO_MEM_LEAK_CB *cb);
+
+/* die if we have to */
+void OpenSSLDie(const char *file,int line,const char *assertion);
+#define OPENSSL_assert(e)       (void)((e) ? 0 : (OpenSSLDie(__FILE__, __LINE__, #e),1))
+
+unsigned long *OPENSSL_ia32cap_loc(void);
+#define OPENSSL_ia32cap (*(OPENSSL_ia32cap_loc()))
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_CRYPTO_strings(void);
+
+/* Error codes for the CRYPTO functions. */
+
+/* Function codes. */
+#define CRYPTO_F_CRYPTO_GET_EX_NEW_INDEX		 100
+#define CRYPTO_F_CRYPTO_GET_NEW_DYNLOCKID		 103
+#define CRYPTO_F_CRYPTO_GET_NEW_LOCKID			 101
+#define CRYPTO_F_CRYPTO_SET_EX_DATA			 102
+#define CRYPTO_F_DEF_ADD_INDEX				 104
+#define CRYPTO_F_DEF_GET_CLASS				 105
+#define CRYPTO_F_INT_DUP_EX_DATA			 106
+#define CRYPTO_F_INT_FREE_EX_DATA			 107
+#define CRYPTO_F_INT_NEW_EX_DATA			 108
+
+/* Reason codes. */
+#define CRYPTO_R_NO_DYNLOCK_CREATE_CALLBACK		 100
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/des.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/des.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/des.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,244 @@
+/* crypto/des/des.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_NEW_DES_H
+#define HEADER_NEW_DES_H
+
+#include <openssl/e_os2.h>	/* OPENSSL_EXTERN, OPENSSL_NO_DES,
+				   DES_LONG (via openssl/opensslconf.h */
+
+#ifdef OPENSSL_NO_DES
+#error DES is disabled.
+#endif
+
+#ifdef OPENSSL_BUILD_SHLIBCRYPTO
+# undef OPENSSL_EXTERN
+# define OPENSSL_EXTERN OPENSSL_EXPORT
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char DES_cblock[8];
+typedef /* const */ unsigned char const_DES_cblock[8];
+/* With "const", gcc 2.8.1 on Solaris thinks that DES_cblock *
+ * and const_DES_cblock * are incompatible pointer types. */
+
+typedef struct DES_ks
+    {
+    union
+	{
+	DES_cblock cblock;
+	/* make sure things are correct size on machines with
+	 * 8 byte longs */
+	DES_LONG deslong[2];
+	} ks[16];
+    } DES_key_schedule;
+
+#ifndef OPENSSL_DISABLE_OLD_DES_SUPPORT
+# ifndef OPENSSL_ENABLE_OLD_DES_SUPPORT
+#  define OPENSSL_ENABLE_OLD_DES_SUPPORT
+# endif
+#endif
+
+#ifdef OPENSSL_ENABLE_OLD_DES_SUPPORT
+# include <openssl/des_old.h>
+#endif
+
+#define DES_KEY_SZ 	(sizeof(DES_cblock))
+#define DES_SCHEDULE_SZ (sizeof(DES_key_schedule))
+
+#define DES_ENCRYPT	1
+#define DES_DECRYPT	0
+
+#define DES_CBC_MODE	0
+#define DES_PCBC_MODE	1
+
+#define DES_ecb2_encrypt(i,o,k1,k2,e) \
+	DES_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
+
+#define DES_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
+	DES_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
+
+#define DES_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
+	DES_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
+
+#define DES_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
+	DES_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
+
+OPENSSL_DECLARE_GLOBAL(int,DES_check_key);	/* defaults to false */
+#define DES_check_key OPENSSL_GLOBAL_REF(DES_check_key)
+OPENSSL_DECLARE_GLOBAL(int,DES_rw_mode);	/* defaults to DES_PCBC_MODE */
+#define DES_rw_mode OPENSSL_GLOBAL_REF(DES_rw_mode)
+
+const char *DES_options(void);
+void DES_ecb3_encrypt(const_DES_cblock *input, DES_cblock *output,
+		      DES_key_schedule *ks1,DES_key_schedule *ks2,
+		      DES_key_schedule *ks3, int enc);
+DES_LONG DES_cbc_cksum(const unsigned char *input,DES_cblock *output,
+		       long length,DES_key_schedule *schedule,
+		       const_DES_cblock *ivec);
+/* DES_cbc_encrypt does not update the IV!  Use DES_ncbc_encrypt instead. */
+void DES_cbc_encrypt(const unsigned char *input,unsigned char *output,
+		     long length,DES_key_schedule *schedule,DES_cblock *ivec,
+		     int enc);
+void DES_ncbc_encrypt(const unsigned char *input,unsigned char *output,
+		      long length,DES_key_schedule *schedule,DES_cblock *ivec,
+		      int enc);
+void DES_xcbc_encrypt(const unsigned char *input,unsigned char *output,
+		      long length,DES_key_schedule *schedule,DES_cblock *ivec,
+		      const_DES_cblock *inw,const_DES_cblock *outw,int enc);
+void DES_cfb_encrypt(const unsigned char *in,unsigned char *out,int numbits,
+		     long length,DES_key_schedule *schedule,DES_cblock *ivec,
+		     int enc);
+void DES_ecb_encrypt(const_DES_cblock *input,DES_cblock *output,
+		     DES_key_schedule *ks,int enc);
+
+/* 	This is the DES encryption function that gets called by just about
+	every other DES routine in the library.  You should not use this
+	function except to implement 'modes' of DES.  I say this because the
+	functions that call this routine do the conversion from 'char *' to
+	long, and this needs to be done to make sure 'non-aligned' memory
+	access do not occur.  The characters are loaded 'little endian'.
+	Data is a pointer to 2 unsigned long's and ks is the
+	DES_key_schedule to use.  enc, is non zero specifies encryption,
+	zero if decryption. */
+void DES_encrypt1(DES_LONG *data,DES_key_schedule *ks, int enc);
+
+/* 	This functions is the same as DES_encrypt1() except that the DES
+	initial permutation (IP) and final permutation (FP) have been left
+	out.  As for DES_encrypt1(), you should not use this function.
+	It is used by the routines in the library that implement triple DES.
+	IP() DES_encrypt2() DES_encrypt2() DES_encrypt2() FP() is the same
+	as DES_encrypt1() DES_encrypt1() DES_encrypt1() except faster :-). */
+void DES_encrypt2(DES_LONG *data,DES_key_schedule *ks, int enc);
+
+void DES_encrypt3(DES_LONG *data, DES_key_schedule *ks1,
+		  DES_key_schedule *ks2, DES_key_schedule *ks3);
+void DES_decrypt3(DES_LONG *data, DES_key_schedule *ks1,
+		  DES_key_schedule *ks2, DES_key_schedule *ks3);
+void DES_ede3_cbc_encrypt(const unsigned char *input,unsigned char *output, 
+			  long length,
+			  DES_key_schedule *ks1,DES_key_schedule *ks2,
+			  DES_key_schedule *ks3,DES_cblock *ivec,int enc);
+void DES_ede3_cbcm_encrypt(const unsigned char *in,unsigned char *out,
+			   long length,
+			   DES_key_schedule *ks1,DES_key_schedule *ks2,
+			   DES_key_schedule *ks3,
+			   DES_cblock *ivec1,DES_cblock *ivec2,
+			   int enc);
+void DES_ede3_cfb64_encrypt(const unsigned char *in,unsigned char *out,
+			    long length,DES_key_schedule *ks1,
+			    DES_key_schedule *ks2,DES_key_schedule *ks3,
+			    DES_cblock *ivec,int *num,int enc);
+void DES_ede3_cfb_encrypt(const unsigned char *in,unsigned char *out,
+			  int numbits,long length,DES_key_schedule *ks1,
+			  DES_key_schedule *ks2,DES_key_schedule *ks3,
+			  DES_cblock *ivec,int enc);
+void DES_ede3_ofb64_encrypt(const unsigned char *in,unsigned char *out,
+			    long length,DES_key_schedule *ks1,
+			    DES_key_schedule *ks2,DES_key_schedule *ks3,
+			    DES_cblock *ivec,int *num);
+
+void DES_xwhite_in2out(const_DES_cblock *DES_key,const_DES_cblock *in_white,
+		       DES_cblock *out_white);
+
+int DES_enc_read(int fd,void *buf,int len,DES_key_schedule *sched,
+		 DES_cblock *iv);
+int DES_enc_write(int fd,const void *buf,int len,DES_key_schedule *sched,
+		  DES_cblock *iv);
+char *DES_fcrypt(const char *buf,const char *salt, char *ret);
+char *DES_crypt(const char *buf,const char *salt);
+void DES_ofb_encrypt(const unsigned char *in,unsigned char *out,int numbits,
+		     long length,DES_key_schedule *schedule,DES_cblock *ivec);
+void DES_pcbc_encrypt(const unsigned char *input,unsigned char *output,
+		      long length,DES_key_schedule *schedule,DES_cblock *ivec,
+		      int enc);
+DES_LONG DES_quad_cksum(const unsigned char *input,DES_cblock output[],
+			long length,int out_count,DES_cblock *seed);
+int DES_random_key(DES_cblock *ret);
+void DES_set_odd_parity(DES_cblock *key);
+int DES_check_key_parity(const_DES_cblock *key);
+int DES_is_weak_key(const_DES_cblock *key);
+/* DES_set_key (= set_key = DES_key_sched = key_sched) calls
+ * DES_set_key_checked if global variable DES_check_key is set,
+ * DES_set_key_unchecked otherwise. */
+int DES_set_key(const_DES_cblock *key,DES_key_schedule *schedule);
+int DES_key_sched(const_DES_cblock *key,DES_key_schedule *schedule);
+int DES_set_key_checked(const_DES_cblock *key,DES_key_schedule *schedule);
+void DES_set_key_unchecked(const_DES_cblock *key,DES_key_schedule *schedule);
+void DES_string_to_key(const char *str,DES_cblock *key);
+void DES_string_to_2keys(const char *str,DES_cblock *key1,DES_cblock *key2);
+void DES_cfb64_encrypt(const unsigned char *in,unsigned char *out,long length,
+		       DES_key_schedule *schedule,DES_cblock *ivec,int *num,
+		       int enc);
+void DES_ofb64_encrypt(const unsigned char *in,unsigned char *out,long length,
+		       DES_key_schedule *schedule,DES_cblock *ivec,int *num);
+
+int DES_read_password(DES_cblock *key, const char *prompt, int verify);
+int DES_read_2passwords(DES_cblock *key1, DES_cblock *key2, const char *prompt,
+	int verify);
+
+#define DES_fixup_key_parity DES_set_odd_parity
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/des_old.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/des_old.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/des_old.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,441 @@
+/* crypto/des/des_old.h -*- mode:C; c-file-style: "eay" -*- */
+
+/* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * The function names in here are deprecated and are only present to
+ * provide an interface compatible with openssl 0.9.6 and older as
+ * well as libdes.  OpenSSL now provides functions where "des_" has
+ * been replaced with "DES_" in the names, to make it possible to
+ * make incompatible changes that are needed for C type security and
+ * other stuff.
+ *
+ * This include files has two compatibility modes:
+ *
+ *   - If OPENSSL_DES_LIBDES_COMPATIBILITY is defined, you get an API
+ *     that is compatible with libdes and SSLeay.
+ *   - If OPENSSL_DES_LIBDES_COMPATIBILITY isn't defined, you get an
+ *     API that is compatible with OpenSSL 0.9.5x to 0.9.6x.
+ *
+ * Note that these modes break earlier snapshots of OpenSSL, where
+ * libdes compatibility was the only available mode or (later on) the
+ * prefered compatibility mode.  However, after much consideration
+ * (and more or less violent discussions with external parties), it
+ * was concluded that OpenSSL should be compatible with earlier versions
+ * of itself before anything else.  Also, in all honesty, libdes is
+ * an old beast that shouldn't really be used any more.
+ *
+ * Please consider starting to use the DES_ functions rather than the
+ * des_ ones.  The des_ functions will disappear completely before
+ * OpenSSL 1.0!
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ */
+
+/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
+ * project 2001.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_DES_H
+#define HEADER_DES_H
+
+#include <openssl/e_os2.h>	/* OPENSSL_EXTERN, OPENSSL_NO_DES, DES_LONG */
+
+#ifdef OPENSSL_NO_DES
+#error DES is disabled.
+#endif
+
+#ifndef HEADER_NEW_DES_H
+#error You must include des.h, not des_old.h directly.
+#endif
+
+#ifdef _KERBEROS_DES_H
+#error <openssl/des_old.h> replaces <kerberos/des.h>.
+#endif
+
+#include <openssl/symhacks.h>
+
+#ifdef OPENSSL_BUILD_SHLIBCRYPTO
+# undef OPENSSL_EXTERN
+# define OPENSSL_EXTERN OPENSSL_EXPORT
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned char _ossl_old_des_cblock[8];
+typedef struct _ossl_old_des_ks_struct
+	{
+	union	{
+		_ossl_old_des_cblock _;
+		/* make sure things are correct size on machines with
+		 * 8 byte longs */
+		DES_LONG pad[2];
+		} ks;
+	} _ossl_old_des_key_schedule[16];
+
+#ifndef OPENSSL_DES_LIBDES_COMPATIBILITY
+#define des_cblock DES_cblock
+#define const_des_cblock const_DES_cblock
+#define des_key_schedule DES_key_schedule
+#define des_ecb3_encrypt(i,o,k1,k2,k3,e)\
+	DES_ecb3_encrypt((i),(o),&(k1),&(k2),&(k3),(e))
+#define des_ede3_cbc_encrypt(i,o,l,k1,k2,k3,iv,e)\
+	DES_ede3_cbc_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(e))
+#define des_ede3_cbcm_encrypt(i,o,l,k1,k2,k3,iv1,iv2,e)\
+	DES_ede3_cbcm_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv1),(iv2),(e))
+#define des_ede3_cfb64_encrypt(i,o,l,k1,k2,k3,iv,n,e)\
+	DES_ede3_cfb64_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(n),(e))
+#define des_ede3_ofb64_encrypt(i,o,l,k1,k2,k3,iv,n)\
+	DES_ede3_ofb64_encrypt((i),(o),(l),&(k1),&(k2),&(k3),(iv),(n))
+#define des_options()\
+	DES_options()
+#define des_cbc_cksum(i,o,l,k,iv)\
+	DES_cbc_cksum((i),(o),(l),&(k),(iv))
+#define des_cbc_encrypt(i,o,l,k,iv,e)\
+	DES_cbc_encrypt((i),(o),(l),&(k),(iv),(e))
+#define des_ncbc_encrypt(i,o,l,k,iv,e)\
+	DES_ncbc_encrypt((i),(o),(l),&(k),(iv),(e))
+#define des_xcbc_encrypt(i,o,l,k,iv,inw,outw,e)\
+	DES_xcbc_encrypt((i),(o),(l),&(k),(iv),(inw),(outw),(e))
+#define des_cfb_encrypt(i,o,n,l,k,iv,e)\
+	DES_cfb_encrypt((i),(o),(n),(l),&(k),(iv),(e))
+#define des_ecb_encrypt(i,o,k,e)\
+	DES_ecb_encrypt((i),(o),&(k),(e))
+#define des_encrypt1(d,k,e)\
+	DES_encrypt1((d),&(k),(e))
+#define des_encrypt2(d,k,e)\
+	DES_encrypt2((d),&(k),(e))
+#define des_encrypt3(d,k1,k2,k3)\
+	DES_encrypt3((d),&(k1),&(k2),&(k3))
+#define des_decrypt3(d,k1,k2,k3)\
+	DES_decrypt3((d),&(k1),&(k2),&(k3))
+#define des_xwhite_in2out(k,i,o)\
+	DES_xwhite_in2out((k),(i),(o))
+#define des_enc_read(f,b,l,k,iv)\
+	DES_enc_read((f),(b),(l),&(k),(iv))
+#define des_enc_write(f,b,l,k,iv)\
+	DES_enc_write((f),(b),(l),&(k),(iv))
+#define des_fcrypt(b,s,r)\
+	DES_fcrypt((b),(s),(r))
+#if 0
+#define des_crypt(b,s)\
+	DES_crypt((b),(s))
+#if !defined(PERL5) && !defined(__FreeBSD__) && !defined(NeXT) && !defined(__OpenBSD__)
+#define crypt(b,s)\
+	DES_crypt((b),(s))
+#endif
+#endif
+#define des_ofb_encrypt(i,o,n,l,k,iv)\
+	DES_ofb_encrypt((i),(o),(n),(l),&(k),(iv))
+#define des_pcbc_encrypt(i,o,l,k,iv,e)\
+	DES_pcbc_encrypt((i),(o),(l),&(k),(iv),(e))
+#define des_quad_cksum(i,o,l,c,s)\
+	DES_quad_cksum((i),(o),(l),(c),(s))
+#define des_random_seed(k)\
+	_ossl_096_des_random_seed((k))
+#define des_random_key(r)\
+	DES_random_key((r))
+#define des_read_password(k,p,v) \
+	DES_read_password((k),(p),(v))
+#define des_read_2passwords(k1,k2,p,v) \
+	DES_read_2passwords((k1),(k2),(p),(v))
+#define des_set_odd_parity(k)\
+	DES_set_odd_parity((k))
+#define des_check_key_parity(k)\
+	DES_check_key_parity((k))
+#define des_is_weak_key(k)\
+	DES_is_weak_key((k))
+#define des_set_key(k,ks)\
+	DES_set_key((k),&(ks))
+#define des_key_sched(k,ks)\
+	DES_key_sched((k),&(ks))
+#define des_set_key_checked(k,ks)\
+	DES_set_key_checked((k),&(ks))
+#define des_set_key_unchecked(k,ks)\
+	DES_set_key_unchecked((k),&(ks))
+#define des_string_to_key(s,k)\
+	DES_string_to_key((s),(k))
+#define des_string_to_2keys(s,k1,k2)\
+	DES_string_to_2keys((s),(k1),(k2))
+#define des_cfb64_encrypt(i,o,l,ks,iv,n,e)\
+	DES_cfb64_encrypt((i),(o),(l),&(ks),(iv),(n),(e))
+#define des_ofb64_encrypt(i,o,l,ks,iv,n)\
+	DES_ofb64_encrypt((i),(o),(l),&(ks),(iv),(n))
+		
+
+#define des_ecb2_encrypt(i,o,k1,k2,e) \
+	des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
+
+#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
+	des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
+
+#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
+	des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
+
+#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
+	des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
+
+#define des_check_key DES_check_key
+#define des_rw_mode DES_rw_mode
+#else /* libdes compatibility */
+/* Map all symbol names to _ossl_old_des_* form, so we avoid all
+   clashes with libdes */
+#define des_cblock _ossl_old_des_cblock
+#define des_key_schedule _ossl_old_des_key_schedule
+#define des_ecb3_encrypt(i,o,k1,k2,k3,e)\
+	_ossl_old_des_ecb3_encrypt((i),(o),(k1),(k2),(k3),(e))
+#define des_ede3_cbc_encrypt(i,o,l,k1,k2,k3,iv,e)\
+	_ossl_old_des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(e))
+#define des_ede3_cfb64_encrypt(i,o,l,k1,k2,k3,iv,n,e)\
+	_ossl_old_des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(n),(e))
+#define des_ede3_ofb64_encrypt(i,o,l,k1,k2,k3,iv,n)\
+	_ossl_old_des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k3),(iv),(n))
+#define des_options()\
+	_ossl_old_des_options()
+#define des_cbc_cksum(i,o,l,k,iv)\
+	_ossl_old_des_cbc_cksum((i),(o),(l),(k),(iv))
+#define des_cbc_encrypt(i,o,l,k,iv,e)\
+	_ossl_old_des_cbc_encrypt((i),(o),(l),(k),(iv),(e))
+#define des_ncbc_encrypt(i,o,l,k,iv,e)\
+	_ossl_old_des_ncbc_encrypt((i),(o),(l),(k),(iv),(e))
+#define des_xcbc_encrypt(i,o,l,k,iv,inw,outw,e)\
+	_ossl_old_des_xcbc_encrypt((i),(o),(l),(k),(iv),(inw),(outw),(e))
+#define des_cfb_encrypt(i,o,n,l,k,iv,e)\
+	_ossl_old_des_cfb_encrypt((i),(o),(n),(l),(k),(iv),(e))
+#define des_ecb_encrypt(i,o,k,e)\
+	_ossl_old_des_ecb_encrypt((i),(o),(k),(e))
+#define des_encrypt(d,k,e)\
+	_ossl_old_des_encrypt((d),(k),(e))
+#define des_encrypt2(d,k,e)\
+	_ossl_old_des_encrypt2((d),(k),(e))
+#define des_encrypt3(d,k1,k2,k3)\
+	_ossl_old_des_encrypt3((d),(k1),(k2),(k3))
+#define des_decrypt3(d,k1,k2,k3)\
+	_ossl_old_des_decrypt3((d),(k1),(k2),(k3))
+#define des_xwhite_in2out(k,i,o)\
+	_ossl_old_des_xwhite_in2out((k),(i),(o))
+#define des_enc_read(f,b,l,k,iv)\
+	_ossl_old_des_enc_read((f),(b),(l),(k),(iv))
+#define des_enc_write(f,b,l,k,iv)\
+	_ossl_old_des_enc_write((f),(b),(l),(k),(iv))
+#define des_fcrypt(b,s,r)\
+	_ossl_old_des_fcrypt((b),(s),(r))
+#define des_crypt(b,s)\
+	_ossl_old_des_crypt((b),(s))
+#if 0
+#define crypt(b,s)\
+	_ossl_old_crypt((b),(s))
+#endif
+#define des_ofb_encrypt(i,o,n,l,k,iv)\
+	_ossl_old_des_ofb_encrypt((i),(o),(n),(l),(k),(iv))
+#define des_pcbc_encrypt(i,o,l,k,iv,e)\
+	_ossl_old_des_pcbc_encrypt((i),(o),(l),(k),(iv),(e))
+#define des_quad_cksum(i,o,l,c,s)\
+	_ossl_old_des_quad_cksum((i),(o),(l),(c),(s))
+#define des_random_seed(k)\
+	_ossl_old_des_random_seed((k))
+#define des_random_key(r)\
+	_ossl_old_des_random_key((r))
+#define des_read_password(k,p,v) \
+	_ossl_old_des_read_password((k),(p),(v))
+#define des_read_2passwords(k1,k2,p,v) \
+	_ossl_old_des_read_2passwords((k1),(k2),(p),(v))
+#define des_set_odd_parity(k)\
+	_ossl_old_des_set_odd_parity((k))
+#define des_is_weak_key(k)\
+	_ossl_old_des_is_weak_key((k))
+#define des_set_key(k,ks)\
+	_ossl_old_des_set_key((k),(ks))
+#define des_key_sched(k,ks)\
+	_ossl_old_des_key_sched((k),(ks))
+#define des_string_to_key(s,k)\
+	_ossl_old_des_string_to_key((s),(k))
+#define des_string_to_2keys(s,k1,k2)\
+	_ossl_old_des_string_to_2keys((s),(k1),(k2))
+#define des_cfb64_encrypt(i,o,l,ks,iv,n,e)\
+	_ossl_old_des_cfb64_encrypt((i),(o),(l),(ks),(iv),(n),(e))
+#define des_ofb64_encrypt(i,o,l,ks,iv,n)\
+	_ossl_old_des_ofb64_encrypt((i),(o),(l),(ks),(iv),(n))
+		
+
+#define des_ecb2_encrypt(i,o,k1,k2,e) \
+	des_ecb3_encrypt((i),(o),(k1),(k2),(k1),(e))
+
+#define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
+	des_ede3_cbc_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(e))
+
+#define des_ede2_cfb64_encrypt(i,o,l,k1,k2,iv,n,e) \
+	des_ede3_cfb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n),(e))
+
+#define des_ede2_ofb64_encrypt(i,o,l,k1,k2,iv,n) \
+	des_ede3_ofb64_encrypt((i),(o),(l),(k1),(k2),(k1),(iv),(n))
+
+#define des_check_key DES_check_key
+#define des_rw_mode DES_rw_mode
+#endif
+
+const char *_ossl_old_des_options(void);
+void _ossl_old_des_ecb3_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,
+	_ossl_old_des_key_schedule ks1,_ossl_old_des_key_schedule ks2,
+	_ossl_old_des_key_schedule ks3, int enc);
+DES_LONG _ossl_old_des_cbc_cksum(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,
+	long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec);
+void _ossl_old_des_cbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length,
+	_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc);
+void _ossl_old_des_ncbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length,
+	_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc);
+void _ossl_old_des_xcbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length,
+	_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,
+	_ossl_old_des_cblock *inw,_ossl_old_des_cblock *outw,int enc);
+void _ossl_old_des_cfb_encrypt(unsigned char *in,unsigned char *out,int numbits,
+	long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc);
+void _ossl_old_des_ecb_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,
+	_ossl_old_des_key_schedule ks,int enc);
+void _ossl_old_des_encrypt(DES_LONG *data,_ossl_old_des_key_schedule ks, int enc);
+void _ossl_old_des_encrypt2(DES_LONG *data,_ossl_old_des_key_schedule ks, int enc);
+void _ossl_old_des_encrypt3(DES_LONG *data, _ossl_old_des_key_schedule ks1,
+	_ossl_old_des_key_schedule ks2, _ossl_old_des_key_schedule ks3);
+void _ossl_old_des_decrypt3(DES_LONG *data, _ossl_old_des_key_schedule ks1,
+	_ossl_old_des_key_schedule ks2, _ossl_old_des_key_schedule ks3);
+void _ossl_old_des_ede3_cbc_encrypt(_ossl_old_des_cblock *input, _ossl_old_des_cblock *output, 
+	long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2, 
+	_ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int enc);
+void _ossl_old_des_ede3_cfb64_encrypt(unsigned char *in, unsigned char *out,
+	long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2,
+	_ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int *num, int enc);
+void _ossl_old_des_ede3_ofb64_encrypt(unsigned char *in, unsigned char *out,
+	long length, _ossl_old_des_key_schedule ks1, _ossl_old_des_key_schedule ks2,
+	_ossl_old_des_key_schedule ks3, _ossl_old_des_cblock *ivec, int *num);
+
+void _ossl_old_des_xwhite_in2out(_ossl_old_des_cblock (*des_key), _ossl_old_des_cblock (*in_white),
+	_ossl_old_des_cblock (*out_white));
+
+int _ossl_old_des_enc_read(int fd,char *buf,int len,_ossl_old_des_key_schedule sched,
+	_ossl_old_des_cblock *iv);
+int _ossl_old_des_enc_write(int fd,char *buf,int len,_ossl_old_des_key_schedule sched,
+	_ossl_old_des_cblock *iv);
+char *_ossl_old_des_fcrypt(const char *buf,const char *salt, char *ret);
+char *_ossl_old_des_crypt(const char *buf,const char *salt);
+#if !defined(PERL5) && !defined(NeXT)
+char *_ossl_old_crypt(const char *buf,const char *salt);
+#endif
+void _ossl_old_des_ofb_encrypt(unsigned char *in,unsigned char *out,
+	int numbits,long length,_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec);
+void _ossl_old_des_pcbc_encrypt(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,long length,
+	_ossl_old_des_key_schedule schedule,_ossl_old_des_cblock *ivec,int enc);
+DES_LONG _ossl_old_des_quad_cksum(_ossl_old_des_cblock *input,_ossl_old_des_cblock *output,
+	long length,int out_count,_ossl_old_des_cblock *seed);
+void _ossl_old_des_random_seed(_ossl_old_des_cblock key);
+void _ossl_old_des_random_key(_ossl_old_des_cblock ret);
+int _ossl_old_des_read_password(_ossl_old_des_cblock *key,const char *prompt,int verify);
+int _ossl_old_des_read_2passwords(_ossl_old_des_cblock *key1,_ossl_old_des_cblock *key2,
+	const char *prompt,int verify);
+void _ossl_old_des_set_odd_parity(_ossl_old_des_cblock *key);
+int _ossl_old_des_is_weak_key(_ossl_old_des_cblock *key);
+int _ossl_old_des_set_key(_ossl_old_des_cblock *key,_ossl_old_des_key_schedule schedule);
+int _ossl_old_des_key_sched(_ossl_old_des_cblock *key,_ossl_old_des_key_schedule schedule);
+void _ossl_old_des_string_to_key(char *str,_ossl_old_des_cblock *key);
+void _ossl_old_des_string_to_2keys(char *str,_ossl_old_des_cblock *key1,_ossl_old_des_cblock *key2);
+void _ossl_old_des_cfb64_encrypt(unsigned char *in, unsigned char *out, long length,
+	_ossl_old_des_key_schedule schedule, _ossl_old_des_cblock *ivec, int *num, int enc);
+void _ossl_old_des_ofb64_encrypt(unsigned char *in, unsigned char *out, long length,
+	_ossl_old_des_key_schedule schedule, _ossl_old_des_cblock *ivec, int *num);
+
+void _ossl_096_des_random_seed(des_cblock *key);
+
+/* The following definitions provide compatibility with the MIT Kerberos
+ * library. The _ossl_old_des_key_schedule structure is not binary compatible. */
+
+#define _KERBEROS_DES_H
+
+#define KRBDES_ENCRYPT DES_ENCRYPT
+#define KRBDES_DECRYPT DES_DECRYPT
+
+#ifdef KERBEROS
+#  define ENCRYPT DES_ENCRYPT
+#  define DECRYPT DES_DECRYPT
+#endif
+
+#ifndef NCOMPAT
+#  define C_Block des_cblock
+#  define Key_schedule des_key_schedule
+#  define KEY_SZ DES_KEY_SZ
+#  define string_to_key des_string_to_key
+#  define read_pw_string des_read_pw_string
+#  define random_key des_random_key
+#  define pcbc_encrypt des_pcbc_encrypt
+#  define set_key des_set_key
+#  define key_sched des_key_sched
+#  define ecb_encrypt des_ecb_encrypt
+#  define cbc_encrypt des_cbc_encrypt
+#  define ncbc_encrypt des_ncbc_encrypt
+#  define xcbc_encrypt des_xcbc_encrypt
+#  define cbc_cksum des_cbc_cksum
+#  define quad_cksum des_quad_cksum
+#  define check_parity des_check_key_parity
+#endif
+
+#define des_fixup_key_parity DES_fixup_key_parity
+
+#ifdef  __cplusplus
+}
+#endif
+
+/* for DES_read_pw_string et al */
+#include <openssl/ui_compat.h>
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dh.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dh.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dh.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,223 @@
+/* crypto/dh/dh.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_DH_H
+#define HEADER_DH_H
+
+#include <openssl/e_os2.h>
+
+#ifdef OPENSSL_NO_DH
+#error DH is disabled.
+#endif
+
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/ossl_typ.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#endif
+	
+#define DH_FLAG_CACHE_MONT_P     0x01
+#define DH_FLAG_NO_EXP_CONSTTIME 0x02 /* new with 0.9.7h; the built-in DH
+                                       * implementation now uses constant time
+                                       * modular exponentiation for secret exponents
+                                       * by default. This flag causes the
+                                       * faster variable sliding window method to
+                                       * be used for all exponents.
+                                       */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Already defined in ossl_typ.h */
+/* typedef struct dh_st DH; */
+/* typedef struct dh_method DH_METHOD; */
+
+struct dh_method
+	{
+	const char *name;
+	/* Methods here */
+	int (*generate_key)(DH *dh);
+	int (*compute_key)(unsigned char *key,const BIGNUM *pub_key,DH *dh);
+	int (*bn_mod_exp)(const DH *dh, BIGNUM *r, const BIGNUM *a,
+				const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx,
+				BN_MONT_CTX *m_ctx); /* Can be null */
+
+	int (*init)(DH *dh);
+	int (*finish)(DH *dh);
+	int flags;
+	char *app_data;
+	/* If this is non-NULL, it will be used to generate parameters */
+	int (*generate_params)(DH *dh, int prime_len, int generator, BN_GENCB *cb);
+	};
+
+struct dh_st
+	{
+	/* This first argument is used to pick up errors when
+	 * a DH is passed instead of a EVP_PKEY */
+	int pad;
+	int version;
+	BIGNUM *p;
+	BIGNUM *g;
+	long length; /* optional */
+	BIGNUM *pub_key;	/* g^x */
+	BIGNUM *priv_key;	/* x */
+
+	int flags;
+	BN_MONT_CTX *method_mont_p;
+	/* Place holders if we want to do X9.42 DH */
+	BIGNUM *q;
+	BIGNUM *j;
+	unsigned char *seed;
+	int seedlen;
+	BIGNUM *counter;
+
+	int references;
+	CRYPTO_EX_DATA ex_data;
+	const DH_METHOD *meth;
+	ENGINE *engine;
+	};
+
+#define DH_GENERATOR_2		2
+/* #define DH_GENERATOR_3	3 */
+#define DH_GENERATOR_5		5
+
+/* DH_check error codes */
+#define DH_CHECK_P_NOT_PRIME		0x01
+#define DH_CHECK_P_NOT_SAFE_PRIME	0x02
+#define DH_UNABLE_TO_CHECK_GENERATOR	0x04
+#define DH_NOT_SUITABLE_GENERATOR	0x08
+
+/* primes p where (p-1)/2 is prime too are called "safe"; we define
+   this for backward compatibility: */
+#define DH_CHECK_P_NOT_STRONG_PRIME	DH_CHECK_P_NOT_SAFE_PRIME
+
+#define DHparams_dup(x) ASN1_dup_of_const(DH,i2d_DHparams,d2i_DHparams,x)
+#define d2i_DHparams_fp(fp,x) (DH *)ASN1_d2i_fp((char *(*)())DH_new, \
+		(char *(*)())d2i_DHparams,(fp),(unsigned char **)(x))
+#define i2d_DHparams_fp(fp,x) ASN1_i2d_fp(i2d_DHparams,(fp), \
+		(unsigned char *)(x))
+#define d2i_DHparams_bio(bp,x) ASN1_d2i_bio_of(DH,DH_new,d2i_DHparams,bp,x)
+#define i2d_DHparams_bio(bp,x) ASN1_i2d_bio_of_const(DH,i2d_DHparams,bp,x)
+
+const DH_METHOD *DH_OpenSSL(void);
+
+void DH_set_default_method(const DH_METHOD *meth);
+const DH_METHOD *DH_get_default_method(void);
+int DH_set_method(DH *dh, const DH_METHOD *meth);
+DH *DH_new_method(ENGINE *engine);
+
+DH *	DH_new(void);
+void	DH_free(DH *dh);
+int	DH_up_ref(DH *dh);
+int	DH_size(const DH *dh);
+int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int DH_set_ex_data(DH *d, int idx, void *arg);
+void *DH_get_ex_data(DH *d, int idx);
+
+/* Deprecated version */
+#ifndef OPENSSL_NO_DEPRECATED
+DH *	DH_generate_parameters(int prime_len,int generator,
+		void (*callback)(int,int,void *),void *cb_arg);
+#endif /* !defined(OPENSSL_NO_DEPRECATED) */
+
+/* New version */
+int	DH_generate_parameters_ex(DH *dh, int prime_len,int generator, BN_GENCB *cb);
+
+int	DH_check(const DH *dh,int *codes);
+int	DH_generate_key(DH *dh);
+int	DH_compute_key(unsigned char *key,const BIGNUM *pub_key,DH *dh);
+DH *	d2i_DHparams(DH **a,const unsigned char **pp, long length);
+int	i2d_DHparams(const DH *a,unsigned char **pp);
+#ifndef OPENSSL_NO_FP_API
+int	DHparams_print_fp(FILE *fp, const DH *x);
+#endif
+#ifndef OPENSSL_NO_BIO
+int	DHparams_print(BIO *bp, const DH *x);
+#else
+int	DHparams_print(char *bp, const DH *x);
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_DH_strings(void);
+
+/* Error codes for the DH functions. */
+
+/* Function codes. */
+#define DH_F_COMPUTE_KEY				 102
+#define DH_F_DHPARAMS_PRINT				 100
+#define DH_F_DHPARAMS_PRINT_FP				 101
+#define DH_F_DH_BUILTIN_GENPARAMS			 106
+#define DH_F_DH_NEW_METHOD				 105
+#define DH_F_GENERATE_KEY				 103
+#define DH_F_GENERATE_PARAMETERS			 104
+
+/* Reason codes. */
+#define DH_R_BAD_GENERATOR				 101
+#define DH_R_NO_PRIVATE_VALUE				 100
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dsa.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dsa.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dsa.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,279 @@
+/* crypto/dsa/dsa.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/*
+ * The DSS routines are based on patches supplied by
+ * Steven Schoch <schoch@sheba.arc.nasa.gov>.  He basically did the
+ * work and I have just tweaked them a little to fit into my
+ * stylistic vision for SSLeay :-) */
+
+#ifndef HEADER_DSA_H
+#define HEADER_DSA_H
+
+#include <openssl/e_os2.h>
+
+#ifdef OPENSSL_NO_DSA
+#error DSA is disabled.
+#endif
+
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/crypto.h>
+#include <openssl/ossl_typ.h>
+
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_DH
+# include <openssl/dh.h>
+#endif
+#endif
+
+#define DSA_FLAG_CACHE_MONT_P	0x01
+#define DSA_FLAG_NO_EXP_CONSTTIME       0x02 /* new with 0.9.7h; the built-in DSA
+                                              * implementation now uses constant time
+                                              * modular exponentiation for secret exponents
+                                              * by default. This flag causes the
+                                              * faster variable sliding window method to
+                                              * be used for all exponents.
+                                              */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Already defined in ossl_typ.h */
+/* typedef struct dsa_st DSA; */
+/* typedef struct dsa_method DSA_METHOD; */
+
+typedef struct DSA_SIG_st
+	{
+	BIGNUM *r;
+	BIGNUM *s;
+	} DSA_SIG;
+
+struct dsa_method
+	{
+	const char *name;
+	DSA_SIG * (*dsa_do_sign)(const unsigned char *dgst, int dlen, DSA *dsa);
+	int (*dsa_sign_setup)(DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp,
+								BIGNUM **rp);
+	int (*dsa_do_verify)(const unsigned char *dgst, int dgst_len,
+							DSA_SIG *sig, DSA *dsa);
+	int (*dsa_mod_exp)(DSA *dsa, BIGNUM *rr, BIGNUM *a1, BIGNUM *p1,
+			BIGNUM *a2, BIGNUM *p2, BIGNUM *m, BN_CTX *ctx,
+			BN_MONT_CTX *in_mont);
+	int (*bn_mod_exp)(DSA *dsa, BIGNUM *r, BIGNUM *a, const BIGNUM *p,
+				const BIGNUM *m, BN_CTX *ctx,
+				BN_MONT_CTX *m_ctx); /* Can be null */
+	int (*init)(DSA *dsa);
+	int (*finish)(DSA *dsa);
+	int flags;
+	char *app_data;
+	/* If this is non-NULL, it is used to generate DSA parameters */
+	int (*dsa_paramgen)(DSA *dsa, int bits,
+			unsigned char *seed, int seed_len,
+			int *counter_ret, unsigned long *h_ret,
+			BN_GENCB *cb);
+	/* If this is non-NULL, it is used to generate DSA keys */
+	int (*dsa_keygen)(DSA *dsa);
+	};
+
+struct dsa_st
+	{
+	/* This first variable is used to pick up errors where
+	 * a DSA is passed instead of of a EVP_PKEY */
+	int pad;
+	long version;
+	int write_params;
+	BIGNUM *p;
+	BIGNUM *q;	/* == 20 */
+	BIGNUM *g;
+
+	BIGNUM *pub_key;  /* y public key */
+	BIGNUM *priv_key; /* x private key */
+
+	BIGNUM *kinv;	/* Signing pre-calc */
+	BIGNUM *r;	/* Signing pre-calc */
+
+	int flags;
+	/* Normally used to cache montgomery values */
+	BN_MONT_CTX *method_mont_p;
+	int references;
+	CRYPTO_EX_DATA ex_data;
+	const DSA_METHOD *meth;
+	/* functional reference if 'meth' is ENGINE-provided */
+	ENGINE *engine;
+	};
+
+#define DSAparams_dup(x) ASN1_dup_of_const(DSA,i2d_DSAparams,d2i_DSAparams,x)
+#define d2i_DSAparams_fp(fp,x) (DSA *)ASN1_d2i_fp((char *(*)())DSA_new, \
+		(char *(*)())d2i_DSAparams,(fp),(unsigned char **)(x))
+#define i2d_DSAparams_fp(fp,x) ASN1_i2d_fp(i2d_DSAparams,(fp), \
+		(unsigned char *)(x))
+#define d2i_DSAparams_bio(bp,x) ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSAparams,bp,x)
+#define i2d_DSAparams_bio(bp,x) ASN1_i2d_bio_of_const(DSA,i2d_DSAparams,bp,x)
+
+
+DSA_SIG * DSA_SIG_new(void);
+void	DSA_SIG_free(DSA_SIG *a);
+int	i2d_DSA_SIG(const DSA_SIG *a, unsigned char **pp);
+DSA_SIG * d2i_DSA_SIG(DSA_SIG **v, const unsigned char **pp, long length);
+
+DSA_SIG * DSA_do_sign(const unsigned char *dgst,int dlen,DSA *dsa);
+int	DSA_do_verify(const unsigned char *dgst,int dgst_len,
+		      DSA_SIG *sig,DSA *dsa);
+
+const DSA_METHOD *DSA_OpenSSL(void);
+
+void	DSA_set_default_method(const DSA_METHOD *);
+const DSA_METHOD *DSA_get_default_method(void);
+int	DSA_set_method(DSA *dsa, const DSA_METHOD *);
+
+DSA *	DSA_new(void);
+DSA *	DSA_new_method(ENGINE *engine);
+void	DSA_free (DSA *r);
+/* "up" the DSA object's reference count */
+int	DSA_up_ref(DSA *r);
+int	DSA_size(const DSA *);
+	/* next 4 return -1 on error */
+int	DSA_sign_setup( DSA *dsa,BN_CTX *ctx_in,BIGNUM **kinvp,BIGNUM **rp);
+int	DSA_sign(int type,const unsigned char *dgst,int dlen,
+		unsigned char *sig, unsigned int *siglen, DSA *dsa);
+int	DSA_verify(int type,const unsigned char *dgst,int dgst_len,
+		const unsigned char *sigbuf, int siglen, DSA *dsa);
+int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int DSA_set_ex_data(DSA *d, int idx, void *arg);
+void *DSA_get_ex_data(DSA *d, int idx);
+
+DSA *	d2i_DSAPublicKey(DSA **a, const unsigned char **pp, long length);
+DSA *	d2i_DSAPrivateKey(DSA **a, const unsigned char **pp, long length);
+DSA * 	d2i_DSAparams(DSA **a, const unsigned char **pp, long length);
+
+/* Deprecated version */
+#ifndef OPENSSL_NO_DEPRECATED
+DSA *	DSA_generate_parameters(int bits,
+		unsigned char *seed,int seed_len,
+		int *counter_ret, unsigned long *h_ret,void
+		(*callback)(int, int, void *),void *cb_arg);
+#endif /* !defined(OPENSSL_NO_DEPRECATED) */
+
+/* New version */
+int	DSA_generate_parameters_ex(DSA *dsa, int bits,
+		unsigned char *seed,int seed_len,
+		int *counter_ret, unsigned long *h_ret, BN_GENCB *cb);
+
+int	DSA_generate_key(DSA *a);
+int	i2d_DSAPublicKey(const DSA *a, unsigned char **pp);
+int 	i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
+int	i2d_DSAparams(const DSA *a,unsigned char **pp);
+
+#ifndef OPENSSL_NO_BIO
+int	DSAparams_print(BIO *bp, const DSA *x);
+int	DSA_print(BIO *bp, const DSA *x, int off);
+#endif
+#ifndef OPENSSL_NO_FP_API
+int	DSAparams_print_fp(FILE *fp, const DSA *x);
+int	DSA_print_fp(FILE *bp, const DSA *x, int off);
+#endif
+
+#define DSS_prime_checks 50
+/* Primality test according to FIPS PUB 186[-1], Appendix 2.1:
+ * 50 rounds of Rabin-Miller */
+#define DSA_is_prime(n, callback, cb_arg) \
+	BN_is_prime(n, DSS_prime_checks, callback, NULL, cb_arg)
+
+#ifndef OPENSSL_NO_DH
+/* Convert DSA structure (key or just parameters) into DH structure
+ * (be careful to avoid small subgroup attacks when using this!) */
+DH *DSA_dup_DH(const DSA *r);
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_DSA_strings(void);
+
+/* Error codes for the DSA functions. */
+
+/* Function codes. */
+#define DSA_F_D2I_DSA_SIG				 110
+#define DSA_F_DSAPARAMS_PRINT				 100
+#define DSA_F_DSAPARAMS_PRINT_FP			 101
+#define DSA_F_DSA_DO_SIGN				 112
+#define DSA_F_DSA_DO_VERIFY				 113
+#define DSA_F_DSA_NEW_METHOD				 103
+#define DSA_F_DSA_PRINT					 104
+#define DSA_F_DSA_PRINT_FP				 105
+#define DSA_F_DSA_SIGN					 106
+#define DSA_F_DSA_SIGN_SETUP				 107
+#define DSA_F_DSA_SIG_NEW				 109
+#define DSA_F_DSA_VERIFY				 108
+#define DSA_F_I2D_DSA_SIG				 111
+#define DSA_F_SIG_CB					 114
+
+/* Reason codes. */
+#define DSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE		 100
+#define DSA_R_MISSING_PARAMETERS			 101
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dso.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dso.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dso.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,368 @@
+/* dso.h -*- mode:C; c-file-style: "eay" -*- */
+/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_DSO_H
+#define HEADER_DSO_H
+
+#include <openssl/crypto.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* These values are used as commands to DSO_ctrl() */
+#define DSO_CTRL_GET_FLAGS	1
+#define DSO_CTRL_SET_FLAGS	2
+#define DSO_CTRL_OR_FLAGS	3
+
+/* By default, DSO_load() will translate the provided filename into a form
+ * typical for the platform (more specifically the DSO_METHOD) using the
+ * dso_name_converter function of the method. Eg. win32 will transform "blah"
+ * into "blah.dll", and dlfcn will transform it into "libblah.so". The
+ * behaviour can be overriden by setting the name_converter callback in the DSO
+ * object (using DSO_set_name_converter()). This callback could even utilise
+ * the DSO_METHOD's converter too if it only wants to override behaviour for
+ * one or two possible DSO methods. However, the following flag can be set in a
+ * DSO to prevent *any* native name-translation at all - eg. if the caller has
+ * prompted the user for a path to a driver library so the filename should be
+ * interpreted as-is. */
+#define DSO_FLAG_NO_NAME_TRANSLATION		0x01
+/* An extra flag to give if only the extension should be added as
+ * translation.  This is obviously only of importance on Unix and
+ * other operating systems where the translation also may prefix
+ * the name with something, like 'lib', and ignored everywhere else.
+ * This flag is also ignored if DSO_FLAG_NO_NAME_TRANSLATION is used
+ * at the same time. */
+#define DSO_FLAG_NAME_TRANSLATION_EXT_ONLY	0x02
+
+/* The following flag controls the translation of symbol names to upper
+ * case.  This is currently only being implemented for OpenVMS.
+ */
+#define DSO_FLAG_UPCASE_SYMBOL			0x10
+
+/* This flag loads the library with public symbols.
+ * Meaning: The exported symbols of this library are public
+ * to all libraries loaded after this library.
+ * At the moment only implemented in unix.
+ */
+#define DSO_FLAG_GLOBAL_SYMBOLS			0x20
+
+
+typedef void (*DSO_FUNC_TYPE)(void);
+
+typedef struct dso_st DSO;
+
+/* The function prototype used for method functions (or caller-provided
+ * callbacks) that transform filenames. They are passed a DSO structure pointer
+ * (or NULL if they are to be used independantly of a DSO object) and a
+ * filename to transform. They should either return NULL (if there is an error
+ * condition) or a newly allocated string containing the transformed form that
+ * the caller will need to free with OPENSSL_free() when done. */
+typedef char* (*DSO_NAME_CONVERTER_FUNC)(DSO *, const char *);
+/* The function prototype used for method functions (or caller-provided
+ * callbacks) that merge two file specifications. They are passed a
+ * DSO structure pointer (or NULL if they are to be used independantly of
+ * a DSO object) and two file specifications to merge. They should
+ * either return NULL (if there is an error condition) or a newly allocated
+ * string containing the result of merging that the caller will need
+ * to free with OPENSSL_free() when done.
+ * Here, merging means that bits and pieces are taken from each of the
+ * file specifications and added together in whatever fashion that is
+ * sensible for the DSO method in question.  The only rule that really
+ * applies is that if the two specification contain pieces of the same
+ * type, the copy from the string string takes priority.  One could see
+ * it as the first specification is the one given by the user and the
+ * second being a bunch of defaults to add on if they're missing in the
+ * first. */
+typedef char* (*DSO_MERGER_FUNC)(DSO *, const char *, const char *);
+
+typedef struct dso_meth_st
+	{
+	const char *name;
+	/* Loads a shared library, NB: new DSO_METHODs must ensure that a
+	 * successful load populates the loaded_filename field, and likewise a
+	 * successful unload OPENSSL_frees and NULLs it out. */
+	int (*dso_load)(DSO *dso);
+	/* Unloads a shared library */
+	int (*dso_unload)(DSO *dso);
+	/* Binds a variable */
+	void *(*dso_bind_var)(DSO *dso, const char *symname);
+	/* Binds a function - assumes a return type of DSO_FUNC_TYPE.
+	 * This should be cast to the real function prototype by the
+	 * caller. Platforms that don't have compatible representations
+	 * for different prototypes (this is possible within ANSI C)
+	 * are highly unlikely to have shared libraries at all, let
+	 * alone a DSO_METHOD implemented for them. */
+	DSO_FUNC_TYPE (*dso_bind_func)(DSO *dso, const char *symname);
+
+/* I don't think this would actually be used in any circumstances. */
+#if 0
+	/* Unbinds a variable */
+	int (*dso_unbind_var)(DSO *dso, char *symname, void *symptr);
+	/* Unbinds a function */
+	int (*dso_unbind_func)(DSO *dso, char *symname, DSO_FUNC_TYPE symptr);
+#endif
+	/* The generic (yuck) "ctrl()" function. NB: Negative return
+	 * values (rather than zero) indicate errors. */
+	long (*dso_ctrl)(DSO *dso, int cmd, long larg, void *parg);
+	/* The default DSO_METHOD-specific function for converting filenames to
+	 * a canonical native form. */
+	DSO_NAME_CONVERTER_FUNC dso_name_converter;
+	/* The default DSO_METHOD-specific function for converting filenames to
+	 * a canonical native form. */
+	DSO_MERGER_FUNC dso_merger;
+
+	/* [De]Initialisation handlers. */
+	int (*init)(DSO *dso);
+	int (*finish)(DSO *dso);
+	} DSO_METHOD;
+
+/**********************************************************************/
+/* The low-level handle type used to refer to a loaded shared library */
+
+struct dso_st
+	{
+	DSO_METHOD *meth;
+	/* Standard dlopen uses a (void *). Win32 uses a HANDLE. VMS
+	 * doesn't use anything but will need to cache the filename
+	 * for use in the dso_bind handler. All in all, let each
+	 * method control its own destiny. "Handles" and such go in
+	 * a STACK. */
+	STACK *meth_data;
+	int references;
+	int flags;
+	/* For use by applications etc ... use this for your bits'n'pieces,
+	 * don't touch meth_data! */
+	CRYPTO_EX_DATA ex_data;
+	/* If this callback function pointer is set to non-NULL, then it will
+	 * be used in DSO_load() in place of meth->dso_name_converter. NB: This
+	 * should normally set using DSO_set_name_converter(). */
+	DSO_NAME_CONVERTER_FUNC name_converter;
+	/* If this callback function pointer is set to non-NULL, then it will
+	 * be used in DSO_load() in place of meth->dso_merger. NB: This
+	 * should normally set using DSO_set_merger(). */
+	DSO_MERGER_FUNC merger;
+	/* This is populated with (a copy of) the platform-independant
+	 * filename used for this DSO. */
+	char *filename;
+	/* This is populated with (a copy of) the translated filename by which
+	 * the DSO was actually loaded. It is NULL iff the DSO is not currently
+	 * loaded. NB: This is here because the filename translation process
+	 * may involve a callback being invoked more than once not only to
+	 * convert to a platform-specific form, but also to try different
+	 * filenames in the process of trying to perform a load. As such, this
+	 * variable can be used to indicate (a) whether this DSO structure
+	 * corresponds to a loaded library or not, and (b) the filename with
+	 * which it was actually loaded. */
+	char *loaded_filename;
+	};
+
+
+DSO *	DSO_new(void);
+DSO *	DSO_new_method(DSO_METHOD *method);
+int	DSO_free(DSO *dso);
+int	DSO_flags(DSO *dso);
+int	DSO_up_ref(DSO *dso);
+long	DSO_ctrl(DSO *dso, int cmd, long larg, void *parg);
+
+/* This function sets the DSO's name_converter callback. If it is non-NULL,
+ * then it will be used instead of the associated DSO_METHOD's function. If
+ * oldcb is non-NULL then it is set to the function pointer value being
+ * replaced. Return value is non-zero for success. */
+int	DSO_set_name_converter(DSO *dso, DSO_NAME_CONVERTER_FUNC cb,
+				DSO_NAME_CONVERTER_FUNC *oldcb);
+/* These functions can be used to get/set the platform-independant filename
+ * used for a DSO. NB: set will fail if the DSO is already loaded. */
+const char *DSO_get_filename(DSO *dso);
+int	DSO_set_filename(DSO *dso, const char *filename);
+/* This function will invoke the DSO's name_converter callback to translate a
+ * filename, or if the callback isn't set it will instead use the DSO_METHOD's
+ * converter. If "filename" is NULL, the "filename" in the DSO itself will be
+ * used. If the DSO_FLAG_NO_NAME_TRANSLATION flag is set, then the filename is
+ * simply duplicated. NB: This function is usually called from within a
+ * DSO_METHOD during the processing of a DSO_load() call, and is exposed so that
+ * caller-created DSO_METHODs can do the same thing. A non-NULL return value
+ * will need to be OPENSSL_free()'d. */
+char	*DSO_convert_filename(DSO *dso, const char *filename);
+/* This function will invoke the DSO's merger callback to merge two file
+ * specifications, or if the callback isn't set it will instead use the
+ * DSO_METHOD's merger.  A non-NULL return value will need to be
+ * OPENSSL_free()'d. */
+char	*DSO_merge(DSO *dso, const char *filespec1, const char *filespec2);
+/* If the DSO is currently loaded, this returns the filename that it was loaded
+ * under, otherwise it returns NULL. So it is also useful as a test as to
+ * whether the DSO is currently loaded. NB: This will not necessarily return
+ * the same value as DSO_convert_filename(dso, dso->filename), because the
+ * DSO_METHOD's load function may have tried a variety of filenames (with
+ * and/or without the aid of the converters) before settling on the one it
+ * actually loaded. */
+const char *DSO_get_loaded_filename(DSO *dso);
+
+void	DSO_set_default_method(DSO_METHOD *meth);
+DSO_METHOD *DSO_get_default_method(void);
+DSO_METHOD *DSO_get_method(DSO *dso);
+DSO_METHOD *DSO_set_method(DSO *dso, DSO_METHOD *meth);
+
+/* The all-singing all-dancing load function, you normally pass NULL
+ * for the first and third parameters. Use DSO_up and DSO_free for
+ * subsequent reference count handling. Any flags passed in will be set
+ * in the constructed DSO after its init() function but before the
+ * load operation. If 'dso' is non-NULL, 'flags' is ignored. */
+DSO *DSO_load(DSO *dso, const char *filename, DSO_METHOD *meth, int flags);
+
+/* This function binds to a variable inside a shared library. */
+void *DSO_bind_var(DSO *dso, const char *symname);
+
+/* This function binds to a function inside a shared library. */
+DSO_FUNC_TYPE DSO_bind_func(DSO *dso, const char *symname);
+
+/* This method is the default, but will beg, borrow, or steal whatever
+ * method should be the default on any particular platform (including
+ * DSO_METH_null() if necessary). */
+DSO_METHOD *DSO_METHOD_openssl(void);
+
+/* This method is defined for all platforms - if a platform has no
+ * DSO support then this will be the only method! */
+DSO_METHOD *DSO_METHOD_null(void);
+
+/* If DSO_DLFCN is defined, the standard dlfcn.h-style functions
+ * (dlopen, dlclose, dlsym, etc) will be used and incorporated into
+ * this method. If not, this method will return NULL. */
+DSO_METHOD *DSO_METHOD_dlfcn(void);
+
+/* If DSO_DL is defined, the standard dl.h-style functions (shl_load, 
+ * shl_unload, shl_findsym, etc) will be used and incorporated into
+ * this method. If not, this method will return NULL. */
+DSO_METHOD *DSO_METHOD_dl(void);
+
+/* If WIN32 is defined, use DLLs. If not, return NULL. */
+DSO_METHOD *DSO_METHOD_win32(void);
+
+/* If VMS is defined, use shared images. If not, return NULL. */
+DSO_METHOD *DSO_METHOD_vms(void);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_DSO_strings(void);
+
+/* Error codes for the DSO functions. */
+
+/* Function codes. */
+#define DSO_F_DLFCN_BIND_FUNC				 100
+#define DSO_F_DLFCN_BIND_VAR				 101
+#define DSO_F_DLFCN_LOAD				 102
+#define DSO_F_DLFCN_MERGER				 130
+#define DSO_F_DLFCN_NAME_CONVERTER			 123
+#define DSO_F_DLFCN_UNLOAD				 103
+#define DSO_F_DL_BIND_FUNC				 104
+#define DSO_F_DL_BIND_VAR				 105
+#define DSO_F_DL_LOAD					 106
+#define DSO_F_DL_MERGER					 131
+#define DSO_F_DL_NAME_CONVERTER				 124
+#define DSO_F_DL_UNLOAD					 107
+#define DSO_F_DSO_BIND_FUNC				 108
+#define DSO_F_DSO_BIND_VAR				 109
+#define DSO_F_DSO_CONVERT_FILENAME			 126
+#define DSO_F_DSO_CTRL					 110
+#define DSO_F_DSO_FREE					 111
+#define DSO_F_DSO_GET_FILENAME				 127
+#define DSO_F_DSO_GET_LOADED_FILENAME			 128
+#define DSO_F_DSO_LOAD					 112
+#define DSO_F_DSO_MERGE					 132
+#define DSO_F_DSO_NEW_METHOD				 113
+#define DSO_F_DSO_SET_FILENAME				 129
+#define DSO_F_DSO_SET_NAME_CONVERTER			 122
+#define DSO_F_DSO_UP_REF				 114
+#define DSO_F_VMS_BIND_SYM				 115
+#define DSO_F_VMS_LOAD					 116
+#define DSO_F_VMS_MERGER				 133
+#define DSO_F_VMS_UNLOAD				 117
+#define DSO_F_WIN32_BIND_FUNC				 118
+#define DSO_F_WIN32_BIND_VAR				 119
+#define DSO_F_WIN32_JOINER				 135
+#define DSO_F_WIN32_LOAD				 120
+#define DSO_F_WIN32_MERGER				 134
+#define DSO_F_WIN32_NAME_CONVERTER			 125
+#define DSO_F_WIN32_SPLITTER				 136
+#define DSO_F_WIN32_UNLOAD				 121
+
+/* Reason codes. */
+#define DSO_R_CTRL_FAILED				 100
+#define DSO_R_DSO_ALREADY_LOADED			 110
+#define DSO_R_EMPTY_FILE_STRUCTURE			 113
+#define DSO_R_FAILURE					 114
+#define DSO_R_FILENAME_TOO_BIG				 101
+#define DSO_R_FINISH_FAILED				 102
+#define DSO_R_INCORRECT_FILE_SYNTAX			 115
+#define DSO_R_LOAD_FAILED				 103
+#define DSO_R_NAME_TRANSLATION_FAILED			 109
+#define DSO_R_NO_FILENAME				 111
+#define DSO_R_NO_FILE_SPECIFICATION			 116
+#define DSO_R_NULL_HANDLE				 104
+#define DSO_R_SET_FILENAME_FAILED			 112
+#define DSO_R_STACK_ERROR				 105
+#define DSO_R_SYM_FAILURE				 106
+#define DSO_R_UNLOAD_FAILED				 107
+#define DSO_R_UNSUPPORTED				 108
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dtls1.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dtls1.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/dtls1.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,212 @@
+/* ssl/dtls1.h */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_DTLS1_H 
+#define HEADER_DTLS1_H 
+
+#include <openssl/buffer.h>
+#include <openssl/pqueue.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define DTLS1_VERSION			0x0100
+#define DTLS1_VERSION_MAJOR		0x01
+#define DTLS1_VERSION_MINOR		0x00
+
+#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE    110
+
+/* lengths of messages */
+#define DTLS1_COOKIE_LENGTH                     32
+
+#define DTLS1_RT_HEADER_LENGTH                  13
+
+#define DTLS1_HM_HEADER_LENGTH                  12
+
+#define DTLS1_HM_BAD_FRAGMENT                   -2
+#define DTLS1_HM_FRAGMENT_RETRY                 -3
+
+#define DTLS1_CCS_HEADER_LENGTH                  3
+
+#define DTLS1_AL_HEADER_LENGTH                   7
+
+
+typedef struct dtls1_bitmap_st
+	{
+	PQ_64BIT map;
+	unsigned long length;     /* sizeof the bitmap in bits */
+	PQ_64BIT max_seq_num;  /* max record number seen so far */
+	} DTLS1_BITMAP;
+
+struct hm_header_st
+	{
+	unsigned char type;
+	unsigned long msg_len;
+	unsigned short seq;
+	unsigned long frag_off;
+	unsigned long frag_len;
+	unsigned int is_ccs;
+	};
+
+struct ccs_header_st
+	{
+	unsigned char type;
+	unsigned short seq;
+	};
+
+struct dtls1_timeout_st
+	{
+	/* Number of read timeouts so far */
+	unsigned int read_timeouts;
+	
+	/* Number of write timeouts so far */
+	unsigned int write_timeouts;
+	
+	/* Number of alerts received so far */
+	unsigned int num_alerts;
+	};
+
+typedef struct record_pqueue_st
+	{
+	unsigned short epoch;
+	pqueue q;
+	} record_pqueue;
+
+typedef struct hm_fragment_st
+	{
+	struct hm_header_st msg_header;
+	unsigned char *fragment;
+	} hm_fragment;
+
+typedef struct dtls1_state_st
+	{
+	unsigned int send_cookie;
+	unsigned char cookie[DTLS1_COOKIE_LENGTH];
+	unsigned char rcvd_cookie[DTLS1_COOKIE_LENGTH];
+	unsigned int cookie_len;
+
+	/* 
+	 * The current data and handshake epoch.  This is initially
+	 * undefined, and starts at zero once the initial handshake is
+	 * completed 
+	 */
+	unsigned short r_epoch;
+	unsigned short w_epoch;
+
+	/* records being received in the current epoch */
+	DTLS1_BITMAP bitmap;
+
+	/* renegotiation starts a new set of sequence numbers */
+	DTLS1_BITMAP next_bitmap;
+
+	/* handshake message numbers */
+	unsigned short handshake_write_seq;
+	unsigned short next_handshake_write_seq;
+
+	unsigned short handshake_read_seq;
+
+	/* Received handshake records (processed and unprocessed) */
+	record_pqueue unprocessed_rcds;
+	record_pqueue processed_rcds;
+
+	/* Buffered handshake messages */
+	pqueue buffered_messages;
+
+	/* Buffered (sent) handshake records */
+	pqueue sent_messages;
+
+	unsigned int mtu; /* max wire packet size */
+
+	struct hm_header_st w_msg_hdr;
+	struct hm_header_st r_msg_hdr;
+
+	struct dtls1_timeout_st timeout;
+	
+	/* storage for Alert/Handshake protocol data received but not
+	 * yet processed by ssl3_read_bytes: */
+	unsigned char alert_fragment[DTLS1_AL_HEADER_LENGTH];
+	unsigned int alert_fragment_len;
+	unsigned char handshake_fragment[DTLS1_HM_HEADER_LENGTH];
+	unsigned int handshake_fragment_len;
+
+	unsigned int retransmitting;
+
+	} DTLS1_STATE;
+
+typedef struct dtls1_record_data_st
+	{
+	unsigned char *packet;
+	unsigned int   packet_length;
+	SSL3_BUFFER    rbuf;
+	SSL3_RECORD    rrec;
+	} DTLS1_RECORD_DATA;
+
+
+/* Timeout multipliers (timeout slice is defined in apps/timeouts.h */
+#define DTLS1_TMO_READ_COUNT                      2
+#define DTLS1_TMO_WRITE_COUNT                     2
+
+#define DTLS1_TMO_ALERT_COUNT                     12
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/e_os2.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/e_os2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/e_os2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,285 @@
+/* e_os2.h */
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include <openssl/opensslconf.h>
+
+#ifndef HEADER_E_OS2_H
+#define HEADER_E_OS2_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************
+ * Detect operating systems.  This probably needs completing.
+ * The result is that at least one OPENSSL_SYS_os macro should be defined.
+ * However, if none is defined, Unix is assumed.
+ **/
+
+#define OPENSSL_SYS_UNIX
+
+/* ----------------------- Macintosh, before MacOS X ----------------------- */
+#if defined(__MWERKS__) && defined(macintosh) || defined(OPENSSL_SYSNAME_MAC)
+# undef OPENSSL_SYS_UNIX
+# define OPENSSL_SYS_MACINTOSH_CLASSIC
+#endif
+
+/* ----------------------- NetWare ----------------------------------------- */
+#if defined(NETWARE) || defined(OPENSSL_SYSNAME_NETWARE)
+# undef OPENSSL_SYS_UNIX
+# define OPENSSL_SYS_NETWARE
+#endif
+
+/* ---------------------- Microsoft operating systems ---------------------- */
+
+/* The 16 bit environments are pretty straightforward */
+#if defined(OPENSSL_SYSNAME_WIN16) || defined(OPENSSL_SYSNAME_MSDOS)
+# undef OPENSSL_SYS_UNIX
+# define OPENSSL_SYS_MSDOS
+#endif
+#if defined(OPENSSL_SYSNAME_WIN16)
+# undef OPENSSL_SYS_UNIX
+# define OPENSSL_SYS_WIN16
+#endif
+
+/* For 32 bit environment, there seems to be the CygWin environment and then
+   all the others that try to do the same thing Microsoft does... */
+#if defined(OPENSSL_SYSNAME_UWIN)
+# undef OPENSSL_SYS_UNIX
+# define OPENSSL_SYS_WIN32_UWIN
+#else
+# if defined(__CYGWIN32__) || defined(OPENSSL_SYSNAME_CYGWIN32)
+#  undef OPENSSL_SYS_UNIX
+#  define OPENSSL_SYS_WIN32_CYGWIN
+# else
+#  if defined(_WIN32) || defined(OPENSSL_SYSNAME_WIN32)
+#   undef OPENSSL_SYS_UNIX
+#   define OPENSSL_SYS_WIN32
+#  endif
+#  if defined(OPENSSL_SYSNAME_WINNT)
+#   undef OPENSSL_SYS_UNIX
+#   define OPENSSL_SYS_WINNT
+#  endif
+#  if defined(OPENSSL_SYSNAME_WINCE)
+#   undef OPENSSL_SYS_UNIX
+#   define OPENSSL_SYS_WINCE
+#  endif
+# endif
+#endif
+
+/* Anything that tries to look like Microsoft is "Windows" */
+#if defined(OPENSSL_SYS_WIN16) || defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_WINNT) || defined(OPENSSL_SYS_WINCE)
+# undef OPENSSL_SYS_UNIX
+# define OPENSSL_SYS_WINDOWS
+# ifndef OPENSSL_SYS_MSDOS
+#  define OPENSSL_SYS_MSDOS
+# endif
+#endif
+
+/* DLL settings.  This part is a bit tough, because it's up to the application
+   implementor how he or she will link the application, so it requires some
+   macro to be used. */
+#ifdef OPENSSL_SYS_WINDOWS
+# ifndef OPENSSL_OPT_WINDLL
+#  if defined(_WINDLL) /* This is used when building OpenSSL to indicate that
+                          DLL linkage should be used */
+#   define OPENSSL_OPT_WINDLL
+#  endif
+# endif
+#endif
+
+/* -------------------------------- OpenVMS -------------------------------- */
+#if defined(__VMS) || defined(VMS) || defined(OPENSSL_SYSNAME_VMS)
+# undef OPENSSL_SYS_UNIX
+# define OPENSSL_SYS_VMS
+# if defined(__DECC)
+#  define OPENSSL_SYS_VMS_DECC
+# elif defined(__DECCXX)
+#  define OPENSSL_SYS_VMS_DECC
+#  define OPENSSL_SYS_VMS_DECCXX
+# else
+#  define OPENSSL_SYS_VMS_NODECC
+# endif
+#endif
+
+/* --------------------------------- OS/2 ---------------------------------- */
+#if defined(__EMX__) || defined(__OS2__)
+# undef OPENSSL_SYS_UNIX
+# define OPENSSL_SYS_OS2
+#endif
+
+/* --------------------------------- Unix ---------------------------------- */
+#ifdef OPENSSL_SYS_UNIX
+# if defined(linux) || defined(__linux__) || defined(OPENSSL_SYSNAME_LINUX)
+#  define OPENSSL_SYS_LINUX
+# endif
+# ifdef OPENSSL_SYSNAME_MPE
+#  define OPENSSL_SYS_MPE
+# endif
+# ifdef OPENSSL_SYSNAME_SNI
+#  define OPENSSL_SYS_SNI
+# endif
+# ifdef OPENSSL_SYSNAME_ULTRASPARC
+#  define OPENSSL_SYS_ULTRASPARC
+# endif
+# ifdef OPENSSL_SYSNAME_NEWS4
+#  define OPENSSL_SYS_NEWS4
+# endif
+# ifdef OPENSSL_SYSNAME_MACOSX
+#  define OPENSSL_SYS_MACOSX
+# endif
+# ifdef OPENSSL_SYSNAME_MACOSX_RHAPSODY
+#  define OPENSSL_SYS_MACOSX_RHAPSODY
+#  define OPENSSL_SYS_MACOSX
+# endif
+# ifdef OPENSSL_SYSNAME_SUNOS
+#  define OPENSSL_SYS_SUNOS
+#endif
+# if defined(_CRAY) || defined(OPENSSL_SYSNAME_CRAY)
+#  define OPENSSL_SYS_CRAY
+# endif
+# if defined(_AIX) || defined(OPENSSL_SYSNAME_AIX)
+#  define OPENSSL_SYS_AIX
+# endif
+#endif
+
+/* --------------------------------- VOS ----------------------------------- */
+#ifdef OPENSSL_SYSNAME_VOS
+# define OPENSSL_SYS_VOS
+#endif
+
+/* ------------------------------- VxWorks --------------------------------- */
+#ifdef OPENSSL_SYSNAME_VXWORKS
+# define OPENSSL_SYS_VXWORKS
+#endif
+
+/**
+ * That's it for OS-specific stuff
+ *****************************************************************************/
+
+
+/* Specials for I/O an exit */
+#ifdef OPENSSL_SYS_WIN16
+# define OPENSSL_NO_FP_API
+#endif
+#ifdef OPENSSL_SYS_MSDOS
+# define OPENSSL_UNISTD_IO <io.h>
+# define OPENSSL_DECLARE_EXIT extern void exit(int);
+#else
+# define OPENSSL_UNISTD_IO OPENSSL_UNISTD
+# define OPENSSL_DECLARE_EXIT /* declared in unistd.h */
+#endif
+
+/* Definitions of OPENSSL_GLOBAL and OPENSSL_EXTERN, to define and declare
+   certain global symbols that, with some compilers under VMS, have to be
+   defined and declared explicitely with globaldef and globalref.
+   Definitions of OPENSSL_EXPORT and OPENSSL_IMPORT, to define and declare
+   DLL exports and imports for compilers under Win32.  These are a little
+   more complicated to use.  Basically, for any library that exports some
+   global variables, the following code must be present in the header file
+   that declares them, before OPENSSL_EXTERN is used:
+
+   #ifdef SOME_BUILD_FLAG_MACRO
+   # undef OPENSSL_EXTERN
+   # define OPENSSL_EXTERN OPENSSL_EXPORT
+   #endif
+
+   The default is to have OPENSSL_EXPORT, OPENSSL_IMPORT and OPENSSL_GLOBAL
+   have some generally sensible values, and for OPENSSL_EXTERN to have the
+   value OPENSSL_IMPORT.
+*/
+
+#if defined(OPENSSL_SYS_VMS_NODECC)
+# define OPENSSL_EXPORT globalref
+# define OPENSSL_IMPORT globalref
+# define OPENSSL_GLOBAL globaldef
+#elif defined(OPENSSL_SYS_WINDOWS) && defined(OPENSSL_OPT_WINDLL)
+# define OPENSSL_EXPORT extern __declspec(dllexport)
+# define OPENSSL_IMPORT extern __declspec(dllimport)
+# define OPENSSL_GLOBAL
+#else
+# define OPENSSL_EXPORT extern
+# define OPENSSL_IMPORT extern
+# define OPENSSL_GLOBAL
+#endif
+#define OPENSSL_EXTERN OPENSSL_IMPORT
+
+/* Macros to allow global variables to be reached through function calls when
+   required (if a shared library version requvres it, for example.
+   The way it's done allows definitions like this:
+
+	// in foobar.c
+	OPENSSL_IMPLEMENT_GLOBAL(int,foobar) = 0;
+	// in foobar.h
+	OPENSSL_DECLARE_GLOBAL(int,foobar);
+	#define foobar OPENSSL_GLOBAL_REF(foobar)
+*/
+#ifdef OPENSSL_EXPORT_VAR_AS_FUNCTION
+# define OPENSSL_IMPLEMENT_GLOBAL(type,name)			     \
+	extern type _hide_##name;				     \
+	type *_shadow_##name(void) { return &_hide_##name; }	     \
+	static type _hide_##name
+# define OPENSSL_DECLARE_GLOBAL(type,name) type *_shadow_##name(void)
+# define OPENSSL_GLOBAL_REF(name) (*(_shadow_##name()))
+#else
+# define OPENSSL_IMPLEMENT_GLOBAL(type,name) OPENSSL_GLOBAL type _shadow_##name
+# define OPENSSL_DECLARE_GLOBAL(type,name) OPENSSL_EXPORT type _shadow_##name
+# define OPENSSL_GLOBAL_REF(name) _shadow_##name
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ebcdic.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ebcdic.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ebcdic.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,19 @@
+/* crypto/ebcdic.h */
+
+#ifndef HEADER_EBCDIC_H
+#define HEADER_EBCDIC_H
+
+#include <sys/types.h>
+
+/* Avoid name clashes with other applications */
+#define os_toascii   _openssl_os_toascii
+#define os_toebcdic  _openssl_os_toebcdic
+#define ebcdic2ascii _openssl_ebcdic2ascii
+#define ascii2ebcdic _openssl_ascii2ebcdic
+
+extern const unsigned char os_toascii[256];
+extern const unsigned char os_toebcdic[256];
+void *ebcdic2ascii(void *dest, const void *srce, size_t count);
+void *ascii2ebcdic(void *dest, const void *srce, size_t count);
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ec.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ec.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ec.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,518 @@
+/* crypto/ec/ec.h */
+/*
+ * Originally written by Bodo Moeller for the OpenSSL project.
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by 
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * The elliptic curve binary polynomial software is originally written by 
+ * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems Laboratories.
+ *
+ */
+
+#ifndef HEADER_EC_H
+#define HEADER_EC_H
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_NO_EC
+#error EC is disabled.
+#endif
+
+#include <openssl/asn1.h>
+#include <openssl/symhacks.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#elif defined(__SUNPRO_C)
+# if __SUNPRO_C >= 0x520
+# pragma error_messages (off,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
+# endif
+#endif
+
+
+typedef enum {
+	/* values as defined in X9.62 (ECDSA) and elsewhere */
+	POINT_CONVERSION_COMPRESSED = 2,
+	POINT_CONVERSION_UNCOMPRESSED = 4,
+	POINT_CONVERSION_HYBRID = 6
+} point_conversion_form_t;
+
+
+typedef struct ec_method_st EC_METHOD;
+
+typedef struct ec_group_st
+	/*
+	 EC_METHOD *meth;
+	 -- field definition
+	 -- curve coefficients
+	 -- optional generator with associated information (order, cofactor)
+	 -- optional extra data (precomputed table for fast computation of multiples of generator)
+	 -- ASN1 stuff
+	*/
+	EC_GROUP;
+
+typedef struct ec_point_st EC_POINT;
+
+
+/* EC_METHODs for curves over GF(p).
+ * EC_GFp_simple_method provides the basis for the optimized methods.
+ */
+const EC_METHOD *EC_GFp_simple_method(void);
+const EC_METHOD *EC_GFp_mont_method(void);
+const EC_METHOD *EC_GFp_nist_method(void);
+
+/* EC_METHOD for curves over GF(2^m).
+ */
+const EC_METHOD *EC_GF2m_simple_method(void);
+
+
+EC_GROUP *EC_GROUP_new(const EC_METHOD *);
+void EC_GROUP_free(EC_GROUP *);
+void EC_GROUP_clear_free(EC_GROUP *);
+int EC_GROUP_copy(EC_GROUP *, const EC_GROUP *);
+EC_GROUP *EC_GROUP_dup(const EC_GROUP *);
+
+const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
+int EC_METHOD_get_field_type(const EC_METHOD *);
+
+int EC_GROUP_set_generator(EC_GROUP *, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor);
+const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
+int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *order, BN_CTX *);
+int EC_GROUP_get_cofactor(const EC_GROUP *, BIGNUM *cofactor, BN_CTX *);
+
+void EC_GROUP_set_curve_name(EC_GROUP *, int nid);
+int EC_GROUP_get_curve_name(const EC_GROUP *);
+
+void EC_GROUP_set_asn1_flag(EC_GROUP *, int flag);
+int EC_GROUP_get_asn1_flag(const EC_GROUP *);
+
+void EC_GROUP_set_point_conversion_form(EC_GROUP *, point_conversion_form_t);
+point_conversion_form_t EC_GROUP_get_point_conversion_form(const EC_GROUP *);
+
+unsigned char *EC_GROUP_get0_seed(const EC_GROUP *);
+size_t EC_GROUP_get_seed_len(const EC_GROUP *);
+size_t EC_GROUP_set_seed(EC_GROUP *, const unsigned char *, size_t len);
+
+int EC_GROUP_set_curve_GFp(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int EC_GROUP_get_curve_GFp(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
+int EC_GROUP_set_curve_GF2m(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+int EC_GROUP_get_curve_GF2m(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *);
+
+/* returns the number of bits needed to represent a field element */
+int EC_GROUP_get_degree(const EC_GROUP *);
+
+/* EC_GROUP_check() returns 1 if 'group' defines a valid group, 0 otherwise */
+int EC_GROUP_check(const EC_GROUP *group, BN_CTX *ctx);
+/* EC_GROUP_check_discriminant() returns 1 if the discriminant of the
+ * elliptic curve is not zero, 0 otherwise */
+int EC_GROUP_check_discriminant(const EC_GROUP *, BN_CTX *);
+
+/* EC_GROUP_cmp() returns 0 if both groups are equal and 1 otherwise */
+int EC_GROUP_cmp(const EC_GROUP *, const EC_GROUP *, BN_CTX *);
+
+/* EC_GROUP_new_GF*() calls EC_GROUP_new() and EC_GROUP_set_GF*()
+ * after choosing an appropriate EC_METHOD */
+EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+EC_GROUP *EC_GROUP_new_curve_GF2m(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *);
+
+/* EC_GROUP_new_by_curve_name() creates a EC_GROUP structure
+ * specified by a curve name (in form of a NID) */
+EC_GROUP *EC_GROUP_new_by_curve_name(int nid);
+/* handling of internal curves */
+typedef struct { 
+	int nid;
+	const char *comment;
+	} EC_builtin_curve;
+/* EC_builtin_curves(EC_builtin_curve *r, size_t size) returns number 
+ * of all available curves or zero if a error occurred. 
+ * In case r ist not zero nitems EC_builtin_curve structures 
+ * are filled with the data of the first nitems internal groups */
+size_t EC_get_builtin_curves(EC_builtin_curve *r, size_t nitems);
+
+
+/* EC_POINT functions */
+
+EC_POINT *EC_POINT_new(const EC_GROUP *);
+void EC_POINT_free(EC_POINT *);
+void EC_POINT_clear_free(EC_POINT *);
+int EC_POINT_copy(EC_POINT *, const EC_POINT *);
+EC_POINT *EC_POINT_dup(const EC_POINT *, const EC_GROUP *);
+ 
+const EC_METHOD *EC_POINT_method_of(const EC_POINT *);
+
+int EC_POINT_set_to_infinity(const EC_GROUP *, EC_POINT *);
+int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *);
+int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *, const EC_POINT *,
+	BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *);
+int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, const BIGNUM *y, BN_CTX *);
+int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *, const EC_POINT *,
+	BIGNUM *x, BIGNUM *y, BN_CTX *);
+int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, int y_bit, BN_CTX *);
+
+int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, const BIGNUM *y, BN_CTX *);
+int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *, const EC_POINT *,
+	BIGNUM *x, BIGNUM *y, BN_CTX *);
+int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *, EC_POINT *,
+	const BIGNUM *x, int y_bit, BN_CTX *);
+
+size_t EC_POINT_point2oct(const EC_GROUP *, const EC_POINT *, point_conversion_form_t form,
+        unsigned char *buf, size_t len, BN_CTX *);
+int EC_POINT_oct2point(const EC_GROUP *, EC_POINT *,
+        const unsigned char *buf, size_t len, BN_CTX *);
+
+/* other interfaces to point2oct/oct2point: */
+BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *,
+	point_conversion_form_t form, BIGNUM *, BN_CTX *);
+EC_POINT *EC_POINT_bn2point(const EC_GROUP *, const BIGNUM *,
+	EC_POINT *, BN_CTX *);
+char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *,
+	point_conversion_form_t form, BN_CTX *);
+EC_POINT *EC_POINT_hex2point(const EC_GROUP *, const char *,
+	EC_POINT *, BN_CTX *);
+
+int EC_POINT_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+int EC_POINT_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *);
+int EC_POINT_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
+
+int EC_POINT_is_at_infinity(const EC_GROUP *, const EC_POINT *);
+int EC_POINT_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
+int EC_POINT_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, BN_CTX *);
+
+int EC_POINT_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int EC_POINTs_make_affine(const EC_GROUP *, size_t num, EC_POINT *[], BN_CTX *);
+
+
+int EC_POINTs_mul(const EC_GROUP *, EC_POINT *r, const BIGNUM *, size_t num, const EC_POINT *[], const BIGNUM *[], BN_CTX *);
+int EC_POINT_mul(const EC_GROUP *, EC_POINT *r, const BIGNUM *, const EC_POINT *, const BIGNUM *, BN_CTX *);
+
+/* EC_GROUP_precompute_mult() stores multiples of generator for faster point multiplication */
+int EC_GROUP_precompute_mult(EC_GROUP *, BN_CTX *);
+/* EC_GROUP_have_precompute_mult() reports whether such precomputation has been done */
+int EC_GROUP_have_precompute_mult(const EC_GROUP *);
+
+
+
+/* ASN1 stuff */
+
+/* EC_GROUP_get_basis_type() returns the NID of the basis type
+ * used to represent the field elements */
+int EC_GROUP_get_basis_type(const EC_GROUP *);
+int EC_GROUP_get_trinomial_basis(const EC_GROUP *, unsigned int *k);
+int EC_GROUP_get_pentanomial_basis(const EC_GROUP *, unsigned int *k1, 
+	unsigned int *k2, unsigned int *k3);
+
+#define OPENSSL_EC_NAMED_CURVE	0x001
+
+typedef struct ecpk_parameters_st ECPKPARAMETERS;
+
+EC_GROUP *d2i_ECPKParameters(EC_GROUP **, const unsigned char **in, long len);
+int i2d_ECPKParameters(const EC_GROUP *, unsigned char **out);
+
+#define d2i_ECPKParameters_bio(bp,x) ASN1_d2i_bio_of(EC_GROUP,NULL,d2i_ECPKParameters,bp,x)
+#define i2d_ECPKParameters_bio(bp,x) ASN1_i2d_bio_of_const(EC_GROUP,i2d_ECPKParameters,bp,x)
+#define d2i_ECPKParameters_fp(fp,x) (EC_GROUP *)ASN1_d2i_fp(NULL, \
+                (char *(*)())d2i_ECPKParameters,(fp),(unsigned char **)(x))
+#define i2d_ECPKParameters_fp(fp,x) ASN1_i2d_fp(i2d_ECPKParameters,(fp), \
+		(unsigned char *)(x))
+
+#ifndef OPENSSL_NO_BIO
+int     ECPKParameters_print(BIO *bp, const EC_GROUP *x, int off);
+#endif
+#ifndef OPENSSL_NO_FP_API
+int     ECPKParameters_print_fp(FILE *fp, const EC_GROUP *x, int off);
+#endif
+
+/* the EC_KEY stuff */
+typedef struct ec_key_st EC_KEY;
+
+/* some values for the encoding_flag */
+#define EC_PKEY_NO_PARAMETERS	0x001
+#define EC_PKEY_NO_PUBKEY	0x002
+
+EC_KEY *EC_KEY_new(void);
+EC_KEY *EC_KEY_new_by_curve_name(int nid);
+void EC_KEY_free(EC_KEY *);
+EC_KEY *EC_KEY_copy(EC_KEY *, const EC_KEY *);
+EC_KEY *EC_KEY_dup(const EC_KEY *);
+
+int EC_KEY_up_ref(EC_KEY *);
+
+const EC_GROUP *EC_KEY_get0_group(const EC_KEY *);
+int EC_KEY_set_group(EC_KEY *, const EC_GROUP *);
+const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *);
+int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *);
+const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *);
+int EC_KEY_set_public_key(EC_KEY *, const EC_POINT *);
+unsigned EC_KEY_get_enc_flags(const EC_KEY *);
+void EC_KEY_set_enc_flags(EC_KEY *, unsigned int);
+point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *);
+void EC_KEY_set_conv_form(EC_KEY *, point_conversion_form_t);
+/* functions to set/get method specific data  */
+void *EC_KEY_get_key_method_data(EC_KEY *, 
+	void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
+void EC_KEY_insert_key_method_data(EC_KEY *, void *data,
+	void *(*dup_func)(void *), void (*free_func)(void *), void (*clear_free_func)(void *));
+/* wrapper functions for the underlying EC_GROUP object */
+void EC_KEY_set_asn1_flag(EC_KEY *, int);
+int EC_KEY_precompute_mult(EC_KEY *, BN_CTX *ctx);
+
+/* EC_KEY_generate_key() creates a ec private (public) key */
+int EC_KEY_generate_key(EC_KEY *);
+/* EC_KEY_check_key() */
+int EC_KEY_check_key(const EC_KEY *);
+
+/* de- and encoding functions for SEC1 ECPrivateKey */
+EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len);
+int i2d_ECPrivateKey(EC_KEY *a, unsigned char **out);
+/* de- and encoding functions for EC parameters */
+EC_KEY *d2i_ECParameters(EC_KEY **a, const unsigned char **in, long len);
+int i2d_ECParameters(EC_KEY *a, unsigned char **out);
+/* de- and encoding functions for EC public key
+ * (octet string, not DER -- hence 'o2i' and 'i2o') */
+EC_KEY *o2i_ECPublicKey(EC_KEY **a, const unsigned char **in, long len);
+int i2o_ECPublicKey(EC_KEY *a, unsigned char **out);
+
+#ifndef OPENSSL_NO_BIO
+int	ECParameters_print(BIO *bp, const EC_KEY *x);
+int	EC_KEY_print(BIO *bp, const EC_KEY *x, int off);
+#endif
+#ifndef OPENSSL_NO_FP_API
+int	ECParameters_print_fp(FILE *fp, const EC_KEY *x);
+int	EC_KEY_print_fp(FILE *fp, const EC_KEY *x, int off);
+#endif
+
+#define ECParameters_dup(x) ASN1_dup_of(EC_KEY,i2d_ECParameters,d2i_ECParameters,x)
+
+#ifndef __cplusplus
+#if defined(__SUNPRO_C)
+#  if __SUNPRO_C >= 0x520
+# pragma error_messages (default,E_ARRAY_OF_INCOMPLETE_NONAME,E_ARRAY_OF_INCOMPLETE)
+#  endif
+# endif
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_EC_strings(void);
+
+/* Error codes for the EC functions. */
+
+/* Function codes. */
+#define EC_F_COMPUTE_WNAF				 143
+#define EC_F_D2I_ECPARAMETERS				 144
+#define EC_F_D2I_ECPKPARAMETERS				 145
+#define EC_F_D2I_ECPRIVATEKEY				 146
+#define EC_F_ECPARAMETERS_PRINT				 147
+#define EC_F_ECPARAMETERS_PRINT_FP			 148
+#define EC_F_ECPKPARAMETERS_PRINT			 149
+#define EC_F_ECPKPARAMETERS_PRINT_FP			 150
+#define EC_F_ECP_NIST_MOD_192				 203
+#define EC_F_ECP_NIST_MOD_224				 204
+#define EC_F_ECP_NIST_MOD_256				 205
+#define EC_F_ECP_NIST_MOD_521				 206
+#define EC_F_EC_ASN1_GROUP2CURVE			 153
+#define EC_F_EC_ASN1_GROUP2FIELDID			 154
+#define EC_F_EC_ASN1_GROUP2PARAMETERS			 155
+#define EC_F_EC_ASN1_GROUP2PKPARAMETERS			 156
+#define EC_F_EC_ASN1_PARAMETERS2GROUP			 157
+#define EC_F_EC_ASN1_PKPARAMETERS2GROUP			 158
+#define EC_F_EC_GF2M_MONTGOMERY_POINT_MULTIPLY		 208
+#define EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT	 159
+#define EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE		 195
+#define EC_F_EC_GF2M_SIMPLE_OCT2POINT			 160
+#define EC_F_EC_GF2M_SIMPLE_POINT2OCT			 161
+#define EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES 162
+#define EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES 163
+#define EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES	 164
+#define EC_F_EC_GFP_MONT_FIELD_DECODE			 133
+#define EC_F_EC_GFP_MONT_FIELD_ENCODE			 134
+#define EC_F_EC_GFP_MONT_FIELD_MUL			 131
+#define EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE		 209
+#define EC_F_EC_GFP_MONT_FIELD_SQR			 132
+#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE		 189
+#define EC_F_EC_GFP_MONT_GROUP_SET_CURVE_GFP		 135
+#define EC_F_EC_GFP_NIST_FIELD_MUL			 200
+#define EC_F_EC_GFP_NIST_FIELD_SQR			 201
+#define EC_F_EC_GFP_NIST_GROUP_SET_CURVE		 202
+#define EC_F_EC_GFP_SIMPLE_GROUP_CHECK_DISCRIMINANT	 165
+#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE		 166
+#define EC_F_EC_GFP_SIMPLE_GROUP_SET_CURVE_GFP		 100
+#define EC_F_EC_GFP_SIMPLE_GROUP_SET_GENERATOR		 101
+#define EC_F_EC_GFP_SIMPLE_MAKE_AFFINE			 102
+#define EC_F_EC_GFP_SIMPLE_OCT2POINT			 103
+#define EC_F_EC_GFP_SIMPLE_POINT2OCT			 104
+#define EC_F_EC_GFP_SIMPLE_POINTS_MAKE_AFFINE		 137
+#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES	 167
+#define EC_F_EC_GFP_SIMPLE_POINT_GET_AFFINE_COORDINATES_GFP 105
+#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES	 168
+#define EC_F_EC_GFP_SIMPLE_POINT_SET_AFFINE_COORDINATES_GFP 128
+#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES	 169
+#define EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES_GFP 129
+#define EC_F_EC_GROUP_CHECK				 170
+#define EC_F_EC_GROUP_CHECK_DISCRIMINANT		 171
+#define EC_F_EC_GROUP_COPY				 106
+#define EC_F_EC_GROUP_GET0_GENERATOR			 139
+#define EC_F_EC_GROUP_GET_COFACTOR			 140
+#define EC_F_EC_GROUP_GET_CURVE_GF2M			 172
+#define EC_F_EC_GROUP_GET_CURVE_GFP			 130
+#define EC_F_EC_GROUP_GET_DEGREE			 173
+#define EC_F_EC_GROUP_GET_ORDER				 141
+#define EC_F_EC_GROUP_GET_PENTANOMIAL_BASIS		 193
+#define EC_F_EC_GROUP_GET_TRINOMIAL_BASIS		 194
+#define EC_F_EC_GROUP_GROUP2NID				 147
+#define EC_F_EC_GROUP_NEW				 108
+#define EC_F_EC_GROUP_NEW_BY_CURVE_NAME			 174
+#define EC_F_EC_GROUP_NEW_FROM_DATA			 175
+#define EC_F_EC_GROUP_PRECOMPUTE_MULT			 142
+#define EC_F_EC_GROUP_SET_CURVE_GF2M			 176
+#define EC_F_EC_GROUP_SET_CURVE_GFP			 109
+#define EC_F_EC_GROUP_SET_EXTRA_DATA			 110
+#define EC_F_EC_GROUP_SET_GENERATOR			 111
+#define EC_F_EC_KEY_CHECK_KEY				 177
+#define EC_F_EC_KEY_COPY				 178
+#define EC_F_EC_KEY_GENERATE_KEY			 179
+#define EC_F_EC_KEY_NEW					 182
+#define EC_F_EC_KEY_PRINT				 180
+#define EC_F_EC_KEY_PRINT_FP				 181
+#define EC_F_EC_POINTS_MAKE_AFFINE			 136
+#define EC_F_EC_POINTS_MUL				 138
+#define EC_F_EC_POINT_ADD				 112
+#define EC_F_EC_POINT_CMP				 113
+#define EC_F_EC_POINT_COPY				 114
+#define EC_F_EC_POINT_DBL				 115
+#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GF2M	 183
+#define EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP	 116
+#define EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP	 117
+#define EC_F_EC_POINT_INVERT				 210
+#define EC_F_EC_POINT_IS_AT_INFINITY			 118
+#define EC_F_EC_POINT_IS_ON_CURVE			 119
+#define EC_F_EC_POINT_MAKE_AFFINE			 120
+#define EC_F_EC_POINT_MUL				 184
+#define EC_F_EC_POINT_NEW				 121
+#define EC_F_EC_POINT_OCT2POINT				 122
+#define EC_F_EC_POINT_POINT2OCT				 123
+#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GF2M	 185
+#define EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP	 124
+#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GF2M	 186
+#define EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP	 125
+#define EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP	 126
+#define EC_F_EC_POINT_SET_TO_INFINITY			 127
+#define EC_F_EC_PRE_COMP_DUP				 207
+#define EC_F_EC_WNAF_MUL				 187
+#define EC_F_EC_WNAF_PRECOMPUTE_MULT			 188
+#define EC_F_I2D_ECPARAMETERS				 190
+#define EC_F_I2D_ECPKPARAMETERS				 191
+#define EC_F_I2D_ECPRIVATEKEY				 192
+#define EC_F_I2O_ECPUBLICKEY				 151
+#define EC_F_O2I_ECPUBLICKEY				 152
+
+/* Reason codes. */
+#define EC_R_ASN1_ERROR					 115
+#define EC_R_ASN1_UNKNOWN_FIELD				 116
+#define EC_R_BUFFER_TOO_SMALL				 100
+#define EC_R_D2I_ECPKPARAMETERS_FAILURE			 117
+#define EC_R_DISCRIMINANT_IS_ZERO			 118
+#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE		 119
+#define EC_R_GROUP2PKPARAMETERS_FAILURE			 120
+#define EC_R_I2D_ECPKPARAMETERS_FAILURE			 121
+#define EC_R_INCOMPATIBLE_OBJECTS			 101
+#define EC_R_INVALID_ARGUMENT				 112
+#define EC_R_INVALID_COMPRESSED_POINT			 110
+#define EC_R_INVALID_COMPRESSION_BIT			 109
+#define EC_R_INVALID_ENCODING				 102
+#define EC_R_INVALID_FIELD				 103
+#define EC_R_INVALID_FORM				 104
+#define EC_R_INVALID_GROUP_ORDER			 122
+#define EC_R_INVALID_PRIVATE_KEY			 123
+#define EC_R_MISSING_PARAMETERS				 124
+#define EC_R_MISSING_PRIVATE_KEY			 125
+#define EC_R_NOT_A_NIST_PRIME				 135
+#define EC_R_NOT_A_SUPPORTED_NIST_PRIME			 136
+#define EC_R_NOT_IMPLEMENTED				 126
+#define EC_R_NOT_INITIALIZED				 111
+#define EC_R_NO_FIELD_MOD				 133
+#define EC_R_PASSED_NULL_PARAMETER			 134
+#define EC_R_PKPARAMETERS2GROUP_FAILURE			 127
+#define EC_R_POINT_AT_INFINITY				 106
+#define EC_R_POINT_IS_NOT_ON_CURVE			 107
+#define EC_R_SLOT_FULL					 108
+#define EC_R_UNDEFINED_GENERATOR			 113
+#define EC_R_UNDEFINED_ORDER				 128
+#define EC_R_UNKNOWN_GROUP				 129
+#define EC_R_UNKNOWN_ORDER				 114
+#define EC_R_UNSUPPORTED_FIELD				 131
+#define EC_R_WRONG_ORDER				 130
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ecdh.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ecdh.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ecdh.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,123 @@
+/* crypto/ecdh/ecdh.h */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
+ * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
+ * to the OpenSSL project.
+ *
+ * The ECC Code is licensed pursuant to the OpenSSL open source
+ * license provided below.
+ *
+ * The ECDH software is originally written by Douglas Stebila of
+ * Sun Microsystems Laboratories.
+ *
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2002 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#ifndef HEADER_ECDH_H
+#define HEADER_ECDH_H
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_NO_ECDH
+#error ECDH is disabled.
+#endif
+
+#include <openssl/ec.h>
+#include <openssl/ossl_typ.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+const ECDH_METHOD *ECDH_OpenSSL(void);
+
+void	  ECDH_set_default_method(const ECDH_METHOD *);
+const ECDH_METHOD *ECDH_get_default_method(void);
+int 	  ECDH_set_method(EC_KEY *, const ECDH_METHOD *);
+
+int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, EC_KEY *ecdh,
+                     void *(*KDF)(const void *in, size_t inlen, void *out, size_t *outlen));
+
+int 	  ECDH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new 
+		*new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int 	  ECDH_set_ex_data(EC_KEY *d, int idx, void *arg);
+void 	  *ECDH_get_ex_data(EC_KEY *d, int idx);
+
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_ECDH_strings(void);
+
+/* Error codes for the ECDH functions. */
+
+/* Function codes. */
+#define ECDH_F_ECDH_COMPUTE_KEY				 100
+#define ECDH_F_ECDH_DATA_NEW_METHOD			 101
+
+/* Reason codes. */
+#define ECDH_R_KDF_FAILED				 102
+#define ECDH_R_NO_PRIVATE_VALUE				 100
+#define ECDH_R_POINT_ARITHMETIC_FAILURE			 101
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ecdsa.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ecdsa.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ecdsa.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,270 @@
+/* crypto/ecdsa/ecdsa.h */
+/**
+ * \file   crypto/ecdsa/ecdsa.h Include file for the OpenSSL ECDSA functions
+ * \author Written by Nils Larsch for the OpenSSL project
+ */
+/* ====================================================================
+ * Copyright (c) 2000-2003 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#ifndef HEADER_ECDSA_H
+#define HEADER_ECDSA_H
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_NO_ECDSA
+#error ECDSA is disabled.
+#endif
+
+#include <openssl/ec.h>
+#include <openssl/ossl_typ.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ECDSA_SIG_st
+	{
+	BIGNUM *r;
+	BIGNUM *s;
+	} ECDSA_SIG;
+
+/** ECDSA_SIG *ECDSA_SIG_new(void)
+ * allocates and initialize a ECDSA_SIG structure
+ * \return pointer to a ECDSA_SIG structure or NULL if an error occurred
+ */
+ECDSA_SIG *ECDSA_SIG_new(void);
+
+/** ECDSA_SIG_free
+ * frees a ECDSA_SIG structure
+ * \param a pointer to the ECDSA_SIG structure
+ */
+void	  ECDSA_SIG_free(ECDSA_SIG *a);
+
+/** i2d_ECDSA_SIG
+ * DER encode content of ECDSA_SIG object (note: this function modifies *pp
+ * (*pp += length of the DER encoded signature)).
+ * \param a  pointer to the ECDSA_SIG object
+ * \param pp pointer to a unsigned char pointer for the output or NULL
+ * \return the length of the DER encoded ECDSA_SIG object or 0 
+ */
+int	  i2d_ECDSA_SIG(const ECDSA_SIG *a, unsigned char **pp);
+
+/** d2i_ECDSA_SIG
+ * decodes a DER encoded ECDSA signature (note: this function changes *pp
+ * (*pp += len)). 
+ * \param v pointer to ECDSA_SIG pointer (may be NULL)
+ * \param pp buffer with the DER encoded signature
+ * \param len bufferlength
+ * \return pointer to the decoded ECDSA_SIG structure (or NULL)
+ */
+ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **v, const unsigned char **pp, long len);
+
+/** ECDSA_do_sign
+ * computes the ECDSA signature of the given hash value using
+ * the supplied private key and returns the created signature.
+ * \param dgst pointer to the hash value
+ * \param dgst_len length of the hash value
+ * \param eckey pointer to the EC_KEY object containing a private EC key
+ * \return pointer to a ECDSA_SIG structure or NULL
+ */
+ECDSA_SIG *ECDSA_do_sign(const unsigned char *dgst,int dgst_len,EC_KEY *eckey);
+
+/** ECDSA_do_sign_ex
+ * computes ECDSA signature of a given hash value using the supplied
+ * private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
+ * \param dgst pointer to the hash value to sign
+ * \param dgstlen length of the hash value
+ * \param kinv optional pointer to a pre-computed inverse k
+ * \param rp optional pointer to the pre-computed rp value (see 
+ *        ECDSA_sign_setup
+ * \param eckey pointer to the EC_KEY object containing a private EC key
+ * \return pointer to a ECDSA_SIG structure or NULL
+ */
+ECDSA_SIG *ECDSA_do_sign_ex(const unsigned char *dgst, int dgstlen, 
+		const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey);
+
+/** ECDSA_do_verify
+ * verifies that the supplied signature is a valid ECDSA
+ * signature of the supplied hash value using the supplied public key.
+ * \param dgst pointer to the hash value
+ * \param dgst_len length of the hash value
+ * \param sig  pointer to the ECDSA_SIG structure
+ * \param eckey pointer to the EC_KEY object containing a public EC key
+ * \return 1 if the signature is valid, 0 if the signature is invalid and -1 on error
+ */
+int	  ECDSA_do_verify(const unsigned char *dgst, int dgst_len,
+		const ECDSA_SIG *sig, EC_KEY* eckey);
+
+const ECDSA_METHOD *ECDSA_OpenSSL(void);
+
+/** ECDSA_set_default_method
+ * sets the default ECDSA method
+ * \param meth the new default ECDSA_METHOD
+ */
+void	  ECDSA_set_default_method(const ECDSA_METHOD *meth);
+
+/** ECDSA_get_default_method
+ * returns the default ECDSA method
+ * \return pointer to ECDSA_METHOD structure containing the default method
+ */
+const ECDSA_METHOD *ECDSA_get_default_method(void);
+
+/** ECDSA_set_method
+ * sets method to be used for the ECDSA operations
+ * \param eckey pointer to the EC_KEY object
+ * \param meth  pointer to the new method
+ * \return 1 on success and 0 otherwise 
+ */
+int 	  ECDSA_set_method(EC_KEY *eckey, const ECDSA_METHOD *meth);
+
+/** ECDSA_size
+ * returns the maximum length of the DER encoded signature
+ * \param  eckey pointer to a EC_KEY object
+ * \return numbers of bytes required for the DER encoded signature
+ */
+int	  ECDSA_size(const EC_KEY *eckey);
+
+/** ECDSA_sign_setup
+ * precompute parts of the signing operation. 
+ * \param eckey pointer to the EC_KEY object containing a private EC key
+ * \param ctx  pointer to a BN_CTX object (may be NULL)
+ * \param kinv pointer to a BIGNUM pointer for the inverse of k
+ * \param rp   pointer to a BIGNUM pointer for x coordinate of k * generator
+ * \return 1 on success and 0 otherwise
+ */
+int 	  ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, 
+		BIGNUM **rp);
+
+/** ECDSA_sign
+ * computes ECDSA signature of a given hash value using the supplied
+ * private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
+ * \param type this parameter is ignored
+ * \param dgst pointer to the hash value to sign
+ * \param dgstlen length of the hash value
+ * \param sig buffer to hold the DER encoded signature
+ * \param siglen pointer to the length of the returned signature
+ * \param eckey pointer to the EC_KEY object containing a private EC key
+ * \return 1 on success and 0 otherwise
+ */
+int	  ECDSA_sign(int type, const unsigned char *dgst, int dgstlen, 
+		unsigned char *sig, unsigned int *siglen, EC_KEY *eckey);
+
+
+/** ECDSA_sign_ex
+ * computes ECDSA signature of a given hash value using the supplied
+ * private key (note: sig must point to ECDSA_size(eckey) bytes of memory).
+ * \param type this parameter is ignored
+ * \param dgst pointer to the hash value to sign
+ * \param dgstlen length of the hash value
+ * \param sig buffer to hold the DER encoded signature
+ * \param siglen pointer to the length of the returned signature
+ * \param kinv optional pointer to a pre-computed inverse k
+ * \param rp optional pointer to the pre-computed rp value (see 
+ *        ECDSA_sign_setup
+ * \param eckey pointer to the EC_KEY object containing a private EC key
+ * \return 1 on success and 0 otherwise
+ */
+int	  ECDSA_sign_ex(int type, const unsigned char *dgst, int dgstlen, 
+		unsigned char *sig, unsigned int *siglen, const BIGNUM *kinv,
+		const BIGNUM *rp, EC_KEY *eckey);
+
+/** ECDSA_verify
+ * verifies that the given signature is valid ECDSA signature
+ * of the supplied hash value using the specified public key.
+ * \param type this parameter is ignored
+ * \param dgst pointer to the hash value 
+ * \param dgstlen length of the hash value
+ * \param sig  pointer to the DER encoded signature
+ * \param siglen length of the DER encoded signature
+ * \param eckey pointer to the EC_KEY object containing a public EC key
+ * \return 1 if the signature is valid, 0 if the signature is invalid and -1 on error
+ */
+int 	  ECDSA_verify(int type, const unsigned char *dgst, int dgstlen, 
+		const unsigned char *sig, int siglen, EC_KEY *eckey);
+
+/* the standard ex_data functions */
+int 	  ECDSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new 
+		*new_func, CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int 	  ECDSA_set_ex_data(EC_KEY *d, int idx, void *arg);
+void 	  *ECDSA_get_ex_data(EC_KEY *d, int idx);
+
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_ECDSA_strings(void);
+
+/* Error codes for the ECDSA functions. */
+
+/* Function codes. */
+#define ECDSA_F_ECDSA_DATA_NEW_METHOD			 100
+#define ECDSA_F_ECDSA_DO_SIGN				 101
+#define ECDSA_F_ECDSA_DO_VERIFY				 102
+#define ECDSA_F_ECDSA_SIGN_SETUP			 103
+
+/* Reason codes. */
+#define ECDSA_R_BAD_SIGNATURE				 100
+#define ECDSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE		 101
+#define ECDSA_R_ERR_EC_LIB				 102
+#define ECDSA_R_MISSING_PARAMETERS			 103
+#define ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED		 104
+#define ECDSA_R_SIGNATURE_MALLOC_FAILED			 105
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/engine.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/engine.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/engine.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,801 @@
+/* openssl/engine.h */
+/* Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECDH support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#ifndef HEADER_ENGINE_H
+#define HEADER_ENGINE_H
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_NO_ENGINE
+#error ENGINE is disabled.
+#endif
+
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#ifndef OPENSSL_NO_RSA
+#include <openssl/rsa.h>
+#endif
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#ifndef OPENSSL_NO_ECDH
+#include <openssl/ecdh.h>
+#endif
+#ifndef OPENSSL_NO_ECDSA
+#include <openssl/ecdsa.h>
+#endif
+#include <openssl/rand.h>
+#include <openssl/store.h>
+#include <openssl/ui.h>
+#include <openssl/err.h>
+#endif
+
+#include <openssl/ossl_typ.h>
+#include <openssl/symhacks.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Fixups for missing algorithms */
+#ifdef OPENSSL_NO_RSA
+typedef void RSA_METHOD;
+#endif
+#ifdef OPENSSL_NO_DSA
+typedef void DSA_METHOD;
+#endif
+#ifdef OPENSSL_NO_DH
+typedef void DH_METHOD;
+#endif
+#ifdef OPENSSL_NO_ECDH
+typedef void ECDH_METHOD;
+#endif
+#ifdef OPENSSL_NO_ECDSA
+typedef void ECDSA_METHOD;
+#endif
+
+/* These flags are used to control combinations of algorithm (methods)
+ * by bitwise "OR"ing. */
+#define ENGINE_METHOD_RSA		(unsigned int)0x0001
+#define ENGINE_METHOD_DSA		(unsigned int)0x0002
+#define ENGINE_METHOD_DH		(unsigned int)0x0004
+#define ENGINE_METHOD_RAND		(unsigned int)0x0008
+#define ENGINE_METHOD_ECDH		(unsigned int)0x0010
+#define ENGINE_METHOD_ECDSA		(unsigned int)0x0020
+#define ENGINE_METHOD_CIPHERS		(unsigned int)0x0040
+#define ENGINE_METHOD_DIGESTS		(unsigned int)0x0080
+#define ENGINE_METHOD_STORE		(unsigned int)0x0100
+/* Obvious all-or-nothing cases. */
+#define ENGINE_METHOD_ALL		(unsigned int)0xFFFF
+#define ENGINE_METHOD_NONE		(unsigned int)0x0000
+
+/* This(ese) flag(s) controls behaviour of the ENGINE_TABLE mechanism used
+ * internally to control registration of ENGINE implementations, and can be set
+ * by ENGINE_set_table_flags(). The "NOINIT" flag prevents attempts to
+ * initialise registered ENGINEs if they are not already initialised. */
+#define ENGINE_TABLE_FLAG_NOINIT	(unsigned int)0x0001
+
+/* ENGINE flags that can be set by ENGINE_set_flags(). */
+/* #define ENGINE_FLAGS_MALLOCED	0x0001 */ /* Not used */
+
+/* This flag is for ENGINEs that wish to handle the various 'CMD'-related
+ * control commands on their own. Without this flag, ENGINE_ctrl() handles these
+ * control commands on behalf of the ENGINE using their "cmd_defns" data. */
+#define ENGINE_FLAGS_MANUAL_CMD_CTRL	(int)0x0002
+
+/* This flag is for ENGINEs who return new duplicate structures when found via
+ * "ENGINE_by_id()". When an ENGINE must store state (eg. if ENGINE_ctrl()
+ * commands are called in sequence as part of some stateful process like
+ * key-generation setup and execution), it can set this flag - then each attempt
+ * to obtain the ENGINE will result in it being copied into a new structure.
+ * Normally, ENGINEs don't declare this flag so ENGINE_by_id() just increments
+ * the existing ENGINE's structural reference count. */
+#define ENGINE_FLAGS_BY_ID_COPY		(int)0x0004
+
+/* ENGINEs can support their own command types, and these flags are used in
+ * ENGINE_CTRL_GET_CMD_FLAGS to indicate to the caller what kind of input each
+ * command expects. Currently only numeric and string input is supported. If a
+ * control command supports none of the _NUMERIC, _STRING, or _NO_INPUT options,
+ * then it is regarded as an "internal" control command - and not for use in
+ * config setting situations. As such, they're not available to the
+ * ENGINE_ctrl_cmd_string() function, only raw ENGINE_ctrl() access. Changes to
+ * this list of 'command types' should be reflected carefully in
+ * ENGINE_cmd_is_executable() and ENGINE_ctrl_cmd_string(). */
+
+/* accepts a 'long' input value (3rd parameter to ENGINE_ctrl) */
+#define ENGINE_CMD_FLAG_NUMERIC		(unsigned int)0x0001
+/* accepts string input (cast from 'void*' to 'const char *', 4th parameter to
+ * ENGINE_ctrl) */
+#define ENGINE_CMD_FLAG_STRING		(unsigned int)0x0002
+/* Indicates that the control command takes *no* input. Ie. the control command
+ * is unparameterised. */
+#define ENGINE_CMD_FLAG_NO_INPUT	(unsigned int)0x0004
+/* Indicates that the control command is internal. This control command won't
+ * be shown in any output, and is only usable through the ENGINE_ctrl_cmd()
+ * function. */
+#define ENGINE_CMD_FLAG_INTERNAL	(unsigned int)0x0008
+
+/* NB: These 3 control commands are deprecated and should not be used. ENGINEs
+ * relying on these commands should compile conditional support for
+ * compatibility (eg. if these symbols are defined) but should also migrate the
+ * same functionality to their own ENGINE-specific control functions that can be
+ * "discovered" by calling applications. The fact these control commands
+ * wouldn't be "executable" (ie. usable by text-based config) doesn't change the
+ * fact that application code can find and use them without requiring per-ENGINE
+ * hacking. */
+
+/* These flags are used to tell the ctrl function what should be done.
+ * All command numbers are shared between all engines, even if some don't
+ * make sense to some engines.  In such a case, they do nothing but return
+ * the error ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED. */
+#define ENGINE_CTRL_SET_LOGSTREAM		1
+#define ENGINE_CTRL_SET_PASSWORD_CALLBACK	2
+#define ENGINE_CTRL_HUP				3 /* Close and reinitialise any
+						     handles/connections etc. */
+#define ENGINE_CTRL_SET_USER_INTERFACE          4 /* Alternative to callback */
+#define ENGINE_CTRL_SET_CALLBACK_DATA           5 /* User-specific data, used
+						     when calling the password
+						     callback and the user
+						     interface */
+#define ENGINE_CTRL_LOAD_CONFIGURATION		6 /* Load a configuration, given
+						     a string that represents a
+						     file name or so */
+#define ENGINE_CTRL_LOAD_SECTION		7 /* Load data from a given
+						     section in the already loaded
+						     configuration */
+
+/* These control commands allow an application to deal with an arbitrary engine
+ * in a dynamic way. Warn: Negative return values indicate errors FOR THESE
+ * COMMANDS because zero is used to indicate 'end-of-list'. Other commands,
+ * including ENGINE-specific command types, return zero for an error.
+ *
+ * An ENGINE can choose to implement these ctrl functions, and can internally
+ * manage things however it chooses - it does so by setting the
+ * ENGINE_FLAGS_MANUAL_CMD_CTRL flag (using ENGINE_set_flags()). Otherwise the
+ * ENGINE_ctrl() code handles this on the ENGINE's behalf using the cmd_defns
+ * data (set using ENGINE_set_cmd_defns()). This means an ENGINE's ctrl()
+ * handler need only implement its own commands - the above "meta" commands will
+ * be taken care of. */
+
+/* Returns non-zero if the supplied ENGINE has a ctrl() handler. If "not", then
+ * all the remaining control commands will return failure, so it is worth
+ * checking this first if the caller is trying to "discover" the engine's
+ * capabilities and doesn't want errors generated unnecessarily. */
+#define ENGINE_CTRL_HAS_CTRL_FUNCTION		10
+/* Returns a positive command number for the first command supported by the
+ * engine. Returns zero if no ctrl commands are supported. */
+#define ENGINE_CTRL_GET_FIRST_CMD_TYPE		11
+/* The 'long' argument specifies a command implemented by the engine, and the
+ * return value is the next command supported, or zero if there are no more. */
+#define ENGINE_CTRL_GET_NEXT_CMD_TYPE		12
+/* The 'void*' argument is a command name (cast from 'const char *'), and the
+ * return value is the command that corresponds to it. */
+#define ENGINE_CTRL_GET_CMD_FROM_NAME		13
+/* The next two allow a command to be converted into its corresponding string
+ * form. In each case, the 'long' argument supplies the command. In the NAME_LEN
+ * case, the return value is the length of the command name (not counting a
+ * trailing EOL). In the NAME case, the 'void*' argument must be a string buffer
+ * large enough, and it will be populated with the name of the command (WITH a
+ * trailing EOL). */
+#define ENGINE_CTRL_GET_NAME_LEN_FROM_CMD	14
+#define ENGINE_CTRL_GET_NAME_FROM_CMD		15
+/* The next two are similar but give a "short description" of a command. */
+#define ENGINE_CTRL_GET_DESC_LEN_FROM_CMD	16
+#define ENGINE_CTRL_GET_DESC_FROM_CMD		17
+/* With this command, the return value is the OR'd combination of
+ * ENGINE_CMD_FLAG_*** values that indicate what kind of input a given
+ * engine-specific ctrl command expects. */
+#define ENGINE_CTRL_GET_CMD_FLAGS		18
+
+/* ENGINE implementations should start the numbering of their own control
+ * commands from this value. (ie. ENGINE_CMD_BASE, ENGINE_CMD_BASE + 1, etc). */
+#define ENGINE_CMD_BASE				200
+
+/* NB: These 2 nCipher "chil" control commands are deprecated, and their
+ * functionality is now available through ENGINE-specific control commands
+ * (exposed through the above-mentioned 'CMD'-handling). Code using these 2
+ * commands should be migrated to the more general command handling before these
+ * are removed. */
+
+/* Flags specific to the nCipher "chil" engine */
+#define ENGINE_CTRL_CHIL_SET_FORKCHECK		100
+	/* Depending on the value of the (long)i argument, this sets or
+	 * unsets the SimpleForkCheck flag in the CHIL API to enable or
+	 * disable checking and workarounds for applications that fork().
+	 */
+#define ENGINE_CTRL_CHIL_NO_LOCKING		101
+	/* This prevents the initialisation function from providing mutex
+	 * callbacks to the nCipher library. */
+
+/* If an ENGINE supports its own specific control commands and wishes the
+ * framework to handle the above 'ENGINE_CMD_***'-manipulation commands on its
+ * behalf, it should supply a null-terminated array of ENGINE_CMD_DEFN entries
+ * to ENGINE_set_cmd_defns(). It should also implement a ctrl() handler that
+ * supports the stated commands (ie. the "cmd_num" entries as described by the
+ * array). NB: The array must be ordered in increasing order of cmd_num.
+ * "null-terminated" means that the last ENGINE_CMD_DEFN element has cmd_num set
+ * to zero and/or cmd_name set to NULL. */
+typedef struct ENGINE_CMD_DEFN_st
+	{
+	unsigned int cmd_num; /* The command number */
+	const char *cmd_name; /* The command name itself */
+	const char *cmd_desc; /* A short description of the command */
+	unsigned int cmd_flags; /* The input the command expects */
+	} ENGINE_CMD_DEFN;
+
+/* Generic function pointer */
+typedef int (*ENGINE_GEN_FUNC_PTR)(void);
+/* Generic function pointer taking no arguments */
+typedef int (*ENGINE_GEN_INT_FUNC_PTR)(ENGINE *);
+/* Specific control function pointer */
+typedef int (*ENGINE_CTRL_FUNC_PTR)(ENGINE *, int, long, void *, void (*f)(void));
+/* Generic load_key function pointer */
+typedef EVP_PKEY * (*ENGINE_LOAD_KEY_PTR)(ENGINE *, const char *,
+	UI_METHOD *ui_method, void *callback_data);
+/* These callback types are for an ENGINE's handler for cipher and digest logic.
+ * These handlers have these prototypes;
+ *   int foo(ENGINE *e, const EVP_CIPHER **cipher, const int **nids, int nid);
+ *   int foo(ENGINE *e, const EVP_MD **digest, const int **nids, int nid);
+ * Looking at how to implement these handlers in the case of cipher support, if
+ * the framework wants the EVP_CIPHER for 'nid', it will call;
+ *   foo(e, &p_evp_cipher, NULL, nid);    (return zero for failure)
+ * If the framework wants a list of supported 'nid's, it will call;
+ *   foo(e, NULL, &p_nids, 0); (returns number of 'nids' or -1 for error)
+ */
+/* Returns to a pointer to the array of supported cipher 'nid's. If the second
+ * parameter is non-NULL it is set to the size of the returned array. */
+typedef int (*ENGINE_CIPHERS_PTR)(ENGINE *, const EVP_CIPHER **, const int **, int);
+typedef int (*ENGINE_DIGESTS_PTR)(ENGINE *, const EVP_MD **, const int **, int);
+
+/* STRUCTURE functions ... all of these functions deal with pointers to ENGINE
+ * structures where the pointers have a "structural reference". This means that
+ * their reference is to allowed access to the structure but it does not imply
+ * that the structure is functional. To simply increment or decrement the
+ * structural reference count, use ENGINE_by_id and ENGINE_free. NB: This is not
+ * required when iterating using ENGINE_get_next as it will automatically
+ * decrement the structural reference count of the "current" ENGINE and
+ * increment the structural reference count of the ENGINE it returns (unless it
+ * is NULL). */
+
+/* Get the first/last "ENGINE" type available. */
+ENGINE *ENGINE_get_first(void);
+ENGINE *ENGINE_get_last(void);
+/* Iterate to the next/previous "ENGINE" type (NULL = end of the list). */
+ENGINE *ENGINE_get_next(ENGINE *e);
+ENGINE *ENGINE_get_prev(ENGINE *e);
+/* Add another "ENGINE" type into the array. */
+int ENGINE_add(ENGINE *e);
+/* Remove an existing "ENGINE" type from the array. */
+int ENGINE_remove(ENGINE *e);
+/* Retrieve an engine from the list by its unique "id" value. */
+ENGINE *ENGINE_by_id(const char *id);
+/* Add all the built-in engines. */
+void ENGINE_load_openssl(void);
+void ENGINE_load_dynamic(void);
+#ifndef OPENSSL_NO_STATIC_ENGINE
+void ENGINE_load_4758cca(void);
+void ENGINE_load_aep(void);
+void ENGINE_load_atalla(void);
+void ENGINE_load_chil(void);
+void ENGINE_load_cswift(void);
+#ifndef OPENSSL_NO_GMP
+void ENGINE_load_gmp(void);
+#endif
+void ENGINE_load_nuron(void);
+void ENGINE_load_sureware(void);
+void ENGINE_load_ubsec(void);
+#endif
+void ENGINE_load_cryptodev(void);
+void ENGINE_load_padlock(void);
+void ENGINE_load_builtin_engines(void);
+
+/* Get and set global flags (ENGINE_TABLE_FLAG_***) for the implementation
+ * "registry" handling. */
+unsigned int ENGINE_get_table_flags(void);
+void ENGINE_set_table_flags(unsigned int flags);
+
+/* Manage registration of ENGINEs per "table". For each type, there are 3
+ * functions;
+ *   ENGINE_register_***(e) - registers the implementation from 'e' (if it has one)
+ *   ENGINE_unregister_***(e) - unregister the implementation from 'e'
+ *   ENGINE_register_all_***() - call ENGINE_register_***() for each 'e' in the list
+ * Cleanup is automatically registered from each table when required, so
+ * ENGINE_cleanup() will reverse any "register" operations. */
+
+int ENGINE_register_RSA(ENGINE *e);
+void ENGINE_unregister_RSA(ENGINE *e);
+void ENGINE_register_all_RSA(void);
+
+int ENGINE_register_DSA(ENGINE *e);
+void ENGINE_unregister_DSA(ENGINE *e);
+void ENGINE_register_all_DSA(void);
+
+int ENGINE_register_ECDH(ENGINE *e);
+void ENGINE_unregister_ECDH(ENGINE *e);
+void ENGINE_register_all_ECDH(void);
+
+int ENGINE_register_ECDSA(ENGINE *e);
+void ENGINE_unregister_ECDSA(ENGINE *e);
+void ENGINE_register_all_ECDSA(void);
+
+int ENGINE_register_DH(ENGINE *e);
+void ENGINE_unregister_DH(ENGINE *e);
+void ENGINE_register_all_DH(void);
+
+int ENGINE_register_RAND(ENGINE *e);
+void ENGINE_unregister_RAND(ENGINE *e);
+void ENGINE_register_all_RAND(void);
+
+int ENGINE_register_STORE(ENGINE *e);
+void ENGINE_unregister_STORE(ENGINE *e);
+void ENGINE_register_all_STORE(void);
+
+int ENGINE_register_ciphers(ENGINE *e);
+void ENGINE_unregister_ciphers(ENGINE *e);
+void ENGINE_register_all_ciphers(void);
+
+int ENGINE_register_digests(ENGINE *e);
+void ENGINE_unregister_digests(ENGINE *e);
+void ENGINE_register_all_digests(void);
+
+/* These functions register all support from the above categories. Note, use of
+ * these functions can result in static linkage of code your application may not
+ * need. If you only need a subset of functionality, consider using more
+ * selective initialisation. */
+int ENGINE_register_complete(ENGINE *e);
+int ENGINE_register_all_complete(void);
+
+/* Send parametrised control commands to the engine. The possibilities to send
+ * down an integer, a pointer to data or a function pointer are provided. Any of
+ * the parameters may or may not be NULL, depending on the command number. In
+ * actuality, this function only requires a structural (rather than functional)
+ * reference to an engine, but many control commands may require the engine be
+ * functional. The caller should be aware of trying commands that require an
+ * operational ENGINE, and only use functional references in such situations. */
+int ENGINE_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f)(void));
+
+/* This function tests if an ENGINE-specific command is usable as a "setting".
+ * Eg. in an application's config file that gets processed through
+ * ENGINE_ctrl_cmd_string(). If this returns zero, it is not available to
+ * ENGINE_ctrl_cmd_string(), only ENGINE_ctrl(). */
+int ENGINE_cmd_is_executable(ENGINE *e, int cmd);
+
+/* This function works like ENGINE_ctrl() with the exception of taking a
+ * command name instead of a command number, and can handle optional commands.
+ * See the comment on ENGINE_ctrl_cmd_string() for an explanation on how to
+ * use the cmd_name and cmd_optional. */
+int ENGINE_ctrl_cmd(ENGINE *e, const char *cmd_name,
+        long i, void *p, void (*f)(void), int cmd_optional);
+
+/* This function passes a command-name and argument to an ENGINE. The cmd_name
+ * is converted to a command number and the control command is called using
+ * 'arg' as an argument (unless the ENGINE doesn't support such a command, in
+ * which case no control command is called). The command is checked for input
+ * flags, and if necessary the argument will be converted to a numeric value. If
+ * cmd_optional is non-zero, then if the ENGINE doesn't support the given
+ * cmd_name the return value will be success anyway. This function is intended
+ * for applications to use so that users (or config files) can supply
+ * engine-specific config data to the ENGINE at run-time to control behaviour of
+ * specific engines. As such, it shouldn't be used for calling ENGINE_ctrl()
+ * functions that return data, deal with binary data, or that are otherwise
+ * supposed to be used directly through ENGINE_ctrl() in application code. Any
+ * "return" data from an ENGINE_ctrl() operation in this function will be lost -
+ * the return value is interpreted as failure if the return value is zero,
+ * success otherwise, and this function returns a boolean value as a result. In
+ * other words, vendors of 'ENGINE'-enabled devices should write ENGINE
+ * implementations with parameterisations that work in this scheme, so that
+ * compliant ENGINE-based applications can work consistently with the same
+ * configuration for the same ENGINE-enabled devices, across applications. */
+int ENGINE_ctrl_cmd_string(ENGINE *e, const char *cmd_name, const char *arg,
+				int cmd_optional);
+
+/* These functions are useful for manufacturing new ENGINE structures. They
+ * don't address reference counting at all - one uses them to populate an ENGINE
+ * structure with personalised implementations of things prior to using it
+ * directly or adding it to the builtin ENGINE list in OpenSSL. These are also
+ * here so that the ENGINE structure doesn't have to be exposed and break binary
+ * compatibility! */
+ENGINE *ENGINE_new(void);
+int ENGINE_free(ENGINE *e);
+int ENGINE_up_ref(ENGINE *e);
+int ENGINE_set_id(ENGINE *e, const char *id);
+int ENGINE_set_name(ENGINE *e, const char *name);
+int ENGINE_set_RSA(ENGINE *e, const RSA_METHOD *rsa_meth);
+int ENGINE_set_DSA(ENGINE *e, const DSA_METHOD *dsa_meth);
+int ENGINE_set_ECDH(ENGINE *e, const ECDH_METHOD *ecdh_meth);
+int ENGINE_set_ECDSA(ENGINE *e, const ECDSA_METHOD *ecdsa_meth);
+int ENGINE_set_DH(ENGINE *e, const DH_METHOD *dh_meth);
+int ENGINE_set_RAND(ENGINE *e, const RAND_METHOD *rand_meth);
+int ENGINE_set_STORE(ENGINE *e, const STORE_METHOD *store_meth);
+int ENGINE_set_destroy_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR destroy_f);
+int ENGINE_set_init_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR init_f);
+int ENGINE_set_finish_function(ENGINE *e, ENGINE_GEN_INT_FUNC_PTR finish_f);
+int ENGINE_set_ctrl_function(ENGINE *e, ENGINE_CTRL_FUNC_PTR ctrl_f);
+int ENGINE_set_load_privkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpriv_f);
+int ENGINE_set_load_pubkey_function(ENGINE *e, ENGINE_LOAD_KEY_PTR loadpub_f);
+int ENGINE_set_ciphers(ENGINE *e, ENGINE_CIPHERS_PTR f);
+int ENGINE_set_digests(ENGINE *e, ENGINE_DIGESTS_PTR f);
+int ENGINE_set_flags(ENGINE *e, int flags);
+int ENGINE_set_cmd_defns(ENGINE *e, const ENGINE_CMD_DEFN *defns);
+/* These functions allow control over any per-structure ENGINE data. */
+int ENGINE_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+		CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int ENGINE_set_ex_data(ENGINE *e, int idx, void *arg);
+void *ENGINE_get_ex_data(const ENGINE *e, int idx);
+
+/* This function cleans up anything that needs it. Eg. the ENGINE_add() function
+ * automatically ensures the list cleanup function is registered to be called
+ * from ENGINE_cleanup(). Similarly, all ENGINE_register_*** functions ensure
+ * ENGINE_cleanup() will clean up after them. */
+void ENGINE_cleanup(void);
+
+/* These return values from within the ENGINE structure. These can be useful
+ * with functional references as well as structural references - it depends
+ * which you obtained. Using the result for functional purposes if you only
+ * obtained a structural reference may be problematic! */
+const char *ENGINE_get_id(const ENGINE *e);
+const char *ENGINE_get_name(const ENGINE *e);
+const RSA_METHOD *ENGINE_get_RSA(const ENGINE *e);
+const DSA_METHOD *ENGINE_get_DSA(const ENGINE *e);
+const ECDH_METHOD *ENGINE_get_ECDH(const ENGINE *e);
+const ECDSA_METHOD *ENGINE_get_ECDSA(const ENGINE *e);
+const DH_METHOD *ENGINE_get_DH(const ENGINE *e);
+const RAND_METHOD *ENGINE_get_RAND(const ENGINE *e);
+const STORE_METHOD *ENGINE_get_STORE(const ENGINE *e);
+ENGINE_GEN_INT_FUNC_PTR ENGINE_get_destroy_function(const ENGINE *e);
+ENGINE_GEN_INT_FUNC_PTR ENGINE_get_init_function(const ENGINE *e);
+ENGINE_GEN_INT_FUNC_PTR ENGINE_get_finish_function(const ENGINE *e);
+ENGINE_CTRL_FUNC_PTR ENGINE_get_ctrl_function(const ENGINE *e);
+ENGINE_LOAD_KEY_PTR ENGINE_get_load_privkey_function(const ENGINE *e);
+ENGINE_LOAD_KEY_PTR ENGINE_get_load_pubkey_function(const ENGINE *e);
+ENGINE_CIPHERS_PTR ENGINE_get_ciphers(const ENGINE *e);
+ENGINE_DIGESTS_PTR ENGINE_get_digests(const ENGINE *e);
+const EVP_CIPHER *ENGINE_get_cipher(ENGINE *e, int nid);
+const EVP_MD *ENGINE_get_digest(ENGINE *e, int nid);
+const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *e);
+int ENGINE_get_flags(const ENGINE *e);
+
+/* FUNCTIONAL functions. These functions deal with ENGINE structures
+ * that have (or will) be initialised for use. Broadly speaking, the
+ * structural functions are useful for iterating the list of available
+ * engine types, creating new engine types, and other "list" operations.
+ * These functions actually deal with ENGINEs that are to be used. As
+ * such these functions can fail (if applicable) when particular
+ * engines are unavailable - eg. if a hardware accelerator is not
+ * attached or not functioning correctly. Each ENGINE has 2 reference
+ * counts; structural and functional. Every time a functional reference
+ * is obtained or released, a corresponding structural reference is
+ * automatically obtained or released too. */
+
+/* Initialise a engine type for use (or up its reference count if it's
+ * already in use). This will fail if the engine is not currently
+ * operational and cannot initialise. */
+int ENGINE_init(ENGINE *e);
+/* Free a functional reference to a engine type. This does not require
+ * a corresponding call to ENGINE_free as it also releases a structural
+ * reference. */
+int ENGINE_finish(ENGINE *e);
+
+/* The following functions handle keys that are stored in some secondary
+ * location, handled by the engine.  The storage may be on a card or
+ * whatever. */
+EVP_PKEY *ENGINE_load_private_key(ENGINE *e, const char *key_id,
+	UI_METHOD *ui_method, void *callback_data);
+EVP_PKEY *ENGINE_load_public_key(ENGINE *e, const char *key_id,
+	UI_METHOD *ui_method, void *callback_data);
+
+/* This returns a pointer for the current ENGINE structure that
+ * is (by default) performing any RSA operations. The value returned
+ * is an incremented reference, so it should be free'd (ENGINE_finish)
+ * before it is discarded. */
+ENGINE *ENGINE_get_default_RSA(void);
+/* Same for the other "methods" */
+ENGINE *ENGINE_get_default_DSA(void);
+ENGINE *ENGINE_get_default_ECDH(void);
+ENGINE *ENGINE_get_default_ECDSA(void);
+ENGINE *ENGINE_get_default_DH(void);
+ENGINE *ENGINE_get_default_RAND(void);
+/* These functions can be used to get a functional reference to perform
+ * ciphering or digesting corresponding to "nid". */
+ENGINE *ENGINE_get_cipher_engine(int nid);
+ENGINE *ENGINE_get_digest_engine(int nid);
+
+/* This sets a new default ENGINE structure for performing RSA
+ * operations. If the result is non-zero (success) then the ENGINE
+ * structure will have had its reference count up'd so the caller
+ * should still free their own reference 'e'. */
+int ENGINE_set_default_RSA(ENGINE *e);
+int ENGINE_set_default_string(ENGINE *e, const char *def_list);
+/* Same for the other "methods" */
+int ENGINE_set_default_DSA(ENGINE *e);
+int ENGINE_set_default_ECDH(ENGINE *e);
+int ENGINE_set_default_ECDSA(ENGINE *e);
+int ENGINE_set_default_DH(ENGINE *e);
+int ENGINE_set_default_RAND(ENGINE *e);
+int ENGINE_set_default_ciphers(ENGINE *e);
+int ENGINE_set_default_digests(ENGINE *e);
+
+/* The combination "set" - the flags are bitwise "OR"d from the
+ * ENGINE_METHOD_*** defines above. As with the "ENGINE_register_complete()"
+ * function, this function can result in unnecessary static linkage. If your
+ * application requires only specific functionality, consider using more
+ * selective functions. */
+int ENGINE_set_default(ENGINE *e, unsigned int flags);
+
+void ENGINE_add_conf_module(void);
+
+/* Deprecated functions ... */
+/* int ENGINE_clear_defaults(void); */
+
+/**************************/
+/* DYNAMIC ENGINE SUPPORT */
+/**************************/
+
+/* Binary/behaviour compatibility levels */
+#define OSSL_DYNAMIC_VERSION		(unsigned long)0x00020000
+/* Binary versions older than this are too old for us (whether we're a loader or
+ * a loadee) */
+#define OSSL_DYNAMIC_OLDEST		(unsigned long)0x00020000
+
+/* When compiling an ENGINE entirely as an external shared library, loadable by
+ * the "dynamic" ENGINE, these types are needed. The 'dynamic_fns' structure
+ * type provides the calling application's (or library's) error functionality
+ * and memory management function pointers to the loaded library. These should
+ * be used/set in the loaded library code so that the loading application's
+ * 'state' will be used/changed in all operations. The 'static_state' pointer
+ * allows the loaded library to know if it shares the same static data as the
+ * calling application (or library), and thus whether these callbacks need to be
+ * set or not. */
+typedef void *(*dyn_MEM_malloc_cb)(size_t);
+typedef void *(*dyn_MEM_realloc_cb)(void *, size_t);
+typedef void (*dyn_MEM_free_cb)(void *);
+typedef struct st_dynamic_MEM_fns {
+	dyn_MEM_malloc_cb			malloc_cb;
+	dyn_MEM_realloc_cb			realloc_cb;
+	dyn_MEM_free_cb				free_cb;
+	} dynamic_MEM_fns;
+/* FIXME: Perhaps the memory and locking code (crypto.h) should declare and use
+ * these types so we (and any other dependant code) can simplify a bit?? */
+typedef void (*dyn_lock_locking_cb)(int,int,const char *,int);
+typedef int (*dyn_lock_add_lock_cb)(int*,int,int,const char *,int);
+typedef struct CRYPTO_dynlock_value *(*dyn_dynlock_create_cb)(
+						const char *,int);
+typedef void (*dyn_dynlock_lock_cb)(int,struct CRYPTO_dynlock_value *,
+						const char *,int);
+typedef void (*dyn_dynlock_destroy_cb)(struct CRYPTO_dynlock_value *,
+						const char *,int);
+typedef struct st_dynamic_LOCK_fns {
+	dyn_lock_locking_cb			lock_locking_cb;
+	dyn_lock_add_lock_cb			lock_add_lock_cb;
+	dyn_dynlock_create_cb			dynlock_create_cb;
+	dyn_dynlock_lock_cb			dynlock_lock_cb;
+	dyn_dynlock_destroy_cb			dynlock_destroy_cb;
+	} dynamic_LOCK_fns;
+/* The top-level structure */
+typedef struct st_dynamic_fns {
+	void 					*static_state;
+	const ERR_FNS				*err_fns;
+	const CRYPTO_EX_DATA_IMPL		*ex_data_fns;
+	dynamic_MEM_fns				mem_fns;
+	dynamic_LOCK_fns			lock_fns;
+	} dynamic_fns;
+
+/* The version checking function should be of this prototype. NB: The
+ * ossl_version value passed in is the OSSL_DYNAMIC_VERSION of the loading code.
+ * If this function returns zero, it indicates a (potential) version
+ * incompatibility and the loaded library doesn't believe it can proceed.
+ * Otherwise, the returned value is the (latest) version supported by the
+ * loading library. The loader may still decide that the loaded code's version
+ * is unsatisfactory and could veto the load. The function is expected to
+ * be implemented with the symbol name "v_check", and a default implementation
+ * can be fully instantiated with IMPLEMENT_DYNAMIC_CHECK_FN(). */
+typedef unsigned long (*dynamic_v_check_fn)(unsigned long ossl_version);
+#define IMPLEMENT_DYNAMIC_CHECK_FN() \
+	unsigned long v_check(unsigned long v) { \
+		if(v >= OSSL_DYNAMIC_OLDEST) return OSSL_DYNAMIC_VERSION; \
+		return 0; }
+
+/* This function is passed the ENGINE structure to initialise with its own
+ * function and command settings. It should not adjust the structural or
+ * functional reference counts. If this function returns zero, (a) the load will
+ * be aborted, (b) the previous ENGINE state will be memcpy'd back onto the
+ * structure, and (c) the shared library will be unloaded. So implementations
+ * should do their own internal cleanup in failure circumstances otherwise they
+ * could leak. The 'id' parameter, if non-NULL, represents the ENGINE id that
+ * the loader is looking for. If this is NULL, the shared library can choose to
+ * return failure or to initialise a 'default' ENGINE. If non-NULL, the shared
+ * library must initialise only an ENGINE matching the passed 'id'. The function
+ * is expected to be implemented with the symbol name "bind_engine". A standard
+ * implementation can be instantiated with IMPLEMENT_DYNAMIC_BIND_FN(fn) where
+ * the parameter 'fn' is a callback function that populates the ENGINE structure
+ * and returns an int value (zero for failure). 'fn' should have prototype;
+ *    [static] int fn(ENGINE *e, const char *id); */
+typedef int (*dynamic_bind_engine)(ENGINE *e, const char *id,
+				const dynamic_fns *fns);
+#define IMPLEMENT_DYNAMIC_BIND_FN(fn) \
+	int bind_engine(ENGINE *e, const char *id, const dynamic_fns *fns) { \
+		if(ENGINE_get_static_state() == fns->static_state) goto skip_cbs; \
+		if(!CRYPTO_set_mem_functions(fns->mem_fns.malloc_cb, \
+			fns->mem_fns.realloc_cb, fns->mem_fns.free_cb)) \
+			return 0; \
+		CRYPTO_set_locking_callback(fns->lock_fns.lock_locking_cb); \
+		CRYPTO_set_add_lock_callback(fns->lock_fns.lock_add_lock_cb); \
+		CRYPTO_set_dynlock_create_callback(fns->lock_fns.dynlock_create_cb); \
+		CRYPTO_set_dynlock_lock_callback(fns->lock_fns.dynlock_lock_cb); \
+		CRYPTO_set_dynlock_destroy_callback(fns->lock_fns.dynlock_destroy_cb); \
+		if(!CRYPTO_set_ex_data_implementation(fns->ex_data_fns)) \
+			return 0; \
+		if(!ERR_set_implementation(fns->err_fns)) return 0; \
+	skip_cbs: \
+		if(!fn(e,id)) return 0; \
+		return 1; }
+
+/* If the loading application (or library) and the loaded ENGINE library share
+ * the same static data (eg. they're both dynamically linked to the same
+ * libcrypto.so) we need a way to avoid trying to set system callbacks - this
+ * would fail, and for the same reason that it's unnecessary to try. If the
+ * loaded ENGINE has (or gets from through the loader) its own copy of the
+ * libcrypto static data, we will need to set the callbacks. The easiest way to
+ * detect this is to have a function that returns a pointer to some static data
+ * and let the loading application and loaded ENGINE compare their respective
+ * values. */
+void *ENGINE_get_static_state(void);
+
+#if defined(__OpenBSD__) || defined(__FreeBSD__)
+void ENGINE_setup_bsd_cryptodev(void);
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_ENGINE_strings(void);
+
+/* Error codes for the ENGINE functions. */
+
+/* Function codes. */
+#define ENGINE_F_DYNAMIC_CTRL				 180
+#define ENGINE_F_DYNAMIC_GET_DATA_CTX			 181
+#define ENGINE_F_DYNAMIC_LOAD				 182
+#define ENGINE_F_DYNAMIC_SET_DATA_CTX			 183
+#define ENGINE_F_ENGINE_ADD				 105
+#define ENGINE_F_ENGINE_BY_ID				 106
+#define ENGINE_F_ENGINE_CMD_IS_EXECUTABLE		 170
+#define ENGINE_F_ENGINE_CTRL				 142
+#define ENGINE_F_ENGINE_CTRL_CMD			 178
+#define ENGINE_F_ENGINE_CTRL_CMD_STRING			 171
+#define ENGINE_F_ENGINE_FINISH				 107
+#define ENGINE_F_ENGINE_FREE_UTIL			 108
+#define ENGINE_F_ENGINE_GET_CIPHER			 185
+#define ENGINE_F_ENGINE_GET_DEFAULT_TYPE		 177
+#define ENGINE_F_ENGINE_GET_DIGEST			 186
+#define ENGINE_F_ENGINE_GET_NEXT			 115
+#define ENGINE_F_ENGINE_GET_PREV			 116
+#define ENGINE_F_ENGINE_INIT				 119
+#define ENGINE_F_ENGINE_LIST_ADD			 120
+#define ENGINE_F_ENGINE_LIST_REMOVE			 121
+#define ENGINE_F_ENGINE_LOAD_PRIVATE_KEY		 150
+#define ENGINE_F_ENGINE_LOAD_PUBLIC_KEY			 151
+#define ENGINE_F_ENGINE_NEW				 122
+#define ENGINE_F_ENGINE_REMOVE				 123
+#define ENGINE_F_ENGINE_SET_DEFAULT_STRING		 189
+#define ENGINE_F_ENGINE_SET_DEFAULT_TYPE		 126
+#define ENGINE_F_ENGINE_SET_ID				 129
+#define ENGINE_F_ENGINE_SET_NAME			 130
+#define ENGINE_F_ENGINE_TABLE_REGISTER			 184
+#define ENGINE_F_ENGINE_UNLOAD_KEY			 152
+#define ENGINE_F_ENGINE_UNLOCKED_FINISH			 191
+#define ENGINE_F_ENGINE_UP_REF				 190
+#define ENGINE_F_INT_CTRL_HELPER			 172
+#define ENGINE_F_INT_ENGINE_CONFIGURE			 188
+#define ENGINE_F_INT_ENGINE_MODULE_INIT			 187
+#define ENGINE_F_LOG_MESSAGE				 141
+
+/* Reason codes. */
+#define ENGINE_R_ALREADY_LOADED				 100
+#define ENGINE_R_ARGUMENT_IS_NOT_A_NUMBER		 133
+#define ENGINE_R_CMD_NOT_EXECUTABLE			 134
+#define ENGINE_R_COMMAND_TAKES_INPUT			 135
+#define ENGINE_R_COMMAND_TAKES_NO_INPUT			 136
+#define ENGINE_R_CONFLICTING_ENGINE_ID			 103
+#define ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED		 119
+#define ENGINE_R_DH_NOT_IMPLEMENTED			 139
+#define ENGINE_R_DSA_NOT_IMPLEMENTED			 140
+#define ENGINE_R_DSO_FAILURE				 104
+#define ENGINE_R_DSO_NOT_FOUND				 132
+#define ENGINE_R_ENGINES_SECTION_ERROR			 148
+#define ENGINE_R_ENGINE_IS_NOT_IN_LIST			 105
+#define ENGINE_R_ENGINE_SECTION_ERROR			 149
+#define ENGINE_R_FAILED_LOADING_PRIVATE_KEY		 128
+#define ENGINE_R_FAILED_LOADING_PUBLIC_KEY		 129
+#define ENGINE_R_FINISH_FAILED				 106
+#define ENGINE_R_GET_HANDLE_FAILED			 107
+#define ENGINE_R_ID_OR_NAME_MISSING			 108
+#define ENGINE_R_INIT_FAILED				 109
+#define ENGINE_R_INTERNAL_LIST_ERROR			 110
+#define ENGINE_R_INVALID_ARGUMENT			 143
+#define ENGINE_R_INVALID_CMD_NAME			 137
+#define ENGINE_R_INVALID_CMD_NUMBER			 138
+#define ENGINE_R_INVALID_INIT_VALUE			 151
+#define ENGINE_R_INVALID_STRING				 150
+#define ENGINE_R_NOT_INITIALISED			 117
+#define ENGINE_R_NOT_LOADED				 112
+#define ENGINE_R_NO_CONTROL_FUNCTION			 120
+#define ENGINE_R_NO_INDEX				 144
+#define ENGINE_R_NO_LOAD_FUNCTION			 125
+#define ENGINE_R_NO_REFERENCE				 130
+#define ENGINE_R_NO_SUCH_ENGINE				 116
+#define ENGINE_R_NO_UNLOAD_FUNCTION			 126
+#define ENGINE_R_PROVIDE_PARAMETERS			 113
+#define ENGINE_R_RSA_NOT_IMPLEMENTED			 141
+#define ENGINE_R_UNIMPLEMENTED_CIPHER			 146
+#define ENGINE_R_UNIMPLEMENTED_DIGEST			 147
+#define ENGINE_R_VERSION_INCOMPATIBILITY		 145
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/err.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/err.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/err.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,318 @@
+/* crypto/err/err.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_ERR_H
+#define HEADER_ERR_H
+
+#include <openssl/e_os2.h>
+
+#ifndef OPENSSL_NO_FP_API
+#include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#include <openssl/ossl_typ.h>
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#ifndef OPENSSL_NO_LHASH
+#include <openssl/lhash.h>
+#endif
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+#ifndef OPENSSL_NO_ERR
+#define ERR_PUT_error(a,b,c,d,e)	ERR_put_error(a,b,c,d,e)
+#else
+#define ERR_PUT_error(a,b,c,d,e)	ERR_put_error(a,b,c,NULL,0)
+#endif
+
+#include <errno.h>
+
+#define ERR_TXT_MALLOCED	0x01
+#define ERR_TXT_STRING		0x02
+
+#define ERR_FLAG_MARK		0x01
+
+#define ERR_NUM_ERRORS	16
+typedef struct err_state_st
+	{
+	unsigned long pid;
+	int err_flags[ERR_NUM_ERRORS];
+	unsigned long err_buffer[ERR_NUM_ERRORS];
+	char *err_data[ERR_NUM_ERRORS];
+	int err_data_flags[ERR_NUM_ERRORS];
+	const char *err_file[ERR_NUM_ERRORS];
+	int err_line[ERR_NUM_ERRORS];
+	int top,bottom;
+	} ERR_STATE;
+
+/* library */
+#define ERR_LIB_NONE		1
+#define ERR_LIB_SYS		2
+#define ERR_LIB_BN		3
+#define ERR_LIB_RSA		4
+#define ERR_LIB_DH		5
+#define ERR_LIB_EVP		6
+#define ERR_LIB_BUF		7
+#define ERR_LIB_OBJ		8
+#define ERR_LIB_PEM		9
+#define ERR_LIB_DSA		10
+#define ERR_LIB_X509		11
+/* #define ERR_LIB_METH         12 */
+#define ERR_LIB_ASN1		13
+#define ERR_LIB_CONF		14
+#define ERR_LIB_CRYPTO		15
+#define ERR_LIB_EC		16
+#define ERR_LIB_SSL		20
+/* #define ERR_LIB_SSL23        21 */
+/* #define ERR_LIB_SSL2         22 */
+/* #define ERR_LIB_SSL3         23 */
+/* #define ERR_LIB_RSAREF       30 */
+/* #define ERR_LIB_PROXY        31 */
+#define ERR_LIB_BIO		32
+#define ERR_LIB_PKCS7		33
+#define ERR_LIB_X509V3		34
+#define ERR_LIB_PKCS12		35
+#define ERR_LIB_RAND		36
+#define ERR_LIB_DSO		37
+#define ERR_LIB_ENGINE		38
+#define ERR_LIB_OCSP            39
+#define ERR_LIB_UI              40
+#define ERR_LIB_COMP            41
+#define ERR_LIB_ECDSA		42
+#define ERR_LIB_ECDH		43
+#define ERR_LIB_STORE           44
+
+#define ERR_LIB_USER		128
+
+#define SYSerr(f,r)  ERR_PUT_error(ERR_LIB_SYS,(f),(r),__FILE__,__LINE__)
+#define BNerr(f,r)   ERR_PUT_error(ERR_LIB_BN,(f),(r),__FILE__,__LINE__)
+#define RSAerr(f,r)  ERR_PUT_error(ERR_LIB_RSA,(f),(r),__FILE__,__LINE__)
+#define DHerr(f,r)   ERR_PUT_error(ERR_LIB_DH,(f),(r),__FILE__,__LINE__)
+#define EVPerr(f,r)  ERR_PUT_error(ERR_LIB_EVP,(f),(r),__FILE__,__LINE__)
+#define BUFerr(f,r)  ERR_PUT_error(ERR_LIB_BUF,(f),(r),__FILE__,__LINE__)
+#define OBJerr(f,r)  ERR_PUT_error(ERR_LIB_OBJ,(f),(r),__FILE__,__LINE__)
+#define PEMerr(f,r)  ERR_PUT_error(ERR_LIB_PEM,(f),(r),__FILE__,__LINE__)
+#define DSAerr(f,r)  ERR_PUT_error(ERR_LIB_DSA,(f),(r),__FILE__,__LINE__)
+#define X509err(f,r) ERR_PUT_error(ERR_LIB_X509,(f),(r),__FILE__,__LINE__)
+#define ASN1err(f,r) ERR_PUT_error(ERR_LIB_ASN1,(f),(r),__FILE__,__LINE__)
+#define CONFerr(f,r) ERR_PUT_error(ERR_LIB_CONF,(f),(r),__FILE__,__LINE__)
+#define CRYPTOerr(f,r) ERR_PUT_error(ERR_LIB_CRYPTO,(f),(r),__FILE__,__LINE__)
+#define ECerr(f,r)   ERR_PUT_error(ERR_LIB_EC,(f),(r),__FILE__,__LINE__)
+#define SSLerr(f,r)  ERR_PUT_error(ERR_LIB_SSL,(f),(r),__FILE__,__LINE__)
+#define BIOerr(f,r)  ERR_PUT_error(ERR_LIB_BIO,(f),(r),__FILE__,__LINE__)
+#define PKCS7err(f,r) ERR_PUT_error(ERR_LIB_PKCS7,(f),(r),__FILE__,__LINE__)
+#define X509V3err(f,r) ERR_PUT_error(ERR_LIB_X509V3,(f),(r),__FILE__,__LINE__)
+#define PKCS12err(f,r) ERR_PUT_error(ERR_LIB_PKCS12,(f),(r),__FILE__,__LINE__)
+#define RANDerr(f,r) ERR_PUT_error(ERR_LIB_RAND,(f),(r),__FILE__,__LINE__)
+#define DSOerr(f,r) ERR_PUT_error(ERR_LIB_DSO,(f),(r),__FILE__,__LINE__)
+#define ENGINEerr(f,r) ERR_PUT_error(ERR_LIB_ENGINE,(f),(r),__FILE__,__LINE__)
+#define OCSPerr(f,r) ERR_PUT_error(ERR_LIB_OCSP,(f),(r),__FILE__,__LINE__)
+#define UIerr(f,r) ERR_PUT_error(ERR_LIB_UI,(f),(r),__FILE__,__LINE__)
+#define COMPerr(f,r) ERR_PUT_error(ERR_LIB_COMP,(f),(r),__FILE__,__LINE__)
+#define ECDSAerr(f,r)  ERR_PUT_error(ERR_LIB_ECDSA,(f),(r),__FILE__,__LINE__)
+#define ECDHerr(f,r)  ERR_PUT_error(ERR_LIB_ECDH,(f),(r),__FILE__,__LINE__)
+#define STOREerr(f,r) ERR_PUT_error(ERR_LIB_STORE,(f),(r),__FILE__,__LINE__)
+
+/* Borland C seems too stupid to be able to shift and do longs in
+ * the pre-processor :-( */
+#define ERR_PACK(l,f,r)		(((((unsigned long)l)&0xffL)*0x1000000)| \
+				((((unsigned long)f)&0xfffL)*0x1000)| \
+				((((unsigned long)r)&0xfffL)))
+#define ERR_GET_LIB(l)		(int)((((unsigned long)l)>>24L)&0xffL)
+#define ERR_GET_FUNC(l)		(int)((((unsigned long)l)>>12L)&0xfffL)
+#define ERR_GET_REASON(l)	(int)((l)&0xfffL)
+#define ERR_FATAL_ERROR(l)	(int)((l)&ERR_R_FATAL)
+
+
+/* OS functions */
+#define SYS_F_FOPEN		1
+#define SYS_F_CONNECT		2
+#define SYS_F_GETSERVBYNAME	3
+#define SYS_F_SOCKET		4
+#define SYS_F_IOCTLSOCKET	5
+#define SYS_F_BIND		6
+#define SYS_F_LISTEN		7
+#define SYS_F_ACCEPT		8
+#define SYS_F_WSASTARTUP	9 /* Winsock stuff */
+#define SYS_F_OPENDIR		10
+#define SYS_F_FREAD		11
+
+
+/* reasons */
+#define ERR_R_SYS_LIB	ERR_LIB_SYS       /* 2 */
+#define ERR_R_BN_LIB	ERR_LIB_BN        /* 3 */
+#define ERR_R_RSA_LIB	ERR_LIB_RSA       /* 4 */
+#define ERR_R_DH_LIB	ERR_LIB_DH        /* 5 */
+#define ERR_R_EVP_LIB	ERR_LIB_EVP       /* 6 */
+#define ERR_R_BUF_LIB	ERR_LIB_BUF       /* 7 */
+#define ERR_R_OBJ_LIB	ERR_LIB_OBJ       /* 8 */
+#define ERR_R_PEM_LIB	ERR_LIB_PEM       /* 9 */
+#define ERR_R_DSA_LIB	ERR_LIB_DSA      /* 10 */
+#define ERR_R_X509_LIB	ERR_LIB_X509     /* 11 */
+#define ERR_R_ASN1_LIB	ERR_LIB_ASN1     /* 13 */
+#define ERR_R_CONF_LIB	ERR_LIB_CONF     /* 14 */
+#define ERR_R_CRYPTO_LIB ERR_LIB_CRYPTO  /* 15 */
+#define ERR_R_EC_LIB	ERR_LIB_EC       /* 16 */
+#define ERR_R_SSL_LIB	ERR_LIB_SSL      /* 20 */
+#define ERR_R_BIO_LIB	ERR_LIB_BIO      /* 32 */
+#define ERR_R_PKCS7_LIB	ERR_LIB_PKCS7    /* 33 */
+#define ERR_R_X509V3_LIB ERR_LIB_X509V3  /* 34 */
+#define ERR_R_PKCS12_LIB ERR_LIB_PKCS12  /* 35 */
+#define ERR_R_RAND_LIB	ERR_LIB_RAND     /* 36 */
+#define ERR_R_DSO_LIB	ERR_LIB_DSO      /* 37 */
+#define ERR_R_ENGINE_LIB ERR_LIB_ENGINE  /* 38 */
+#define ERR_R_OCSP_LIB  ERR_LIB_OCSP     /* 39 */
+#define ERR_R_UI_LIB    ERR_LIB_UI       /* 40 */
+#define ERR_R_COMP_LIB	ERR_LIB_COMP     /* 41 */
+#define ERR_R_ECDSA_LIB ERR_LIB_ECDSA	 /* 42 */
+#define ERR_R_ECDH_LIB  ERR_LIB_ECDH	 /* 43 */
+#define ERR_R_STORE_LIB ERR_LIB_STORE    /* 44 */
+
+#define ERR_R_NESTED_ASN1_ERROR			58
+#define ERR_R_BAD_ASN1_OBJECT_HEADER		59
+#define ERR_R_BAD_GET_ASN1_OBJECT_CALL		60
+#define ERR_R_EXPECTING_AN_ASN1_SEQUENCE	61
+#define ERR_R_ASN1_LENGTH_MISMATCH		62
+#define ERR_R_MISSING_ASN1_EOS			63
+
+/* fatal error */
+#define ERR_R_FATAL				64
+#define	ERR_R_MALLOC_FAILURE			(1|ERR_R_FATAL)
+#define	ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED	(2|ERR_R_FATAL)
+#define	ERR_R_PASSED_NULL_PARAMETER		(3|ERR_R_FATAL)
+#define	ERR_R_INTERNAL_ERROR			(4|ERR_R_FATAL)
+#define	ERR_R_DISABLED				(5|ERR_R_FATAL)
+
+/* 99 is the maximum possible ERR_R_... code, higher values
+ * are reserved for the individual libraries */
+
+
+typedef struct ERR_string_data_st
+	{
+	unsigned long error;
+	const char *string;
+	} ERR_STRING_DATA;
+
+void ERR_put_error(int lib, int func,int reason,const char *file,int line);
+void ERR_set_error_data(char *data,int flags);
+
+unsigned long ERR_get_error(void);
+unsigned long ERR_get_error_line(const char **file,int *line);
+unsigned long ERR_get_error_line_data(const char **file,int *line,
+				      const char **data, int *flags);
+unsigned long ERR_peek_error(void);
+unsigned long ERR_peek_error_line(const char **file,int *line);
+unsigned long ERR_peek_error_line_data(const char **file,int *line,
+				       const char **data,int *flags);
+unsigned long ERR_peek_last_error(void);
+unsigned long ERR_peek_last_error_line(const char **file,int *line);
+unsigned long ERR_peek_last_error_line_data(const char **file,int *line,
+				       const char **data,int *flags);
+void ERR_clear_error(void );
+char *ERR_error_string(unsigned long e,char *buf);
+void ERR_error_string_n(unsigned long e, char *buf, size_t len);
+const char *ERR_lib_error_string(unsigned long e);
+const char *ERR_func_error_string(unsigned long e);
+const char *ERR_reason_error_string(unsigned long e);
+void ERR_print_errors_cb(int (*cb)(const char *str, size_t len, void *u),
+			 void *u);
+#ifndef OPENSSL_NO_FP_API
+void ERR_print_errors_fp(FILE *fp);
+#endif
+#ifndef OPENSSL_NO_BIO
+void ERR_print_errors(BIO *bp);
+void ERR_add_error_data(int num, ...);
+#endif
+void ERR_load_strings(int lib,ERR_STRING_DATA str[]);
+void ERR_unload_strings(int lib,ERR_STRING_DATA str[]);
+void ERR_load_ERR_strings(void);
+void ERR_load_crypto_strings(void);
+void ERR_free_strings(void);
+
+void ERR_remove_state(unsigned long pid); /* if zero we look it up */
+ERR_STATE *ERR_get_state(void);
+
+#ifndef OPENSSL_NO_LHASH
+LHASH *ERR_get_string_table(void);
+LHASH *ERR_get_err_state_table(void);
+void ERR_release_err_state_table(LHASH **hash);
+#endif
+
+int ERR_get_next_error_library(void);
+
+int ERR_set_mark(void);
+int ERR_pop_to_mark(void);
+
+/* Already defined in ossl_typ.h */
+/* typedef struct st_ERR_FNS ERR_FNS; */
+/* An application can use this function and provide the return value to loaded
+ * modules that should use the application's ERR state/functionality */
+const ERR_FNS *ERR_get_implementation(void);
+/* A loaded module should call this function prior to any ERR operations using
+ * the application's "ERR_FNS". */
+int ERR_set_implementation(const ERR_FNS *fns);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/evp.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/evp.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/evp.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,939 @@
+/* crypto/evp/evp.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_ENVELOPE_H
+#define HEADER_ENVELOPE_H
+
+#ifdef OPENSSL_ALGORITHM_DEFINES
+# include <openssl/opensslconf.h>
+#else
+# define OPENSSL_ALGORITHM_DEFINES
+# include <openssl/opensslconf.h>
+# undef OPENSSL_ALGORITHM_DEFINES
+#endif
+
+#include <openssl/ossl_typ.h>
+
+#include <openssl/symhacks.h>
+
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+
+/*
+#define EVP_RC2_KEY_SIZE		16
+#define EVP_RC4_KEY_SIZE		16
+#define EVP_BLOWFISH_KEY_SIZE		16
+#define EVP_CAST5_KEY_SIZE		16
+#define EVP_RC5_32_12_16_KEY_SIZE	16
+*/
+#define EVP_MAX_MD_SIZE			64	/* longest known is SHA512 */
+#define EVP_MAX_KEY_LENGTH		32
+#define EVP_MAX_IV_LENGTH		16
+#define EVP_MAX_BLOCK_LENGTH		32
+
+#define PKCS5_SALT_LEN			8
+/* Default PKCS#5 iteration count */
+#define PKCS5_DEFAULT_ITER		2048
+
+#include <openssl/objects.h>
+
+#define EVP_PK_RSA	0x0001
+#define EVP_PK_DSA	0x0002
+#define EVP_PK_DH	0x0004
+#define EVP_PK_EC	0x0008
+#define EVP_PKT_SIGN	0x0010
+#define EVP_PKT_ENC	0x0020
+#define EVP_PKT_EXCH	0x0040
+#define EVP_PKS_RSA	0x0100
+#define EVP_PKS_DSA	0x0200
+#define EVP_PKS_EC	0x0400
+#define EVP_PKT_EXP	0x1000 /* <= 512 bit key */
+
+#define EVP_PKEY_NONE	NID_undef
+#define EVP_PKEY_RSA	NID_rsaEncryption
+#define EVP_PKEY_RSA2	NID_rsa
+#define EVP_PKEY_DSA	NID_dsa
+#define EVP_PKEY_DSA1	NID_dsa_2
+#define EVP_PKEY_DSA2	NID_dsaWithSHA
+#define EVP_PKEY_DSA3	NID_dsaWithSHA1
+#define EVP_PKEY_DSA4	NID_dsaWithSHA1_2
+#define EVP_PKEY_DH	NID_dhKeyAgreement
+#define EVP_PKEY_EC	NID_X9_62_id_ecPublicKey
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/* Type needs to be a bit field
+ * Sub-type needs to be for variations on the method, as in, can it do
+ * arbitrary encryption.... */
+struct evp_pkey_st
+	{
+	int type;
+	int save_type;
+	int references;
+	union	{
+		char *ptr;
+#ifndef OPENSSL_NO_RSA
+		struct rsa_st *rsa;	/* RSA */
+#endif
+#ifndef OPENSSL_NO_DSA
+		struct dsa_st *dsa;	/* DSA */
+#endif
+#ifndef OPENSSL_NO_DH
+		struct dh_st *dh;	/* DH */
+#endif
+#ifndef OPENSSL_NO_EC
+		struct ec_key_st *ec;	/* ECC */
+#endif
+		} pkey;
+	int save_parameters;
+	STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
+	} /* EVP_PKEY */;
+
+#define EVP_PKEY_MO_SIGN	0x0001
+#define EVP_PKEY_MO_VERIFY	0x0002
+#define EVP_PKEY_MO_ENCRYPT	0x0004
+#define EVP_PKEY_MO_DECRYPT	0x0008
+
+#if 0
+/* This structure is required to tie the message digest and signing together.
+ * The lookup can be done by md/pkey_method, oid, oid/pkey_method, or
+ * oid, md and pkey.
+ * This is required because for various smart-card perform the digest and
+ * signing/verification on-board.  To handle this case, the specific
+ * EVP_MD and EVP_PKEY_METHODs need to be closely associated.
+ * When a PKEY is created, it will have a EVP_PKEY_METHOD associated with it.
+ * This can either be software or a token to provide the required low level
+ * routines.
+ */
+typedef struct evp_pkey_md_st
+	{
+	int oid;
+	EVP_MD *md;
+	EVP_PKEY_METHOD *pkey;
+	} EVP_PKEY_MD;
+
+#define EVP_rsa_md2() \
+		EVP_PKEY_MD_add(NID_md2WithRSAEncryption,\
+			EVP_rsa_pkcs1(),EVP_md2())
+#define EVP_rsa_md5() \
+		EVP_PKEY_MD_add(NID_md5WithRSAEncryption,\
+			EVP_rsa_pkcs1(),EVP_md5())
+#define EVP_rsa_sha0() \
+		EVP_PKEY_MD_add(NID_shaWithRSAEncryption,\
+			EVP_rsa_pkcs1(),EVP_sha())
+#define EVP_rsa_sha1() \
+		EVP_PKEY_MD_add(NID_sha1WithRSAEncryption,\
+			EVP_rsa_pkcs1(),EVP_sha1())
+#define EVP_rsa_ripemd160() \
+		EVP_PKEY_MD_add(NID_ripemd160WithRSA,\
+			EVP_rsa_pkcs1(),EVP_ripemd160())
+#define EVP_rsa_mdc2() \
+		EVP_PKEY_MD_add(NID_mdc2WithRSA,\
+			EVP_rsa_octet_string(),EVP_mdc2())
+#define EVP_dsa_sha() \
+		EVP_PKEY_MD_add(NID_dsaWithSHA,\
+			EVP_dsa(),EVP_sha())
+#define EVP_dsa_sha1() \
+		EVP_PKEY_MD_add(NID_dsaWithSHA1,\
+			EVP_dsa(),EVP_sha1())
+
+typedef struct evp_pkey_method_st
+	{
+	char *name;
+	int flags;
+	int type;		/* RSA, DSA, an SSLeay specific constant */
+	int oid;		/* For the pub-key type */
+	int encrypt_oid;	/* pub/priv key encryption */
+
+	int (*sign)();
+	int (*verify)();
+	struct	{
+		int (*set)();	/* get and/or set the underlying type */
+		int (*get)();
+		int (*encrypt)();
+		int (*decrypt)();
+		int (*i2d)();
+		int (*d2i)();
+		int (*dup)();
+		} pub,priv;
+	int (*set_asn1_parameters)();
+	int (*get_asn1_parameters)();
+	} EVP_PKEY_METHOD;
+#endif
+
+#ifndef EVP_MD
+struct env_md_st
+	{
+	int type;
+	int pkey_type;
+	int md_size;
+	unsigned long flags;
+	int (*init)(EVP_MD_CTX *ctx);
+	int (*update)(EVP_MD_CTX *ctx,const void *data,size_t count);
+	int (*final)(EVP_MD_CTX *ctx,unsigned char *md);
+	int (*copy)(EVP_MD_CTX *to,const EVP_MD_CTX *from);
+	int (*cleanup)(EVP_MD_CTX *ctx);
+
+	/* FIXME: prototype these some day */
+	int (*sign)(int type, const unsigned char *m, unsigned int m_length,
+		    unsigned char *sigret, unsigned int *siglen, void *key);
+	int (*verify)(int type, const unsigned char *m, unsigned int m_length,
+		      const unsigned char *sigbuf, unsigned int siglen,
+		      void *key);
+	int required_pkey_type[5]; /*EVP_PKEY_xxx */
+	int block_size;
+	int ctx_size; /* how big does the ctx->md_data need to be */
+	} /* EVP_MD */;
+
+typedef int evp_sign_method(int type,const unsigned char *m,
+			    unsigned int m_length,unsigned char *sigret,
+			    unsigned int *siglen, void *key);
+typedef int evp_verify_method(int type,const unsigned char *m,
+			    unsigned int m_length,const unsigned char *sigbuf,
+			    unsigned int siglen, void *key);
+
+#define EVP_MD_FLAG_ONESHOT	0x0001 /* digest can only handle a single
+					* block */
+
+#define EVP_PKEY_NULL_method	NULL,NULL,{0,0,0,0}
+
+#ifndef OPENSSL_NO_DSA
+#define EVP_PKEY_DSA_method	(evp_sign_method *)DSA_sign, \
+				(evp_verify_method *)DSA_verify, \
+				{EVP_PKEY_DSA,EVP_PKEY_DSA2,EVP_PKEY_DSA3, \
+					EVP_PKEY_DSA4,0}
+#else
+#define EVP_PKEY_DSA_method	EVP_PKEY_NULL_method
+#endif
+
+#ifndef OPENSSL_NO_ECDSA
+#define EVP_PKEY_ECDSA_method   (evp_sign_method *)ECDSA_sign, \
+				(evp_verify_method *)ECDSA_verify, \
+                                 {EVP_PKEY_EC,0,0,0}
+#else   
+#define EVP_PKEY_ECDSA_method   EVP_PKEY_NULL_method
+#endif
+
+#ifndef OPENSSL_NO_RSA
+#define EVP_PKEY_RSA_method	(evp_sign_method *)RSA_sign, \
+				(evp_verify_method *)RSA_verify, \
+				{EVP_PKEY_RSA,EVP_PKEY_RSA2,0,0}
+#define EVP_PKEY_RSA_ASN1_OCTET_STRING_method \
+				(evp_sign_method *)RSA_sign_ASN1_OCTET_STRING, \
+				(evp_verify_method *)RSA_verify_ASN1_OCTET_STRING, \
+				{EVP_PKEY_RSA,EVP_PKEY_RSA2,0,0}
+#else
+#define EVP_PKEY_RSA_method	EVP_PKEY_NULL_method
+#define EVP_PKEY_RSA_ASN1_OCTET_STRING_method EVP_PKEY_NULL_method
+#endif
+
+#endif /* !EVP_MD */
+
+struct env_md_ctx_st
+	{
+	const EVP_MD *digest;
+	ENGINE *engine; /* functional reference if 'digest' is ENGINE-provided */
+	unsigned long flags;
+	void *md_data;
+	} /* EVP_MD_CTX */;
+
+/* values for EVP_MD_CTX flags */
+
+#define EVP_MD_CTX_FLAG_ONESHOT		0x0001 /* digest update will be called
+						* once only */
+#define EVP_MD_CTX_FLAG_CLEANED		0x0002 /* context has already been
+						* cleaned */
+#define EVP_MD_CTX_FLAG_REUSE		0x0004 /* Don't free up ctx->md_data
+						* in EVP_MD_CTX_cleanup */
+
+struct evp_cipher_st
+	{
+	int nid;
+	int block_size;
+	int key_len;		/* Default value for variable length ciphers */
+	int iv_len;
+	unsigned long flags;	/* Various flags */
+	int (*init)(EVP_CIPHER_CTX *ctx, const unsigned char *key,
+		    const unsigned char *iv, int enc);	/* init key */
+	int (*do_cipher)(EVP_CIPHER_CTX *ctx, unsigned char *out,
+			 const unsigned char *in, unsigned int inl);/* encrypt/decrypt data */
+	int (*cleanup)(EVP_CIPHER_CTX *); /* cleanup ctx */
+	int ctx_size;		/* how big ctx->cipher_data needs to be */
+	int (*set_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Populate a ASN1_TYPE with parameters */
+	int (*get_asn1_parameters)(EVP_CIPHER_CTX *, ASN1_TYPE *); /* Get parameters from a ASN1_TYPE */
+	int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); /* Miscellaneous operations */
+	void *app_data;		/* Application data */
+	} /* EVP_CIPHER */;
+
+/* Values for cipher flags */
+
+/* Modes for ciphers */
+
+#define		EVP_CIPH_STREAM_CIPHER		0x0
+#define		EVP_CIPH_ECB_MODE		0x1
+#define		EVP_CIPH_CBC_MODE		0x2
+#define		EVP_CIPH_CFB_MODE		0x3
+#define		EVP_CIPH_OFB_MODE		0x4
+#define 	EVP_CIPH_MODE			0x7
+/* Set if variable length cipher */
+#define 	EVP_CIPH_VARIABLE_LENGTH	0x8
+/* Set if the iv handling should be done by the cipher itself */
+#define 	EVP_CIPH_CUSTOM_IV		0x10
+/* Set if the cipher's init() function should be called if key is NULL */
+#define 	EVP_CIPH_ALWAYS_CALL_INIT	0x20
+/* Call ctrl() to init cipher parameters */
+#define 	EVP_CIPH_CTRL_INIT		0x40
+/* Don't use standard key length function */
+#define 	EVP_CIPH_CUSTOM_KEY_LENGTH	0x80
+/* Don't use standard block padding */
+#define 	EVP_CIPH_NO_PADDING		0x100
+/* cipher handles random key generation */
+#define 	EVP_CIPH_RAND_KEY		0x200
+
+/* ctrl() values */
+
+#define		EVP_CTRL_INIT			0x0
+#define 	EVP_CTRL_SET_KEY_LENGTH		0x1
+#define 	EVP_CTRL_GET_RC2_KEY_BITS	0x2
+#define 	EVP_CTRL_SET_RC2_KEY_BITS	0x3
+#define 	EVP_CTRL_GET_RC5_ROUNDS		0x4
+#define 	EVP_CTRL_SET_RC5_ROUNDS		0x5
+#define 	EVP_CTRL_RAND_KEY		0x6
+
+typedef struct evp_cipher_info_st
+	{
+	const EVP_CIPHER *cipher;
+	unsigned char iv[EVP_MAX_IV_LENGTH];
+	} EVP_CIPHER_INFO;
+
+struct evp_cipher_ctx_st
+	{
+	const EVP_CIPHER *cipher;
+	ENGINE *engine;	/* functional reference if 'cipher' is ENGINE-provided */
+	int encrypt;		/* encrypt or decrypt */
+	int buf_len;		/* number we have left */
+
+	unsigned char  oiv[EVP_MAX_IV_LENGTH];	/* original iv */
+	unsigned char  iv[EVP_MAX_IV_LENGTH];	/* working iv */
+	unsigned char buf[EVP_MAX_BLOCK_LENGTH];/* saved partial block */
+	int num;				/* used by cfb/ofb mode */
+
+	void *app_data;		/* application stuff */
+	int key_len;		/* May change for variable length cipher */
+	unsigned long flags;	/* Various flags */
+	void *cipher_data; /* per EVP data */
+	int final_used;
+	int block_mask;
+	unsigned char final[EVP_MAX_BLOCK_LENGTH];/* possible final block */
+	} /* EVP_CIPHER_CTX */;
+
+typedef struct evp_Encode_Ctx_st
+	{
+	int num;	/* number saved in a partial encode/decode */
+	int length;	/* The length is either the output line length
+			 * (in input bytes) or the shortest input line
+			 * length that is ok.  Once decoding begins,
+			 * the length is adjusted up each time a longer
+			 * line is decoded */
+	unsigned char enc_data[80];	/* data to encode */
+	int line_num;	/* number read on current line */
+	int expect_nl;
+	} EVP_ENCODE_CTX;
+
+/* Password based encryption function */
+typedef int (EVP_PBE_KEYGEN)(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
+		ASN1_TYPE *param, const EVP_CIPHER *cipher,
+                const EVP_MD *md, int en_de);
+
+#ifndef OPENSSL_NO_RSA
+#define EVP_PKEY_assign_RSA(pkey,rsa) EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
+					(char *)(rsa))
+#endif
+
+#ifndef OPENSSL_NO_DSA
+#define EVP_PKEY_assign_DSA(pkey,dsa) EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
+					(char *)(dsa))
+#endif
+
+#ifndef OPENSSL_NO_DH
+#define EVP_PKEY_assign_DH(pkey,dh) EVP_PKEY_assign((pkey),EVP_PKEY_DH,\
+					(char *)(dh))
+#endif
+
+#ifndef OPENSSL_NO_EC
+#define EVP_PKEY_assign_EC_KEY(pkey,eckey) EVP_PKEY_assign((pkey),EVP_PKEY_EC,\
+                                        (char *)(eckey))
+#endif
+
+/* Add some extra combinations */
+#define EVP_get_digestbynid(a) EVP_get_digestbyname(OBJ_nid2sn(a))
+#define EVP_get_digestbyobj(a) EVP_get_digestbynid(OBJ_obj2nid(a))
+#define EVP_get_cipherbynid(a) EVP_get_cipherbyname(OBJ_nid2sn(a))
+#define EVP_get_cipherbyobj(a) EVP_get_cipherbynid(OBJ_obj2nid(a))
+
+#define EVP_MD_type(e)			((e)->type)
+#define EVP_MD_nid(e)			EVP_MD_type(e)
+#define EVP_MD_name(e)			OBJ_nid2sn(EVP_MD_nid(e))
+#define EVP_MD_pkey_type(e)		((e)->pkey_type)
+#define EVP_MD_size(e)			((e)->md_size)
+#define EVP_MD_block_size(e)		((e)->block_size)
+
+#define EVP_MD_CTX_md(e)		((e)->digest)
+#define EVP_MD_CTX_size(e)		EVP_MD_size((e)->digest)
+#define EVP_MD_CTX_block_size(e)	EVP_MD_block_size((e)->digest)
+#define EVP_MD_CTX_type(e)		EVP_MD_type((e)->digest)
+
+#define EVP_CIPHER_nid(e)		((e)->nid)
+#define EVP_CIPHER_name(e)		OBJ_nid2sn(EVP_CIPHER_nid(e))
+#define EVP_CIPHER_block_size(e)	((e)->block_size)
+#define EVP_CIPHER_key_length(e)	((e)->key_len)
+#define EVP_CIPHER_iv_length(e)		((e)->iv_len)
+#define EVP_CIPHER_flags(e)		((e)->flags)
+#define EVP_CIPHER_mode(e)		(((e)->flags) & EVP_CIPH_MODE)
+
+#define EVP_CIPHER_CTX_cipher(e)	((e)->cipher)
+#define EVP_CIPHER_CTX_nid(e)		((e)->cipher->nid)
+#define EVP_CIPHER_CTX_block_size(e)	((e)->cipher->block_size)
+#define EVP_CIPHER_CTX_key_length(e)	((e)->key_len)
+#define EVP_CIPHER_CTX_iv_length(e)	((e)->cipher->iv_len)
+#define EVP_CIPHER_CTX_get_app_data(e)	((e)->app_data)
+#define EVP_CIPHER_CTX_set_app_data(e,d) ((e)->app_data=(char *)(d))
+#define EVP_CIPHER_CTX_type(c)         EVP_CIPHER_type(EVP_CIPHER_CTX_cipher(c))
+#define EVP_CIPHER_CTX_flags(e)		((e)->cipher->flags)
+#define EVP_CIPHER_CTX_mode(e)		((e)->cipher->flags & EVP_CIPH_MODE)
+
+#define EVP_ENCODE_LENGTH(l)	(((l+2)/3*4)+(l/48+1)*2+80)
+#define EVP_DECODE_LENGTH(l)	((l+3)/4*3+80)
+
+#define EVP_SignInit_ex(a,b,c)		EVP_DigestInit_ex(a,b,c)
+#define EVP_SignInit(a,b)		EVP_DigestInit(a,b)
+#define EVP_SignUpdate(a,b,c)		EVP_DigestUpdate(a,b,c)
+#define	EVP_VerifyInit_ex(a,b,c)	EVP_DigestInit_ex(a,b,c)
+#define	EVP_VerifyInit(a,b)		EVP_DigestInit(a,b)
+#define	EVP_VerifyUpdate(a,b,c)		EVP_DigestUpdate(a,b,c)
+#define EVP_OpenUpdate(a,b,c,d,e)	EVP_DecryptUpdate(a,b,c,d,e)
+#define EVP_SealUpdate(a,b,c,d,e)	EVP_EncryptUpdate(a,b,c,d,e)	
+
+#ifdef CONST_STRICT
+void BIO_set_md(BIO *,const EVP_MD *md);
+#else
+# define BIO_set_md(b,md)		BIO_ctrl(b,BIO_C_SET_MD,0,(char *)md)
+#endif
+#define BIO_get_md(b,mdp)		BIO_ctrl(b,BIO_C_GET_MD,0,(char *)mdp)
+#define BIO_get_md_ctx(b,mdcp)     BIO_ctrl(b,BIO_C_GET_MD_CTX,0,(char *)mdcp)
+#define BIO_get_cipher_status(b)	BIO_ctrl(b,BIO_C_GET_CIPHER_STATUS,0,NULL)
+#define BIO_get_cipher_ctx(b,c_pp)	BIO_ctrl(b,BIO_C_GET_CIPHER_CTX,0,(char *)c_pp)
+
+#define	EVP_Cipher(c,o,i,l)	(c)->cipher->do_cipher((c),(o),(i),(l))
+
+#define EVP_add_cipher_alias(n,alias) \
+	OBJ_NAME_add((alias),OBJ_NAME_TYPE_CIPHER_METH|OBJ_NAME_ALIAS,(n))
+#define EVP_add_digest_alias(n,alias) \
+	OBJ_NAME_add((alias),OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS,(n))
+#define EVP_delete_cipher_alias(alias) \
+	OBJ_NAME_remove(alias,OBJ_NAME_TYPE_CIPHER_METH|OBJ_NAME_ALIAS);
+#define EVP_delete_digest_alias(alias) \
+	OBJ_NAME_remove(alias,OBJ_NAME_TYPE_MD_METH|OBJ_NAME_ALIAS);
+
+void	EVP_MD_CTX_init(EVP_MD_CTX *ctx);
+int	EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx);
+EVP_MD_CTX *EVP_MD_CTX_create(void);
+void	EVP_MD_CTX_destroy(EVP_MD_CTX *ctx);
+int     EVP_MD_CTX_copy_ex(EVP_MD_CTX *out,const EVP_MD_CTX *in);  
+#define EVP_MD_CTX_set_flags(ctx,flgs) ((ctx)->flags|=(flgs))
+#define EVP_MD_CTX_clear_flags(ctx,flgs) ((ctx)->flags&=~(flgs))
+#define EVP_MD_CTX_test_flags(ctx,flgs) ((ctx)->flags&(flgs))
+int	EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl);
+int	EVP_DigestUpdate(EVP_MD_CTX *ctx,const void *d,
+			 size_t cnt);
+int	EVP_DigestFinal_ex(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s);
+int	EVP_Digest(const void *data, size_t count,
+		unsigned char *md, unsigned int *size, const EVP_MD *type, ENGINE *impl);
+
+int     EVP_MD_CTX_copy(EVP_MD_CTX *out,const EVP_MD_CTX *in);  
+int	EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type);
+int	EVP_DigestFinal(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s);
+
+int	EVP_read_pw_string(char *buf,int length,const char *prompt,int verify);
+void	EVP_set_pw_prompt(const char *prompt);
+char *	EVP_get_pw_prompt(void);
+
+int	EVP_BytesToKey(const EVP_CIPHER *type,const EVP_MD *md,
+		const unsigned char *salt, const unsigned char *data,
+		int datal, int count, unsigned char *key,unsigned char *iv);
+
+int	EVP_EncryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
+		const unsigned char *key, const unsigned char *iv);
+int	EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
+		const unsigned char *key, const unsigned char *iv);
+int	EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
+		int *outl, const unsigned char *in, int inl);
+int	EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
+int	EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
+
+int	EVP_DecryptInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
+		const unsigned char *key, const unsigned char *iv);
+int	EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
+		const unsigned char *key, const unsigned char *iv);
+int	EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
+		int *outl, const unsigned char *in, int inl);
+int	EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
+int	EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
+
+int	EVP_CipherInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher,
+		       const unsigned char *key,const unsigned char *iv,
+		       int enc);
+int	EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *cipher, ENGINE *impl,
+		       const unsigned char *key,const unsigned char *iv,
+		       int enc);
+int	EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out,
+		int *outl, const unsigned char *in, int inl);
+int	EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
+int	EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl);
+
+int	EVP_SignFinal(EVP_MD_CTX *ctx,unsigned char *md,unsigned int *s,
+		EVP_PKEY *pkey);
+
+int	EVP_VerifyFinal(EVP_MD_CTX *ctx,const unsigned char *sigbuf,
+		unsigned int siglen,EVP_PKEY *pkey);
+
+int	EVP_OpenInit(EVP_CIPHER_CTX *ctx,const EVP_CIPHER *type,
+		const unsigned char *ek, int ekl, const unsigned char *iv,
+		EVP_PKEY *priv);
+int	EVP_OpenFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl);
+
+int	EVP_SealInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type,
+		 unsigned char **ek, int *ekl, unsigned char *iv,
+		EVP_PKEY **pubk, int npubk);
+int	EVP_SealFinal(EVP_CIPHER_CTX *ctx,unsigned char *out,int *outl);
+
+void	EVP_EncodeInit(EVP_ENCODE_CTX *ctx);
+void	EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl,
+		const unsigned char *in,int inl);
+void	EVP_EncodeFinal(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl);
+int	EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int n);
+
+void	EVP_DecodeInit(EVP_ENCODE_CTX *ctx);
+int	EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx,unsigned char *out,int *outl,
+		const unsigned char *in, int inl);
+int	EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned
+		char *out, int *outl);
+int	EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n);
+
+void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *a);
+int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *a);
+int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *x, int keylen);
+int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *c, int pad);
+int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr);
+int EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key);
+
+#ifndef OPENSSL_NO_BIO
+BIO_METHOD *BIO_f_md(void);
+BIO_METHOD *BIO_f_base64(void);
+BIO_METHOD *BIO_f_cipher(void);
+BIO_METHOD *BIO_f_reliable(void);
+void BIO_set_cipher(BIO *b,const EVP_CIPHER *c,const unsigned char *k,
+		const unsigned char *i, int enc);
+#endif
+
+const EVP_MD *EVP_md_null(void);
+#ifndef OPENSSL_NO_MD2
+const EVP_MD *EVP_md2(void);
+#endif
+#ifndef OPENSSL_NO_MD4
+const EVP_MD *EVP_md4(void);
+#endif
+#ifndef OPENSSL_NO_MD5
+const EVP_MD *EVP_md5(void);
+#endif
+#ifndef OPENSSL_NO_SHA
+const EVP_MD *EVP_sha(void);
+const EVP_MD *EVP_sha1(void);
+const EVP_MD *EVP_dss(void);
+const EVP_MD *EVP_dss1(void);
+const EVP_MD *EVP_ecdsa(void);
+#endif
+#ifndef OPENSSL_NO_SHA256
+const EVP_MD *EVP_sha224(void);
+const EVP_MD *EVP_sha256(void);
+#endif
+#ifndef OPENSSL_NO_SHA512
+const EVP_MD *EVP_sha384(void);
+const EVP_MD *EVP_sha512(void);
+#endif
+#ifndef OPENSSL_NO_MDC2
+const EVP_MD *EVP_mdc2(void);
+#endif
+#ifndef OPENSSL_NO_RIPEMD
+const EVP_MD *EVP_ripemd160(void);
+#endif
+const EVP_CIPHER *EVP_enc_null(void);		/* does nothing :-) */
+#ifndef OPENSSL_NO_DES
+const EVP_CIPHER *EVP_des_ecb(void);
+const EVP_CIPHER *EVP_des_ede(void);
+const EVP_CIPHER *EVP_des_ede3(void);
+const EVP_CIPHER *EVP_des_ede_ecb(void);
+const EVP_CIPHER *EVP_des_ede3_ecb(void);
+const EVP_CIPHER *EVP_des_cfb64(void);
+# define EVP_des_cfb EVP_des_cfb64
+const EVP_CIPHER *EVP_des_cfb1(void);
+const EVP_CIPHER *EVP_des_cfb8(void);
+const EVP_CIPHER *EVP_des_ede_cfb64(void);
+# define EVP_des_ede_cfb EVP_des_ede_cfb64
+#if 0
+const EVP_CIPHER *EVP_des_ede_cfb1(void);
+const EVP_CIPHER *EVP_des_ede_cfb8(void);
+#endif
+const EVP_CIPHER *EVP_des_ede3_cfb64(void);
+# define EVP_des_ede3_cfb EVP_des_ede3_cfb64
+const EVP_CIPHER *EVP_des_ede3_cfb1(void);
+const EVP_CIPHER *EVP_des_ede3_cfb8(void);
+const EVP_CIPHER *EVP_des_ofb(void);
+const EVP_CIPHER *EVP_des_ede_ofb(void);
+const EVP_CIPHER *EVP_des_ede3_ofb(void);
+const EVP_CIPHER *EVP_des_cbc(void);
+const EVP_CIPHER *EVP_des_ede_cbc(void);
+const EVP_CIPHER *EVP_des_ede3_cbc(void);
+const EVP_CIPHER *EVP_desx_cbc(void);
+/* This should now be supported through the dev_crypto ENGINE. But also, why are
+ * rc4 and md5 declarations made here inside a "NO_DES" precompiler branch? */
+#if 0
+# ifdef OPENSSL_OPENBSD_DEV_CRYPTO
+const EVP_CIPHER *EVP_dev_crypto_des_ede3_cbc(void);
+const EVP_CIPHER *EVP_dev_crypto_rc4(void);
+const EVP_MD *EVP_dev_crypto_md5(void);
+# endif
+#endif
+#endif
+#ifndef OPENSSL_NO_RC4
+const EVP_CIPHER *EVP_rc4(void);
+const EVP_CIPHER *EVP_rc4_40(void);
+#endif
+#ifndef OPENSSL_NO_IDEA
+const EVP_CIPHER *EVP_idea_ecb(void);
+const EVP_CIPHER *EVP_idea_cfb64(void);
+# define EVP_idea_cfb EVP_idea_cfb64
+const EVP_CIPHER *EVP_idea_ofb(void);
+const EVP_CIPHER *EVP_idea_cbc(void);
+#endif
+#ifndef OPENSSL_NO_RC2
+const EVP_CIPHER *EVP_rc2_ecb(void);
+const EVP_CIPHER *EVP_rc2_cbc(void);
+const EVP_CIPHER *EVP_rc2_40_cbc(void);
+const EVP_CIPHER *EVP_rc2_64_cbc(void);
+const EVP_CIPHER *EVP_rc2_cfb64(void);
+# define EVP_rc2_cfb EVP_rc2_cfb64
+const EVP_CIPHER *EVP_rc2_ofb(void);
+#endif
+#ifndef OPENSSL_NO_BF
+const EVP_CIPHER *EVP_bf_ecb(void);
+const EVP_CIPHER *EVP_bf_cbc(void);
+const EVP_CIPHER *EVP_bf_cfb64(void);
+# define EVP_bf_cfb EVP_bf_cfb64
+const EVP_CIPHER *EVP_bf_ofb(void);
+#endif
+#ifndef OPENSSL_NO_CAST
+const EVP_CIPHER *EVP_cast5_ecb(void);
+const EVP_CIPHER *EVP_cast5_cbc(void);
+const EVP_CIPHER *EVP_cast5_cfb64(void);
+# define EVP_cast5_cfb EVP_cast5_cfb64
+const EVP_CIPHER *EVP_cast5_ofb(void);
+#endif
+#ifndef OPENSSL_NO_RC5
+const EVP_CIPHER *EVP_rc5_32_12_16_cbc(void);
+const EVP_CIPHER *EVP_rc5_32_12_16_ecb(void);
+const EVP_CIPHER *EVP_rc5_32_12_16_cfb64(void);
+# define EVP_rc5_32_12_16_cfb EVP_rc5_32_12_16_cfb64
+const EVP_CIPHER *EVP_rc5_32_12_16_ofb(void);
+#endif
+#ifndef OPENSSL_NO_AES
+const EVP_CIPHER *EVP_aes_128_ecb(void);
+const EVP_CIPHER *EVP_aes_128_cbc(void);
+const EVP_CIPHER *EVP_aes_128_cfb1(void);
+const EVP_CIPHER *EVP_aes_128_cfb8(void);
+const EVP_CIPHER *EVP_aes_128_cfb128(void);
+# define EVP_aes_128_cfb EVP_aes_128_cfb128
+const EVP_CIPHER *EVP_aes_128_ofb(void);
+#if 0
+const EVP_CIPHER *EVP_aes_128_ctr(void);
+#endif
+const EVP_CIPHER *EVP_aes_192_ecb(void);
+const EVP_CIPHER *EVP_aes_192_cbc(void);
+const EVP_CIPHER *EVP_aes_192_cfb1(void);
+const EVP_CIPHER *EVP_aes_192_cfb8(void);
+const EVP_CIPHER *EVP_aes_192_cfb128(void);
+# define EVP_aes_192_cfb EVP_aes_192_cfb128
+const EVP_CIPHER *EVP_aes_192_ofb(void);
+#if 0
+const EVP_CIPHER *EVP_aes_192_ctr(void);
+#endif
+const EVP_CIPHER *EVP_aes_256_ecb(void);
+const EVP_CIPHER *EVP_aes_256_cbc(void);
+const EVP_CIPHER *EVP_aes_256_cfb1(void);
+const EVP_CIPHER *EVP_aes_256_cfb8(void);
+const EVP_CIPHER *EVP_aes_256_cfb128(void);
+# define EVP_aes_256_cfb EVP_aes_256_cfb128
+const EVP_CIPHER *EVP_aes_256_ofb(void);
+#if 0
+const EVP_CIPHER *EVP_aes_256_ctr(void);
+#endif
+#endif
+
+void OPENSSL_add_all_algorithms_noconf(void);
+void OPENSSL_add_all_algorithms_conf(void);
+
+#ifdef OPENSSL_LOAD_CONF
+#define OpenSSL_add_all_algorithms() \
+		OPENSSL_add_all_algorithms_conf()
+#else
+#define OpenSSL_add_all_algorithms() \
+		OPENSSL_add_all_algorithms_noconf()
+#endif
+
+void OpenSSL_add_all_ciphers(void);
+void OpenSSL_add_all_digests(void);
+#define SSLeay_add_all_algorithms() OpenSSL_add_all_algorithms()
+#define SSLeay_add_all_ciphers() OpenSSL_add_all_ciphers()
+#define SSLeay_add_all_digests() OpenSSL_add_all_digests()
+
+int EVP_add_cipher(const EVP_CIPHER *cipher);
+int EVP_add_digest(const EVP_MD *digest);
+
+const EVP_CIPHER *EVP_get_cipherbyname(const char *name);
+const EVP_MD *EVP_get_digestbyname(const char *name);
+void EVP_cleanup(void);
+
+int		EVP_PKEY_decrypt(unsigned char *dec_key,
+			const unsigned char *enc_key,int enc_key_len,
+			EVP_PKEY *private_key);
+int		EVP_PKEY_encrypt(unsigned char *enc_key,
+			const unsigned char *key,int key_len,
+			EVP_PKEY *pub_key);
+int		EVP_PKEY_type(int type);
+int		EVP_PKEY_bits(EVP_PKEY *pkey);
+int		EVP_PKEY_size(EVP_PKEY *pkey);
+int 		EVP_PKEY_assign(EVP_PKEY *pkey,int type,char *key);
+
+#ifndef OPENSSL_NO_RSA
+struct rsa_st;
+int EVP_PKEY_set1_RSA(EVP_PKEY *pkey,struct rsa_st *key);
+struct rsa_st *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
+#endif
+#ifndef OPENSSL_NO_DSA
+struct dsa_st;
+int EVP_PKEY_set1_DSA(EVP_PKEY *pkey,struct dsa_st *key);
+struct dsa_st *EVP_PKEY_get1_DSA(EVP_PKEY *pkey);
+#endif
+#ifndef OPENSSL_NO_DH
+struct dh_st;
+int EVP_PKEY_set1_DH(EVP_PKEY *pkey,struct dh_st *key);
+struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey);
+#endif
+#ifndef OPENSSL_NO_EC
+struct ec_key_st;
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey,struct ec_key_st *key);
+struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey);
+#endif
+
+EVP_PKEY *	EVP_PKEY_new(void);
+void		EVP_PKEY_free(EVP_PKEY *pkey);
+
+EVP_PKEY *	d2i_PublicKey(int type,EVP_PKEY **a, const unsigned char **pp,
+			long length);
+int		i2d_PublicKey(EVP_PKEY *a, unsigned char **pp);
+
+EVP_PKEY *	d2i_PrivateKey(int type,EVP_PKEY **a, const unsigned char **pp,
+			long length);
+EVP_PKEY *	d2i_AutoPrivateKey(EVP_PKEY **a, const unsigned char **pp,
+			long length);
+int		i2d_PrivateKey(EVP_PKEY *a, unsigned char **pp);
+
+int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from);
+int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey);
+int EVP_PKEY_save_parameters(EVP_PKEY *pkey,int mode);
+int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b);
+
+int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b);
+
+int EVP_CIPHER_type(const EVP_CIPHER *ctx);
+
+/* calls methods */
+int EVP_CIPHER_param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
+int EVP_CIPHER_asn1_to_param(EVP_CIPHER_CTX *c, ASN1_TYPE *type);
+
+/* These are used by EVP_CIPHER methods */
+int EVP_CIPHER_set_asn1_iv(EVP_CIPHER_CTX *c,ASN1_TYPE *type);
+int EVP_CIPHER_get_asn1_iv(EVP_CIPHER_CTX *c,ASN1_TYPE *type);
+
+/* PKCS5 password based encryption */
+int PKCS5_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
+			 ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md,
+			 int en_de);
+int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen,
+			   const unsigned char *salt, int saltlen, int iter,
+			   int keylen, unsigned char *out);
+int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
+			 ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md,
+			 int en_de);
+
+void PKCS5_PBE_add(void);
+
+int EVP_PBE_CipherInit (ASN1_OBJECT *pbe_obj, const char *pass, int passlen,
+	     ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int en_de);
+int EVP_PBE_alg_add(int nid, const EVP_CIPHER *cipher, const EVP_MD *md,
+		    EVP_PBE_KEYGEN *keygen);
+void EVP_PBE_cleanup(void);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_EVP_strings(void);
+
+/* Error codes for the EVP functions. */
+
+/* Function codes. */
+#define EVP_F_AES_INIT_KEY				 133
+#define EVP_F_D2I_PKEY					 100
+#define EVP_F_DSAPKEY2PKCS8				 134
+#define EVP_F_DSA_PKEY2PKCS8				 135
+#define EVP_F_ECDSA_PKEY2PKCS8				 129
+#define EVP_F_ECKEY_PKEY2PKCS8				 132
+#define EVP_F_EVP_CIPHERINIT_EX				 123
+#define EVP_F_EVP_CIPHER_CTX_CTRL			 124
+#define EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH		 122
+#define EVP_F_EVP_DECRYPTFINAL_EX			 101
+#define EVP_F_EVP_DIGESTINIT_EX				 128
+#define EVP_F_EVP_ENCRYPTFINAL_EX			 127
+#define EVP_F_EVP_MD_CTX_COPY_EX			 110
+#define EVP_F_EVP_OPENINIT				 102
+#define EVP_F_EVP_PBE_ALG_ADD				 115
+#define EVP_F_EVP_PBE_CIPHERINIT			 116
+#define EVP_F_EVP_PKCS82PKEY				 111
+#define EVP_F_EVP_PKEY2PKCS8_BROKEN			 113
+#define EVP_F_EVP_PKEY_COPY_PARAMETERS			 103
+#define EVP_F_EVP_PKEY_DECRYPT				 104
+#define EVP_F_EVP_PKEY_ENCRYPT				 105
+#define EVP_F_EVP_PKEY_GET1_DH				 119
+#define EVP_F_EVP_PKEY_GET1_DSA				 120
+#define EVP_F_EVP_PKEY_GET1_ECDSA			 130
+#define EVP_F_EVP_PKEY_GET1_EC_KEY			 131
+#define EVP_F_EVP_PKEY_GET1_RSA				 121
+#define EVP_F_EVP_PKEY_NEW				 106
+#define EVP_F_EVP_RIJNDAEL				 126
+#define EVP_F_EVP_SIGNFINAL				 107
+#define EVP_F_EVP_VERIFYFINAL				 108
+#define EVP_F_PKCS5_PBE_KEYIVGEN			 117
+#define EVP_F_PKCS5_V2_PBE_KEYIVGEN			 118
+#define EVP_F_PKCS8_SET_BROKEN				 112
+#define EVP_F_RC2_MAGIC_TO_METH				 109
+#define EVP_F_RC5_CTRL					 125
+
+/* Reason codes. */
+#define EVP_R_AES_KEY_SETUP_FAILED			 143
+#define EVP_R_ASN1_LIB					 140
+#define EVP_R_BAD_BLOCK_LENGTH				 136
+#define EVP_R_BAD_DECRYPT				 100
+#define EVP_R_BAD_KEY_LENGTH				 137
+#define EVP_R_BN_DECODE_ERROR				 112
+#define EVP_R_BN_PUBKEY_ERROR				 113
+#define EVP_R_CIPHER_PARAMETER_ERROR			 122
+#define EVP_R_CTRL_NOT_IMPLEMENTED			 132
+#define EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED		 133
+#define EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH		 138
+#define EVP_R_DECODE_ERROR				 114
+#define EVP_R_DIFFERENT_KEY_TYPES			 101
+#define EVP_R_ENCODE_ERROR				 115
+#define EVP_R_EVP_PBE_CIPHERINIT_ERROR			 119
+#define EVP_R_EXPECTING_AN_RSA_KEY			 127
+#define EVP_R_EXPECTING_A_DH_KEY			 128
+#define EVP_R_EXPECTING_A_DSA_KEY			 129
+#define EVP_R_EXPECTING_A_ECDSA_KEY			 141
+#define EVP_R_EXPECTING_A_EC_KEY			 142
+#define EVP_R_INITIALIZATION_ERROR			 134
+#define EVP_R_INPUT_NOT_INITIALIZED			 111
+#define EVP_R_INVALID_KEY_LENGTH			 130
+#define EVP_R_IV_TOO_LARGE				 102
+#define EVP_R_KEYGEN_FAILURE				 120
+#define EVP_R_MISSING_PARAMETERS			 103
+#define EVP_R_NO_CIPHER_SET				 131
+#define EVP_R_NO_DIGEST_SET				 139
+#define EVP_R_NO_DSA_PARAMETERS				 116
+#define EVP_R_NO_SIGN_FUNCTION_CONFIGURED		 104
+#define EVP_R_NO_VERIFY_FUNCTION_CONFIGURED		 105
+#define EVP_R_PKCS8_UNKNOWN_BROKEN_TYPE			 117
+#define EVP_R_PUBLIC_KEY_NOT_RSA			 106
+#define EVP_R_UNKNOWN_PBE_ALGORITHM			 121
+#define EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS		 135
+#define EVP_R_UNSUPPORTED_CIPHER			 107
+#define EVP_R_UNSUPPORTED_KEYLENGTH			 123
+#define EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION	 124
+#define EVP_R_UNSUPPORTED_KEY_SIZE			 108
+#define EVP_R_UNSUPPORTED_PRF				 125
+#define EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM		 118
+#define EVP_R_UNSUPPORTED_SALT_TYPE			 126
+#define EVP_R_WRONG_FINAL_BLOCK_LENGTH			 109
+#define EVP_R_WRONG_PUBLIC_KEY_TYPE			 110
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/fips.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/fips.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/fips.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,126 @@
+/* ====================================================================
+ * Copyright (c) 2003 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_FIPS
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Note that these are defined in crypto/cryptlib.c so they're
+ * available even without -lfips.
+ */
+struct dsa_st;
+
+int FIPS_mode_set(int onoff,const char *path);
+void FIPS_allow_md5(int onoff);
+int FIPS_md5_allowed(void);
+int FIPS_selftest_failed(void);
+int FIPS_dsa_check(struct dsa_st *dsa);
+void FIPS_corrupt_sha1(void);
+int FIPS_selftest_sha1(void);
+void FIPS_corrupt_aes(void);
+int FIPS_selftest_aes(void);
+void FIPS_corrupt_des(void);
+int FIPS_selftest_des(void);
+void FIPS_corrupt_rsa(void);
+int FIPS_selftest_rsa(void);
+void FIPS_corrupt_dsa(void);
+int FIPS_selftest_dsa(void);
+
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_FIPS_strings(void);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_FIPS_strings(void);
+
+/* Error codes for the FIPS functions. */
+
+/* Function codes. */
+#define FIPS_F_DSA_DO_SIGN				 111
+#define FIPS_F_DSA_DO_VERIFY				 112
+#define FIPS_F_DSA_GENERATE_PARAMETERS			 110
+#define FIPS_F_FIPS_CHECK_DSA				 116
+#define FIPS_F_FIPS_CHECK_EXE				 106
+#define FIPS_F_FIPS_CHECK_RSA				 115
+#define FIPS_F_FIPS_DSA_CHECK				 102
+#define FIPS_F_FIPS_MODE_SET				 105
+#define FIPS_F_FIPS_SELFTEST_AES			 104
+#define FIPS_F_FIPS_SELFTEST_DES			 107
+#define FIPS_F_FIPS_SELFTEST_DSA			 109
+#define FIPS_F_FIPS_SELFTEST_RSA			 108
+#define FIPS_F_FIPS_SELFTEST_SHA1			 103
+#define FIPS_F_HASH_FINAL				 100
+#define FIPS_F_DH_GENERATE_PARAMETERS			 117
+#define FIPS_F_RSA_EAY_PUBLIC_ENCRYPT			 114
+#define FIPS_F_RSA_GENERATE_KEY				 113
+#define FIPS_F_SSLEAY_RAND_BYTES			 101
+
+/* Reason codes. */
+#define FIPS_R_CANNOT_READ_EXE				 103
+#define FIPS_R_CANNOT_READ_EXE_DIGEST			 104
+#define FIPS_R_EXE_DIGEST_DOES_NOT_MATCH		 105
+#define FIPS_R_FIPS_MODE_ALREADY_SET			 102
+#define FIPS_R_FIPS_SELFTEST_FAILED			 106
+#define FIPS_R_NON_FIPS_METHOD				 100
+#define FIPS_R_PAIRWISE_TEST_FAILED			 107
+#define FIPS_R_SELFTEST_FAILED				 101
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/fips_rand.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/fips_rand.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/fips_rand.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,74 @@
+/* ====================================================================
+ * Copyright (c) 2003 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef HEADER_FIPS_RAND_H
+#define HEADER_FIPS_RAND_H
+
+#include "des.h"
+
+#ifdef OPENSSL_FIPS
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+void FIPS_set_prng_key(const unsigned char k1[8],const unsigned char k2[8]);
+void FIPS_test_mode(int test,const unsigned char faketime[8]);
+void FIPS_rand_seed(const void *buf, FIPS_RAND_SIZE_T num);
+/* NB: this returns true if _partially_ seeded */
+int FIPS_rand_seeded(void);
+
+RAND_METHOD *FIPS_rand_method(void);
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/hmac.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/hmac.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/hmac.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,108 @@
+/* crypto/hmac/hmac.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+#ifndef HEADER_HMAC_H
+#define HEADER_HMAC_H
+
+#include <openssl/opensslconf.h>
+
+#ifdef OPENSSL_NO_HMAC
+#error HMAC is disabled.
+#endif
+
+#include <openssl/evp.h>
+
+#define HMAC_MAX_MD_CBLOCK	128	/* largest known is SHA512 */
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct hmac_ctx_st
+	{
+	const EVP_MD *md;
+	EVP_MD_CTX md_ctx;
+	EVP_MD_CTX i_ctx;
+	EVP_MD_CTX o_ctx;
+	unsigned int key_length;
+	unsigned char key[HMAC_MAX_MD_CBLOCK];
+	} HMAC_CTX;
+
+#define HMAC_size(e)	(EVP_MD_size((e)->md))
+
+
+void HMAC_CTX_init(HMAC_CTX *ctx);
+void HMAC_CTX_cleanup(HMAC_CTX *ctx);
+
+#define HMAC_cleanup(ctx) HMAC_CTX_cleanup(ctx) /* deprecated */
+
+void HMAC_Init(HMAC_CTX *ctx, const void *key, int len,
+	       const EVP_MD *md); /* deprecated */
+void HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
+		  const EVP_MD *md, ENGINE *impl);
+void HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len);
+void HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len);
+unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
+		    const unsigned char *d, size_t n, unsigned char *md,
+		    unsigned int *md_len);
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/idea.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/idea.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/idea.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,100 @@
+/* crypto/idea/idea.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_IDEA_H
+#define HEADER_IDEA_H
+
+#include <openssl/opensslconf.h> /* IDEA_INT, OPENSSL_NO_IDEA */
+
+#ifdef OPENSSL_NO_IDEA
+#error IDEA is disabled.
+#endif
+
+#define IDEA_ENCRYPT	1
+#define IDEA_DECRYPT	0
+
+#define IDEA_BLOCK	8
+#define IDEA_KEY_LENGTH	16
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct idea_key_st
+	{
+	IDEA_INT data[9][6];
+	} IDEA_KEY_SCHEDULE;
+
+const char *idea_options(void);
+void idea_ecb_encrypt(const unsigned char *in, unsigned char *out,
+	IDEA_KEY_SCHEDULE *ks);
+void idea_set_encrypt_key(const unsigned char *key, IDEA_KEY_SCHEDULE *ks);
+void idea_set_decrypt_key(IDEA_KEY_SCHEDULE *ek, IDEA_KEY_SCHEDULE *dk);
+void idea_cbc_encrypt(const unsigned char *in, unsigned char *out,
+	long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv,int enc);
+void idea_cfb64_encrypt(const unsigned char *in, unsigned char *out,
+	long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv,
+	int *num,int enc);
+void idea_ofb64_encrypt(const unsigned char *in, unsigned char *out,
+	long length, IDEA_KEY_SCHEDULE *ks, unsigned char *iv, int *num);
+void idea_encrypt(unsigned long *in, IDEA_KEY_SCHEDULE *ks);
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/krb5_asn.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/krb5_asn.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/krb5_asn.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,256 @@
+/* krb5_asn.h */
+/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project,
+** using ocsp/{*.h,*asn*.c} as a starting point
+*/
+
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_KRB5_ASN_H
+#define HEADER_KRB5_ASN_H
+
+/*
+#include <krb5.h>
+*/
+#include <openssl/safestack.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+
+/*	ASN.1 from Kerberos RFC 1510
+*/
+
+/*	EncryptedData ::=   SEQUENCE {
+**		etype[0]                      INTEGER, -- EncryptionType
+**		kvno[1]                       INTEGER OPTIONAL,
+**		cipher[2]                     OCTET STRING -- ciphertext
+**	}
+*/
+typedef	struct	krb5_encdata_st
+	{
+	ASN1_INTEGER			*etype;
+	ASN1_INTEGER			*kvno;
+	ASN1_OCTET_STRING		*cipher;
+	}	KRB5_ENCDATA;
+
+DECLARE_STACK_OF(KRB5_ENCDATA)
+
+/*	PrincipalName ::=   SEQUENCE {
+**		name-type[0]                  INTEGER,
+**		name-string[1]                SEQUENCE OF GeneralString
+**	}
+*/
+typedef	struct	krb5_princname_st
+	{
+	ASN1_INTEGER			*nametype;
+	STACK_OF(ASN1_GENERALSTRING)	*namestring;
+	}	KRB5_PRINCNAME;
+
+DECLARE_STACK_OF(KRB5_PRINCNAME)
+
+
+/*	Ticket ::=	[APPLICATION 1] SEQUENCE {
+**		tkt-vno[0]                    INTEGER,
+**		realm[1]                      Realm,
+**		sname[2]                      PrincipalName,
+**		enc-part[3]                   EncryptedData
+**	}
+*/
+typedef	struct	krb5_tktbody_st
+	{
+	ASN1_INTEGER			*tktvno;
+	ASN1_GENERALSTRING		*realm;
+	KRB5_PRINCNAME			*sname;
+	KRB5_ENCDATA			*encdata;
+	}	KRB5_TKTBODY;
+
+typedef STACK_OF(KRB5_TKTBODY) KRB5_TICKET;
+DECLARE_STACK_OF(KRB5_TKTBODY)
+
+
+/*	AP-REQ ::=      [APPLICATION 14] SEQUENCE {
+**		pvno[0]                       INTEGER,
+**		msg-type[1]                   INTEGER,
+**		ap-options[2]                 APOptions,
+**		ticket[3]                     Ticket,
+**		authenticator[4]              EncryptedData
+**	}
+**
+**	APOptions ::=   BIT STRING {
+**		reserved(0), use-session-key(1), mutual-required(2) }
+*/
+typedef	struct	krb5_ap_req_st
+	{
+	ASN1_INTEGER			*pvno;
+	ASN1_INTEGER			*msgtype;
+	ASN1_BIT_STRING			*apoptions;
+	KRB5_TICKET			*ticket;
+	KRB5_ENCDATA			*authenticator;
+	}	KRB5_APREQBODY;
+
+typedef STACK_OF(KRB5_APREQBODY) KRB5_APREQ;
+DECLARE_STACK_OF(KRB5_APREQBODY)
+
+
+/*	Authenticator Stuff	*/
+
+
+/*	Checksum ::=   SEQUENCE {
+**		cksumtype[0]                  INTEGER,
+**		checksum[1]                   OCTET STRING
+**	}
+*/
+typedef	struct	krb5_checksum_st
+	{
+	ASN1_INTEGER			*ctype;
+	ASN1_OCTET_STRING		*checksum;
+	}	KRB5_CHECKSUM;
+
+DECLARE_STACK_OF(KRB5_CHECKSUM)
+
+
+/*	EncryptionKey ::=   SEQUENCE {
+**		keytype[0]                    INTEGER,
+**		keyvalue[1]                   OCTET STRING
+**	}
+*/
+typedef struct  krb5_encryptionkey_st
+	{
+	ASN1_INTEGER			*ktype;
+	ASN1_OCTET_STRING		*keyvalue;
+	}	KRB5_ENCKEY;
+
+DECLARE_STACK_OF(KRB5_ENCKEY)
+
+
+/*	AuthorizationData ::=   SEQUENCE OF SEQUENCE {
+**		ad-type[0]                    INTEGER,
+**              ad-data[1]                    OCTET STRING
+**	}
+*/
+typedef struct	krb5_authorization_st
+	{
+	ASN1_INTEGER			*adtype;
+	ASN1_OCTET_STRING		*addata;
+	}	KRB5_AUTHDATA;
+
+DECLARE_STACK_OF(KRB5_AUTHDATA)
+
+			
+/*	-- Unencrypted authenticator
+**	Authenticator ::=    [APPLICATION 2] SEQUENCE    {
+**		authenticator-vno[0]          INTEGER,
+**		crealm[1]                     Realm,
+**		cname[2]                      PrincipalName,
+**		cksum[3]                      Checksum OPTIONAL,
+**		cusec[4]                      INTEGER,
+**		ctime[5]                      KerberosTime,
+**		subkey[6]                     EncryptionKey OPTIONAL,
+**		seq-number[7]                 INTEGER OPTIONAL,
+**		authorization-data[8]         AuthorizationData OPTIONAL
+**	}
+*/
+typedef struct	krb5_authenticator_st
+	{
+	ASN1_INTEGER			*avno;
+	ASN1_GENERALSTRING		*crealm;
+	KRB5_PRINCNAME			*cname;
+	KRB5_CHECKSUM			*cksum;
+	ASN1_INTEGER			*cusec;
+	ASN1_GENERALIZEDTIME		*ctime;
+	KRB5_ENCKEY			*subkey;
+	ASN1_INTEGER			*seqnum;
+	KRB5_AUTHDATA			*authorization;
+	}	KRB5_AUTHENTBODY;
+
+typedef STACK_OF(KRB5_AUTHENTBODY) KRB5_AUTHENT;
+DECLARE_STACK_OF(KRB5_AUTHENTBODY)
+
+
+/*  DECLARE_ASN1_FUNCTIONS(type) = DECLARE_ASN1_FUNCTIONS_name(type, type) =
+**	type *name##_new(void);
+**	void name##_free(type *a);
+**	DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) =
+**	 DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) =
+**	  type *d2i_##name(type **a, const unsigned char **in, long len);
+**	  int i2d_##name(type *a, unsigned char **out);
+**	  DECLARE_ASN1_ITEM(itname) = OPENSSL_EXTERN const ASN1_ITEM itname##_it
+*/
+
+DECLARE_ASN1_FUNCTIONS(KRB5_ENCDATA)
+DECLARE_ASN1_FUNCTIONS(KRB5_PRINCNAME)
+DECLARE_ASN1_FUNCTIONS(KRB5_TKTBODY)
+DECLARE_ASN1_FUNCTIONS(KRB5_APREQBODY)
+DECLARE_ASN1_FUNCTIONS(KRB5_TICKET)
+DECLARE_ASN1_FUNCTIONS(KRB5_APREQ)
+
+DECLARE_ASN1_FUNCTIONS(KRB5_CHECKSUM)
+DECLARE_ASN1_FUNCTIONS(KRB5_ENCKEY)
+DECLARE_ASN1_FUNCTIONS(KRB5_AUTHDATA)
+DECLARE_ASN1_FUNCTIONS(KRB5_AUTHENTBODY)
+DECLARE_ASN1_FUNCTIONS(KRB5_AUTHENT)
+
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/kssl.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/kssl.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/kssl.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,179 @@
+/* ssl/kssl.h -*- mode: C; c-file-style: "eay" -*- */
+/* Written by Vern Staats <staatsvr@asc.hpc.mil> for the OpenSSL project 2000.
+ * project 2000.
+ */
+/* ====================================================================
+ * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*
+**	19990701	VRS 	Started.
+*/
+
+#ifndef	KSSL_H
+#define	KSSL_H
+
+#include <openssl/opensslconf.h>
+
+#ifndef OPENSSL_NO_KRB5
+
+#include <stdio.h>
+#include <ctype.h>
+#include <krb5.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+**	Depending on which KRB5 implementation used, some types from
+**	the other may be missing.  Resolve that here and now
+*/
+#ifdef KRB5_HEIMDAL
+typedef unsigned char krb5_octet;
+#define FAR
+#else
+
+#ifndef FAR
+#define FAR
+#endif
+
+#endif
+
+/*	Uncomment this to debug kssl problems or
+**	to trace usage of the Kerberos session key
+**
+**	#define		KSSL_DEBUG
+*/
+
+#ifndef	KRB5SVC
+#define KRB5SVC	"host"
+#endif
+
+#ifndef	KRB5KEYTAB
+#define KRB5KEYTAB	"/etc/krb5.keytab"
+#endif
+
+#ifndef KRB5SENDAUTH
+#define KRB5SENDAUTH	1
+#endif
+
+#ifndef KRB5CHECKAUTH
+#define KRB5CHECKAUTH	1
+#endif
+
+#ifndef KSSL_CLOCKSKEW
+#define	KSSL_CLOCKSKEW	300;
+#endif
+
+#define	KSSL_ERR_MAX	255
+typedef struct kssl_err_st  {
+	int  reason;
+	char text[KSSL_ERR_MAX+1];
+	} KSSL_ERR;
+
+
+/*	Context for passing
+**		(1) Kerberos session key to SSL, and
+**		(2)	Config data between application and SSL lib
+*/
+typedef struct kssl_ctx_st
+        {
+                                /*	used by:    disposition:            */
+	char *service_name;	/*	C,S	    default ok (kssl)       */
+	char *service_host;	/*	C	    input, REQUIRED         */
+	char *client_princ;	/*	S	    output from krb5 ticket */
+	char *keytab_file;	/*      S	    NULL (/etc/krb5.keytab) */
+	char *cred_cache;	/*	C	    NULL (default)          */
+	krb5_enctype enctype;
+	int length;
+	krb5_octet FAR *key;
+	} KSSL_CTX;
+
+#define	KSSL_CLIENT 	1
+#define KSSL_SERVER 	2
+#define	KSSL_SERVICE	3
+#define	KSSL_KEYTAB 	4
+
+#define KSSL_CTX_OK 	0
+#define KSSL_CTX_ERR	1
+#define KSSL_NOMEM	2
+
+/* Public (for use by applications that use OpenSSL with Kerberos 5 support */
+krb5_error_code kssl_ctx_setstring(KSSL_CTX *kssl_ctx, int which, char *text);
+KSSL_CTX *kssl_ctx_new(void);
+KSSL_CTX *kssl_ctx_free(KSSL_CTX *kssl_ctx);
+void kssl_ctx_show(KSSL_CTX *kssl_ctx);
+krb5_error_code kssl_ctx_setprinc(KSSL_CTX *kssl_ctx, int which,
+        krb5_data *realm, krb5_data *entity, int nentities);
+krb5_error_code	kssl_cget_tkt(KSSL_CTX *kssl_ctx,  krb5_data **enc_tktp,
+        krb5_data *authenp, KSSL_ERR *kssl_err);
+krb5_error_code	kssl_sget_tkt(KSSL_CTX *kssl_ctx,  krb5_data *indata,
+        krb5_ticket_times *ttimes, KSSL_ERR *kssl_err);
+krb5_error_code kssl_ctx_setkey(KSSL_CTX *kssl_ctx, krb5_keyblock *session);
+void	kssl_err_set(KSSL_ERR *kssl_err, int reason, char *text);
+void kssl_krb5_free_data_contents(krb5_context context, krb5_data *data);
+krb5_error_code  kssl_build_principal_2(krb5_context context,
+			krb5_principal *princ, int rlen, const char *realm,
+			int slen, const char *svc, int hlen, const char *host);
+krb5_error_code  kssl_validate_times(krb5_timestamp atime,
+					krb5_ticket_times *ttimes);
+krb5_error_code  kssl_check_authent(KSSL_CTX *kssl_ctx, krb5_data *authentp,
+			            krb5_timestamp *atimep, KSSL_ERR *kssl_err);
+unsigned char	*kssl_skip_confound(krb5_enctype enctype, unsigned char *authn);
+
+#ifdef  __cplusplus
+}
+#endif
+#endif	/* OPENSSL_NO_KRB5	*/
+#endif	/* KSSL_H 	*/
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/lhash.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/lhash.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/lhash.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,200 @@
+/* crypto/lhash/lhash.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* Header for dynamic hash table routines
+ * Author - Eric Young
+ */
+
+#ifndef HEADER_LHASH_H
+#define HEADER_LHASH_H
+
+#include <openssl/e_os2.h>
+#ifndef OPENSSL_NO_FP_API
+#include <stdio.h>
+#endif
+
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct lhash_node_st
+	{
+	void *data;
+	struct lhash_node_st *next;
+#ifndef OPENSSL_NO_HASH_COMP
+	unsigned long hash;
+#endif
+	} LHASH_NODE;
+
+typedef int (*LHASH_COMP_FN_TYPE)(const void *, const void *);
+typedef unsigned long (*LHASH_HASH_FN_TYPE)(const void *);
+typedef void (*LHASH_DOALL_FN_TYPE)(void *);
+typedef void (*LHASH_DOALL_ARG_FN_TYPE)(void *, void *);
+
+/* Macros for declaring and implementing type-safe wrappers for LHASH callbacks.
+ * This way, callbacks can be provided to LHASH structures without function
+ * pointer casting and the macro-defined callbacks provide per-variable casting
+ * before deferring to the underlying type-specific callbacks. NB: It is
+ * possible to place a "static" in front of both the DECLARE and IMPLEMENT
+ * macros if the functions are strictly internal. */
+
+/* First: "hash" functions */
+#define DECLARE_LHASH_HASH_FN(f_name,o_type) \
+	unsigned long f_name##_LHASH_HASH(const void *);
+#define IMPLEMENT_LHASH_HASH_FN(f_name,o_type) \
+	unsigned long f_name##_LHASH_HASH(const void *arg) { \
+		o_type a = (o_type)arg; \
+		return f_name(a); }
+#define LHASH_HASH_FN(f_name) f_name##_LHASH_HASH
+
+/* Second: "compare" functions */
+#define DECLARE_LHASH_COMP_FN(f_name,o_type) \
+	int f_name##_LHASH_COMP(const void *, const void *);
+#define IMPLEMENT_LHASH_COMP_FN(f_name,o_type) \
+	int f_name##_LHASH_COMP(const void *arg1, const void *arg2) { \
+		o_type a = (o_type)arg1; \
+		o_type b = (o_type)arg2; \
+		return f_name(a,b); }
+#define LHASH_COMP_FN(f_name) f_name##_LHASH_COMP
+
+/* Third: "doall" functions */
+#define DECLARE_LHASH_DOALL_FN(f_name,o_type) \
+	void f_name##_LHASH_DOALL(void *);
+#define IMPLEMENT_LHASH_DOALL_FN(f_name,o_type) \
+	void f_name##_LHASH_DOALL(void *arg) { \
+		o_type a = (o_type)arg; \
+		f_name(a); }
+#define LHASH_DOALL_FN(f_name) f_name##_LHASH_DOALL
+
+/* Fourth: "doall_arg" functions */
+#define DECLARE_LHASH_DOALL_ARG_FN(f_name,o_type,a_type) \
+	void f_name##_LHASH_DOALL_ARG(void *, void *);
+#define IMPLEMENT_LHASH_DOALL_ARG_FN(f_name,o_type,a_type) \
+	void f_name##_LHASH_DOALL_ARG(void *arg1, void *arg2) { \
+		o_type a = (o_type)arg1; \
+		a_type b = (a_type)arg2; \
+		f_name(a,b); }
+#define LHASH_DOALL_ARG_FN(f_name) f_name##_LHASH_DOALL_ARG
+
+typedef struct lhash_st
+	{
+	LHASH_NODE **b;
+	LHASH_COMP_FN_TYPE comp;
+	LHASH_HASH_FN_TYPE hash;
+	unsigned int num_nodes;
+	unsigned int num_alloc_nodes;
+	unsigned int p;
+	unsigned int pmax;
+	unsigned long up_load; /* load times 256 */
+	unsigned long down_load; /* load times 256 */
+	unsigned long num_items;
+
+	unsigned long num_expands;
+	unsigned long num_expand_reallocs;
+	unsigned long num_contracts;
+	unsigned long num_contract_reallocs;
+	unsigned long num_hash_calls;
+	unsigned long num_comp_calls;
+	unsigned long num_insert;
+	unsigned long num_replace;
+	unsigned long num_delete;
+	unsigned long num_no_delete;
+	unsigned long num_retrieve;
+	unsigned long num_retrieve_miss;
+	unsigned long num_hash_comps;
+
+	int error;
+	} LHASH;
+
+#define LH_LOAD_MULT	256
+
+/* Indicates a malloc() error in the last call, this is only bad
+ * in lh_insert(). */
+#define lh_error(lh)	((lh)->error)
+
+LHASH *lh_new(LHASH_HASH_FN_TYPE h, LHASH_COMP_FN_TYPE c);
+void lh_free(LHASH *lh);
+void *lh_insert(LHASH *lh, void *data);
+void *lh_delete(LHASH *lh, const void *data);
+void *lh_retrieve(LHASH *lh, const void *data);
+void lh_doall(LHASH *lh, LHASH_DOALL_FN_TYPE func);
+void lh_doall_arg(LHASH *lh, LHASH_DOALL_ARG_FN_TYPE func, void *arg);
+unsigned long lh_strhash(const char *c);
+unsigned long lh_num_items(const LHASH *lh);
+
+#ifndef OPENSSL_NO_FP_API
+void lh_stats(const LHASH *lh, FILE *out);
+void lh_node_stats(const LHASH *lh, FILE *out);
+void lh_node_usage_stats(const LHASH *lh, FILE *out);
+#endif
+
+#ifndef OPENSSL_NO_BIO
+void lh_stats_bio(const LHASH *lh, BIO *out);
+void lh_node_stats_bio(const LHASH *lh, BIO *out);
+void lh_node_usage_stats_bio(const LHASH *lh, BIO *out);
+#endif
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md2.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,91 @@
+/* crypto/md/md2.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_MD2_H
+#define HEADER_MD2_H
+
+#include <openssl/opensslconf.h> /* OPENSSL_NO_MD2, MD2_INT */
+#ifdef OPENSSL_NO_MD2
+#error MD2 is disabled.
+#endif
+
+#define MD2_DIGEST_LENGTH	16
+#define MD2_BLOCK       	16
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct MD2state_st
+	{
+	unsigned int num;
+	unsigned char data[MD2_BLOCK];
+	MD2_INT cksm[MD2_BLOCK];
+	MD2_INT state[MD2_BLOCK];
+	} MD2_CTX;
+
+const char *MD2_options(void);
+int MD2_Init(MD2_CTX *c);
+int MD2_Update(MD2_CTX *c, const unsigned char *data, size_t len);
+int MD2_Final(unsigned char *md, MD2_CTX *c);
+unsigned char *MD2(const unsigned char *d, size_t n,unsigned char *md);
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md4.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md4.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md4.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,116 @@
+/* crypto/md4/md4.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_MD4_H
+#define HEADER_MD4_H
+
+#include <openssl/e_os2.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_NO_MD4
+#error MD4 is disabled.
+#endif
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! MD4_LONG has to be at least 32 bits wide. If it's wider, then !
+ * ! MD4_LONG_LOG2 has to be defined along.			   !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__)
+#define MD4_LONG unsigned long
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
+#define MD4_LONG unsigned long
+#define MD4_LONG_LOG2 3
+/*
+ * _CRAY note. I could declare short, but I have no idea what impact
+ * does it have on performance on none-T3E machines. I could declare
+ * int, but at least on C90 sizeof(int) can be chosen at compile time.
+ * So I've chosen long...
+ *					<appro@fy.chalmers.se>
+ */
+#else
+#define MD4_LONG unsigned int
+#endif
+
+#define MD4_CBLOCK	64
+#define MD4_LBLOCK	(MD4_CBLOCK/4)
+#define MD4_DIGEST_LENGTH 16
+
+typedef struct MD4state_st
+	{
+	MD4_LONG A,B,C,D;
+	MD4_LONG Nl,Nh;
+	MD4_LONG data[MD4_LBLOCK];
+	unsigned int num;
+	} MD4_CTX;
+
+int MD4_Init(MD4_CTX *c);
+int MD4_Update(MD4_CTX *c, const void *data, size_t len);
+int MD4_Final(unsigned char *md, MD4_CTX *c);
+unsigned char *MD4(const unsigned char *d, size_t n, unsigned char *md);
+void MD4_Transform(MD4_CTX *c, const unsigned char *b);
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md5.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md5.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/md5.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,116 @@
+/* crypto/md5/md5.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_MD5_H
+#define HEADER_MD5_H
+
+#include <openssl/e_os2.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_NO_MD5
+#error MD5 is disabled.
+#endif
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! MD5_LONG has to be at least 32 bits wide. If it's wider, then !
+ * ! MD5_LONG_LOG2 has to be defined along.			   !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__)
+#define MD5_LONG unsigned long
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
+#define MD5_LONG unsigned long
+#define MD5_LONG_LOG2 3
+/*
+ * _CRAY note. I could declare short, but I have no idea what impact
+ * does it have on performance on none-T3E machines. I could declare
+ * int, but at least on C90 sizeof(int) can be chosen at compile time.
+ * So I've chosen long...
+ *					<appro@fy.chalmers.se>
+ */
+#else
+#define MD5_LONG unsigned int
+#endif
+
+#define MD5_CBLOCK	64
+#define MD5_LBLOCK	(MD5_CBLOCK/4)
+#define MD5_DIGEST_LENGTH 16
+
+typedef struct MD5state_st
+	{
+	MD5_LONG A,B,C,D;
+	MD5_LONG Nl,Nh;
+	MD5_LONG data[MD5_LBLOCK];
+	unsigned int num;
+	} MD5_CTX;
+
+int MD5_Init(MD5_CTX *c);
+int MD5_Update(MD5_CTX *c, const void *data, size_t len);
+int MD5_Final(unsigned char *md, MD5_CTX *c);
+unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);
+void MD5_Transform(MD5_CTX *c, const unsigned char *b);
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/mdc2.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/mdc2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/mdc2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,98 @@
+/* crypto/mdc2/mdc2.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_MDC2_H
+#define HEADER_MDC2_H
+
+#include <openssl/des.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_NO_MDC2
+#error MDC2 is disabled.
+#endif
+
+#define MDC2_BLOCK              8
+#define MDC2_DIGEST_LENGTH      16
+ 
+typedef struct mdc2_ctx_st
+	{
+	int num;
+	unsigned char data[MDC2_BLOCK];
+	DES_cblock h,hh;
+	int pad_type; /* either 1 or 2, default 1 */
+	} MDC2_CTX;
+
+#ifdef OPENSSL_FIPS
+int private_MDC2_Init(MDC2_CTX *c);
+#endif
+int MDC2_Init(MDC2_CTX *c);
+int MDC2_Update(MDC2_CTX *c, const unsigned char *data, unsigned long len);
+int MDC2_Final(unsigned char *md, MDC2_CTX *c);
+unsigned char *MDC2(const unsigned char *d, unsigned long n,
+	unsigned char *md);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/obj_mac.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/obj_mac.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/obj_mac.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,3305 @@
+/* crypto/objects/obj_mac.h */
+
+/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the
+ * following command:
+ * perl objects.pl objects.txt obj_mac.num obj_mac.h
+ */
+
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#define SN_undef			"UNDEF"
+#define LN_undef			"undefined"
+#define NID_undef			0
+#define OBJ_undef			0L
+
+#define SN_itu_t		"ITU-T"
+#define LN_itu_t		"itu-t"
+#define NID_itu_t		645
+#define OBJ_itu_t		0L
+
+#define NID_ccitt		404
+#define OBJ_ccitt		OBJ_itu_t
+
+#define SN_iso		"ISO"
+#define LN_iso		"iso"
+#define NID_iso		181
+#define OBJ_iso		1L
+
+#define SN_joint_iso_itu_t		"JOINT-ISO-ITU-T"
+#define LN_joint_iso_itu_t		"joint-iso-itu-t"
+#define NID_joint_iso_itu_t		646
+#define OBJ_joint_iso_itu_t		2L
+
+#define NID_joint_iso_ccitt		393
+#define OBJ_joint_iso_ccitt		OBJ_joint_iso_itu_t
+
+#define SN_member_body		"member-body"
+#define LN_member_body		"ISO Member Body"
+#define NID_member_body		182
+#define OBJ_member_body		OBJ_iso,2L
+
+#define SN_identified_organization		"identified-organization"
+#define NID_identified_organization		676
+#define OBJ_identified_organization		OBJ_iso,3L
+
+#define SN_certicom_arc		"certicom-arc"
+#define NID_certicom_arc		677
+#define OBJ_certicom_arc		OBJ_identified_organization,132L
+
+#define SN_international_organizations		"international-organizations"
+#define LN_international_organizations		"International Organizations"
+#define NID_international_organizations		647
+#define OBJ_international_organizations		OBJ_joint_iso_itu_t,23L
+
+#define SN_wap		"wap"
+#define NID_wap		678
+#define OBJ_wap		OBJ_international_organizations,43L
+
+#define SN_wap_wsg		"wap-wsg"
+#define NID_wap_wsg		679
+#define OBJ_wap_wsg		OBJ_wap,13L
+
+#define SN_selected_attribute_types		"selected-attribute-types"
+#define LN_selected_attribute_types		"Selected Attribute Types"
+#define NID_selected_attribute_types		394
+#define OBJ_selected_attribute_types		OBJ_joint_iso_itu_t,5L,1L,5L
+
+#define SN_clearance		"clearance"
+#define NID_clearance		395
+#define OBJ_clearance		OBJ_selected_attribute_types,55L
+
+#define SN_ISO_US		"ISO-US"
+#define LN_ISO_US		"ISO US Member Body"
+#define NID_ISO_US		183
+#define OBJ_ISO_US		OBJ_member_body,840L
+
+#define SN_X9_57		"X9-57"
+#define LN_X9_57		"X9.57"
+#define NID_X9_57		184
+#define OBJ_X9_57		OBJ_ISO_US,10040L
+
+#define SN_X9cm		"X9cm"
+#define LN_X9cm		"X9.57 CM ?"
+#define NID_X9cm		185
+#define OBJ_X9cm		OBJ_X9_57,4L
+
+#define SN_dsa		"DSA"
+#define LN_dsa		"dsaEncryption"
+#define NID_dsa		116
+#define OBJ_dsa		OBJ_X9cm,1L
+
+#define SN_dsaWithSHA1		"DSA-SHA1"
+#define LN_dsaWithSHA1		"dsaWithSHA1"
+#define NID_dsaWithSHA1		113
+#define OBJ_dsaWithSHA1		OBJ_X9cm,3L
+
+#define SN_ansi_X9_62		"ansi-X9-62"
+#define LN_ansi_X9_62		"ANSI X9.62"
+#define NID_ansi_X9_62		405
+#define OBJ_ansi_X9_62		OBJ_ISO_US,10045L
+
+#define OBJ_X9_62_id_fieldType		OBJ_ansi_X9_62,1L
+
+#define SN_X9_62_prime_field		"prime-field"
+#define NID_X9_62_prime_field		406
+#define OBJ_X9_62_prime_field		OBJ_X9_62_id_fieldType,1L
+
+#define SN_X9_62_characteristic_two_field		"characteristic-two-field"
+#define NID_X9_62_characteristic_two_field		407
+#define OBJ_X9_62_characteristic_two_field		OBJ_X9_62_id_fieldType,2L
+
+#define SN_X9_62_id_characteristic_two_basis		"id-characteristic-two-basis"
+#define NID_X9_62_id_characteristic_two_basis		680
+#define OBJ_X9_62_id_characteristic_two_basis		OBJ_X9_62_characteristic_two_field,3L
+
+#define SN_X9_62_onBasis		"onBasis"
+#define NID_X9_62_onBasis		681
+#define OBJ_X9_62_onBasis		OBJ_X9_62_id_characteristic_two_basis,1L
+
+#define SN_X9_62_tpBasis		"tpBasis"
+#define NID_X9_62_tpBasis		682
+#define OBJ_X9_62_tpBasis		OBJ_X9_62_id_characteristic_two_basis,2L
+
+#define SN_X9_62_ppBasis		"ppBasis"
+#define NID_X9_62_ppBasis		683
+#define OBJ_X9_62_ppBasis		OBJ_X9_62_id_characteristic_two_basis,3L
+
+#define OBJ_X9_62_id_publicKeyType		OBJ_ansi_X9_62,2L
+
+#define SN_X9_62_id_ecPublicKey		"id-ecPublicKey"
+#define NID_X9_62_id_ecPublicKey		408
+#define OBJ_X9_62_id_ecPublicKey		OBJ_X9_62_id_publicKeyType,1L
+
+#define OBJ_X9_62_ellipticCurve		OBJ_ansi_X9_62,3L
+
+#define OBJ_X9_62_c_TwoCurve		OBJ_X9_62_ellipticCurve,0L
+
+#define SN_X9_62_c2pnb163v1		"c2pnb163v1"
+#define NID_X9_62_c2pnb163v1		684
+#define OBJ_X9_62_c2pnb163v1		OBJ_X9_62_c_TwoCurve,1L
+
+#define SN_X9_62_c2pnb163v2		"c2pnb163v2"
+#define NID_X9_62_c2pnb163v2		685
+#define OBJ_X9_62_c2pnb163v2		OBJ_X9_62_c_TwoCurve,2L
+
+#define SN_X9_62_c2pnb163v3		"c2pnb163v3"
+#define NID_X9_62_c2pnb163v3		686
+#define OBJ_X9_62_c2pnb163v3		OBJ_X9_62_c_TwoCurve,3L
+
+#define SN_X9_62_c2pnb176v1		"c2pnb176v1"
+#define NID_X9_62_c2pnb176v1		687
+#define OBJ_X9_62_c2pnb176v1		OBJ_X9_62_c_TwoCurve,4L
+
+#define SN_X9_62_c2tnb191v1		"c2tnb191v1"
+#define NID_X9_62_c2tnb191v1		688
+#define OBJ_X9_62_c2tnb191v1		OBJ_X9_62_c_TwoCurve,5L
+
+#define SN_X9_62_c2tnb191v2		"c2tnb191v2"
+#define NID_X9_62_c2tnb191v2		689
+#define OBJ_X9_62_c2tnb191v2		OBJ_X9_62_c_TwoCurve,6L
+
+#define SN_X9_62_c2tnb191v3		"c2tnb191v3"
+#define NID_X9_62_c2tnb191v3		690
+#define OBJ_X9_62_c2tnb191v3		OBJ_X9_62_c_TwoCurve,7L
+
+#define SN_X9_62_c2onb191v4		"c2onb191v4"
+#define NID_X9_62_c2onb191v4		691
+#define OBJ_X9_62_c2onb191v4		OBJ_X9_62_c_TwoCurve,8L
+
+#define SN_X9_62_c2onb191v5		"c2onb191v5"
+#define NID_X9_62_c2onb191v5		692
+#define OBJ_X9_62_c2onb191v5		OBJ_X9_62_c_TwoCurve,9L
+
+#define SN_X9_62_c2pnb208w1		"c2pnb208w1"
+#define NID_X9_62_c2pnb208w1		693
+#define OBJ_X9_62_c2pnb208w1		OBJ_X9_62_c_TwoCurve,10L
+
+#define SN_X9_62_c2tnb239v1		"c2tnb239v1"
+#define NID_X9_62_c2tnb239v1		694
+#define OBJ_X9_62_c2tnb239v1		OBJ_X9_62_c_TwoCurve,11L
+
+#define SN_X9_62_c2tnb239v2		"c2tnb239v2"
+#define NID_X9_62_c2tnb239v2		695
+#define OBJ_X9_62_c2tnb239v2		OBJ_X9_62_c_TwoCurve,12L
+
+#define SN_X9_62_c2tnb239v3		"c2tnb239v3"
+#define NID_X9_62_c2tnb239v3		696
+#define OBJ_X9_62_c2tnb239v3		OBJ_X9_62_c_TwoCurve,13L
+
+#define SN_X9_62_c2onb239v4		"c2onb239v4"
+#define NID_X9_62_c2onb239v4		697
+#define OBJ_X9_62_c2onb239v4		OBJ_X9_62_c_TwoCurve,14L
+
+#define SN_X9_62_c2onb239v5		"c2onb239v5"
+#define NID_X9_62_c2onb239v5		698
+#define OBJ_X9_62_c2onb239v5		OBJ_X9_62_c_TwoCurve,15L
+
+#define SN_X9_62_c2pnb272w1		"c2pnb272w1"
+#define NID_X9_62_c2pnb272w1		699
+#define OBJ_X9_62_c2pnb272w1		OBJ_X9_62_c_TwoCurve,16L
+
+#define SN_X9_62_c2pnb304w1		"c2pnb304w1"
+#define NID_X9_62_c2pnb304w1		700
+#define OBJ_X9_62_c2pnb304w1		OBJ_X9_62_c_TwoCurve,17L
+
+#define SN_X9_62_c2tnb359v1		"c2tnb359v1"
+#define NID_X9_62_c2tnb359v1		701
+#define OBJ_X9_62_c2tnb359v1		OBJ_X9_62_c_TwoCurve,18L
+
+#define SN_X9_62_c2pnb368w1		"c2pnb368w1"
+#define NID_X9_62_c2pnb368w1		702
+#define OBJ_X9_62_c2pnb368w1		OBJ_X9_62_c_TwoCurve,19L
+
+#define SN_X9_62_c2tnb431r1		"c2tnb431r1"
+#define NID_X9_62_c2tnb431r1		703
+#define OBJ_X9_62_c2tnb431r1		OBJ_X9_62_c_TwoCurve,20L
+
+#define OBJ_X9_62_primeCurve		OBJ_X9_62_ellipticCurve,1L
+
+#define SN_X9_62_prime192v1		"prime192v1"
+#define NID_X9_62_prime192v1		409
+#define OBJ_X9_62_prime192v1		OBJ_X9_62_primeCurve,1L
+
+#define SN_X9_62_prime192v2		"prime192v2"
+#define NID_X9_62_prime192v2		410
+#define OBJ_X9_62_prime192v2		OBJ_X9_62_primeCurve,2L
+
+#define SN_X9_62_prime192v3		"prime192v3"
+#define NID_X9_62_prime192v3		411
+#define OBJ_X9_62_prime192v3		OBJ_X9_62_primeCurve,3L
+
+#define SN_X9_62_prime239v1		"prime239v1"
+#define NID_X9_62_prime239v1		412
+#define OBJ_X9_62_prime239v1		OBJ_X9_62_primeCurve,4L
+
+#define SN_X9_62_prime239v2		"prime239v2"
+#define NID_X9_62_prime239v2		413
+#define OBJ_X9_62_prime239v2		OBJ_X9_62_primeCurve,5L
+
+#define SN_X9_62_prime239v3		"prime239v3"
+#define NID_X9_62_prime239v3		414
+#define OBJ_X9_62_prime239v3		OBJ_X9_62_primeCurve,6L
+
+#define SN_X9_62_prime256v1		"prime256v1"
+#define NID_X9_62_prime256v1		415
+#define OBJ_X9_62_prime256v1		OBJ_X9_62_primeCurve,7L
+
+#define OBJ_X9_62_id_ecSigType		OBJ_ansi_X9_62,4L
+
+#define SN_ecdsa_with_SHA1		"ecdsa-with-SHA1"
+#define NID_ecdsa_with_SHA1		416
+#define OBJ_ecdsa_with_SHA1		OBJ_X9_62_id_ecSigType,1L
+
+#define OBJ_secg_ellipticCurve		OBJ_certicom_arc,0L
+
+#define SN_secp112r1		"secp112r1"
+#define NID_secp112r1		704
+#define OBJ_secp112r1		OBJ_secg_ellipticCurve,6L
+
+#define SN_secp112r2		"secp112r2"
+#define NID_secp112r2		705
+#define OBJ_secp112r2		OBJ_secg_ellipticCurve,7L
+
+#define SN_secp128r1		"secp128r1"
+#define NID_secp128r1		706
+#define OBJ_secp128r1		OBJ_secg_ellipticCurve,28L
+
+#define SN_secp128r2		"secp128r2"
+#define NID_secp128r2		707
+#define OBJ_secp128r2		OBJ_secg_ellipticCurve,29L
+
+#define SN_secp160k1		"secp160k1"
+#define NID_secp160k1		708
+#define OBJ_secp160k1		OBJ_secg_ellipticCurve,9L
+
+#define SN_secp160r1		"secp160r1"
+#define NID_secp160r1		709
+#define OBJ_secp160r1		OBJ_secg_ellipticCurve,8L
+
+#define SN_secp160r2		"secp160r2"
+#define NID_secp160r2		710
+#define OBJ_secp160r2		OBJ_secg_ellipticCurve,30L
+
+#define SN_secp192k1		"secp192k1"
+#define NID_secp192k1		711
+#define OBJ_secp192k1		OBJ_secg_ellipticCurve,31L
+
+#define SN_secp224k1		"secp224k1"
+#define NID_secp224k1		712
+#define OBJ_secp224k1		OBJ_secg_ellipticCurve,32L
+
+#define SN_secp224r1		"secp224r1"
+#define NID_secp224r1		713
+#define OBJ_secp224r1		OBJ_secg_ellipticCurve,33L
+
+#define SN_secp256k1		"secp256k1"
+#define NID_secp256k1		714
+#define OBJ_secp256k1		OBJ_secg_ellipticCurve,10L
+
+#define SN_secp384r1		"secp384r1"
+#define NID_secp384r1		715
+#define OBJ_secp384r1		OBJ_secg_ellipticCurve,34L
+
+#define SN_secp521r1		"secp521r1"
+#define NID_secp521r1		716
+#define OBJ_secp521r1		OBJ_secg_ellipticCurve,35L
+
+#define SN_sect113r1		"sect113r1"
+#define NID_sect113r1		717
+#define OBJ_sect113r1		OBJ_secg_ellipticCurve,4L
+
+#define SN_sect113r2		"sect113r2"
+#define NID_sect113r2		718
+#define OBJ_sect113r2		OBJ_secg_ellipticCurve,5L
+
+#define SN_sect131r1		"sect131r1"
+#define NID_sect131r1		719
+#define OBJ_sect131r1		OBJ_secg_ellipticCurve,22L
+
+#define SN_sect131r2		"sect131r2"
+#define NID_sect131r2		720
+#define OBJ_sect131r2		OBJ_secg_ellipticCurve,23L
+
+#define SN_sect163k1		"sect163k1"
+#define NID_sect163k1		721
+#define OBJ_sect163k1		OBJ_secg_ellipticCurve,1L
+
+#define SN_sect163r1		"sect163r1"
+#define NID_sect163r1		722
+#define OBJ_sect163r1		OBJ_secg_ellipticCurve,2L
+
+#define SN_sect163r2		"sect163r2"
+#define NID_sect163r2		723
+#define OBJ_sect163r2		OBJ_secg_ellipticCurve,15L
+
+#define SN_sect193r1		"sect193r1"
+#define NID_sect193r1		724
+#define OBJ_sect193r1		OBJ_secg_ellipticCurve,24L
+
+#define SN_sect193r2		"sect193r2"
+#define NID_sect193r2		725
+#define OBJ_sect193r2		OBJ_secg_ellipticCurve,25L
+
+#define SN_sect233k1		"sect233k1"
+#define NID_sect233k1		726
+#define OBJ_sect233k1		OBJ_secg_ellipticCurve,26L
+
+#define SN_sect233r1		"sect233r1"
+#define NID_sect233r1		727
+#define OBJ_sect233r1		OBJ_secg_ellipticCurve,27L
+
+#define SN_sect239k1		"sect239k1"
+#define NID_sect239k1		728
+#define OBJ_sect239k1		OBJ_secg_ellipticCurve,3L
+
+#define SN_sect283k1		"sect283k1"
+#define NID_sect283k1		729
+#define OBJ_sect283k1		OBJ_secg_ellipticCurve,16L
+
+#define SN_sect283r1		"sect283r1"
+#define NID_sect283r1		730
+#define OBJ_sect283r1		OBJ_secg_ellipticCurve,17L
+
+#define SN_sect409k1		"sect409k1"
+#define NID_sect409k1		731
+#define OBJ_sect409k1		OBJ_secg_ellipticCurve,36L
+
+#define SN_sect409r1		"sect409r1"
+#define NID_sect409r1		732
+#define OBJ_sect409r1		OBJ_secg_ellipticCurve,37L
+
+#define SN_sect571k1		"sect571k1"
+#define NID_sect571k1		733
+#define OBJ_sect571k1		OBJ_secg_ellipticCurve,38L
+
+#define SN_sect571r1		"sect571r1"
+#define NID_sect571r1		734
+#define OBJ_sect571r1		OBJ_secg_ellipticCurve,39L
+
+#define OBJ_wap_wsg_idm_ecid		OBJ_wap_wsg,4L
+
+#define SN_wap_wsg_idm_ecid_wtls1		"wap-wsg-idm-ecid-wtls1"
+#define NID_wap_wsg_idm_ecid_wtls1		735
+#define OBJ_wap_wsg_idm_ecid_wtls1		OBJ_wap_wsg_idm_ecid,1L
+
+#define SN_wap_wsg_idm_ecid_wtls3		"wap-wsg-idm-ecid-wtls3"
+#define NID_wap_wsg_idm_ecid_wtls3		736
+#define OBJ_wap_wsg_idm_ecid_wtls3		OBJ_wap_wsg_idm_ecid,3L
+
+#define SN_wap_wsg_idm_ecid_wtls4		"wap-wsg-idm-ecid-wtls4"
+#define NID_wap_wsg_idm_ecid_wtls4		737
+#define OBJ_wap_wsg_idm_ecid_wtls4		OBJ_wap_wsg_idm_ecid,4L
+
+#define SN_wap_wsg_idm_ecid_wtls5		"wap-wsg-idm-ecid-wtls5"
+#define NID_wap_wsg_idm_ecid_wtls5		738
+#define OBJ_wap_wsg_idm_ecid_wtls5		OBJ_wap_wsg_idm_ecid,5L
+
+#define SN_wap_wsg_idm_ecid_wtls6		"wap-wsg-idm-ecid-wtls6"
+#define NID_wap_wsg_idm_ecid_wtls6		739
+#define OBJ_wap_wsg_idm_ecid_wtls6		OBJ_wap_wsg_idm_ecid,6L
+
+#define SN_wap_wsg_idm_ecid_wtls7		"wap-wsg-idm-ecid-wtls7"
+#define NID_wap_wsg_idm_ecid_wtls7		740
+#define OBJ_wap_wsg_idm_ecid_wtls7		OBJ_wap_wsg_idm_ecid,7L
+
+#define SN_wap_wsg_idm_ecid_wtls8		"wap-wsg-idm-ecid-wtls8"
+#define NID_wap_wsg_idm_ecid_wtls8		741
+#define OBJ_wap_wsg_idm_ecid_wtls8		OBJ_wap_wsg_idm_ecid,8L
+
+#define SN_wap_wsg_idm_ecid_wtls9		"wap-wsg-idm-ecid-wtls9"
+#define NID_wap_wsg_idm_ecid_wtls9		742
+#define OBJ_wap_wsg_idm_ecid_wtls9		OBJ_wap_wsg_idm_ecid,9L
+
+#define SN_wap_wsg_idm_ecid_wtls10		"wap-wsg-idm-ecid-wtls10"
+#define NID_wap_wsg_idm_ecid_wtls10		743
+#define OBJ_wap_wsg_idm_ecid_wtls10		OBJ_wap_wsg_idm_ecid,10L
+
+#define SN_wap_wsg_idm_ecid_wtls11		"wap-wsg-idm-ecid-wtls11"
+#define NID_wap_wsg_idm_ecid_wtls11		744
+#define OBJ_wap_wsg_idm_ecid_wtls11		OBJ_wap_wsg_idm_ecid,11L
+
+#define SN_wap_wsg_idm_ecid_wtls12		"wap-wsg-idm-ecid-wtls12"
+#define NID_wap_wsg_idm_ecid_wtls12		745
+#define OBJ_wap_wsg_idm_ecid_wtls12		OBJ_wap_wsg_idm_ecid,12L
+
+#define SN_cast5_cbc		"CAST5-CBC"
+#define LN_cast5_cbc		"cast5-cbc"
+#define NID_cast5_cbc		108
+#define OBJ_cast5_cbc		OBJ_ISO_US,113533L,7L,66L,10L
+
+#define SN_cast5_ecb		"CAST5-ECB"
+#define LN_cast5_ecb		"cast5-ecb"
+#define NID_cast5_ecb		109
+
+#define SN_cast5_cfb64		"CAST5-CFB"
+#define LN_cast5_cfb64		"cast5-cfb"
+#define NID_cast5_cfb64		110
+
+#define SN_cast5_ofb64		"CAST5-OFB"
+#define LN_cast5_ofb64		"cast5-ofb"
+#define NID_cast5_ofb64		111
+
+#define LN_pbeWithMD5AndCast5_CBC		"pbeWithMD5AndCast5CBC"
+#define NID_pbeWithMD5AndCast5_CBC		112
+#define OBJ_pbeWithMD5AndCast5_CBC		OBJ_ISO_US,113533L,7L,66L,12L
+
+#define SN_rsadsi		"rsadsi"
+#define LN_rsadsi		"RSA Data Security, Inc."
+#define NID_rsadsi		1
+#define OBJ_rsadsi		OBJ_ISO_US,113549L
+
+#define SN_pkcs		"pkcs"
+#define LN_pkcs		"RSA Data Security, Inc. PKCS"
+#define NID_pkcs		2
+#define OBJ_pkcs		OBJ_rsadsi,1L
+
+#define SN_pkcs1		"pkcs1"
+#define NID_pkcs1		186
+#define OBJ_pkcs1		OBJ_pkcs,1L
+
+#define LN_rsaEncryption		"rsaEncryption"
+#define NID_rsaEncryption		6
+#define OBJ_rsaEncryption		OBJ_pkcs1,1L
+
+#define SN_md2WithRSAEncryption		"RSA-MD2"
+#define LN_md2WithRSAEncryption		"md2WithRSAEncryption"
+#define NID_md2WithRSAEncryption		7
+#define OBJ_md2WithRSAEncryption		OBJ_pkcs1,2L
+
+#define SN_md4WithRSAEncryption		"RSA-MD4"
+#define LN_md4WithRSAEncryption		"md4WithRSAEncryption"
+#define NID_md4WithRSAEncryption		396
+#define OBJ_md4WithRSAEncryption		OBJ_pkcs1,3L
+
+#define SN_md5WithRSAEncryption		"RSA-MD5"
+#define LN_md5WithRSAEncryption		"md5WithRSAEncryption"
+#define NID_md5WithRSAEncryption		8
+#define OBJ_md5WithRSAEncryption		OBJ_pkcs1,4L
+
+#define SN_sha1WithRSAEncryption		"RSA-SHA1"
+#define LN_sha1WithRSAEncryption		"sha1WithRSAEncryption"
+#define NID_sha1WithRSAEncryption		65
+#define OBJ_sha1WithRSAEncryption		OBJ_pkcs1,5L
+
+#define SN_sha256WithRSAEncryption		"RSA-SHA256"
+#define LN_sha256WithRSAEncryption		"sha256WithRSAEncryption"
+#define NID_sha256WithRSAEncryption		668
+#define OBJ_sha256WithRSAEncryption		OBJ_pkcs1,11L
+
+#define SN_sha384WithRSAEncryption		"RSA-SHA384"
+#define LN_sha384WithRSAEncryption		"sha384WithRSAEncryption"
+#define NID_sha384WithRSAEncryption		669
+#define OBJ_sha384WithRSAEncryption		OBJ_pkcs1,12L
+
+#define SN_sha512WithRSAEncryption		"RSA-SHA512"
+#define LN_sha512WithRSAEncryption		"sha512WithRSAEncryption"
+#define NID_sha512WithRSAEncryption		670
+#define OBJ_sha512WithRSAEncryption		OBJ_pkcs1,13L
+
+#define SN_sha224WithRSAEncryption		"RSA-SHA224"
+#define LN_sha224WithRSAEncryption		"sha224WithRSAEncryption"
+#define NID_sha224WithRSAEncryption		671
+#define OBJ_sha224WithRSAEncryption		OBJ_pkcs1,14L
+
+#define SN_pkcs3		"pkcs3"
+#define NID_pkcs3		27
+#define OBJ_pkcs3		OBJ_pkcs,3L
+
+#define LN_dhKeyAgreement		"dhKeyAgreement"
+#define NID_dhKeyAgreement		28
+#define OBJ_dhKeyAgreement		OBJ_pkcs3,1L
+
+#define SN_pkcs5		"pkcs5"
+#define NID_pkcs5		187
+#define OBJ_pkcs5		OBJ_pkcs,5L
+
+#define SN_pbeWithMD2AndDES_CBC		"PBE-MD2-DES"
+#define LN_pbeWithMD2AndDES_CBC		"pbeWithMD2AndDES-CBC"
+#define NID_pbeWithMD2AndDES_CBC		9
+#define OBJ_pbeWithMD2AndDES_CBC		OBJ_pkcs5,1L
+
+#define SN_pbeWithMD5AndDES_CBC		"PBE-MD5-DES"
+#define LN_pbeWithMD5AndDES_CBC		"pbeWithMD5AndDES-CBC"
+#define NID_pbeWithMD5AndDES_CBC		10
+#define OBJ_pbeWithMD5AndDES_CBC		OBJ_pkcs5,3L
+
+#define SN_pbeWithMD2AndRC2_CBC		"PBE-MD2-RC2-64"
+#define LN_pbeWithMD2AndRC2_CBC		"pbeWithMD2AndRC2-CBC"
+#define NID_pbeWithMD2AndRC2_CBC		168
+#define OBJ_pbeWithMD2AndRC2_CBC		OBJ_pkcs5,4L
+
+#define SN_pbeWithMD5AndRC2_CBC		"PBE-MD5-RC2-64"
+#define LN_pbeWithMD5AndRC2_CBC		"pbeWithMD5AndRC2-CBC"
+#define NID_pbeWithMD5AndRC2_CBC		169
+#define OBJ_pbeWithMD5AndRC2_CBC		OBJ_pkcs5,6L
+
+#define SN_pbeWithSHA1AndDES_CBC		"PBE-SHA1-DES"
+#define LN_pbeWithSHA1AndDES_CBC		"pbeWithSHA1AndDES-CBC"
+#define NID_pbeWithSHA1AndDES_CBC		170
+#define OBJ_pbeWithSHA1AndDES_CBC		OBJ_pkcs5,10L
+
+#define SN_pbeWithSHA1AndRC2_CBC		"PBE-SHA1-RC2-64"
+#define LN_pbeWithSHA1AndRC2_CBC		"pbeWithSHA1AndRC2-CBC"
+#define NID_pbeWithSHA1AndRC2_CBC		68
+#define OBJ_pbeWithSHA1AndRC2_CBC		OBJ_pkcs5,11L
+
+#define LN_id_pbkdf2		"PBKDF2"
+#define NID_id_pbkdf2		69
+#define OBJ_id_pbkdf2		OBJ_pkcs5,12L
+
+#define LN_pbes2		"PBES2"
+#define NID_pbes2		161
+#define OBJ_pbes2		OBJ_pkcs5,13L
+
+#define LN_pbmac1		"PBMAC1"
+#define NID_pbmac1		162
+#define OBJ_pbmac1		OBJ_pkcs5,14L
+
+#define SN_pkcs7		"pkcs7"
+#define NID_pkcs7		20
+#define OBJ_pkcs7		OBJ_pkcs,7L
+
+#define LN_pkcs7_data		"pkcs7-data"
+#define NID_pkcs7_data		21
+#define OBJ_pkcs7_data		OBJ_pkcs7,1L
+
+#define LN_pkcs7_signed		"pkcs7-signedData"
+#define NID_pkcs7_signed		22
+#define OBJ_pkcs7_signed		OBJ_pkcs7,2L
+
+#define LN_pkcs7_enveloped		"pkcs7-envelopedData"
+#define NID_pkcs7_enveloped		23
+#define OBJ_pkcs7_enveloped		OBJ_pkcs7,3L
+
+#define LN_pkcs7_signedAndEnveloped		"pkcs7-signedAndEnvelopedData"
+#define NID_pkcs7_signedAndEnveloped		24
+#define OBJ_pkcs7_signedAndEnveloped		OBJ_pkcs7,4L
+
+#define LN_pkcs7_digest		"pkcs7-digestData"
+#define NID_pkcs7_digest		25
+#define OBJ_pkcs7_digest		OBJ_pkcs7,5L
+
+#define LN_pkcs7_encrypted		"pkcs7-encryptedData"
+#define NID_pkcs7_encrypted		26
+#define OBJ_pkcs7_encrypted		OBJ_pkcs7,6L
+
+#define SN_pkcs9		"pkcs9"
+#define NID_pkcs9		47
+#define OBJ_pkcs9		OBJ_pkcs,9L
+
+#define LN_pkcs9_emailAddress		"emailAddress"
+#define NID_pkcs9_emailAddress		48
+#define OBJ_pkcs9_emailAddress		OBJ_pkcs9,1L
+
+#define LN_pkcs9_unstructuredName		"unstructuredName"
+#define NID_pkcs9_unstructuredName		49
+#define OBJ_pkcs9_unstructuredName		OBJ_pkcs9,2L
+
+#define LN_pkcs9_contentType		"contentType"
+#define NID_pkcs9_contentType		50
+#define OBJ_pkcs9_contentType		OBJ_pkcs9,3L
+
+#define LN_pkcs9_messageDigest		"messageDigest"
+#define NID_pkcs9_messageDigest		51
+#define OBJ_pkcs9_messageDigest		OBJ_pkcs9,4L
+
+#define LN_pkcs9_signingTime		"signingTime"
+#define NID_pkcs9_signingTime		52
+#define OBJ_pkcs9_signingTime		OBJ_pkcs9,5L
+
+#define LN_pkcs9_countersignature		"countersignature"
+#define NID_pkcs9_countersignature		53
+#define OBJ_pkcs9_countersignature		OBJ_pkcs9,6L
+
+#define LN_pkcs9_challengePassword		"challengePassword"
+#define NID_pkcs9_challengePassword		54
+#define OBJ_pkcs9_challengePassword		OBJ_pkcs9,7L
+
+#define LN_pkcs9_unstructuredAddress		"unstructuredAddress"
+#define NID_pkcs9_unstructuredAddress		55
+#define OBJ_pkcs9_unstructuredAddress		OBJ_pkcs9,8L
+
+#define LN_pkcs9_extCertAttributes		"extendedCertificateAttributes"
+#define NID_pkcs9_extCertAttributes		56
+#define OBJ_pkcs9_extCertAttributes		OBJ_pkcs9,9L
+
+#define SN_ext_req		"extReq"
+#define LN_ext_req		"Extension Request"
+#define NID_ext_req		172
+#define OBJ_ext_req		OBJ_pkcs9,14L
+
+#define SN_SMIMECapabilities		"SMIME-CAPS"
+#define LN_SMIMECapabilities		"S/MIME Capabilities"
+#define NID_SMIMECapabilities		167
+#define OBJ_SMIMECapabilities		OBJ_pkcs9,15L
+
+#define SN_SMIME		"SMIME"
+#define LN_SMIME		"S/MIME"
+#define NID_SMIME		188
+#define OBJ_SMIME		OBJ_pkcs9,16L
+
+#define SN_id_smime_mod		"id-smime-mod"
+#define NID_id_smime_mod		189
+#define OBJ_id_smime_mod		OBJ_SMIME,0L
+
+#define SN_id_smime_ct		"id-smime-ct"
+#define NID_id_smime_ct		190
+#define OBJ_id_smime_ct		OBJ_SMIME,1L
+
+#define SN_id_smime_aa		"id-smime-aa"
+#define NID_id_smime_aa		191
+#define OBJ_id_smime_aa		OBJ_SMIME,2L
+
+#define SN_id_smime_alg		"id-smime-alg"
+#define NID_id_smime_alg		192
+#define OBJ_id_smime_alg		OBJ_SMIME,3L
+
+#define SN_id_smime_cd		"id-smime-cd"
+#define NID_id_smime_cd		193
+#define OBJ_id_smime_cd		OBJ_SMIME,4L
+
+#define SN_id_smime_spq		"id-smime-spq"
+#define NID_id_smime_spq		194
+#define OBJ_id_smime_spq		OBJ_SMIME,5L
+
+#define SN_id_smime_cti		"id-smime-cti"
+#define NID_id_smime_cti		195
+#define OBJ_id_smime_cti		OBJ_SMIME,6L
+
+#define SN_id_smime_mod_cms		"id-smime-mod-cms"
+#define NID_id_smime_mod_cms		196
+#define OBJ_id_smime_mod_cms		OBJ_id_smime_mod,1L
+
+#define SN_id_smime_mod_ess		"id-smime-mod-ess"
+#define NID_id_smime_mod_ess		197
+#define OBJ_id_smime_mod_ess		OBJ_id_smime_mod,2L
+
+#define SN_id_smime_mod_oid		"id-smime-mod-oid"
+#define NID_id_smime_mod_oid		198
+#define OBJ_id_smime_mod_oid		OBJ_id_smime_mod,3L
+
+#define SN_id_smime_mod_msg_v3		"id-smime-mod-msg-v3"
+#define NID_id_smime_mod_msg_v3		199
+#define OBJ_id_smime_mod_msg_v3		OBJ_id_smime_mod,4L
+
+#define SN_id_smime_mod_ets_eSignature_88		"id-smime-mod-ets-eSignature-88"
+#define NID_id_smime_mod_ets_eSignature_88		200
+#define OBJ_id_smime_mod_ets_eSignature_88		OBJ_id_smime_mod,5L
+
+#define SN_id_smime_mod_ets_eSignature_97		"id-smime-mod-ets-eSignature-97"
+#define NID_id_smime_mod_ets_eSignature_97		201
+#define OBJ_id_smime_mod_ets_eSignature_97		OBJ_id_smime_mod,6L
+
+#define SN_id_smime_mod_ets_eSigPolicy_88		"id-smime-mod-ets-eSigPolicy-88"
+#define NID_id_smime_mod_ets_eSigPolicy_88		202
+#define OBJ_id_smime_mod_ets_eSigPolicy_88		OBJ_id_smime_mod,7L
+
+#define SN_id_smime_mod_ets_eSigPolicy_97		"id-smime-mod-ets-eSigPolicy-97"
+#define NID_id_smime_mod_ets_eSigPolicy_97		203
+#define OBJ_id_smime_mod_ets_eSigPolicy_97		OBJ_id_smime_mod,8L
+
+#define SN_id_smime_ct_receipt		"id-smime-ct-receipt"
+#define NID_id_smime_ct_receipt		204
+#define OBJ_id_smime_ct_receipt		OBJ_id_smime_ct,1L
+
+#define SN_id_smime_ct_authData		"id-smime-ct-authData"
+#define NID_id_smime_ct_authData		205
+#define OBJ_id_smime_ct_authData		OBJ_id_smime_ct,2L
+
+#define SN_id_smime_ct_publishCert		"id-smime-ct-publishCert"
+#define NID_id_smime_ct_publishCert		206
+#define OBJ_id_smime_ct_publishCert		OBJ_id_smime_ct,3L
+
+#define SN_id_smime_ct_TSTInfo		"id-smime-ct-TSTInfo"
+#define NID_id_smime_ct_TSTInfo		207
+#define OBJ_id_smime_ct_TSTInfo		OBJ_id_smime_ct,4L
+
+#define SN_id_smime_ct_TDTInfo		"id-smime-ct-TDTInfo"
+#define NID_id_smime_ct_TDTInfo		208
+#define OBJ_id_smime_ct_TDTInfo		OBJ_id_smime_ct,5L
+
+#define SN_id_smime_ct_contentInfo		"id-smime-ct-contentInfo"
+#define NID_id_smime_ct_contentInfo		209
+#define OBJ_id_smime_ct_contentInfo		OBJ_id_smime_ct,6L
+
+#define SN_id_smime_ct_DVCSRequestData		"id-smime-ct-DVCSRequestData"
+#define NID_id_smime_ct_DVCSRequestData		210
+#define OBJ_id_smime_ct_DVCSRequestData		OBJ_id_smime_ct,7L
+
+#define SN_id_smime_ct_DVCSResponseData		"id-smime-ct-DVCSResponseData"
+#define NID_id_smime_ct_DVCSResponseData		211
+#define OBJ_id_smime_ct_DVCSResponseData		OBJ_id_smime_ct,8L
+
+#define SN_id_smime_aa_receiptRequest		"id-smime-aa-receiptRequest"
+#define NID_id_smime_aa_receiptRequest		212
+#define OBJ_id_smime_aa_receiptRequest		OBJ_id_smime_aa,1L
+
+#define SN_id_smime_aa_securityLabel		"id-smime-aa-securityLabel"
+#define NID_id_smime_aa_securityLabel		213
+#define OBJ_id_smime_aa_securityLabel		OBJ_id_smime_aa,2L
+
+#define SN_id_smime_aa_mlExpandHistory		"id-smime-aa-mlExpandHistory"
+#define NID_id_smime_aa_mlExpandHistory		214
+#define OBJ_id_smime_aa_mlExpandHistory		OBJ_id_smime_aa,3L
+
+#define SN_id_smime_aa_contentHint		"id-smime-aa-contentHint"
+#define NID_id_smime_aa_contentHint		215
+#define OBJ_id_smime_aa_contentHint		OBJ_id_smime_aa,4L
+
+#define SN_id_smime_aa_msgSigDigest		"id-smime-aa-msgSigDigest"
+#define NID_id_smime_aa_msgSigDigest		216
+#define OBJ_id_smime_aa_msgSigDigest		OBJ_id_smime_aa,5L
+
+#define SN_id_smime_aa_encapContentType		"id-smime-aa-encapContentType"
+#define NID_id_smime_aa_encapContentType		217
+#define OBJ_id_smime_aa_encapContentType		OBJ_id_smime_aa,6L
+
+#define SN_id_smime_aa_contentIdentifier		"id-smime-aa-contentIdentifier"
+#define NID_id_smime_aa_contentIdentifier		218
+#define OBJ_id_smime_aa_contentIdentifier		OBJ_id_smime_aa,7L
+
+#define SN_id_smime_aa_macValue		"id-smime-aa-macValue"
+#define NID_id_smime_aa_macValue		219
+#define OBJ_id_smime_aa_macValue		OBJ_id_smime_aa,8L
+
+#define SN_id_smime_aa_equivalentLabels		"id-smime-aa-equivalentLabels"
+#define NID_id_smime_aa_equivalentLabels		220
+#define OBJ_id_smime_aa_equivalentLabels		OBJ_id_smime_aa,9L
+
+#define SN_id_smime_aa_contentReference		"id-smime-aa-contentReference"
+#define NID_id_smime_aa_contentReference		221
+#define OBJ_id_smime_aa_contentReference		OBJ_id_smime_aa,10L
+
+#define SN_id_smime_aa_encrypKeyPref		"id-smime-aa-encrypKeyPref"
+#define NID_id_smime_aa_encrypKeyPref		222
+#define OBJ_id_smime_aa_encrypKeyPref		OBJ_id_smime_aa,11L
+
+#define SN_id_smime_aa_signingCertificate		"id-smime-aa-signingCertificate"
+#define NID_id_smime_aa_signingCertificate		223
+#define OBJ_id_smime_aa_signingCertificate		OBJ_id_smime_aa,12L
+
+#define SN_id_smime_aa_smimeEncryptCerts		"id-smime-aa-smimeEncryptCerts"
+#define NID_id_smime_aa_smimeEncryptCerts		224
+#define OBJ_id_smime_aa_smimeEncryptCerts		OBJ_id_smime_aa,13L
+
+#define SN_id_smime_aa_timeStampToken		"id-smime-aa-timeStampToken"
+#define NID_id_smime_aa_timeStampToken		225
+#define OBJ_id_smime_aa_timeStampToken		OBJ_id_smime_aa,14L
+
+#define SN_id_smime_aa_ets_sigPolicyId		"id-smime-aa-ets-sigPolicyId"
+#define NID_id_smime_aa_ets_sigPolicyId		226
+#define OBJ_id_smime_aa_ets_sigPolicyId		OBJ_id_smime_aa,15L
+
+#define SN_id_smime_aa_ets_commitmentType		"id-smime-aa-ets-commitmentType"
+#define NID_id_smime_aa_ets_commitmentType		227
+#define OBJ_id_smime_aa_ets_commitmentType		OBJ_id_smime_aa,16L
+
+#define SN_id_smime_aa_ets_signerLocation		"id-smime-aa-ets-signerLocation"
+#define NID_id_smime_aa_ets_signerLocation		228
+#define OBJ_id_smime_aa_ets_signerLocation		OBJ_id_smime_aa,17L
+
+#define SN_id_smime_aa_ets_signerAttr		"id-smime-aa-ets-signerAttr"
+#define NID_id_smime_aa_ets_signerAttr		229
+#define OBJ_id_smime_aa_ets_signerAttr		OBJ_id_smime_aa,18L
+
+#define SN_id_smime_aa_ets_otherSigCert		"id-smime-aa-ets-otherSigCert"
+#define NID_id_smime_aa_ets_otherSigCert		230
+#define OBJ_id_smime_aa_ets_otherSigCert		OBJ_id_smime_aa,19L
+
+#define SN_id_smime_aa_ets_contentTimestamp		"id-smime-aa-ets-contentTimestamp"
+#define NID_id_smime_aa_ets_contentTimestamp		231
+#define OBJ_id_smime_aa_ets_contentTimestamp		OBJ_id_smime_aa,20L
+
+#define SN_id_smime_aa_ets_CertificateRefs		"id-smime-aa-ets-CertificateRefs"
+#define NID_id_smime_aa_ets_CertificateRefs		232
+#define OBJ_id_smime_aa_ets_CertificateRefs		OBJ_id_smime_aa,21L
+
+#define SN_id_smime_aa_ets_RevocationRefs		"id-smime-aa-ets-RevocationRefs"
+#define NID_id_smime_aa_ets_RevocationRefs		233
+#define OBJ_id_smime_aa_ets_RevocationRefs		OBJ_id_smime_aa,22L
+
+#define SN_id_smime_aa_ets_certValues		"id-smime-aa-ets-certValues"
+#define NID_id_smime_aa_ets_certValues		234
+#define OBJ_id_smime_aa_ets_certValues		OBJ_id_smime_aa,23L
+
+#define SN_id_smime_aa_ets_revocationValues		"id-smime-aa-ets-revocationValues"
+#define NID_id_smime_aa_ets_revocationValues		235
+#define OBJ_id_smime_aa_ets_revocationValues		OBJ_id_smime_aa,24L
+
+#define SN_id_smime_aa_ets_escTimeStamp		"id-smime-aa-ets-escTimeStamp"
+#define NID_id_smime_aa_ets_escTimeStamp		236
+#define OBJ_id_smime_aa_ets_escTimeStamp		OBJ_id_smime_aa,25L
+
+#define SN_id_smime_aa_ets_certCRLTimestamp		"id-smime-aa-ets-certCRLTimestamp"
+#define NID_id_smime_aa_ets_certCRLTimestamp		237
+#define OBJ_id_smime_aa_ets_certCRLTimestamp		OBJ_id_smime_aa,26L
+
+#define SN_id_smime_aa_ets_archiveTimeStamp		"id-smime-aa-ets-archiveTimeStamp"
+#define NID_id_smime_aa_ets_archiveTimeStamp		238
+#define OBJ_id_smime_aa_ets_archiveTimeStamp		OBJ_id_smime_aa,27L
+
+#define SN_id_smime_aa_signatureType		"id-smime-aa-signatureType"
+#define NID_id_smime_aa_signatureType		239
+#define OBJ_id_smime_aa_signatureType		OBJ_id_smime_aa,28L
+
+#define SN_id_smime_aa_dvcs_dvc		"id-smime-aa-dvcs-dvc"
+#define NID_id_smime_aa_dvcs_dvc		240
+#define OBJ_id_smime_aa_dvcs_dvc		OBJ_id_smime_aa,29L
+
+#define SN_id_smime_alg_ESDHwith3DES		"id-smime-alg-ESDHwith3DES"
+#define NID_id_smime_alg_ESDHwith3DES		241
+#define OBJ_id_smime_alg_ESDHwith3DES		OBJ_id_smime_alg,1L
+
+#define SN_id_smime_alg_ESDHwithRC2		"id-smime-alg-ESDHwithRC2"
+#define NID_id_smime_alg_ESDHwithRC2		242
+#define OBJ_id_smime_alg_ESDHwithRC2		OBJ_id_smime_alg,2L
+
+#define SN_id_smime_alg_3DESwrap		"id-smime-alg-3DESwrap"
+#define NID_id_smime_alg_3DESwrap		243
+#define OBJ_id_smime_alg_3DESwrap		OBJ_id_smime_alg,3L
+
+#define SN_id_smime_alg_RC2wrap		"id-smime-alg-RC2wrap"
+#define NID_id_smime_alg_RC2wrap		244
+#define OBJ_id_smime_alg_RC2wrap		OBJ_id_smime_alg,4L
+
+#define SN_id_smime_alg_ESDH		"id-smime-alg-ESDH"
+#define NID_id_smime_alg_ESDH		245
+#define OBJ_id_smime_alg_ESDH		OBJ_id_smime_alg,5L
+
+#define SN_id_smime_alg_CMS3DESwrap		"id-smime-alg-CMS3DESwrap"
+#define NID_id_smime_alg_CMS3DESwrap		246
+#define OBJ_id_smime_alg_CMS3DESwrap		OBJ_id_smime_alg,6L
+
+#define SN_id_smime_alg_CMSRC2wrap		"id-smime-alg-CMSRC2wrap"
+#define NID_id_smime_alg_CMSRC2wrap		247
+#define OBJ_id_smime_alg_CMSRC2wrap		OBJ_id_smime_alg,7L
+
+#define SN_id_smime_cd_ldap		"id-smime-cd-ldap"
+#define NID_id_smime_cd_ldap		248
+#define OBJ_id_smime_cd_ldap		OBJ_id_smime_cd,1L
+
+#define SN_id_smime_spq_ets_sqt_uri		"id-smime-spq-ets-sqt-uri"
+#define NID_id_smime_spq_ets_sqt_uri		249
+#define OBJ_id_smime_spq_ets_sqt_uri		OBJ_id_smime_spq,1L
+
+#define SN_id_smime_spq_ets_sqt_unotice		"id-smime-spq-ets-sqt-unotice"
+#define NID_id_smime_spq_ets_sqt_unotice		250
+#define OBJ_id_smime_spq_ets_sqt_unotice		OBJ_id_smime_spq,2L
+
+#define SN_id_smime_cti_ets_proofOfOrigin		"id-smime-cti-ets-proofOfOrigin"
+#define NID_id_smime_cti_ets_proofOfOrigin		251
+#define OBJ_id_smime_cti_ets_proofOfOrigin		OBJ_id_smime_cti,1L
+
+#define SN_id_smime_cti_ets_proofOfReceipt		"id-smime-cti-ets-proofOfReceipt"
+#define NID_id_smime_cti_ets_proofOfReceipt		252
+#define OBJ_id_smime_cti_ets_proofOfReceipt		OBJ_id_smime_cti,2L
+
+#define SN_id_smime_cti_ets_proofOfDelivery		"id-smime-cti-ets-proofOfDelivery"
+#define NID_id_smime_cti_ets_proofOfDelivery		253
+#define OBJ_id_smime_cti_ets_proofOfDelivery		OBJ_id_smime_cti,3L
+
+#define SN_id_smime_cti_ets_proofOfSender		"id-smime-cti-ets-proofOfSender"
+#define NID_id_smime_cti_ets_proofOfSender		254
+#define OBJ_id_smime_cti_ets_proofOfSender		OBJ_id_smime_cti,4L
+
+#define SN_id_smime_cti_ets_proofOfApproval		"id-smime-cti-ets-proofOfApproval"
+#define NID_id_smime_cti_ets_proofOfApproval		255
+#define OBJ_id_smime_cti_ets_proofOfApproval		OBJ_id_smime_cti,5L
+
+#define SN_id_smime_cti_ets_proofOfCreation		"id-smime-cti-ets-proofOfCreation"
+#define NID_id_smime_cti_ets_proofOfCreation		256
+#define OBJ_id_smime_cti_ets_proofOfCreation		OBJ_id_smime_cti,6L
+
+#define LN_friendlyName		"friendlyName"
+#define NID_friendlyName		156
+#define OBJ_friendlyName		OBJ_pkcs9,20L
+
+#define LN_localKeyID		"localKeyID"
+#define NID_localKeyID		157
+#define OBJ_localKeyID		OBJ_pkcs9,21L
+
+#define SN_ms_csp_name		"CSPName"
+#define LN_ms_csp_name		"Microsoft CSP Name"
+#define NID_ms_csp_name		417
+#define OBJ_ms_csp_name		1L,3L,6L,1L,4L,1L,311L,17L,1L
+
+#define OBJ_certTypes		OBJ_pkcs9,22L
+
+#define LN_x509Certificate		"x509Certificate"
+#define NID_x509Certificate		158
+#define OBJ_x509Certificate		OBJ_certTypes,1L
+
+#define LN_sdsiCertificate		"sdsiCertificate"
+#define NID_sdsiCertificate		159
+#define OBJ_sdsiCertificate		OBJ_certTypes,2L
+
+#define OBJ_crlTypes		OBJ_pkcs9,23L
+
+#define LN_x509Crl		"x509Crl"
+#define NID_x509Crl		160
+#define OBJ_x509Crl		OBJ_crlTypes,1L
+
+#define OBJ_pkcs12		OBJ_pkcs,12L
+
+#define OBJ_pkcs12_pbeids		OBJ_pkcs12,1L
+
+#define SN_pbe_WithSHA1And128BitRC4		"PBE-SHA1-RC4-128"
+#define LN_pbe_WithSHA1And128BitRC4		"pbeWithSHA1And128BitRC4"
+#define NID_pbe_WithSHA1And128BitRC4		144
+#define OBJ_pbe_WithSHA1And128BitRC4		OBJ_pkcs12_pbeids,1L
+
+#define SN_pbe_WithSHA1And40BitRC4		"PBE-SHA1-RC4-40"
+#define LN_pbe_WithSHA1And40BitRC4		"pbeWithSHA1And40BitRC4"
+#define NID_pbe_WithSHA1And40BitRC4		145
+#define OBJ_pbe_WithSHA1And40BitRC4		OBJ_pkcs12_pbeids,2L
+
+#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC		"PBE-SHA1-3DES"
+#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC		"pbeWithSHA1And3-KeyTripleDES-CBC"
+#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC		146
+#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC		OBJ_pkcs12_pbeids,3L
+
+#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC		"PBE-SHA1-2DES"
+#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC		"pbeWithSHA1And2-KeyTripleDES-CBC"
+#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC		147
+#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC		OBJ_pkcs12_pbeids,4L
+
+#define SN_pbe_WithSHA1And128BitRC2_CBC		"PBE-SHA1-RC2-128"
+#define LN_pbe_WithSHA1And128BitRC2_CBC		"pbeWithSHA1And128BitRC2-CBC"
+#define NID_pbe_WithSHA1And128BitRC2_CBC		148
+#define OBJ_pbe_WithSHA1And128BitRC2_CBC		OBJ_pkcs12_pbeids,5L
+
+#define SN_pbe_WithSHA1And40BitRC2_CBC		"PBE-SHA1-RC2-40"
+#define LN_pbe_WithSHA1And40BitRC2_CBC		"pbeWithSHA1And40BitRC2-CBC"
+#define NID_pbe_WithSHA1And40BitRC2_CBC		149
+#define OBJ_pbe_WithSHA1And40BitRC2_CBC		OBJ_pkcs12_pbeids,6L
+
+#define OBJ_pkcs12_Version1		OBJ_pkcs12,10L
+
+#define OBJ_pkcs12_BagIds		OBJ_pkcs12_Version1,1L
+
+#define LN_keyBag		"keyBag"
+#define NID_keyBag		150
+#define OBJ_keyBag		OBJ_pkcs12_BagIds,1L
+
+#define LN_pkcs8ShroudedKeyBag		"pkcs8ShroudedKeyBag"
+#define NID_pkcs8ShroudedKeyBag		151
+#define OBJ_pkcs8ShroudedKeyBag		OBJ_pkcs12_BagIds,2L
+
+#define LN_certBag		"certBag"
+#define NID_certBag		152
+#define OBJ_certBag		OBJ_pkcs12_BagIds,3L
+
+#define LN_crlBag		"crlBag"
+#define NID_crlBag		153
+#define OBJ_crlBag		OBJ_pkcs12_BagIds,4L
+
+#define LN_secretBag		"secretBag"
+#define NID_secretBag		154
+#define OBJ_secretBag		OBJ_pkcs12_BagIds,5L
+
+#define LN_safeContentsBag		"safeContentsBag"
+#define NID_safeContentsBag		155
+#define OBJ_safeContentsBag		OBJ_pkcs12_BagIds,6L
+
+#define SN_md2		"MD2"
+#define LN_md2		"md2"
+#define NID_md2		3
+#define OBJ_md2		OBJ_rsadsi,2L,2L
+
+#define SN_md4		"MD4"
+#define LN_md4		"md4"
+#define NID_md4		257
+#define OBJ_md4		OBJ_rsadsi,2L,4L
+
+#define SN_md5		"MD5"
+#define LN_md5		"md5"
+#define NID_md5		4
+#define OBJ_md5		OBJ_rsadsi,2L,5L
+
+#define SN_md5_sha1		"MD5-SHA1"
+#define LN_md5_sha1		"md5-sha1"
+#define NID_md5_sha1		114
+
+#define LN_hmacWithSHA1		"hmacWithSHA1"
+#define NID_hmacWithSHA1		163
+#define OBJ_hmacWithSHA1		OBJ_rsadsi,2L,7L
+
+#define SN_rc2_cbc		"RC2-CBC"
+#define LN_rc2_cbc		"rc2-cbc"
+#define NID_rc2_cbc		37
+#define OBJ_rc2_cbc		OBJ_rsadsi,3L,2L
+
+#define SN_rc2_ecb		"RC2-ECB"
+#define LN_rc2_ecb		"rc2-ecb"
+#define NID_rc2_ecb		38
+
+#define SN_rc2_cfb64		"RC2-CFB"
+#define LN_rc2_cfb64		"rc2-cfb"
+#define NID_rc2_cfb64		39
+
+#define SN_rc2_ofb64		"RC2-OFB"
+#define LN_rc2_ofb64		"rc2-ofb"
+#define NID_rc2_ofb64		40
+
+#define SN_rc2_40_cbc		"RC2-40-CBC"
+#define LN_rc2_40_cbc		"rc2-40-cbc"
+#define NID_rc2_40_cbc		98
+
+#define SN_rc2_64_cbc		"RC2-64-CBC"
+#define LN_rc2_64_cbc		"rc2-64-cbc"
+#define NID_rc2_64_cbc		166
+
+#define SN_rc4		"RC4"
+#define LN_rc4		"rc4"
+#define NID_rc4		5
+#define OBJ_rc4		OBJ_rsadsi,3L,4L
+
+#define SN_rc4_40		"RC4-40"
+#define LN_rc4_40		"rc4-40"
+#define NID_rc4_40		97
+
+#define SN_des_ede3_cbc		"DES-EDE3-CBC"
+#define LN_des_ede3_cbc		"des-ede3-cbc"
+#define NID_des_ede3_cbc		44
+#define OBJ_des_ede3_cbc		OBJ_rsadsi,3L,7L
+
+#define SN_rc5_cbc		"RC5-CBC"
+#define LN_rc5_cbc		"rc5-cbc"
+#define NID_rc5_cbc		120
+#define OBJ_rc5_cbc		OBJ_rsadsi,3L,8L
+
+#define SN_rc5_ecb		"RC5-ECB"
+#define LN_rc5_ecb		"rc5-ecb"
+#define NID_rc5_ecb		121
+
+#define SN_rc5_cfb64		"RC5-CFB"
+#define LN_rc5_cfb64		"rc5-cfb"
+#define NID_rc5_cfb64		122
+
+#define SN_rc5_ofb64		"RC5-OFB"
+#define LN_rc5_ofb64		"rc5-ofb"
+#define NID_rc5_ofb64		123
+
+#define SN_ms_ext_req		"msExtReq"
+#define LN_ms_ext_req		"Microsoft Extension Request"
+#define NID_ms_ext_req		171
+#define OBJ_ms_ext_req		1L,3L,6L,1L,4L,1L,311L,2L,1L,14L
+
+#define SN_ms_code_ind		"msCodeInd"
+#define LN_ms_code_ind		"Microsoft Individual Code Signing"
+#define NID_ms_code_ind		134
+#define OBJ_ms_code_ind		1L,3L,6L,1L,4L,1L,311L,2L,1L,21L
+
+#define SN_ms_code_com		"msCodeCom"
+#define LN_ms_code_com		"Microsoft Commercial Code Signing"
+#define NID_ms_code_com		135
+#define OBJ_ms_code_com		1L,3L,6L,1L,4L,1L,311L,2L,1L,22L
+
+#define SN_ms_ctl_sign		"msCTLSign"
+#define LN_ms_ctl_sign		"Microsoft Trust List Signing"
+#define NID_ms_ctl_sign		136
+#define OBJ_ms_ctl_sign		1L,3L,6L,1L,4L,1L,311L,10L,3L,1L
+
+#define SN_ms_sgc		"msSGC"
+#define LN_ms_sgc		"Microsoft Server Gated Crypto"
+#define NID_ms_sgc		137
+#define OBJ_ms_sgc		1L,3L,6L,1L,4L,1L,311L,10L,3L,3L
+
+#define SN_ms_efs		"msEFS"
+#define LN_ms_efs		"Microsoft Encrypted File System"
+#define NID_ms_efs		138
+#define OBJ_ms_efs		1L,3L,6L,1L,4L,1L,311L,10L,3L,4L
+
+#define SN_ms_smartcard_login		"msSmartcardLogin"
+#define LN_ms_smartcard_login		"Microsoft Smartcardlogin"
+#define NID_ms_smartcard_login		648
+#define OBJ_ms_smartcard_login		1L,3L,6L,1L,4L,1L,311L,20L,2L,2L
+
+#define SN_ms_upn		"msUPN"
+#define LN_ms_upn		"Microsoft Universal Principal Name"
+#define NID_ms_upn		649
+#define OBJ_ms_upn		1L,3L,6L,1L,4L,1L,311L,20L,2L,3L
+
+#define SN_idea_cbc		"IDEA-CBC"
+#define LN_idea_cbc		"idea-cbc"
+#define NID_idea_cbc		34
+#define OBJ_idea_cbc		1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L
+
+#define SN_idea_ecb		"IDEA-ECB"
+#define LN_idea_ecb		"idea-ecb"
+#define NID_idea_ecb		36
+
+#define SN_idea_cfb64		"IDEA-CFB"
+#define LN_idea_cfb64		"idea-cfb"
+#define NID_idea_cfb64		35
+
+#define SN_idea_ofb64		"IDEA-OFB"
+#define LN_idea_ofb64		"idea-ofb"
+#define NID_idea_ofb64		46
+
+#define SN_bf_cbc		"BF-CBC"
+#define LN_bf_cbc		"bf-cbc"
+#define NID_bf_cbc		91
+#define OBJ_bf_cbc		1L,3L,6L,1L,4L,1L,3029L,1L,2L
+
+#define SN_bf_ecb		"BF-ECB"
+#define LN_bf_ecb		"bf-ecb"
+#define NID_bf_ecb		92
+
+#define SN_bf_cfb64		"BF-CFB"
+#define LN_bf_cfb64		"bf-cfb"
+#define NID_bf_cfb64		93
+
+#define SN_bf_ofb64		"BF-OFB"
+#define LN_bf_ofb64		"bf-ofb"
+#define NID_bf_ofb64		94
+
+#define SN_id_pkix		"PKIX"
+#define NID_id_pkix		127
+#define OBJ_id_pkix		1L,3L,6L,1L,5L,5L,7L
+
+#define SN_id_pkix_mod		"id-pkix-mod"
+#define NID_id_pkix_mod		258
+#define OBJ_id_pkix_mod		OBJ_id_pkix,0L
+
+#define SN_id_pe		"id-pe"
+#define NID_id_pe		175
+#define OBJ_id_pe		OBJ_id_pkix,1L
+
+#define SN_id_qt		"id-qt"
+#define NID_id_qt		259
+#define OBJ_id_qt		OBJ_id_pkix,2L
+
+#define SN_id_kp		"id-kp"
+#define NID_id_kp		128
+#define OBJ_id_kp		OBJ_id_pkix,3L
+
+#define SN_id_it		"id-it"
+#define NID_id_it		260
+#define OBJ_id_it		OBJ_id_pkix,4L
+
+#define SN_id_pkip		"id-pkip"
+#define NID_id_pkip		261
+#define OBJ_id_pkip		OBJ_id_pkix,5L
+
+#define SN_id_alg		"id-alg"
+#define NID_id_alg		262
+#define OBJ_id_alg		OBJ_id_pkix,6L
+
+#define SN_id_cmc		"id-cmc"
+#define NID_id_cmc		263
+#define OBJ_id_cmc		OBJ_id_pkix,7L
+
+#define SN_id_on		"id-on"
+#define NID_id_on		264
+#define OBJ_id_on		OBJ_id_pkix,8L
+
+#define SN_id_pda		"id-pda"
+#define NID_id_pda		265
+#define OBJ_id_pda		OBJ_id_pkix,9L
+
+#define SN_id_aca		"id-aca"
+#define NID_id_aca		266
+#define OBJ_id_aca		OBJ_id_pkix,10L
+
+#define SN_id_qcs		"id-qcs"
+#define NID_id_qcs		267
+#define OBJ_id_qcs		OBJ_id_pkix,11L
+
+#define SN_id_cct		"id-cct"
+#define NID_id_cct		268
+#define OBJ_id_cct		OBJ_id_pkix,12L
+
+#define SN_id_ppl		"id-ppl"
+#define NID_id_ppl		662
+#define OBJ_id_ppl		OBJ_id_pkix,21L
+
+#define SN_id_ad		"id-ad"
+#define NID_id_ad		176
+#define OBJ_id_ad		OBJ_id_pkix,48L
+
+#define SN_id_pkix1_explicit_88		"id-pkix1-explicit-88"
+#define NID_id_pkix1_explicit_88		269
+#define OBJ_id_pkix1_explicit_88		OBJ_id_pkix_mod,1L
+
+#define SN_id_pkix1_implicit_88		"id-pkix1-implicit-88"
+#define NID_id_pkix1_implicit_88		270
+#define OBJ_id_pkix1_implicit_88		OBJ_id_pkix_mod,2L
+
+#define SN_id_pkix1_explicit_93		"id-pkix1-explicit-93"
+#define NID_id_pkix1_explicit_93		271
+#define OBJ_id_pkix1_explicit_93		OBJ_id_pkix_mod,3L
+
+#define SN_id_pkix1_implicit_93		"id-pkix1-implicit-93"
+#define NID_id_pkix1_implicit_93		272
+#define OBJ_id_pkix1_implicit_93		OBJ_id_pkix_mod,4L
+
+#define SN_id_mod_crmf		"id-mod-crmf"
+#define NID_id_mod_crmf		273
+#define OBJ_id_mod_crmf		OBJ_id_pkix_mod,5L
+
+#define SN_id_mod_cmc		"id-mod-cmc"
+#define NID_id_mod_cmc		274
+#define OBJ_id_mod_cmc		OBJ_id_pkix_mod,6L
+
+#define SN_id_mod_kea_profile_88		"id-mod-kea-profile-88"
+#define NID_id_mod_kea_profile_88		275
+#define OBJ_id_mod_kea_profile_88		OBJ_id_pkix_mod,7L
+
+#define SN_id_mod_kea_profile_93		"id-mod-kea-profile-93"
+#define NID_id_mod_kea_profile_93		276
+#define OBJ_id_mod_kea_profile_93		OBJ_id_pkix_mod,8L
+
+#define SN_id_mod_cmp		"id-mod-cmp"
+#define NID_id_mod_cmp		277
+#define OBJ_id_mod_cmp		OBJ_id_pkix_mod,9L
+
+#define SN_id_mod_qualified_cert_88		"id-mod-qualified-cert-88"
+#define NID_id_mod_qualified_cert_88		278
+#define OBJ_id_mod_qualified_cert_88		OBJ_id_pkix_mod,10L
+
+#define SN_id_mod_qualified_cert_93		"id-mod-qualified-cert-93"
+#define NID_id_mod_qualified_cert_93		279
+#define OBJ_id_mod_qualified_cert_93		OBJ_id_pkix_mod,11L
+
+#define SN_id_mod_attribute_cert		"id-mod-attribute-cert"
+#define NID_id_mod_attribute_cert		280
+#define OBJ_id_mod_attribute_cert		OBJ_id_pkix_mod,12L
+
+#define SN_id_mod_timestamp_protocol		"id-mod-timestamp-protocol"
+#define NID_id_mod_timestamp_protocol		281
+#define OBJ_id_mod_timestamp_protocol		OBJ_id_pkix_mod,13L
+
+#define SN_id_mod_ocsp		"id-mod-ocsp"
+#define NID_id_mod_ocsp		282
+#define OBJ_id_mod_ocsp		OBJ_id_pkix_mod,14L
+
+#define SN_id_mod_dvcs		"id-mod-dvcs"
+#define NID_id_mod_dvcs		283
+#define OBJ_id_mod_dvcs		OBJ_id_pkix_mod,15L
+
+#define SN_id_mod_cmp2000		"id-mod-cmp2000"
+#define NID_id_mod_cmp2000		284
+#define OBJ_id_mod_cmp2000		OBJ_id_pkix_mod,16L
+
+#define SN_info_access		"authorityInfoAccess"
+#define LN_info_access		"Authority Information Access"
+#define NID_info_access		177
+#define OBJ_info_access		OBJ_id_pe,1L
+
+#define SN_biometricInfo		"biometricInfo"
+#define LN_biometricInfo		"Biometric Info"
+#define NID_biometricInfo		285
+#define OBJ_biometricInfo		OBJ_id_pe,2L
+
+#define SN_qcStatements		"qcStatements"
+#define NID_qcStatements		286
+#define OBJ_qcStatements		OBJ_id_pe,3L
+
+#define SN_ac_auditEntity		"ac-auditEntity"
+#define NID_ac_auditEntity		287
+#define OBJ_ac_auditEntity		OBJ_id_pe,4L
+
+#define SN_ac_targeting		"ac-targeting"
+#define NID_ac_targeting		288
+#define OBJ_ac_targeting		OBJ_id_pe,5L
+
+#define SN_aaControls		"aaControls"
+#define NID_aaControls		289
+#define OBJ_aaControls		OBJ_id_pe,6L
+
+#define SN_sbqp_ipAddrBlock		"sbqp-ipAddrBlock"
+#define NID_sbqp_ipAddrBlock		290
+#define OBJ_sbqp_ipAddrBlock		OBJ_id_pe,7L
+
+#define SN_sbqp_autonomousSysNum		"sbqp-autonomousSysNum"
+#define NID_sbqp_autonomousSysNum		291
+#define OBJ_sbqp_autonomousSysNum		OBJ_id_pe,8L
+
+#define SN_sbqp_routerIdentifier		"sbqp-routerIdentifier"
+#define NID_sbqp_routerIdentifier		292
+#define OBJ_sbqp_routerIdentifier		OBJ_id_pe,9L
+
+#define SN_ac_proxying		"ac-proxying"
+#define NID_ac_proxying		397
+#define OBJ_ac_proxying		OBJ_id_pe,10L
+
+#define SN_sinfo_access		"subjectInfoAccess"
+#define LN_sinfo_access		"Subject Information Access"
+#define NID_sinfo_access		398
+#define OBJ_sinfo_access		OBJ_id_pe,11L
+
+#define SN_proxyCertInfo		"proxyCertInfo"
+#define LN_proxyCertInfo		"Proxy Certificate Information"
+#define NID_proxyCertInfo		663
+#define OBJ_proxyCertInfo		OBJ_id_pe,14L
+
+#define SN_id_qt_cps		"id-qt-cps"
+#define LN_id_qt_cps		"Policy Qualifier CPS"
+#define NID_id_qt_cps		164
+#define OBJ_id_qt_cps		OBJ_id_qt,1L
+
+#define SN_id_qt_unotice		"id-qt-unotice"
+#define LN_id_qt_unotice		"Policy Qualifier User Notice"
+#define NID_id_qt_unotice		165
+#define OBJ_id_qt_unotice		OBJ_id_qt,2L
+
+#define SN_textNotice		"textNotice"
+#define NID_textNotice		293
+#define OBJ_textNotice		OBJ_id_qt,3L
+
+#define SN_server_auth		"serverAuth"
+#define LN_server_auth		"TLS Web Server Authentication"
+#define NID_server_auth		129
+#define OBJ_server_auth		OBJ_id_kp,1L
+
+#define SN_client_auth		"clientAuth"
+#define LN_client_auth		"TLS Web Client Authentication"
+#define NID_client_auth		130
+#define OBJ_client_auth		OBJ_id_kp,2L
+
+#define SN_code_sign		"codeSigning"
+#define LN_code_sign		"Code Signing"
+#define NID_code_sign		131
+#define OBJ_code_sign		OBJ_id_kp,3L
+
+#define SN_email_protect		"emailProtection"
+#define LN_email_protect		"E-mail Protection"
+#define NID_email_protect		132
+#define OBJ_email_protect		OBJ_id_kp,4L
+
+#define SN_ipsecEndSystem		"ipsecEndSystem"
+#define LN_ipsecEndSystem		"IPSec End System"
+#define NID_ipsecEndSystem		294
+#define OBJ_ipsecEndSystem		OBJ_id_kp,5L
+
+#define SN_ipsecTunnel		"ipsecTunnel"
+#define LN_ipsecTunnel		"IPSec Tunnel"
+#define NID_ipsecTunnel		295
+#define OBJ_ipsecTunnel		OBJ_id_kp,6L
+
+#define SN_ipsecUser		"ipsecUser"
+#define LN_ipsecUser		"IPSec User"
+#define NID_ipsecUser		296
+#define OBJ_ipsecUser		OBJ_id_kp,7L
+
+#define SN_time_stamp		"timeStamping"
+#define LN_time_stamp		"Time Stamping"
+#define NID_time_stamp		133
+#define OBJ_time_stamp		OBJ_id_kp,8L
+
+#define SN_OCSP_sign		"OCSPSigning"
+#define LN_OCSP_sign		"OCSP Signing"
+#define NID_OCSP_sign		180
+#define OBJ_OCSP_sign		OBJ_id_kp,9L
+
+#define SN_dvcs		"DVCS"
+#define LN_dvcs		"dvcs"
+#define NID_dvcs		297
+#define OBJ_dvcs		OBJ_id_kp,10L
+
+#define SN_id_it_caProtEncCert		"id-it-caProtEncCert"
+#define NID_id_it_caProtEncCert		298
+#define OBJ_id_it_caProtEncCert		OBJ_id_it,1L
+
+#define SN_id_it_signKeyPairTypes		"id-it-signKeyPairTypes"
+#define NID_id_it_signKeyPairTypes		299
+#define OBJ_id_it_signKeyPairTypes		OBJ_id_it,2L
+
+#define SN_id_it_encKeyPairTypes		"id-it-encKeyPairTypes"
+#define NID_id_it_encKeyPairTypes		300
+#define OBJ_id_it_encKeyPairTypes		OBJ_id_it,3L
+
+#define SN_id_it_preferredSymmAlg		"id-it-preferredSymmAlg"
+#define NID_id_it_preferredSymmAlg		301
+#define OBJ_id_it_preferredSymmAlg		OBJ_id_it,4L
+
+#define SN_id_it_caKeyUpdateInfo		"id-it-caKeyUpdateInfo"
+#define NID_id_it_caKeyUpdateInfo		302
+#define OBJ_id_it_caKeyUpdateInfo		OBJ_id_it,5L
+
+#define SN_id_it_currentCRL		"id-it-currentCRL"
+#define NID_id_it_currentCRL		303
+#define OBJ_id_it_currentCRL		OBJ_id_it,6L
+
+#define SN_id_it_unsupportedOIDs		"id-it-unsupportedOIDs"
+#define NID_id_it_unsupportedOIDs		304
+#define OBJ_id_it_unsupportedOIDs		OBJ_id_it,7L
+
+#define SN_id_it_subscriptionRequest		"id-it-subscriptionRequest"
+#define NID_id_it_subscriptionRequest		305
+#define OBJ_id_it_subscriptionRequest		OBJ_id_it,8L
+
+#define SN_id_it_subscriptionResponse		"id-it-subscriptionResponse"
+#define NID_id_it_subscriptionResponse		306
+#define OBJ_id_it_subscriptionResponse		OBJ_id_it,9L
+
+#define SN_id_it_keyPairParamReq		"id-it-keyPairParamReq"
+#define NID_id_it_keyPairParamReq		307
+#define OBJ_id_it_keyPairParamReq		OBJ_id_it,10L
+
+#define SN_id_it_keyPairParamRep		"id-it-keyPairParamRep"
+#define NID_id_it_keyPairParamRep		308
+#define OBJ_id_it_keyPairParamRep		OBJ_id_it,11L
+
+#define SN_id_it_revPassphrase		"id-it-revPassphrase"
+#define NID_id_it_revPassphrase		309
+#define OBJ_id_it_revPassphrase		OBJ_id_it,12L
+
+#define SN_id_it_implicitConfirm		"id-it-implicitConfirm"
+#define NID_id_it_implicitConfirm		310
+#define OBJ_id_it_implicitConfirm		OBJ_id_it,13L
+
+#define SN_id_it_confirmWaitTime		"id-it-confirmWaitTime"
+#define NID_id_it_confirmWaitTime		311
+#define OBJ_id_it_confirmWaitTime		OBJ_id_it,14L
+
+#define SN_id_it_origPKIMessage		"id-it-origPKIMessage"
+#define NID_id_it_origPKIMessage		312
+#define OBJ_id_it_origPKIMessage		OBJ_id_it,15L
+
+#define SN_id_regCtrl		"id-regCtrl"
+#define NID_id_regCtrl		313
+#define OBJ_id_regCtrl		OBJ_id_pkip,1L
+
+#define SN_id_regInfo		"id-regInfo"
+#define NID_id_regInfo		314
+#define OBJ_id_regInfo		OBJ_id_pkip,2L
+
+#define SN_id_regCtrl_regToken		"id-regCtrl-regToken"
+#define NID_id_regCtrl_regToken		315
+#define OBJ_id_regCtrl_regToken		OBJ_id_regCtrl,1L
+
+#define SN_id_regCtrl_authenticator		"id-regCtrl-authenticator"
+#define NID_id_regCtrl_authenticator		316
+#define OBJ_id_regCtrl_authenticator		OBJ_id_regCtrl,2L
+
+#define SN_id_regCtrl_pkiPublicationInfo		"id-regCtrl-pkiPublicationInfo"
+#define NID_id_regCtrl_pkiPublicationInfo		317
+#define OBJ_id_regCtrl_pkiPublicationInfo		OBJ_id_regCtrl,3L
+
+#define SN_id_regCtrl_pkiArchiveOptions		"id-regCtrl-pkiArchiveOptions"
+#define NID_id_regCtrl_pkiArchiveOptions		318
+#define OBJ_id_regCtrl_pkiArchiveOptions		OBJ_id_regCtrl,4L
+
+#define SN_id_regCtrl_oldCertID		"id-regCtrl-oldCertID"
+#define NID_id_regCtrl_oldCertID		319
+#define OBJ_id_regCtrl_oldCertID		OBJ_id_regCtrl,5L
+
+#define SN_id_regCtrl_protocolEncrKey		"id-regCtrl-protocolEncrKey"
+#define NID_id_regCtrl_protocolEncrKey		320
+#define OBJ_id_regCtrl_protocolEncrKey		OBJ_id_regCtrl,6L
+
+#define SN_id_regInfo_utf8Pairs		"id-regInfo-utf8Pairs"
+#define NID_id_regInfo_utf8Pairs		321
+#define OBJ_id_regInfo_utf8Pairs		OBJ_id_regInfo,1L
+
+#define SN_id_regInfo_certReq		"id-regInfo-certReq"
+#define NID_id_regInfo_certReq		322
+#define OBJ_id_regInfo_certReq		OBJ_id_regInfo,2L
+
+#define SN_id_alg_des40		"id-alg-des40"
+#define NID_id_alg_des40		323
+#define OBJ_id_alg_des40		OBJ_id_alg,1L
+
+#define SN_id_alg_noSignature		"id-alg-noSignature"
+#define NID_id_alg_noSignature		324
+#define OBJ_id_alg_noSignature		OBJ_id_alg,2L
+
+#define SN_id_alg_dh_sig_hmac_sha1		"id-alg-dh-sig-hmac-sha1"
+#define NID_id_alg_dh_sig_hmac_sha1		325
+#define OBJ_id_alg_dh_sig_hmac_sha1		OBJ_id_alg,3L
+
+#define SN_id_alg_dh_pop		"id-alg-dh-pop"
+#define NID_id_alg_dh_pop		326
+#define OBJ_id_alg_dh_pop		OBJ_id_alg,4L
+
+#define SN_id_cmc_statusInfo		"id-cmc-statusInfo"
+#define NID_id_cmc_statusInfo		327
+#define OBJ_id_cmc_statusInfo		OBJ_id_cmc,1L
+
+#define SN_id_cmc_identification		"id-cmc-identification"
+#define NID_id_cmc_identification		328
+#define OBJ_id_cmc_identification		OBJ_id_cmc,2L
+
+#define SN_id_cmc_identityProof		"id-cmc-identityProof"
+#define NID_id_cmc_identityProof		329
+#define OBJ_id_cmc_identityProof		OBJ_id_cmc,3L
+
+#define SN_id_cmc_dataReturn		"id-cmc-dataReturn"
+#define NID_id_cmc_dataReturn		330
+#define OBJ_id_cmc_dataReturn		OBJ_id_cmc,4L
+
+#define SN_id_cmc_transactionId		"id-cmc-transactionId"
+#define NID_id_cmc_transactionId		331
+#define OBJ_id_cmc_transactionId		OBJ_id_cmc,5L
+
+#define SN_id_cmc_senderNonce		"id-cmc-senderNonce"
+#define NID_id_cmc_senderNonce		332
+#define OBJ_id_cmc_senderNonce		OBJ_id_cmc,6L
+
+#define SN_id_cmc_recipientNonce		"id-cmc-recipientNonce"
+#define NID_id_cmc_recipientNonce		333
+#define OBJ_id_cmc_recipientNonce		OBJ_id_cmc,7L
+
+#define SN_id_cmc_addExtensions		"id-cmc-addExtensions"
+#define NID_id_cmc_addExtensions		334
+#define OBJ_id_cmc_addExtensions		OBJ_id_cmc,8L
+
+#define SN_id_cmc_encryptedPOP		"id-cmc-encryptedPOP"
+#define NID_id_cmc_encryptedPOP		335
+#define OBJ_id_cmc_encryptedPOP		OBJ_id_cmc,9L
+
+#define SN_id_cmc_decryptedPOP		"id-cmc-decryptedPOP"
+#define NID_id_cmc_decryptedPOP		336
+#define OBJ_id_cmc_decryptedPOP		OBJ_id_cmc,10L
+
+#define SN_id_cmc_lraPOPWitness		"id-cmc-lraPOPWitness"
+#define NID_id_cmc_lraPOPWitness		337
+#define OBJ_id_cmc_lraPOPWitness		OBJ_id_cmc,11L
+
+#define SN_id_cmc_getCert		"id-cmc-getCert"
+#define NID_id_cmc_getCert		338
+#define OBJ_id_cmc_getCert		OBJ_id_cmc,15L
+
+#define SN_id_cmc_getCRL		"id-cmc-getCRL"
+#define NID_id_cmc_getCRL		339
+#define OBJ_id_cmc_getCRL		OBJ_id_cmc,16L
+
+#define SN_id_cmc_revokeRequest		"id-cmc-revokeRequest"
+#define NID_id_cmc_revokeRequest		340
+#define OBJ_id_cmc_revokeRequest		OBJ_id_cmc,17L
+
+#define SN_id_cmc_regInfo		"id-cmc-regInfo"
+#define NID_id_cmc_regInfo		341
+#define OBJ_id_cmc_regInfo		OBJ_id_cmc,18L
+
+#define SN_id_cmc_responseInfo		"id-cmc-responseInfo"
+#define NID_id_cmc_responseInfo		342
+#define OBJ_id_cmc_responseInfo		OBJ_id_cmc,19L
+
+#define SN_id_cmc_queryPending		"id-cmc-queryPending"
+#define NID_id_cmc_queryPending		343
+#define OBJ_id_cmc_queryPending		OBJ_id_cmc,21L
+
+#define SN_id_cmc_popLinkRandom		"id-cmc-popLinkRandom"
+#define NID_id_cmc_popLinkRandom		344
+#define OBJ_id_cmc_popLinkRandom		OBJ_id_cmc,22L
+
+#define SN_id_cmc_popLinkWitness		"id-cmc-popLinkWitness"
+#define NID_id_cmc_popLinkWitness		345
+#define OBJ_id_cmc_popLinkWitness		OBJ_id_cmc,23L
+
+#define SN_id_cmc_confirmCertAcceptance		"id-cmc-confirmCertAcceptance"
+#define NID_id_cmc_confirmCertAcceptance		346
+#define OBJ_id_cmc_confirmCertAcceptance		OBJ_id_cmc,24L
+
+#define SN_id_on_personalData		"id-on-personalData"
+#define NID_id_on_personalData		347
+#define OBJ_id_on_personalData		OBJ_id_on,1L
+
+#define SN_id_pda_dateOfBirth		"id-pda-dateOfBirth"
+#define NID_id_pda_dateOfBirth		348
+#define OBJ_id_pda_dateOfBirth		OBJ_id_pda,1L
+
+#define SN_id_pda_placeOfBirth		"id-pda-placeOfBirth"
+#define NID_id_pda_placeOfBirth		349
+#define OBJ_id_pda_placeOfBirth		OBJ_id_pda,2L
+
+#define SN_id_pda_gender		"id-pda-gender"
+#define NID_id_pda_gender		351
+#define OBJ_id_pda_gender		OBJ_id_pda,3L
+
+#define SN_id_pda_countryOfCitizenship		"id-pda-countryOfCitizenship"
+#define NID_id_pda_countryOfCitizenship		352
+#define OBJ_id_pda_countryOfCitizenship		OBJ_id_pda,4L
+
+#define SN_id_pda_countryOfResidence		"id-pda-countryOfResidence"
+#define NID_id_pda_countryOfResidence		353
+#define OBJ_id_pda_countryOfResidence		OBJ_id_pda,5L
+
+#define SN_id_aca_authenticationInfo		"id-aca-authenticationInfo"
+#define NID_id_aca_authenticationInfo		354
+#define OBJ_id_aca_authenticationInfo		OBJ_id_aca,1L
+
+#define SN_id_aca_accessIdentity		"id-aca-accessIdentity"
+#define NID_id_aca_accessIdentity		355
+#define OBJ_id_aca_accessIdentity		OBJ_id_aca,2L
+
+#define SN_id_aca_chargingIdentity		"id-aca-chargingIdentity"
+#define NID_id_aca_chargingIdentity		356
+#define OBJ_id_aca_chargingIdentity		OBJ_id_aca,3L
+
+#define SN_id_aca_group		"id-aca-group"
+#define NID_id_aca_group		357
+#define OBJ_id_aca_group		OBJ_id_aca,4L
+
+#define SN_id_aca_role		"id-aca-role"
+#define NID_id_aca_role		358
+#define OBJ_id_aca_role		OBJ_id_aca,5L
+
+#define SN_id_aca_encAttrs		"id-aca-encAttrs"
+#define NID_id_aca_encAttrs		399
+#define OBJ_id_aca_encAttrs		OBJ_id_aca,6L
+
+#define SN_id_qcs_pkixQCSyntax_v1		"id-qcs-pkixQCSyntax-v1"
+#define NID_id_qcs_pkixQCSyntax_v1		359
+#define OBJ_id_qcs_pkixQCSyntax_v1		OBJ_id_qcs,1L
+
+#define SN_id_cct_crs		"id-cct-crs"
+#define NID_id_cct_crs		360
+#define OBJ_id_cct_crs		OBJ_id_cct,1L
+
+#define SN_id_cct_PKIData		"id-cct-PKIData"
+#define NID_id_cct_PKIData		361
+#define OBJ_id_cct_PKIData		OBJ_id_cct,2L
+
+#define SN_id_cct_PKIResponse		"id-cct-PKIResponse"
+#define NID_id_cct_PKIResponse		362
+#define OBJ_id_cct_PKIResponse		OBJ_id_cct,3L
+
+#define SN_id_ppl_anyLanguage		"id-ppl-anyLanguage"
+#define LN_id_ppl_anyLanguage		"Any language"
+#define NID_id_ppl_anyLanguage		664
+#define OBJ_id_ppl_anyLanguage		OBJ_id_ppl,0L
+
+#define SN_id_ppl_inheritAll		"id-ppl-inheritAll"
+#define LN_id_ppl_inheritAll		"Inherit all"
+#define NID_id_ppl_inheritAll		665
+#define OBJ_id_ppl_inheritAll		OBJ_id_ppl,1L
+
+#define SN_Independent		"id-ppl-independent"
+#define LN_Independent		"Independent"
+#define NID_Independent		667
+#define OBJ_Independent		OBJ_id_ppl,2L
+
+#define SN_ad_OCSP		"OCSP"
+#define LN_ad_OCSP		"OCSP"
+#define NID_ad_OCSP		178
+#define OBJ_ad_OCSP		OBJ_id_ad,1L
+
+#define SN_ad_ca_issuers		"caIssuers"
+#define LN_ad_ca_issuers		"CA Issuers"
+#define NID_ad_ca_issuers		179
+#define OBJ_ad_ca_issuers		OBJ_id_ad,2L
+
+#define SN_ad_timeStamping		"ad_timestamping"
+#define LN_ad_timeStamping		"AD Time Stamping"
+#define NID_ad_timeStamping		363
+#define OBJ_ad_timeStamping		OBJ_id_ad,3L
+
+#define SN_ad_dvcs		"AD_DVCS"
+#define LN_ad_dvcs		"ad dvcs"
+#define NID_ad_dvcs		364
+#define OBJ_ad_dvcs		OBJ_id_ad,4L
+
+#define OBJ_id_pkix_OCSP		OBJ_ad_OCSP
+
+#define SN_id_pkix_OCSP_basic		"basicOCSPResponse"
+#define LN_id_pkix_OCSP_basic		"Basic OCSP Response"
+#define NID_id_pkix_OCSP_basic		365
+#define OBJ_id_pkix_OCSP_basic		OBJ_id_pkix_OCSP,1L
+
+#define SN_id_pkix_OCSP_Nonce		"Nonce"
+#define LN_id_pkix_OCSP_Nonce		"OCSP Nonce"
+#define NID_id_pkix_OCSP_Nonce		366
+#define OBJ_id_pkix_OCSP_Nonce		OBJ_id_pkix_OCSP,2L
+
+#define SN_id_pkix_OCSP_CrlID		"CrlID"
+#define LN_id_pkix_OCSP_CrlID		"OCSP CRL ID"
+#define NID_id_pkix_OCSP_CrlID		367
+#define OBJ_id_pkix_OCSP_CrlID		OBJ_id_pkix_OCSP,3L
+
+#define SN_id_pkix_OCSP_acceptableResponses		"acceptableResponses"
+#define LN_id_pkix_OCSP_acceptableResponses		"Acceptable OCSP Responses"
+#define NID_id_pkix_OCSP_acceptableResponses		368
+#define OBJ_id_pkix_OCSP_acceptableResponses		OBJ_id_pkix_OCSP,4L
+
+#define SN_id_pkix_OCSP_noCheck		"noCheck"
+#define LN_id_pkix_OCSP_noCheck		"OCSP No Check"
+#define NID_id_pkix_OCSP_noCheck		369
+#define OBJ_id_pkix_OCSP_noCheck		OBJ_id_pkix_OCSP,5L
+
+#define SN_id_pkix_OCSP_archiveCutoff		"archiveCutoff"
+#define LN_id_pkix_OCSP_archiveCutoff		"OCSP Archive Cutoff"
+#define NID_id_pkix_OCSP_archiveCutoff		370
+#define OBJ_id_pkix_OCSP_archiveCutoff		OBJ_id_pkix_OCSP,6L
+
+#define SN_id_pkix_OCSP_serviceLocator		"serviceLocator"
+#define LN_id_pkix_OCSP_serviceLocator		"OCSP Service Locator"
+#define NID_id_pkix_OCSP_serviceLocator		371
+#define OBJ_id_pkix_OCSP_serviceLocator		OBJ_id_pkix_OCSP,7L
+
+#define SN_id_pkix_OCSP_extendedStatus		"extendedStatus"
+#define LN_id_pkix_OCSP_extendedStatus		"Extended OCSP Status"
+#define NID_id_pkix_OCSP_extendedStatus		372
+#define OBJ_id_pkix_OCSP_extendedStatus		OBJ_id_pkix_OCSP,8L
+
+#define SN_id_pkix_OCSP_valid		"valid"
+#define NID_id_pkix_OCSP_valid		373
+#define OBJ_id_pkix_OCSP_valid		OBJ_id_pkix_OCSP,9L
+
+#define SN_id_pkix_OCSP_path		"path"
+#define NID_id_pkix_OCSP_path		374
+#define OBJ_id_pkix_OCSP_path		OBJ_id_pkix_OCSP,10L
+
+#define SN_id_pkix_OCSP_trustRoot		"trustRoot"
+#define LN_id_pkix_OCSP_trustRoot		"Trust Root"
+#define NID_id_pkix_OCSP_trustRoot		375
+#define OBJ_id_pkix_OCSP_trustRoot		OBJ_id_pkix_OCSP,11L
+
+#define SN_algorithm		"algorithm"
+#define LN_algorithm		"algorithm"
+#define NID_algorithm		376
+#define OBJ_algorithm		1L,3L,14L,3L,2L
+
+#define SN_md5WithRSA		"RSA-NP-MD5"
+#define LN_md5WithRSA		"md5WithRSA"
+#define NID_md5WithRSA		104
+#define OBJ_md5WithRSA		OBJ_algorithm,3L
+
+#define SN_des_ecb		"DES-ECB"
+#define LN_des_ecb		"des-ecb"
+#define NID_des_ecb		29
+#define OBJ_des_ecb		OBJ_algorithm,6L
+
+#define SN_des_cbc		"DES-CBC"
+#define LN_des_cbc		"des-cbc"
+#define NID_des_cbc		31
+#define OBJ_des_cbc		OBJ_algorithm,7L
+
+#define SN_des_ofb64		"DES-OFB"
+#define LN_des_ofb64		"des-ofb"
+#define NID_des_ofb64		45
+#define OBJ_des_ofb64		OBJ_algorithm,8L
+
+#define SN_des_cfb64		"DES-CFB"
+#define LN_des_cfb64		"des-cfb"
+#define NID_des_cfb64		30
+#define OBJ_des_cfb64		OBJ_algorithm,9L
+
+#define SN_rsaSignature		"rsaSignature"
+#define NID_rsaSignature		377
+#define OBJ_rsaSignature		OBJ_algorithm,11L
+
+#define SN_dsa_2		"DSA-old"
+#define LN_dsa_2		"dsaEncryption-old"
+#define NID_dsa_2		67
+#define OBJ_dsa_2		OBJ_algorithm,12L
+
+#define SN_dsaWithSHA		"DSA-SHA"
+#define LN_dsaWithSHA		"dsaWithSHA"
+#define NID_dsaWithSHA		66
+#define OBJ_dsaWithSHA		OBJ_algorithm,13L
+
+#define SN_shaWithRSAEncryption		"RSA-SHA"
+#define LN_shaWithRSAEncryption		"shaWithRSAEncryption"
+#define NID_shaWithRSAEncryption		42
+#define OBJ_shaWithRSAEncryption		OBJ_algorithm,15L
+
+#define SN_des_ede_ecb		"DES-EDE"
+#define LN_des_ede_ecb		"des-ede"
+#define NID_des_ede_ecb		32
+#define OBJ_des_ede_ecb		OBJ_algorithm,17L
+
+#define SN_des_ede3_ecb		"DES-EDE3"
+#define LN_des_ede3_ecb		"des-ede3"
+#define NID_des_ede3_ecb		33
+
+#define SN_des_ede_cbc		"DES-EDE-CBC"
+#define LN_des_ede_cbc		"des-ede-cbc"
+#define NID_des_ede_cbc		43
+
+#define SN_des_ede_cfb64		"DES-EDE-CFB"
+#define LN_des_ede_cfb64		"des-ede-cfb"
+#define NID_des_ede_cfb64		60
+
+#define SN_des_ede3_cfb64		"DES-EDE3-CFB"
+#define LN_des_ede3_cfb64		"des-ede3-cfb"
+#define NID_des_ede3_cfb64		61
+
+#define SN_des_ede_ofb64		"DES-EDE-OFB"
+#define LN_des_ede_ofb64		"des-ede-ofb"
+#define NID_des_ede_ofb64		62
+
+#define SN_des_ede3_ofb64		"DES-EDE3-OFB"
+#define LN_des_ede3_ofb64		"des-ede3-ofb"
+#define NID_des_ede3_ofb64		63
+
+#define SN_desx_cbc		"DESX-CBC"
+#define LN_desx_cbc		"desx-cbc"
+#define NID_desx_cbc		80
+
+#define SN_sha		"SHA"
+#define LN_sha		"sha"
+#define NID_sha		41
+#define OBJ_sha		OBJ_algorithm,18L
+
+#define SN_sha1		"SHA1"
+#define LN_sha1		"sha1"
+#define NID_sha1		64
+#define OBJ_sha1		OBJ_algorithm,26L
+
+#define SN_dsaWithSHA1_2		"DSA-SHA1-old"
+#define LN_dsaWithSHA1_2		"dsaWithSHA1-old"
+#define NID_dsaWithSHA1_2		70
+#define OBJ_dsaWithSHA1_2		OBJ_algorithm,27L
+
+#define SN_sha1WithRSA		"RSA-SHA1-2"
+#define LN_sha1WithRSA		"sha1WithRSA"
+#define NID_sha1WithRSA		115
+#define OBJ_sha1WithRSA		OBJ_algorithm,29L
+
+#define SN_ripemd160		"RIPEMD160"
+#define LN_ripemd160		"ripemd160"
+#define NID_ripemd160		117
+#define OBJ_ripemd160		1L,3L,36L,3L,2L,1L
+
+#define SN_ripemd160WithRSA		"RSA-RIPEMD160"
+#define LN_ripemd160WithRSA		"ripemd160WithRSA"
+#define NID_ripemd160WithRSA		119
+#define OBJ_ripemd160WithRSA		1L,3L,36L,3L,3L,1L,2L
+
+#define SN_sxnet		"SXNetID"
+#define LN_sxnet		"Strong Extranet ID"
+#define NID_sxnet		143
+#define OBJ_sxnet		1L,3L,101L,1L,4L,1L
+
+#define SN_X500		"X500"
+#define LN_X500		"directory services (X.500)"
+#define NID_X500		11
+#define OBJ_X500		2L,5L
+
+#define SN_X509		"X509"
+#define NID_X509		12
+#define OBJ_X509		OBJ_X500,4L
+
+#define SN_commonName		"CN"
+#define LN_commonName		"commonName"
+#define NID_commonName		13
+#define OBJ_commonName		OBJ_X509,3L
+
+#define SN_surname		"SN"
+#define LN_surname		"surname"
+#define NID_surname		100
+#define OBJ_surname		OBJ_X509,4L
+
+#define LN_serialNumber		"serialNumber"
+#define NID_serialNumber		105
+#define OBJ_serialNumber		OBJ_X509,5L
+
+#define SN_countryName		"C"
+#define LN_countryName		"countryName"
+#define NID_countryName		14
+#define OBJ_countryName		OBJ_X509,6L
+
+#define SN_localityName		"L"
+#define LN_localityName		"localityName"
+#define NID_localityName		15
+#define OBJ_localityName		OBJ_X509,7L
+
+#define SN_stateOrProvinceName		"ST"
+#define LN_stateOrProvinceName		"stateOrProvinceName"
+#define NID_stateOrProvinceName		16
+#define OBJ_stateOrProvinceName		OBJ_X509,8L
+
+#define LN_streetAddress		"streetAddress"
+#define NID_streetAddress		660
+#define OBJ_streetAddress		OBJ_X509,9L
+
+#define SN_organizationName		"O"
+#define LN_organizationName		"organizationName"
+#define NID_organizationName		17
+#define OBJ_organizationName		OBJ_X509,10L
+
+#define SN_organizationalUnitName		"OU"
+#define LN_organizationalUnitName		"organizationalUnitName"
+#define NID_organizationalUnitName		18
+#define OBJ_organizationalUnitName		OBJ_X509,11L
+
+#define LN_title		"title"
+#define NID_title		106
+#define OBJ_title		OBJ_X509,12L
+
+#define LN_description		"description"
+#define NID_description		107
+#define OBJ_description		OBJ_X509,13L
+
+#define LN_postalCode		"postalCode"
+#define NID_postalCode		661
+#define OBJ_postalCode		OBJ_X509,17L
+
+#define SN_name		"name"
+#define LN_name		"name"
+#define NID_name		173
+#define OBJ_name		OBJ_X509,41L
+
+#define SN_givenName		"GN"
+#define LN_givenName		"givenName"
+#define NID_givenName		99
+#define OBJ_givenName		OBJ_X509,42L
+
+#define LN_initials		"initials"
+#define NID_initials		101
+#define OBJ_initials		OBJ_X509,43L
+
+#define LN_generationQualifier		"generationQualifier"
+#define NID_generationQualifier		509
+#define OBJ_generationQualifier		OBJ_X509,44L
+
+#define LN_x500UniqueIdentifier		"x500UniqueIdentifier"
+#define NID_x500UniqueIdentifier		503
+#define OBJ_x500UniqueIdentifier		OBJ_X509,45L
+
+#define SN_dnQualifier		"dnQualifier"
+#define LN_dnQualifier		"dnQualifier"
+#define NID_dnQualifier		174
+#define OBJ_dnQualifier		OBJ_X509,46L
+
+#define LN_pseudonym		"pseudonym"
+#define NID_pseudonym		510
+#define OBJ_pseudonym		OBJ_X509,65L
+
+#define SN_role		"role"
+#define LN_role		"role"
+#define NID_role		400
+#define OBJ_role		OBJ_X509,72L
+
+#define SN_X500algorithms		"X500algorithms"
+#define LN_X500algorithms		"directory services - algorithms"
+#define NID_X500algorithms		378
+#define OBJ_X500algorithms		OBJ_X500,8L
+
+#define SN_rsa		"RSA"
+#define LN_rsa		"rsa"
+#define NID_rsa		19
+#define OBJ_rsa		OBJ_X500algorithms,1L,1L
+
+#define SN_mdc2WithRSA		"RSA-MDC2"
+#define LN_mdc2WithRSA		"mdc2WithRSA"
+#define NID_mdc2WithRSA		96
+#define OBJ_mdc2WithRSA		OBJ_X500algorithms,3L,100L
+
+#define SN_mdc2		"MDC2"
+#define LN_mdc2		"mdc2"
+#define NID_mdc2		95
+#define OBJ_mdc2		OBJ_X500algorithms,3L,101L
+
+#define SN_id_ce		"id-ce"
+#define NID_id_ce		81
+#define OBJ_id_ce		OBJ_X500,29L
+
+#define SN_subject_key_identifier		"subjectKeyIdentifier"
+#define LN_subject_key_identifier		"X509v3 Subject Key Identifier"
+#define NID_subject_key_identifier		82
+#define OBJ_subject_key_identifier		OBJ_id_ce,14L
+
+#define SN_key_usage		"keyUsage"
+#define LN_key_usage		"X509v3 Key Usage"
+#define NID_key_usage		83
+#define OBJ_key_usage		OBJ_id_ce,15L
+
+#define SN_private_key_usage_period		"privateKeyUsagePeriod"
+#define LN_private_key_usage_period		"X509v3 Private Key Usage Period"
+#define NID_private_key_usage_period		84
+#define OBJ_private_key_usage_period		OBJ_id_ce,16L
+
+#define SN_subject_alt_name		"subjectAltName"
+#define LN_subject_alt_name		"X509v3 Subject Alternative Name"
+#define NID_subject_alt_name		85
+#define OBJ_subject_alt_name		OBJ_id_ce,17L
+
+#define SN_issuer_alt_name		"issuerAltName"
+#define LN_issuer_alt_name		"X509v3 Issuer Alternative Name"
+#define NID_issuer_alt_name		86
+#define OBJ_issuer_alt_name		OBJ_id_ce,18L
+
+#define SN_basic_constraints		"basicConstraints"
+#define LN_basic_constraints		"X509v3 Basic Constraints"
+#define NID_basic_constraints		87
+#define OBJ_basic_constraints		OBJ_id_ce,19L
+
+#define SN_crl_number		"crlNumber"
+#define LN_crl_number		"X509v3 CRL Number"
+#define NID_crl_number		88
+#define OBJ_crl_number		OBJ_id_ce,20L
+
+#define SN_crl_reason		"CRLReason"
+#define LN_crl_reason		"X509v3 CRL Reason Code"
+#define NID_crl_reason		141
+#define OBJ_crl_reason		OBJ_id_ce,21L
+
+#define SN_invalidity_date		"invalidityDate"
+#define LN_invalidity_date		"Invalidity Date"
+#define NID_invalidity_date		142
+#define OBJ_invalidity_date		OBJ_id_ce,24L
+
+#define SN_delta_crl		"deltaCRL"
+#define LN_delta_crl		"X509v3 Delta CRL Indicator"
+#define NID_delta_crl		140
+#define OBJ_delta_crl		OBJ_id_ce,27L
+
+#define SN_name_constraints		"nameConstraints"
+#define LN_name_constraints		"X509v3 Name Constraints"
+#define NID_name_constraints		666
+#define OBJ_name_constraints		OBJ_id_ce,30L
+
+#define SN_crl_distribution_points		"crlDistributionPoints"
+#define LN_crl_distribution_points		"X509v3 CRL Distribution Points"
+#define NID_crl_distribution_points		103
+#define OBJ_crl_distribution_points		OBJ_id_ce,31L
+
+#define SN_certificate_policies		"certificatePolicies"
+#define LN_certificate_policies		"X509v3 Certificate Policies"
+#define NID_certificate_policies		89
+#define OBJ_certificate_policies		OBJ_id_ce,32L
+
+#define SN_any_policy		"anyPolicy"
+#define LN_any_policy		"X509v3 Any Policy"
+#define NID_any_policy		746
+#define OBJ_any_policy		OBJ_certificate_policies,0L
+
+#define SN_policy_mappings		"policyMappings"
+#define LN_policy_mappings		"X509v3 Policy Mappings"
+#define NID_policy_mappings		747
+#define OBJ_policy_mappings		OBJ_id_ce,33L
+
+#define SN_authority_key_identifier		"authorityKeyIdentifier"
+#define LN_authority_key_identifier		"X509v3 Authority Key Identifier"
+#define NID_authority_key_identifier		90
+#define OBJ_authority_key_identifier		OBJ_id_ce,35L
+
+#define SN_policy_constraints		"policyConstraints"
+#define LN_policy_constraints		"X509v3 Policy Constraints"
+#define NID_policy_constraints		401
+#define OBJ_policy_constraints		OBJ_id_ce,36L
+
+#define SN_ext_key_usage		"extendedKeyUsage"
+#define LN_ext_key_usage		"X509v3 Extended Key Usage"
+#define NID_ext_key_usage		126
+#define OBJ_ext_key_usage		OBJ_id_ce,37L
+
+#define SN_inhibit_any_policy		"inhibitAnyPolicy"
+#define LN_inhibit_any_policy		"X509v3 Inhibit Any Policy"
+#define NID_inhibit_any_policy		748
+#define OBJ_inhibit_any_policy		OBJ_id_ce,54L
+
+#define SN_target_information		"targetInformation"
+#define LN_target_information		"X509v3 AC Targeting"
+#define NID_target_information		402
+#define OBJ_target_information		OBJ_id_ce,55L
+
+#define SN_no_rev_avail		"noRevAvail"
+#define LN_no_rev_avail		"X509v3 No Revocation Available"
+#define NID_no_rev_avail		403
+#define OBJ_no_rev_avail		OBJ_id_ce,56L
+
+#define SN_netscape		"Netscape"
+#define LN_netscape		"Netscape Communications Corp."
+#define NID_netscape		57
+#define OBJ_netscape		2L,16L,840L,1L,113730L
+
+#define SN_netscape_cert_extension		"nsCertExt"
+#define LN_netscape_cert_extension		"Netscape Certificate Extension"
+#define NID_netscape_cert_extension		58
+#define OBJ_netscape_cert_extension		OBJ_netscape,1L
+
+#define SN_netscape_data_type		"nsDataType"
+#define LN_netscape_data_type		"Netscape Data Type"
+#define NID_netscape_data_type		59
+#define OBJ_netscape_data_type		OBJ_netscape,2L
+
+#define SN_netscape_cert_type		"nsCertType"
+#define LN_netscape_cert_type		"Netscape Cert Type"
+#define NID_netscape_cert_type		71
+#define OBJ_netscape_cert_type		OBJ_netscape_cert_extension,1L
+
+#define SN_netscape_base_url		"nsBaseUrl"
+#define LN_netscape_base_url		"Netscape Base Url"
+#define NID_netscape_base_url		72
+#define OBJ_netscape_base_url		OBJ_netscape_cert_extension,2L
+
+#define SN_netscape_revocation_url		"nsRevocationUrl"
+#define LN_netscape_revocation_url		"Netscape Revocation Url"
+#define NID_netscape_revocation_url		73
+#define OBJ_netscape_revocation_url		OBJ_netscape_cert_extension,3L
+
+#define SN_netscape_ca_revocation_url		"nsCaRevocationUrl"
+#define LN_netscape_ca_revocation_url		"Netscape CA Revocation Url"
+#define NID_netscape_ca_revocation_url		74
+#define OBJ_netscape_ca_revocation_url		OBJ_netscape_cert_extension,4L
+
+#define SN_netscape_renewal_url		"nsRenewalUrl"
+#define LN_netscape_renewal_url		"Netscape Renewal Url"
+#define NID_netscape_renewal_url		75
+#define OBJ_netscape_renewal_url		OBJ_netscape_cert_extension,7L
+
+#define SN_netscape_ca_policy_url		"nsCaPolicyUrl"
+#define LN_netscape_ca_policy_url		"Netscape CA Policy Url"
+#define NID_netscape_ca_policy_url		76
+#define OBJ_netscape_ca_policy_url		OBJ_netscape_cert_extension,8L
+
+#define SN_netscape_ssl_server_name		"nsSslServerName"
+#define LN_netscape_ssl_server_name		"Netscape SSL Server Name"
+#define NID_netscape_ssl_server_name		77
+#define OBJ_netscape_ssl_server_name		OBJ_netscape_cert_extension,12L
+
+#define SN_netscape_comment		"nsComment"
+#define LN_netscape_comment		"Netscape Comment"
+#define NID_netscape_comment		78
+#define OBJ_netscape_comment		OBJ_netscape_cert_extension,13L
+
+#define SN_netscape_cert_sequence		"nsCertSequence"
+#define LN_netscape_cert_sequence		"Netscape Certificate Sequence"
+#define NID_netscape_cert_sequence		79
+#define OBJ_netscape_cert_sequence		OBJ_netscape_data_type,5L
+
+#define SN_ns_sgc		"nsSGC"
+#define LN_ns_sgc		"Netscape Server Gated Crypto"
+#define NID_ns_sgc		139
+#define OBJ_ns_sgc		OBJ_netscape,4L,1L
+
+#define SN_org		"ORG"
+#define LN_org		"org"
+#define NID_org		379
+#define OBJ_org		OBJ_iso,3L
+
+#define SN_dod		"DOD"
+#define LN_dod		"dod"
+#define NID_dod		380
+#define OBJ_dod		OBJ_org,6L
+
+#define SN_iana		"IANA"
+#define LN_iana		"iana"
+#define NID_iana		381
+#define OBJ_iana		OBJ_dod,1L
+
+#define OBJ_internet		OBJ_iana
+
+#define SN_Directory		"directory"
+#define LN_Directory		"Directory"
+#define NID_Directory		382
+#define OBJ_Directory		OBJ_internet,1L
+
+#define SN_Management		"mgmt"
+#define LN_Management		"Management"
+#define NID_Management		383
+#define OBJ_Management		OBJ_internet,2L
+
+#define SN_Experimental		"experimental"
+#define LN_Experimental		"Experimental"
+#define NID_Experimental		384
+#define OBJ_Experimental		OBJ_internet,3L
+
+#define SN_Private		"private"
+#define LN_Private		"Private"
+#define NID_Private		385
+#define OBJ_Private		OBJ_internet,4L
+
+#define SN_Security		"security"
+#define LN_Security		"Security"
+#define NID_Security		386
+#define OBJ_Security		OBJ_internet,5L
+
+#define SN_SNMPv2		"snmpv2"
+#define LN_SNMPv2		"SNMPv2"
+#define NID_SNMPv2		387
+#define OBJ_SNMPv2		OBJ_internet,6L
+
+#define LN_Mail		"Mail"
+#define NID_Mail		388
+#define OBJ_Mail		OBJ_internet,7L
+
+#define SN_Enterprises		"enterprises"
+#define LN_Enterprises		"Enterprises"
+#define NID_Enterprises		389
+#define OBJ_Enterprises		OBJ_Private,1L
+
+#define SN_dcObject		"dcobject"
+#define LN_dcObject		"dcObject"
+#define NID_dcObject		390
+#define OBJ_dcObject		OBJ_Enterprises,1466L,344L
+
+#define SN_mime_mhs		"mime-mhs"
+#define LN_mime_mhs		"MIME MHS"
+#define NID_mime_mhs		504
+#define OBJ_mime_mhs		OBJ_Mail,1L
+
+#define SN_mime_mhs_headings		"mime-mhs-headings"
+#define LN_mime_mhs_headings		"mime-mhs-headings"
+#define NID_mime_mhs_headings		505
+#define OBJ_mime_mhs_headings		OBJ_mime_mhs,1L
+
+#define SN_mime_mhs_bodies		"mime-mhs-bodies"
+#define LN_mime_mhs_bodies		"mime-mhs-bodies"
+#define NID_mime_mhs_bodies		506
+#define OBJ_mime_mhs_bodies		OBJ_mime_mhs,2L
+
+#define SN_id_hex_partial_message		"id-hex-partial-message"
+#define LN_id_hex_partial_message		"id-hex-partial-message"
+#define NID_id_hex_partial_message		507
+#define OBJ_id_hex_partial_message		OBJ_mime_mhs_headings,1L
+
+#define SN_id_hex_multipart_message		"id-hex-multipart-message"
+#define LN_id_hex_multipart_message		"id-hex-multipart-message"
+#define NID_id_hex_multipart_message		508
+#define OBJ_id_hex_multipart_message		OBJ_mime_mhs_headings,2L
+
+#define SN_rle_compression		"RLE"
+#define LN_rle_compression		"run length compression"
+#define NID_rle_compression		124
+#define OBJ_rle_compression		1L,1L,1L,1L,666L,1L
+
+#define SN_zlib_compression		"ZLIB"
+#define LN_zlib_compression		"zlib compression"
+#define NID_zlib_compression		125
+#define OBJ_zlib_compression		1L,1L,1L,1L,666L,2L
+
+#define OBJ_csor		2L,16L,840L,1L,101L,3L
+
+#define OBJ_nistAlgorithms		OBJ_csor,4L
+
+#define OBJ_aes		OBJ_nistAlgorithms,1L
+
+#define SN_aes_128_ecb		"AES-128-ECB"
+#define LN_aes_128_ecb		"aes-128-ecb"
+#define NID_aes_128_ecb		418
+#define OBJ_aes_128_ecb		OBJ_aes,1L
+
+#define SN_aes_128_cbc		"AES-128-CBC"
+#define LN_aes_128_cbc		"aes-128-cbc"
+#define NID_aes_128_cbc		419
+#define OBJ_aes_128_cbc		OBJ_aes,2L
+
+#define SN_aes_128_ofb128		"AES-128-OFB"
+#define LN_aes_128_ofb128		"aes-128-ofb"
+#define NID_aes_128_ofb128		420
+#define OBJ_aes_128_ofb128		OBJ_aes,3L
+
+#define SN_aes_128_cfb128		"AES-128-CFB"
+#define LN_aes_128_cfb128		"aes-128-cfb"
+#define NID_aes_128_cfb128		421
+#define OBJ_aes_128_cfb128		OBJ_aes,4L
+
+#define SN_aes_192_ecb		"AES-192-ECB"
+#define LN_aes_192_ecb		"aes-192-ecb"
+#define NID_aes_192_ecb		422
+#define OBJ_aes_192_ecb		OBJ_aes,21L
+
+#define SN_aes_192_cbc		"AES-192-CBC"
+#define LN_aes_192_cbc		"aes-192-cbc"
+#define NID_aes_192_cbc		423
+#define OBJ_aes_192_cbc		OBJ_aes,22L
+
+#define SN_aes_192_ofb128		"AES-192-OFB"
+#define LN_aes_192_ofb128		"aes-192-ofb"
+#define NID_aes_192_ofb128		424
+#define OBJ_aes_192_ofb128		OBJ_aes,23L
+
+#define SN_aes_192_cfb128		"AES-192-CFB"
+#define LN_aes_192_cfb128		"aes-192-cfb"
+#define NID_aes_192_cfb128		425
+#define OBJ_aes_192_cfb128		OBJ_aes,24L
+
+#define SN_aes_256_ecb		"AES-256-ECB"
+#define LN_aes_256_ecb		"aes-256-ecb"
+#define NID_aes_256_ecb		426
+#define OBJ_aes_256_ecb		OBJ_aes,41L
+
+#define SN_aes_256_cbc		"AES-256-CBC"
+#define LN_aes_256_cbc		"aes-256-cbc"
+#define NID_aes_256_cbc		427
+#define OBJ_aes_256_cbc		OBJ_aes,42L
+
+#define SN_aes_256_ofb128		"AES-256-OFB"
+#define LN_aes_256_ofb128		"aes-256-ofb"
+#define NID_aes_256_ofb128		428
+#define OBJ_aes_256_ofb128		OBJ_aes,43L
+
+#define SN_aes_256_cfb128		"AES-256-CFB"
+#define LN_aes_256_cfb128		"aes-256-cfb"
+#define NID_aes_256_cfb128		429
+#define OBJ_aes_256_cfb128		OBJ_aes,44L
+
+#define SN_aes_128_cfb1		"AES-128-CFB1"
+#define LN_aes_128_cfb1		"aes-128-cfb1"
+#define NID_aes_128_cfb1		650
+
+#define SN_aes_192_cfb1		"AES-192-CFB1"
+#define LN_aes_192_cfb1		"aes-192-cfb1"
+#define NID_aes_192_cfb1		651
+
+#define SN_aes_256_cfb1		"AES-256-CFB1"
+#define LN_aes_256_cfb1		"aes-256-cfb1"
+#define NID_aes_256_cfb1		652
+
+#define SN_aes_128_cfb8		"AES-128-CFB8"
+#define LN_aes_128_cfb8		"aes-128-cfb8"
+#define NID_aes_128_cfb8		653
+
+#define SN_aes_192_cfb8		"AES-192-CFB8"
+#define LN_aes_192_cfb8		"aes-192-cfb8"
+#define NID_aes_192_cfb8		654
+
+#define SN_aes_256_cfb8		"AES-256-CFB8"
+#define LN_aes_256_cfb8		"aes-256-cfb8"
+#define NID_aes_256_cfb8		655
+
+#define SN_des_cfb1		"DES-CFB1"
+#define LN_des_cfb1		"des-cfb1"
+#define NID_des_cfb1		656
+
+#define SN_des_cfb8		"DES-CFB8"
+#define LN_des_cfb8		"des-cfb8"
+#define NID_des_cfb8		657
+
+#define SN_des_ede3_cfb1		"DES-EDE3-CFB1"
+#define LN_des_ede3_cfb1		"des-ede3-cfb1"
+#define NID_des_ede3_cfb1		658
+
+#define SN_des_ede3_cfb8		"DES-EDE3-CFB8"
+#define LN_des_ede3_cfb8		"des-ede3-cfb8"
+#define NID_des_ede3_cfb8		659
+
+#define OBJ_nist_hashalgs		OBJ_nistAlgorithms,2L
+
+#define SN_sha256		"SHA256"
+#define LN_sha256		"sha256"
+#define NID_sha256		672
+#define OBJ_sha256		OBJ_nist_hashalgs,1L
+
+#define SN_sha384		"SHA384"
+#define LN_sha384		"sha384"
+#define NID_sha384		673
+#define OBJ_sha384		OBJ_nist_hashalgs,2L
+
+#define SN_sha512		"SHA512"
+#define LN_sha512		"sha512"
+#define NID_sha512		674
+#define OBJ_sha512		OBJ_nist_hashalgs,3L
+
+#define SN_sha224		"SHA224"
+#define LN_sha224		"sha224"
+#define NID_sha224		675
+#define OBJ_sha224		OBJ_nist_hashalgs,4L
+
+#define SN_hold_instruction_code		"holdInstructionCode"
+#define LN_hold_instruction_code		"Hold Instruction Code"
+#define NID_hold_instruction_code		430
+#define OBJ_hold_instruction_code		OBJ_id_ce,23L
+
+#define OBJ_holdInstruction		OBJ_X9_57,2L
+
+#define SN_hold_instruction_none		"holdInstructionNone"
+#define LN_hold_instruction_none		"Hold Instruction None"
+#define NID_hold_instruction_none		431
+#define OBJ_hold_instruction_none		OBJ_holdInstruction,1L
+
+#define SN_hold_instruction_call_issuer		"holdInstructionCallIssuer"
+#define LN_hold_instruction_call_issuer		"Hold Instruction Call Issuer"
+#define NID_hold_instruction_call_issuer		432
+#define OBJ_hold_instruction_call_issuer		OBJ_holdInstruction,2L
+
+#define SN_hold_instruction_reject		"holdInstructionReject"
+#define LN_hold_instruction_reject		"Hold Instruction Reject"
+#define NID_hold_instruction_reject		433
+#define OBJ_hold_instruction_reject		OBJ_holdInstruction,3L
+
+#define SN_data		"data"
+#define NID_data		434
+#define OBJ_data		OBJ_itu_t,9L
+
+#define SN_pss		"pss"
+#define NID_pss		435
+#define OBJ_pss		OBJ_data,2342L
+
+#define SN_ucl		"ucl"
+#define NID_ucl		436
+#define OBJ_ucl		OBJ_pss,19200300L
+
+#define SN_pilot		"pilot"
+#define NID_pilot		437
+#define OBJ_pilot		OBJ_ucl,100L
+
+#define LN_pilotAttributeType		"pilotAttributeType"
+#define NID_pilotAttributeType		438
+#define OBJ_pilotAttributeType		OBJ_pilot,1L
+
+#define LN_pilotAttributeSyntax		"pilotAttributeSyntax"
+#define NID_pilotAttributeSyntax		439
+#define OBJ_pilotAttributeSyntax		OBJ_pilot,3L
+
+#define LN_pilotObjectClass		"pilotObjectClass"
+#define NID_pilotObjectClass		440
+#define OBJ_pilotObjectClass		OBJ_pilot,4L
+
+#define LN_pilotGroups		"pilotGroups"
+#define NID_pilotGroups		441
+#define OBJ_pilotGroups		OBJ_pilot,10L
+
+#define LN_iA5StringSyntax		"iA5StringSyntax"
+#define NID_iA5StringSyntax		442
+#define OBJ_iA5StringSyntax		OBJ_pilotAttributeSyntax,4L
+
+#define LN_caseIgnoreIA5StringSyntax		"caseIgnoreIA5StringSyntax"
+#define NID_caseIgnoreIA5StringSyntax		443
+#define OBJ_caseIgnoreIA5StringSyntax		OBJ_pilotAttributeSyntax,5L
+
+#define LN_pilotObject		"pilotObject"
+#define NID_pilotObject		444
+#define OBJ_pilotObject		OBJ_pilotObjectClass,3L
+
+#define LN_pilotPerson		"pilotPerson"
+#define NID_pilotPerson		445
+#define OBJ_pilotPerson		OBJ_pilotObjectClass,4L
+
+#define SN_account		"account"
+#define NID_account		446
+#define OBJ_account		OBJ_pilotObjectClass,5L
+
+#define SN_document		"document"
+#define NID_document		447
+#define OBJ_document		OBJ_pilotObjectClass,6L
+
+#define SN_room		"room"
+#define NID_room		448
+#define OBJ_room		OBJ_pilotObjectClass,7L
+
+#define LN_documentSeries		"documentSeries"
+#define NID_documentSeries		449
+#define OBJ_documentSeries		OBJ_pilotObjectClass,9L
+
+#define SN_Domain		"domain"
+#define LN_Domain		"Domain"
+#define NID_Domain		392
+#define OBJ_Domain		OBJ_pilotObjectClass,13L
+
+#define LN_rFC822localPart		"rFC822localPart"
+#define NID_rFC822localPart		450
+#define OBJ_rFC822localPart		OBJ_pilotObjectClass,14L
+
+#define LN_dNSDomain		"dNSDomain"
+#define NID_dNSDomain		451
+#define OBJ_dNSDomain		OBJ_pilotObjectClass,15L
+
+#define LN_domainRelatedObject		"domainRelatedObject"
+#define NID_domainRelatedObject		452
+#define OBJ_domainRelatedObject		OBJ_pilotObjectClass,17L
+
+#define LN_friendlyCountry		"friendlyCountry"
+#define NID_friendlyCountry		453
+#define OBJ_friendlyCountry		OBJ_pilotObjectClass,18L
+
+#define LN_simpleSecurityObject		"simpleSecurityObject"
+#define NID_simpleSecurityObject		454
+#define OBJ_simpleSecurityObject		OBJ_pilotObjectClass,19L
+
+#define LN_pilotOrganization		"pilotOrganization"
+#define NID_pilotOrganization		455
+#define OBJ_pilotOrganization		OBJ_pilotObjectClass,20L
+
+#define LN_pilotDSA		"pilotDSA"
+#define NID_pilotDSA		456
+#define OBJ_pilotDSA		OBJ_pilotObjectClass,21L
+
+#define LN_qualityLabelledData		"qualityLabelledData"
+#define NID_qualityLabelledData		457
+#define OBJ_qualityLabelledData		OBJ_pilotObjectClass,22L
+
+#define SN_userId		"UID"
+#define LN_userId		"userId"
+#define NID_userId		458
+#define OBJ_userId		OBJ_pilotAttributeType,1L
+
+#define LN_textEncodedORAddress		"textEncodedORAddress"
+#define NID_textEncodedORAddress		459
+#define OBJ_textEncodedORAddress		OBJ_pilotAttributeType,2L
+
+#define SN_rfc822Mailbox		"mail"
+#define LN_rfc822Mailbox		"rfc822Mailbox"
+#define NID_rfc822Mailbox		460
+#define OBJ_rfc822Mailbox		OBJ_pilotAttributeType,3L
+
+#define SN_info		"info"
+#define NID_info		461
+#define OBJ_info		OBJ_pilotAttributeType,4L
+
+#define LN_favouriteDrink		"favouriteDrink"
+#define NID_favouriteDrink		462
+#define OBJ_favouriteDrink		OBJ_pilotAttributeType,5L
+
+#define LN_roomNumber		"roomNumber"
+#define NID_roomNumber		463
+#define OBJ_roomNumber		OBJ_pilotAttributeType,6L
+
+#define SN_photo		"photo"
+#define NID_photo		464
+#define OBJ_photo		OBJ_pilotAttributeType,7L
+
+#define LN_userClass		"userClass"
+#define NID_userClass		465
+#define OBJ_userClass		OBJ_pilotAttributeType,8L
+
+#define SN_host		"host"
+#define NID_host		466
+#define OBJ_host		OBJ_pilotAttributeType,9L
+
+#define SN_manager		"manager"
+#define NID_manager		467
+#define OBJ_manager		OBJ_pilotAttributeType,10L
+
+#define LN_documentIdentifier		"documentIdentifier"
+#define NID_documentIdentifier		468
+#define OBJ_documentIdentifier		OBJ_pilotAttributeType,11L
+
+#define LN_documentTitle		"documentTitle"
+#define NID_documentTitle		469
+#define OBJ_documentTitle		OBJ_pilotAttributeType,12L
+
+#define LN_documentVersion		"documentVersion"
+#define NID_documentVersion		470
+#define OBJ_documentVersion		OBJ_pilotAttributeType,13L
+
+#define LN_documentAuthor		"documentAuthor"
+#define NID_documentAuthor		471
+#define OBJ_documentAuthor		OBJ_pilotAttributeType,14L
+
+#define LN_documentLocation		"documentLocation"
+#define NID_documentLocation		472
+#define OBJ_documentLocation		OBJ_pilotAttributeType,15L
+
+#define LN_homeTelephoneNumber		"homeTelephoneNumber"
+#define NID_homeTelephoneNumber		473
+#define OBJ_homeTelephoneNumber		OBJ_pilotAttributeType,20L
+
+#define SN_secretary		"secretary"
+#define NID_secretary		474
+#define OBJ_secretary		OBJ_pilotAttributeType,21L
+
+#define LN_otherMailbox		"otherMailbox"
+#define NID_otherMailbox		475
+#define OBJ_otherMailbox		OBJ_pilotAttributeType,22L
+
+#define LN_lastModifiedTime		"lastModifiedTime"
+#define NID_lastModifiedTime		476
+#define OBJ_lastModifiedTime		OBJ_pilotAttributeType,23L
+
+#define LN_lastModifiedBy		"lastModifiedBy"
+#define NID_lastModifiedBy		477
+#define OBJ_lastModifiedBy		OBJ_pilotAttributeType,24L
+
+#define SN_domainComponent		"DC"
+#define LN_domainComponent		"domainComponent"
+#define NID_domainComponent		391
+#define OBJ_domainComponent		OBJ_pilotAttributeType,25L
+
+#define LN_aRecord		"aRecord"
+#define NID_aRecord		478
+#define OBJ_aRecord		OBJ_pilotAttributeType,26L
+
+#define LN_pilotAttributeType27		"pilotAttributeType27"
+#define NID_pilotAttributeType27		479
+#define OBJ_pilotAttributeType27		OBJ_pilotAttributeType,27L
+
+#define LN_mXRecord		"mXRecord"
+#define NID_mXRecord		480
+#define OBJ_mXRecord		OBJ_pilotAttributeType,28L
+
+#define LN_nSRecord		"nSRecord"
+#define NID_nSRecord		481
+#define OBJ_nSRecord		OBJ_pilotAttributeType,29L
+
+#define LN_sOARecord		"sOARecord"
+#define NID_sOARecord		482
+#define OBJ_sOARecord		OBJ_pilotAttributeType,30L
+
+#define LN_cNAMERecord		"cNAMERecord"
+#define NID_cNAMERecord		483
+#define OBJ_cNAMERecord		OBJ_pilotAttributeType,31L
+
+#define LN_associatedDomain		"associatedDomain"
+#define NID_associatedDomain		484
+#define OBJ_associatedDomain		OBJ_pilotAttributeType,37L
+
+#define LN_associatedName		"associatedName"
+#define NID_associatedName		485
+#define OBJ_associatedName		OBJ_pilotAttributeType,38L
+
+#define LN_homePostalAddress		"homePostalAddress"
+#define NID_homePostalAddress		486
+#define OBJ_homePostalAddress		OBJ_pilotAttributeType,39L
+
+#define LN_personalTitle		"personalTitle"
+#define NID_personalTitle		487
+#define OBJ_personalTitle		OBJ_pilotAttributeType,40L
+
+#define LN_mobileTelephoneNumber		"mobileTelephoneNumber"
+#define NID_mobileTelephoneNumber		488
+#define OBJ_mobileTelephoneNumber		OBJ_pilotAttributeType,41L
+
+#define LN_pagerTelephoneNumber		"pagerTelephoneNumber"
+#define NID_pagerTelephoneNumber		489
+#define OBJ_pagerTelephoneNumber		OBJ_pilotAttributeType,42L
+
+#define LN_friendlyCountryName		"friendlyCountryName"
+#define NID_friendlyCountryName		490
+#define OBJ_friendlyCountryName		OBJ_pilotAttributeType,43L
+
+#define LN_organizationalStatus		"organizationalStatus"
+#define NID_organizationalStatus		491
+#define OBJ_organizationalStatus		OBJ_pilotAttributeType,45L
+
+#define LN_janetMailbox		"janetMailbox"
+#define NID_janetMailbox		492
+#define OBJ_janetMailbox		OBJ_pilotAttributeType,46L
+
+#define LN_mailPreferenceOption		"mailPreferenceOption"
+#define NID_mailPreferenceOption		493
+#define OBJ_mailPreferenceOption		OBJ_pilotAttributeType,47L
+
+#define LN_buildingName		"buildingName"
+#define NID_buildingName		494
+#define OBJ_buildingName		OBJ_pilotAttributeType,48L
+
+#define LN_dSAQuality		"dSAQuality"
+#define NID_dSAQuality		495
+#define OBJ_dSAQuality		OBJ_pilotAttributeType,49L
+
+#define LN_singleLevelQuality		"singleLevelQuality"
+#define NID_singleLevelQuality		496
+#define OBJ_singleLevelQuality		OBJ_pilotAttributeType,50L
+
+#define LN_subtreeMinimumQuality		"subtreeMinimumQuality"
+#define NID_subtreeMinimumQuality		497
+#define OBJ_subtreeMinimumQuality		OBJ_pilotAttributeType,51L
+
+#define LN_subtreeMaximumQuality		"subtreeMaximumQuality"
+#define NID_subtreeMaximumQuality		498
+#define OBJ_subtreeMaximumQuality		OBJ_pilotAttributeType,52L
+
+#define LN_personalSignature		"personalSignature"
+#define NID_personalSignature		499
+#define OBJ_personalSignature		OBJ_pilotAttributeType,53L
+
+#define LN_dITRedirect		"dITRedirect"
+#define NID_dITRedirect		500
+#define OBJ_dITRedirect		OBJ_pilotAttributeType,54L
+
+#define SN_audio		"audio"
+#define NID_audio		501
+#define OBJ_audio		OBJ_pilotAttributeType,55L
+
+#define LN_documentPublisher		"documentPublisher"
+#define NID_documentPublisher		502
+#define OBJ_documentPublisher		OBJ_pilotAttributeType,56L
+
+#define SN_id_set		"id-set"
+#define LN_id_set		"Secure Electronic Transactions"
+#define NID_id_set		512
+#define OBJ_id_set		OBJ_international_organizations,42L
+
+#define SN_set_ctype		"set-ctype"
+#define LN_set_ctype		"content types"
+#define NID_set_ctype		513
+#define OBJ_set_ctype		OBJ_id_set,0L
+
+#define SN_set_msgExt		"set-msgExt"
+#define LN_set_msgExt		"message extensions"
+#define NID_set_msgExt		514
+#define OBJ_set_msgExt		OBJ_id_set,1L
+
+#define SN_set_attr		"set-attr"
+#define NID_set_attr		515
+#define OBJ_set_attr		OBJ_id_set,3L
+
+#define SN_set_policy		"set-policy"
+#define NID_set_policy		516
+#define OBJ_set_policy		OBJ_id_set,5L
+
+#define SN_set_certExt		"set-certExt"
+#define LN_set_certExt		"certificate extensions"
+#define NID_set_certExt		517
+#define OBJ_set_certExt		OBJ_id_set,7L
+
+#define SN_set_brand		"set-brand"
+#define NID_set_brand		518
+#define OBJ_set_brand		OBJ_id_set,8L
+
+#define SN_setct_PANData		"setct-PANData"
+#define NID_setct_PANData		519
+#define OBJ_setct_PANData		OBJ_set_ctype,0L
+
+#define SN_setct_PANToken		"setct-PANToken"
+#define NID_setct_PANToken		520
+#define OBJ_setct_PANToken		OBJ_set_ctype,1L
+
+#define SN_setct_PANOnly		"setct-PANOnly"
+#define NID_setct_PANOnly		521
+#define OBJ_setct_PANOnly		OBJ_set_ctype,2L
+
+#define SN_setct_OIData		"setct-OIData"
+#define NID_setct_OIData		522
+#define OBJ_setct_OIData		OBJ_set_ctype,3L
+
+#define SN_setct_PI		"setct-PI"
+#define NID_setct_PI		523
+#define OBJ_setct_PI		OBJ_set_ctype,4L
+
+#define SN_setct_PIData		"setct-PIData"
+#define NID_setct_PIData		524
+#define OBJ_setct_PIData		OBJ_set_ctype,5L
+
+#define SN_setct_PIDataUnsigned		"setct-PIDataUnsigned"
+#define NID_setct_PIDataUnsigned		525
+#define OBJ_setct_PIDataUnsigned		OBJ_set_ctype,6L
+
+#define SN_setct_HODInput		"setct-HODInput"
+#define NID_setct_HODInput		526
+#define OBJ_setct_HODInput		OBJ_set_ctype,7L
+
+#define SN_setct_AuthResBaggage		"setct-AuthResBaggage"
+#define NID_setct_AuthResBaggage		527
+#define OBJ_setct_AuthResBaggage		OBJ_set_ctype,8L
+
+#define SN_setct_AuthRevReqBaggage		"setct-AuthRevReqBaggage"
+#define NID_setct_AuthRevReqBaggage		528
+#define OBJ_setct_AuthRevReqBaggage		OBJ_set_ctype,9L
+
+#define SN_setct_AuthRevResBaggage		"setct-AuthRevResBaggage"
+#define NID_setct_AuthRevResBaggage		529
+#define OBJ_setct_AuthRevResBaggage		OBJ_set_ctype,10L
+
+#define SN_setct_CapTokenSeq		"setct-CapTokenSeq"
+#define NID_setct_CapTokenSeq		530
+#define OBJ_setct_CapTokenSeq		OBJ_set_ctype,11L
+
+#define SN_setct_PInitResData		"setct-PInitResData"
+#define NID_setct_PInitResData		531
+#define OBJ_setct_PInitResData		OBJ_set_ctype,12L
+
+#define SN_setct_PI_TBS		"setct-PI-TBS"
+#define NID_setct_PI_TBS		532
+#define OBJ_setct_PI_TBS		OBJ_set_ctype,13L
+
+#define SN_setct_PResData		"setct-PResData"
+#define NID_setct_PResData		533
+#define OBJ_setct_PResData		OBJ_set_ctype,14L
+
+#define SN_setct_AuthReqTBS		"setct-AuthReqTBS"
+#define NID_setct_AuthReqTBS		534
+#define OBJ_setct_AuthReqTBS		OBJ_set_ctype,16L
+
+#define SN_setct_AuthResTBS		"setct-AuthResTBS"
+#define NID_setct_AuthResTBS		535
+#define OBJ_setct_AuthResTBS		OBJ_set_ctype,17L
+
+#define SN_setct_AuthResTBSX		"setct-AuthResTBSX"
+#define NID_setct_AuthResTBSX		536
+#define OBJ_setct_AuthResTBSX		OBJ_set_ctype,18L
+
+#define SN_setct_AuthTokenTBS		"setct-AuthTokenTBS"
+#define NID_setct_AuthTokenTBS		537
+#define OBJ_setct_AuthTokenTBS		OBJ_set_ctype,19L
+
+#define SN_setct_CapTokenData		"setct-CapTokenData"
+#define NID_setct_CapTokenData		538
+#define OBJ_setct_CapTokenData		OBJ_set_ctype,20L
+
+#define SN_setct_CapTokenTBS		"setct-CapTokenTBS"
+#define NID_setct_CapTokenTBS		539
+#define OBJ_setct_CapTokenTBS		OBJ_set_ctype,21L
+
+#define SN_setct_AcqCardCodeMsg		"setct-AcqCardCodeMsg"
+#define NID_setct_AcqCardCodeMsg		540
+#define OBJ_setct_AcqCardCodeMsg		OBJ_set_ctype,22L
+
+#define SN_setct_AuthRevReqTBS		"setct-AuthRevReqTBS"
+#define NID_setct_AuthRevReqTBS		541
+#define OBJ_setct_AuthRevReqTBS		OBJ_set_ctype,23L
+
+#define SN_setct_AuthRevResData		"setct-AuthRevResData"
+#define NID_setct_AuthRevResData		542
+#define OBJ_setct_AuthRevResData		OBJ_set_ctype,24L
+
+#define SN_setct_AuthRevResTBS		"setct-AuthRevResTBS"
+#define NID_setct_AuthRevResTBS		543
+#define OBJ_setct_AuthRevResTBS		OBJ_set_ctype,25L
+
+#define SN_setct_CapReqTBS		"setct-CapReqTBS"
+#define NID_setct_CapReqTBS		544
+#define OBJ_setct_CapReqTBS		OBJ_set_ctype,26L
+
+#define SN_setct_CapReqTBSX		"setct-CapReqTBSX"
+#define NID_setct_CapReqTBSX		545
+#define OBJ_setct_CapReqTBSX		OBJ_set_ctype,27L
+
+#define SN_setct_CapResData		"setct-CapResData"
+#define NID_setct_CapResData		546
+#define OBJ_setct_CapResData		OBJ_set_ctype,28L
+
+#define SN_setct_CapRevReqTBS		"setct-CapRevReqTBS"
+#define NID_setct_CapRevReqTBS		547
+#define OBJ_setct_CapRevReqTBS		OBJ_set_ctype,29L
+
+#define SN_setct_CapRevReqTBSX		"setct-CapRevReqTBSX"
+#define NID_setct_CapRevReqTBSX		548
+#define OBJ_setct_CapRevReqTBSX		OBJ_set_ctype,30L
+
+#define SN_setct_CapRevResData		"setct-CapRevResData"
+#define NID_setct_CapRevResData		549
+#define OBJ_setct_CapRevResData		OBJ_set_ctype,31L
+
+#define SN_setct_CredReqTBS		"setct-CredReqTBS"
+#define NID_setct_CredReqTBS		550
+#define OBJ_setct_CredReqTBS		OBJ_set_ctype,32L
+
+#define SN_setct_CredReqTBSX		"setct-CredReqTBSX"
+#define NID_setct_CredReqTBSX		551
+#define OBJ_setct_CredReqTBSX		OBJ_set_ctype,33L
+
+#define SN_setct_CredResData		"setct-CredResData"
+#define NID_setct_CredResData		552
+#define OBJ_setct_CredResData		OBJ_set_ctype,34L
+
+#define SN_setct_CredRevReqTBS		"setct-CredRevReqTBS"
+#define NID_setct_CredRevReqTBS		553
+#define OBJ_setct_CredRevReqTBS		OBJ_set_ctype,35L
+
+#define SN_setct_CredRevReqTBSX		"setct-CredRevReqTBSX"
+#define NID_setct_CredRevReqTBSX		554
+#define OBJ_setct_CredRevReqTBSX		OBJ_set_ctype,36L
+
+#define SN_setct_CredRevResData		"setct-CredRevResData"
+#define NID_setct_CredRevResData		555
+#define OBJ_setct_CredRevResData		OBJ_set_ctype,37L
+
+#define SN_setct_PCertReqData		"setct-PCertReqData"
+#define NID_setct_PCertReqData		556
+#define OBJ_setct_PCertReqData		OBJ_set_ctype,38L
+
+#define SN_setct_PCertResTBS		"setct-PCertResTBS"
+#define NID_setct_PCertResTBS		557
+#define OBJ_setct_PCertResTBS		OBJ_set_ctype,39L
+
+#define SN_setct_BatchAdminReqData		"setct-BatchAdminReqData"
+#define NID_setct_BatchAdminReqData		558
+#define OBJ_setct_BatchAdminReqData		OBJ_set_ctype,40L
+
+#define SN_setct_BatchAdminResData		"setct-BatchAdminResData"
+#define NID_setct_BatchAdminResData		559
+#define OBJ_setct_BatchAdminResData		OBJ_set_ctype,41L
+
+#define SN_setct_CardCInitResTBS		"setct-CardCInitResTBS"
+#define NID_setct_CardCInitResTBS		560
+#define OBJ_setct_CardCInitResTBS		OBJ_set_ctype,42L
+
+#define SN_setct_MeAqCInitResTBS		"setct-MeAqCInitResTBS"
+#define NID_setct_MeAqCInitResTBS		561
+#define OBJ_setct_MeAqCInitResTBS		OBJ_set_ctype,43L
+
+#define SN_setct_RegFormResTBS		"setct-RegFormResTBS"
+#define NID_setct_RegFormResTBS		562
+#define OBJ_setct_RegFormResTBS		OBJ_set_ctype,44L
+
+#define SN_setct_CertReqData		"setct-CertReqData"
+#define NID_setct_CertReqData		563
+#define OBJ_setct_CertReqData		OBJ_set_ctype,45L
+
+#define SN_setct_CertReqTBS		"setct-CertReqTBS"
+#define NID_setct_CertReqTBS		564
+#define OBJ_setct_CertReqTBS		OBJ_set_ctype,46L
+
+#define SN_setct_CertResData		"setct-CertResData"
+#define NID_setct_CertResData		565
+#define OBJ_setct_CertResData		OBJ_set_ctype,47L
+
+#define SN_setct_CertInqReqTBS		"setct-CertInqReqTBS"
+#define NID_setct_CertInqReqTBS		566
+#define OBJ_setct_CertInqReqTBS		OBJ_set_ctype,48L
+
+#define SN_setct_ErrorTBS		"setct-ErrorTBS"
+#define NID_setct_ErrorTBS		567
+#define OBJ_setct_ErrorTBS		OBJ_set_ctype,49L
+
+#define SN_setct_PIDualSignedTBE		"setct-PIDualSignedTBE"
+#define NID_setct_PIDualSignedTBE		568
+#define OBJ_setct_PIDualSignedTBE		OBJ_set_ctype,50L
+
+#define SN_setct_PIUnsignedTBE		"setct-PIUnsignedTBE"
+#define NID_setct_PIUnsignedTBE		569
+#define OBJ_setct_PIUnsignedTBE		OBJ_set_ctype,51L
+
+#define SN_setct_AuthReqTBE		"setct-AuthReqTBE"
+#define NID_setct_AuthReqTBE		570
+#define OBJ_setct_AuthReqTBE		OBJ_set_ctype,52L
+
+#define SN_setct_AuthResTBE		"setct-AuthResTBE"
+#define NID_setct_AuthResTBE		571
+#define OBJ_setct_AuthResTBE		OBJ_set_ctype,53L
+
+#define SN_setct_AuthResTBEX		"setct-AuthResTBEX"
+#define NID_setct_AuthResTBEX		572
+#define OBJ_setct_AuthResTBEX		OBJ_set_ctype,54L
+
+#define SN_setct_AuthTokenTBE		"setct-AuthTokenTBE"
+#define NID_setct_AuthTokenTBE		573
+#define OBJ_setct_AuthTokenTBE		OBJ_set_ctype,55L
+
+#define SN_setct_CapTokenTBE		"setct-CapTokenTBE"
+#define NID_setct_CapTokenTBE		574
+#define OBJ_setct_CapTokenTBE		OBJ_set_ctype,56L
+
+#define SN_setct_CapTokenTBEX		"setct-CapTokenTBEX"
+#define NID_setct_CapTokenTBEX		575
+#define OBJ_setct_CapTokenTBEX		OBJ_set_ctype,57L
+
+#define SN_setct_AcqCardCodeMsgTBE		"setct-AcqCardCodeMsgTBE"
+#define NID_setct_AcqCardCodeMsgTBE		576
+#define OBJ_setct_AcqCardCodeMsgTBE		OBJ_set_ctype,58L
+
+#define SN_setct_AuthRevReqTBE		"setct-AuthRevReqTBE"
+#define NID_setct_AuthRevReqTBE		577
+#define OBJ_setct_AuthRevReqTBE		OBJ_set_ctype,59L
+
+#define SN_setct_AuthRevResTBE		"setct-AuthRevResTBE"
+#define NID_setct_AuthRevResTBE		578
+#define OBJ_setct_AuthRevResTBE		OBJ_set_ctype,60L
+
+#define SN_setct_AuthRevResTBEB		"setct-AuthRevResTBEB"
+#define NID_setct_AuthRevResTBEB		579
+#define OBJ_setct_AuthRevResTBEB		OBJ_set_ctype,61L
+
+#define SN_setct_CapReqTBE		"setct-CapReqTBE"
+#define NID_setct_CapReqTBE		580
+#define OBJ_setct_CapReqTBE		OBJ_set_ctype,62L
+
+#define SN_setct_CapReqTBEX		"setct-CapReqTBEX"
+#define NID_setct_CapReqTBEX		581
+#define OBJ_setct_CapReqTBEX		OBJ_set_ctype,63L
+
+#define SN_setct_CapResTBE		"setct-CapResTBE"
+#define NID_setct_CapResTBE		582
+#define OBJ_setct_CapResTBE		OBJ_set_ctype,64L
+
+#define SN_setct_CapRevReqTBE		"setct-CapRevReqTBE"
+#define NID_setct_CapRevReqTBE		583
+#define OBJ_setct_CapRevReqTBE		OBJ_set_ctype,65L
+
+#define SN_setct_CapRevReqTBEX		"setct-CapRevReqTBEX"
+#define NID_setct_CapRevReqTBEX		584
+#define OBJ_setct_CapRevReqTBEX		OBJ_set_ctype,66L
+
+#define SN_setct_CapRevResTBE		"setct-CapRevResTBE"
+#define NID_setct_CapRevResTBE		585
+#define OBJ_setct_CapRevResTBE		OBJ_set_ctype,67L
+
+#define SN_setct_CredReqTBE		"setct-CredReqTBE"
+#define NID_setct_CredReqTBE		586
+#define OBJ_setct_CredReqTBE		OBJ_set_ctype,68L
+
+#define SN_setct_CredReqTBEX		"setct-CredReqTBEX"
+#define NID_setct_CredReqTBEX		587
+#define OBJ_setct_CredReqTBEX		OBJ_set_ctype,69L
+
+#define SN_setct_CredResTBE		"setct-CredResTBE"
+#define NID_setct_CredResTBE		588
+#define OBJ_setct_CredResTBE		OBJ_set_ctype,70L
+
+#define SN_setct_CredRevReqTBE		"setct-CredRevReqTBE"
+#define NID_setct_CredRevReqTBE		589
+#define OBJ_setct_CredRevReqTBE		OBJ_set_ctype,71L
+
+#define SN_setct_CredRevReqTBEX		"setct-CredRevReqTBEX"
+#define NID_setct_CredRevReqTBEX		590
+#define OBJ_setct_CredRevReqTBEX		OBJ_set_ctype,72L
+
+#define SN_setct_CredRevResTBE		"setct-CredRevResTBE"
+#define NID_setct_CredRevResTBE		591
+#define OBJ_setct_CredRevResTBE		OBJ_set_ctype,73L
+
+#define SN_setct_BatchAdminReqTBE		"setct-BatchAdminReqTBE"
+#define NID_setct_BatchAdminReqTBE		592
+#define OBJ_setct_BatchAdminReqTBE		OBJ_set_ctype,74L
+
+#define SN_setct_BatchAdminResTBE		"setct-BatchAdminResTBE"
+#define NID_setct_BatchAdminResTBE		593
+#define OBJ_setct_BatchAdminResTBE		OBJ_set_ctype,75L
+
+#define SN_setct_RegFormReqTBE		"setct-RegFormReqTBE"
+#define NID_setct_RegFormReqTBE		594
+#define OBJ_setct_RegFormReqTBE		OBJ_set_ctype,76L
+
+#define SN_setct_CertReqTBE		"setct-CertReqTBE"
+#define NID_setct_CertReqTBE		595
+#define OBJ_setct_CertReqTBE		OBJ_set_ctype,77L
+
+#define SN_setct_CertReqTBEX		"setct-CertReqTBEX"
+#define NID_setct_CertReqTBEX		596
+#define OBJ_setct_CertReqTBEX		OBJ_set_ctype,78L
+
+#define SN_setct_CertResTBE		"setct-CertResTBE"
+#define NID_setct_CertResTBE		597
+#define OBJ_setct_CertResTBE		OBJ_set_ctype,79L
+
+#define SN_setct_CRLNotificationTBS		"setct-CRLNotificationTBS"
+#define NID_setct_CRLNotificationTBS		598
+#define OBJ_setct_CRLNotificationTBS		OBJ_set_ctype,80L
+
+#define SN_setct_CRLNotificationResTBS		"setct-CRLNotificationResTBS"
+#define NID_setct_CRLNotificationResTBS		599
+#define OBJ_setct_CRLNotificationResTBS		OBJ_set_ctype,81L
+
+#define SN_setct_BCIDistributionTBS		"setct-BCIDistributionTBS"
+#define NID_setct_BCIDistributionTBS		600
+#define OBJ_setct_BCIDistributionTBS		OBJ_set_ctype,82L
+
+#define SN_setext_genCrypt		"setext-genCrypt"
+#define LN_setext_genCrypt		"generic cryptogram"
+#define NID_setext_genCrypt		601
+#define OBJ_setext_genCrypt		OBJ_set_msgExt,1L
+
+#define SN_setext_miAuth		"setext-miAuth"
+#define LN_setext_miAuth		"merchant initiated auth"
+#define NID_setext_miAuth		602
+#define OBJ_setext_miAuth		OBJ_set_msgExt,3L
+
+#define SN_setext_pinSecure		"setext-pinSecure"
+#define NID_setext_pinSecure		603
+#define OBJ_setext_pinSecure		OBJ_set_msgExt,4L
+
+#define SN_setext_pinAny		"setext-pinAny"
+#define NID_setext_pinAny		604
+#define OBJ_setext_pinAny		OBJ_set_msgExt,5L
+
+#define SN_setext_track2		"setext-track2"
+#define NID_setext_track2		605
+#define OBJ_setext_track2		OBJ_set_msgExt,7L
+
+#define SN_setext_cv		"setext-cv"
+#define LN_setext_cv		"additional verification"
+#define NID_setext_cv		606
+#define OBJ_setext_cv		OBJ_set_msgExt,8L
+
+#define SN_set_policy_root		"set-policy-root"
+#define NID_set_policy_root		607
+#define OBJ_set_policy_root		OBJ_set_policy,0L
+
+#define SN_setCext_hashedRoot		"setCext-hashedRoot"
+#define NID_setCext_hashedRoot		608
+#define OBJ_setCext_hashedRoot		OBJ_set_certExt,0L
+
+#define SN_setCext_certType		"setCext-certType"
+#define NID_setCext_certType		609
+#define OBJ_setCext_certType		OBJ_set_certExt,1L
+
+#define SN_setCext_merchData		"setCext-merchData"
+#define NID_setCext_merchData		610
+#define OBJ_setCext_merchData		OBJ_set_certExt,2L
+
+#define SN_setCext_cCertRequired		"setCext-cCertRequired"
+#define NID_setCext_cCertRequired		611
+#define OBJ_setCext_cCertRequired		OBJ_set_certExt,3L
+
+#define SN_setCext_tunneling		"setCext-tunneling"
+#define NID_setCext_tunneling		612
+#define OBJ_setCext_tunneling		OBJ_set_certExt,4L
+
+#define SN_setCext_setExt		"setCext-setExt"
+#define NID_setCext_setExt		613
+#define OBJ_setCext_setExt		OBJ_set_certExt,5L
+
+#define SN_setCext_setQualf		"setCext-setQualf"
+#define NID_setCext_setQualf		614
+#define OBJ_setCext_setQualf		OBJ_set_certExt,6L
+
+#define SN_setCext_PGWYcapabilities		"setCext-PGWYcapabilities"
+#define NID_setCext_PGWYcapabilities		615
+#define OBJ_setCext_PGWYcapabilities		OBJ_set_certExt,7L
+
+#define SN_setCext_TokenIdentifier		"setCext-TokenIdentifier"
+#define NID_setCext_TokenIdentifier		616
+#define OBJ_setCext_TokenIdentifier		OBJ_set_certExt,8L
+
+#define SN_setCext_Track2Data		"setCext-Track2Data"
+#define NID_setCext_Track2Data		617
+#define OBJ_setCext_Track2Data		OBJ_set_certExt,9L
+
+#define SN_setCext_TokenType		"setCext-TokenType"
+#define NID_setCext_TokenType		618
+#define OBJ_setCext_TokenType		OBJ_set_certExt,10L
+
+#define SN_setCext_IssuerCapabilities		"setCext-IssuerCapabilities"
+#define NID_setCext_IssuerCapabilities		619
+#define OBJ_setCext_IssuerCapabilities		OBJ_set_certExt,11L
+
+#define SN_setAttr_Cert		"setAttr-Cert"
+#define NID_setAttr_Cert		620
+#define OBJ_setAttr_Cert		OBJ_set_attr,0L
+
+#define SN_setAttr_PGWYcap		"setAttr-PGWYcap"
+#define LN_setAttr_PGWYcap		"payment gateway capabilities"
+#define NID_setAttr_PGWYcap		621
+#define OBJ_setAttr_PGWYcap		OBJ_set_attr,1L
+
+#define SN_setAttr_TokenType		"setAttr-TokenType"
+#define NID_setAttr_TokenType		622
+#define OBJ_setAttr_TokenType		OBJ_set_attr,2L
+
+#define SN_setAttr_IssCap		"setAttr-IssCap"
+#define LN_setAttr_IssCap		"issuer capabilities"
+#define NID_setAttr_IssCap		623
+#define OBJ_setAttr_IssCap		OBJ_set_attr,3L
+
+#define SN_set_rootKeyThumb		"set-rootKeyThumb"
+#define NID_set_rootKeyThumb		624
+#define OBJ_set_rootKeyThumb		OBJ_setAttr_Cert,0L
+
+#define SN_set_addPolicy		"set-addPolicy"
+#define NID_set_addPolicy		625
+#define OBJ_set_addPolicy		OBJ_setAttr_Cert,1L
+
+#define SN_setAttr_Token_EMV		"setAttr-Token-EMV"
+#define NID_setAttr_Token_EMV		626
+#define OBJ_setAttr_Token_EMV		OBJ_setAttr_TokenType,1L
+
+#define SN_setAttr_Token_B0Prime		"setAttr-Token-B0Prime"
+#define NID_setAttr_Token_B0Prime		627
+#define OBJ_setAttr_Token_B0Prime		OBJ_setAttr_TokenType,2L
+
+#define SN_setAttr_IssCap_CVM		"setAttr-IssCap-CVM"
+#define NID_setAttr_IssCap_CVM		628
+#define OBJ_setAttr_IssCap_CVM		OBJ_setAttr_IssCap,3L
+
+#define SN_setAttr_IssCap_T2		"setAttr-IssCap-T2"
+#define NID_setAttr_IssCap_T2		629
+#define OBJ_setAttr_IssCap_T2		OBJ_setAttr_IssCap,4L
+
+#define SN_setAttr_IssCap_Sig		"setAttr-IssCap-Sig"
+#define NID_setAttr_IssCap_Sig		630
+#define OBJ_setAttr_IssCap_Sig		OBJ_setAttr_IssCap,5L
+
+#define SN_setAttr_GenCryptgrm		"setAttr-GenCryptgrm"
+#define LN_setAttr_GenCryptgrm		"generate cryptogram"
+#define NID_setAttr_GenCryptgrm		631
+#define OBJ_setAttr_GenCryptgrm		OBJ_setAttr_IssCap_CVM,1L
+
+#define SN_setAttr_T2Enc		"setAttr-T2Enc"
+#define LN_setAttr_T2Enc		"encrypted track 2"
+#define NID_setAttr_T2Enc		632
+#define OBJ_setAttr_T2Enc		OBJ_setAttr_IssCap_T2,1L
+
+#define SN_setAttr_T2cleartxt		"setAttr-T2cleartxt"
+#define LN_setAttr_T2cleartxt		"cleartext track 2"
+#define NID_setAttr_T2cleartxt		633
+#define OBJ_setAttr_T2cleartxt		OBJ_setAttr_IssCap_T2,2L
+
+#define SN_setAttr_TokICCsig		"setAttr-TokICCsig"
+#define LN_setAttr_TokICCsig		"ICC or token signature"
+#define NID_setAttr_TokICCsig		634
+#define OBJ_setAttr_TokICCsig		OBJ_setAttr_IssCap_Sig,1L
+
+#define SN_setAttr_SecDevSig		"setAttr-SecDevSig"
+#define LN_setAttr_SecDevSig		"secure device signature"
+#define NID_setAttr_SecDevSig		635
+#define OBJ_setAttr_SecDevSig		OBJ_setAttr_IssCap_Sig,2L
+
+#define SN_set_brand_IATA_ATA		"set-brand-IATA-ATA"
+#define NID_set_brand_IATA_ATA		636
+#define OBJ_set_brand_IATA_ATA		OBJ_set_brand,1L
+
+#define SN_set_brand_Diners		"set-brand-Diners"
+#define NID_set_brand_Diners		637
+#define OBJ_set_brand_Diners		OBJ_set_brand,30L
+
+#define SN_set_brand_AmericanExpress		"set-brand-AmericanExpress"
+#define NID_set_brand_AmericanExpress		638
+#define OBJ_set_brand_AmericanExpress		OBJ_set_brand,34L
+
+#define SN_set_brand_JCB		"set-brand-JCB"
+#define NID_set_brand_JCB		639
+#define OBJ_set_brand_JCB		OBJ_set_brand,35L
+
+#define SN_set_brand_Visa		"set-brand-Visa"
+#define NID_set_brand_Visa		640
+#define OBJ_set_brand_Visa		OBJ_set_brand,4L
+
+#define SN_set_brand_MasterCard		"set-brand-MasterCard"
+#define NID_set_brand_MasterCard		641
+#define OBJ_set_brand_MasterCard		OBJ_set_brand,5L
+
+#define SN_set_brand_Novus		"set-brand-Novus"
+#define NID_set_brand_Novus		642
+#define OBJ_set_brand_Novus		OBJ_set_brand,6011L
+
+#define SN_des_cdmf		"DES-CDMF"
+#define LN_des_cdmf		"des-cdmf"
+#define NID_des_cdmf		643
+#define OBJ_des_cdmf		OBJ_rsadsi,3L,10L
+
+#define SN_rsaOAEPEncryptionSET		"rsaOAEPEncryptionSET"
+#define NID_rsaOAEPEncryptionSET		644
+#define OBJ_rsaOAEPEncryptionSET		OBJ_rsadsi,1L,1L,6L
+
+#define SN_ipsec3		"Oakley-EC2N-3"
+#define LN_ipsec3		"ipsec3"
+#define NID_ipsec3		749
+
+#define SN_ipsec4		"Oakley-EC2N-4"
+#define LN_ipsec4		"ipsec4"
+#define NID_ipsec4		750
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/objects.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/objects.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/objects.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1049 @@
+/* crypto/objects/objects.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_OBJECTS_H
+#define HEADER_OBJECTS_H
+
+#define USE_OBJ_MAC
+
+#ifdef USE_OBJ_MAC
+#include <openssl/obj_mac.h>
+#else
+#define SN_undef			"UNDEF"
+#define LN_undef			"undefined"
+#define NID_undef			0
+#define OBJ_undef			0L
+
+#define SN_Algorithm			"Algorithm"
+#define LN_algorithm			"algorithm"
+#define NID_algorithm			38
+#define OBJ_algorithm			1L,3L,14L,3L,2L
+
+#define LN_rsadsi			"rsadsi"
+#define NID_rsadsi			1
+#define OBJ_rsadsi			1L,2L,840L,113549L
+
+#define LN_pkcs				"pkcs"
+#define NID_pkcs			2
+#define OBJ_pkcs			OBJ_rsadsi,1L
+
+#define SN_md2				"MD2"
+#define LN_md2				"md2"
+#define NID_md2				3
+#define OBJ_md2				OBJ_rsadsi,2L,2L
+
+#define SN_md5				"MD5"
+#define LN_md5				"md5"
+#define NID_md5				4
+#define OBJ_md5				OBJ_rsadsi,2L,5L
+
+#define SN_rc4				"RC4"
+#define LN_rc4				"rc4"
+#define NID_rc4				5
+#define OBJ_rc4				OBJ_rsadsi,3L,4L
+
+#define LN_rsaEncryption		"rsaEncryption"
+#define NID_rsaEncryption		6
+#define OBJ_rsaEncryption		OBJ_pkcs,1L,1L
+
+#define SN_md2WithRSAEncryption		"RSA-MD2"
+#define LN_md2WithRSAEncryption		"md2WithRSAEncryption"
+#define NID_md2WithRSAEncryption	7
+#define OBJ_md2WithRSAEncryption	OBJ_pkcs,1L,2L
+
+#define SN_md5WithRSAEncryption		"RSA-MD5"
+#define LN_md5WithRSAEncryption		"md5WithRSAEncryption"
+#define NID_md5WithRSAEncryption	8
+#define OBJ_md5WithRSAEncryption	OBJ_pkcs,1L,4L
+
+#define SN_pbeWithMD2AndDES_CBC		"PBE-MD2-DES"
+#define LN_pbeWithMD2AndDES_CBC		"pbeWithMD2AndDES-CBC"
+#define NID_pbeWithMD2AndDES_CBC	9
+#define OBJ_pbeWithMD2AndDES_CBC	OBJ_pkcs,5L,1L
+
+#define SN_pbeWithMD5AndDES_CBC		"PBE-MD5-DES"
+#define LN_pbeWithMD5AndDES_CBC		"pbeWithMD5AndDES-CBC"
+#define NID_pbeWithMD5AndDES_CBC	10
+#define OBJ_pbeWithMD5AndDES_CBC	OBJ_pkcs,5L,3L
+
+#define LN_X500				"X500"
+#define NID_X500			11
+#define OBJ_X500			2L,5L
+
+#define LN_X509				"X509"
+#define NID_X509			12
+#define OBJ_X509			OBJ_X500,4L
+
+#define SN_commonName			"CN"
+#define LN_commonName			"commonName"
+#define NID_commonName			13
+#define OBJ_commonName			OBJ_X509,3L
+
+#define SN_countryName			"C"
+#define LN_countryName			"countryName"
+#define NID_countryName			14
+#define OBJ_countryName			OBJ_X509,6L
+
+#define SN_localityName			"L"
+#define LN_localityName			"localityName"
+#define NID_localityName		15
+#define OBJ_localityName		OBJ_X509,7L
+
+/* Postal Address? PA */
+
+/* should be "ST" (rfc1327) but MS uses 'S' */
+#define SN_stateOrProvinceName		"ST"
+#define LN_stateOrProvinceName		"stateOrProvinceName"
+#define NID_stateOrProvinceName		16
+#define OBJ_stateOrProvinceName		OBJ_X509,8L
+
+#define SN_organizationName		"O"
+#define LN_organizationName		"organizationName"
+#define NID_organizationName		17
+#define OBJ_organizationName		OBJ_X509,10L
+
+#define SN_organizationalUnitName	"OU"
+#define LN_organizationalUnitName	"organizationalUnitName"
+#define NID_organizationalUnitName	18
+#define OBJ_organizationalUnitName	OBJ_X509,11L
+
+#define SN_rsa				"RSA"
+#define LN_rsa				"rsa"
+#define NID_rsa				19
+#define OBJ_rsa				OBJ_X500,8L,1L,1L
+
+#define LN_pkcs7			"pkcs7"
+#define NID_pkcs7			20
+#define OBJ_pkcs7			OBJ_pkcs,7L
+
+#define LN_pkcs7_data			"pkcs7-data"
+#define NID_pkcs7_data			21
+#define OBJ_pkcs7_data			OBJ_pkcs7,1L
+
+#define LN_pkcs7_signed			"pkcs7-signedData"
+#define NID_pkcs7_signed		22
+#define OBJ_pkcs7_signed		OBJ_pkcs7,2L
+
+#define LN_pkcs7_enveloped		"pkcs7-envelopedData"
+#define NID_pkcs7_enveloped		23
+#define OBJ_pkcs7_enveloped		OBJ_pkcs7,3L
+
+#define LN_pkcs7_signedAndEnveloped	"pkcs7-signedAndEnvelopedData"
+#define NID_pkcs7_signedAndEnveloped	24
+#define OBJ_pkcs7_signedAndEnveloped	OBJ_pkcs7,4L
+
+#define LN_pkcs7_digest			"pkcs7-digestData"
+#define NID_pkcs7_digest		25
+#define OBJ_pkcs7_digest		OBJ_pkcs7,5L
+
+#define LN_pkcs7_encrypted		"pkcs7-encryptedData"
+#define NID_pkcs7_encrypted		26
+#define OBJ_pkcs7_encrypted		OBJ_pkcs7,6L
+
+#define LN_pkcs3			"pkcs3"
+#define NID_pkcs3			27
+#define OBJ_pkcs3			OBJ_pkcs,3L
+
+#define LN_dhKeyAgreement		"dhKeyAgreement"
+#define NID_dhKeyAgreement		28
+#define OBJ_dhKeyAgreement		OBJ_pkcs3,1L
+
+#define SN_des_ecb			"DES-ECB"
+#define LN_des_ecb			"des-ecb"
+#define NID_des_ecb			29
+#define OBJ_des_ecb			OBJ_algorithm,6L
+
+#define SN_des_cfb64			"DES-CFB"
+#define LN_des_cfb64			"des-cfb"
+#define NID_des_cfb64			30
+/* IV + num */
+#define OBJ_des_cfb64			OBJ_algorithm,9L
+
+#define SN_des_cbc			"DES-CBC"
+#define LN_des_cbc			"des-cbc"
+#define NID_des_cbc			31
+/* IV */
+#define OBJ_des_cbc			OBJ_algorithm,7L
+
+#define SN_des_ede			"DES-EDE"
+#define LN_des_ede			"des-ede"
+#define NID_des_ede			32
+/* ?? */
+#define OBJ_des_ede			OBJ_algorithm,17L
+
+#define SN_des_ede3			"DES-EDE3"
+#define LN_des_ede3			"des-ede3"
+#define NID_des_ede3			33
+
+#define SN_idea_cbc			"IDEA-CBC"
+#define LN_idea_cbc			"idea-cbc"
+#define NID_idea_cbc			34
+#define OBJ_idea_cbc			1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L
+
+#define SN_idea_cfb64			"IDEA-CFB"
+#define LN_idea_cfb64			"idea-cfb"
+#define NID_idea_cfb64			35
+
+#define SN_idea_ecb			"IDEA-ECB"
+#define LN_idea_ecb			"idea-ecb"
+#define NID_idea_ecb			36
+
+#define SN_rc2_cbc			"RC2-CBC"
+#define LN_rc2_cbc			"rc2-cbc"
+#define NID_rc2_cbc			37
+#define OBJ_rc2_cbc			OBJ_rsadsi,3L,2L
+
+#define SN_rc2_ecb			"RC2-ECB"
+#define LN_rc2_ecb			"rc2-ecb"
+#define NID_rc2_ecb			38
+
+#define SN_rc2_cfb64			"RC2-CFB"
+#define LN_rc2_cfb64			"rc2-cfb"
+#define NID_rc2_cfb64			39
+
+#define SN_rc2_ofb64			"RC2-OFB"
+#define LN_rc2_ofb64			"rc2-ofb"
+#define NID_rc2_ofb64			40
+
+#define SN_sha				"SHA"
+#define LN_sha				"sha"
+#define NID_sha				41
+#define OBJ_sha				OBJ_algorithm,18L
+
+#define SN_shaWithRSAEncryption		"RSA-SHA"
+#define LN_shaWithRSAEncryption		"shaWithRSAEncryption"
+#define NID_shaWithRSAEncryption	42
+#define OBJ_shaWithRSAEncryption	OBJ_algorithm,15L
+
+#define SN_des_ede_cbc			"DES-EDE-CBC"
+#define LN_des_ede_cbc			"des-ede-cbc"
+#define NID_des_ede_cbc			43
+
+#define SN_des_ede3_cbc			"DES-EDE3-CBC"
+#define LN_des_ede3_cbc			"des-ede3-cbc"
+#define NID_des_ede3_cbc		44
+#define OBJ_des_ede3_cbc		OBJ_rsadsi,3L,7L
+
+#define SN_des_ofb64			"DES-OFB"
+#define LN_des_ofb64			"des-ofb"
+#define NID_des_ofb64			45
+#define OBJ_des_ofb64			OBJ_algorithm,8L
+
+#define SN_idea_ofb64			"IDEA-OFB"
+#define LN_idea_ofb64			"idea-ofb"
+#define NID_idea_ofb64			46
+
+#define LN_pkcs9			"pkcs9"
+#define NID_pkcs9			47
+#define OBJ_pkcs9			OBJ_pkcs,9L
+
+#define SN_pkcs9_emailAddress		"Email"
+#define LN_pkcs9_emailAddress		"emailAddress"
+#define NID_pkcs9_emailAddress		48
+#define OBJ_pkcs9_emailAddress		OBJ_pkcs9,1L
+
+#define LN_pkcs9_unstructuredName	"unstructuredName"
+#define NID_pkcs9_unstructuredName	49
+#define OBJ_pkcs9_unstructuredName	OBJ_pkcs9,2L
+
+#define LN_pkcs9_contentType		"contentType"
+#define NID_pkcs9_contentType		50
+#define OBJ_pkcs9_contentType		OBJ_pkcs9,3L
+
+#define LN_pkcs9_messageDigest		"messageDigest"
+#define NID_pkcs9_messageDigest		51
+#define OBJ_pkcs9_messageDigest		OBJ_pkcs9,4L
+
+#define LN_pkcs9_signingTime		"signingTime"
+#define NID_pkcs9_signingTime		52
+#define OBJ_pkcs9_signingTime		OBJ_pkcs9,5L
+
+#define LN_pkcs9_countersignature	"countersignature"
+#define NID_pkcs9_countersignature	53
+#define OBJ_pkcs9_countersignature	OBJ_pkcs9,6L
+
+#define LN_pkcs9_challengePassword	"challengePassword"
+#define NID_pkcs9_challengePassword	54
+#define OBJ_pkcs9_challengePassword	OBJ_pkcs9,7L
+
+#define LN_pkcs9_unstructuredAddress	"unstructuredAddress"
+#define NID_pkcs9_unstructuredAddress	55
+#define OBJ_pkcs9_unstructuredAddress	OBJ_pkcs9,8L
+
+#define LN_pkcs9_extCertAttributes	"extendedCertificateAttributes"
+#define NID_pkcs9_extCertAttributes	56
+#define OBJ_pkcs9_extCertAttributes	OBJ_pkcs9,9L
+
+#define SN_netscape			"Netscape"
+#define LN_netscape			"Netscape Communications Corp."
+#define NID_netscape			57
+#define OBJ_netscape			2L,16L,840L,1L,113730L
+
+#define SN_netscape_cert_extension	"nsCertExt"
+#define LN_netscape_cert_extension	"Netscape Certificate Extension"
+#define NID_netscape_cert_extension	58
+#define OBJ_netscape_cert_extension	OBJ_netscape,1L
+
+#define SN_netscape_data_type		"nsDataType"
+#define LN_netscape_data_type		"Netscape Data Type"
+#define NID_netscape_data_type		59
+#define OBJ_netscape_data_type		OBJ_netscape,2L
+
+#define SN_des_ede_cfb64		"DES-EDE-CFB"
+#define LN_des_ede_cfb64		"des-ede-cfb"
+#define NID_des_ede_cfb64		60
+
+#define SN_des_ede3_cfb64		"DES-EDE3-CFB"
+#define LN_des_ede3_cfb64		"des-ede3-cfb"
+#define NID_des_ede3_cfb64		61
+
+#define SN_des_ede_ofb64		"DES-EDE-OFB"
+#define LN_des_ede_ofb64		"des-ede-ofb"
+#define NID_des_ede_ofb64		62
+
+#define SN_des_ede3_ofb64		"DES-EDE3-OFB"
+#define LN_des_ede3_ofb64		"des-ede3-ofb"
+#define NID_des_ede3_ofb64		63
+
+/* I'm not sure about the object ID */
+#define SN_sha1				"SHA1"
+#define LN_sha1				"sha1"
+#define NID_sha1			64
+#define OBJ_sha1			OBJ_algorithm,26L
+/* 28 Jun 1996 - eay */
+/* #define OBJ_sha1			1L,3L,14L,2L,26L,05L <- wrong */
+
+#define SN_sha1WithRSAEncryption	"RSA-SHA1"
+#define LN_sha1WithRSAEncryption	"sha1WithRSAEncryption"
+#define NID_sha1WithRSAEncryption	65
+#define OBJ_sha1WithRSAEncryption	OBJ_pkcs,1L,5L
+
+#define SN_dsaWithSHA			"DSA-SHA"
+#define LN_dsaWithSHA			"dsaWithSHA"
+#define NID_dsaWithSHA			66
+#define OBJ_dsaWithSHA			OBJ_algorithm,13L
+
+#define SN_dsa_2			"DSA-old"
+#define LN_dsa_2			"dsaEncryption-old"
+#define NID_dsa_2			67
+#define OBJ_dsa_2			OBJ_algorithm,12L
+
+/* proposed by microsoft to RSA */
+#define SN_pbeWithSHA1AndRC2_CBC	"PBE-SHA1-RC2-64"
+#define LN_pbeWithSHA1AndRC2_CBC	"pbeWithSHA1AndRC2-CBC"
+#define NID_pbeWithSHA1AndRC2_CBC	68
+#define OBJ_pbeWithSHA1AndRC2_CBC	OBJ_pkcs,5L,11L 
+
+/* proposed by microsoft to RSA as pbeWithSHA1AndRC4: it is now
+ * defined explicitly in PKCS#5 v2.0 as id-PBKDF2 which is something
+ * completely different.
+ */
+#define LN_id_pbkdf2			"PBKDF2"
+#define NID_id_pbkdf2			69
+#define OBJ_id_pbkdf2			OBJ_pkcs,5L,12L 
+
+#define SN_dsaWithSHA1_2		"DSA-SHA1-old"
+#define LN_dsaWithSHA1_2		"dsaWithSHA1-old"
+#define NID_dsaWithSHA1_2		70
+/* Got this one from 'sdn706r20.pdf' which is actually an NSA document :-) */
+#define OBJ_dsaWithSHA1_2		OBJ_algorithm,27L
+
+#define SN_netscape_cert_type		"nsCertType"
+#define LN_netscape_cert_type		"Netscape Cert Type"
+#define NID_netscape_cert_type		71
+#define OBJ_netscape_cert_type		OBJ_netscape_cert_extension,1L
+
+#define SN_netscape_base_url		"nsBaseUrl"
+#define LN_netscape_base_url		"Netscape Base Url"
+#define NID_netscape_base_url		72
+#define OBJ_netscape_base_url		OBJ_netscape_cert_extension,2L
+
+#define SN_netscape_revocation_url	"nsRevocationUrl"
+#define LN_netscape_revocation_url	"Netscape Revocation Url"
+#define NID_netscape_revocation_url	73
+#define OBJ_netscape_revocation_url	OBJ_netscape_cert_extension,3L
+
+#define SN_netscape_ca_revocation_url	"nsCaRevocationUrl"
+#define LN_netscape_ca_revocation_url	"Netscape CA Revocation Url"
+#define NID_netscape_ca_revocation_url	74
+#define OBJ_netscape_ca_revocation_url	OBJ_netscape_cert_extension,4L
+
+#define SN_netscape_renewal_url		"nsRenewalUrl"
+#define LN_netscape_renewal_url		"Netscape Renewal Url"
+#define NID_netscape_renewal_url	75
+#define OBJ_netscape_renewal_url	OBJ_netscape_cert_extension,7L
+
+#define SN_netscape_ca_policy_url	"nsCaPolicyUrl"
+#define LN_netscape_ca_policy_url	"Netscape CA Policy Url"
+#define NID_netscape_ca_policy_url	76
+#define OBJ_netscape_ca_policy_url	OBJ_netscape_cert_extension,8L
+
+#define SN_netscape_ssl_server_name	"nsSslServerName"
+#define LN_netscape_ssl_server_name	"Netscape SSL Server Name"
+#define NID_netscape_ssl_server_name	77
+#define OBJ_netscape_ssl_server_name	OBJ_netscape_cert_extension,12L
+
+#define SN_netscape_comment		"nsComment"
+#define LN_netscape_comment		"Netscape Comment"
+#define NID_netscape_comment		78
+#define OBJ_netscape_comment		OBJ_netscape_cert_extension,13L
+
+#define SN_netscape_cert_sequence	"nsCertSequence"
+#define LN_netscape_cert_sequence	"Netscape Certificate Sequence"
+#define NID_netscape_cert_sequence	79
+#define OBJ_netscape_cert_sequence	OBJ_netscape_data_type,5L
+
+#define SN_desx_cbc			"DESX-CBC"
+#define LN_desx_cbc			"desx-cbc"
+#define NID_desx_cbc			80
+
+#define SN_id_ce			"id-ce"
+#define NID_id_ce			81
+#define OBJ_id_ce			2L,5L,29L
+
+#define SN_subject_key_identifier	"subjectKeyIdentifier"
+#define LN_subject_key_identifier	"X509v3 Subject Key Identifier"
+#define NID_subject_key_identifier	82
+#define OBJ_subject_key_identifier	OBJ_id_ce,14L
+
+#define SN_key_usage			"keyUsage"
+#define LN_key_usage			"X509v3 Key Usage"
+#define NID_key_usage			83
+#define OBJ_key_usage			OBJ_id_ce,15L
+
+#define SN_private_key_usage_period	"privateKeyUsagePeriod"
+#define LN_private_key_usage_period	"X509v3 Private Key Usage Period"
+#define NID_private_key_usage_period	84
+#define OBJ_private_key_usage_period	OBJ_id_ce,16L
+
+#define SN_subject_alt_name		"subjectAltName"
+#define LN_subject_alt_name		"X509v3 Subject Alternative Name"
+#define NID_subject_alt_name		85
+#define OBJ_subject_alt_name		OBJ_id_ce,17L
+
+#define SN_issuer_alt_name		"issuerAltName"
+#define LN_issuer_alt_name		"X509v3 Issuer Alternative Name"
+#define NID_issuer_alt_name		86
+#define OBJ_issuer_alt_name		OBJ_id_ce,18L
+
+#define SN_basic_constraints		"basicConstraints"
+#define LN_basic_constraints		"X509v3 Basic Constraints"
+#define NID_basic_constraints		87
+#define OBJ_basic_constraints		OBJ_id_ce,19L
+
+#define SN_crl_number			"crlNumber"
+#define LN_crl_number			"X509v3 CRL Number"
+#define NID_crl_number			88
+#define OBJ_crl_number			OBJ_id_ce,20L
+
+#define SN_certificate_policies		"certificatePolicies"
+#define LN_certificate_policies		"X509v3 Certificate Policies"
+#define NID_certificate_policies	89
+#define OBJ_certificate_policies	OBJ_id_ce,32L
+
+#define SN_authority_key_identifier	"authorityKeyIdentifier"
+#define LN_authority_key_identifier	"X509v3 Authority Key Identifier"
+#define NID_authority_key_identifier	90
+#define OBJ_authority_key_identifier	OBJ_id_ce,35L
+
+#define SN_bf_cbc			"BF-CBC"
+#define LN_bf_cbc			"bf-cbc"
+#define NID_bf_cbc			91
+#define OBJ_bf_cbc			1L,3L,6L,1L,4L,1L,3029L,1L,2L
+
+#define SN_bf_ecb			"BF-ECB"
+#define LN_bf_ecb			"bf-ecb"
+#define NID_bf_ecb			92
+
+#define SN_bf_cfb64			"BF-CFB"
+#define LN_bf_cfb64			"bf-cfb"
+#define NID_bf_cfb64			93
+
+#define SN_bf_ofb64			"BF-OFB"
+#define LN_bf_ofb64			"bf-ofb"
+#define NID_bf_ofb64			94
+
+#define SN_mdc2				"MDC2"
+#define LN_mdc2				"mdc2"
+#define NID_mdc2			95
+#define OBJ_mdc2			2L,5L,8L,3L,101L
+/* An alternative?			1L,3L,14L,3L,2L,19L */
+
+#define SN_mdc2WithRSA			"RSA-MDC2"
+#define LN_mdc2WithRSA			"mdc2withRSA"
+#define NID_mdc2WithRSA			96
+#define OBJ_mdc2WithRSA			2L,5L,8L,3L,100L
+
+#define SN_rc4_40			"RC4-40"
+#define LN_rc4_40			"rc4-40"
+#define NID_rc4_40			97
+
+#define SN_rc2_40_cbc			"RC2-40-CBC"
+#define LN_rc2_40_cbc			"rc2-40-cbc"
+#define NID_rc2_40_cbc			98
+
+#define SN_givenName			"G"
+#define LN_givenName			"givenName"
+#define NID_givenName			99
+#define OBJ_givenName			OBJ_X509,42L
+
+#define SN_surname			"S"
+#define LN_surname			"surname"
+#define NID_surname			100
+#define OBJ_surname			OBJ_X509,4L
+
+#define SN_initials			"I"
+#define LN_initials			"initials"
+#define NID_initials			101
+#define OBJ_initials			OBJ_X509,43L
+
+#define SN_uniqueIdentifier		"UID"
+#define LN_uniqueIdentifier		"uniqueIdentifier"
+#define NID_uniqueIdentifier		102
+#define OBJ_uniqueIdentifier		OBJ_X509,45L
+
+#define SN_crl_distribution_points	"crlDistributionPoints"
+#define LN_crl_distribution_points	"X509v3 CRL Distribution Points"
+#define NID_crl_distribution_points	103
+#define OBJ_crl_distribution_points	OBJ_id_ce,31L
+
+#define SN_md5WithRSA			"RSA-NP-MD5"
+#define LN_md5WithRSA			"md5WithRSA"
+#define NID_md5WithRSA			104
+#define OBJ_md5WithRSA			OBJ_algorithm,3L
+
+#define SN_serialNumber			"SN"
+#define LN_serialNumber			"serialNumber"
+#define NID_serialNumber		105
+#define OBJ_serialNumber		OBJ_X509,5L
+
+#define SN_title			"T"
+#define LN_title			"title"
+#define NID_title			106
+#define OBJ_title			OBJ_X509,12L
+
+#define SN_description			"D"
+#define LN_description			"description"
+#define NID_description			107
+#define OBJ_description			OBJ_X509,13L
+
+/* CAST5 is CAST-128, I'm just sticking with the documentation */
+#define SN_cast5_cbc			"CAST5-CBC"
+#define LN_cast5_cbc			"cast5-cbc"
+#define NID_cast5_cbc			108
+#define OBJ_cast5_cbc			1L,2L,840L,113533L,7L,66L,10L
+
+#define SN_cast5_ecb			"CAST5-ECB"
+#define LN_cast5_ecb			"cast5-ecb"
+#define NID_cast5_ecb			109
+
+#define SN_cast5_cfb64			"CAST5-CFB"
+#define LN_cast5_cfb64			"cast5-cfb"
+#define NID_cast5_cfb64			110
+
+#define SN_cast5_ofb64			"CAST5-OFB"
+#define LN_cast5_ofb64			"cast5-ofb"
+#define NID_cast5_ofb64			111
+
+#define LN_pbeWithMD5AndCast5_CBC	"pbeWithMD5AndCast5CBC"
+#define NID_pbeWithMD5AndCast5_CBC	112
+#define OBJ_pbeWithMD5AndCast5_CBC	1L,2L,840L,113533L,7L,66L,12L
+
+/* This is one sun will soon be using :-(
+ * id-dsa-with-sha1 ID  ::= {
+ *   iso(1) member-body(2) us(840) x9-57 (10040) x9cm(4) 3 }
+ */
+#define SN_dsaWithSHA1			"DSA-SHA1"
+#define LN_dsaWithSHA1			"dsaWithSHA1"
+#define NID_dsaWithSHA1			113
+#define OBJ_dsaWithSHA1			1L,2L,840L,10040L,4L,3L
+
+#define NID_md5_sha1			114
+#define SN_md5_sha1			"MD5-SHA1"
+#define LN_md5_sha1			"md5-sha1"
+
+#define SN_sha1WithRSA			"RSA-SHA1-2"
+#define LN_sha1WithRSA			"sha1WithRSA"
+#define NID_sha1WithRSA			115
+#define OBJ_sha1WithRSA			OBJ_algorithm,29L
+
+#define SN_dsa				"DSA"
+#define LN_dsa				"dsaEncryption"
+#define NID_dsa				116
+#define OBJ_dsa				1L,2L,840L,10040L,4L,1L
+
+#define SN_ripemd160			"RIPEMD160"
+#define LN_ripemd160			"ripemd160"
+#define NID_ripemd160			117
+#define OBJ_ripemd160			1L,3L,36L,3L,2L,1L
+
+/* The name should actually be rsaSignatureWithripemd160, but I'm going
+ * to continue using the convention I'm using with the other ciphers */
+#define SN_ripemd160WithRSA		"RSA-RIPEMD160"
+#define LN_ripemd160WithRSA		"ripemd160WithRSA"
+#define NID_ripemd160WithRSA		119
+#define OBJ_ripemd160WithRSA		1L,3L,36L,3L,3L,1L,2L
+
+/* Taken from rfc2040
+ *  RC5_CBC_Parameters ::= SEQUENCE {
+ *	version           INTEGER (v1_0(16)),
+ *	rounds            INTEGER (8..127),
+ *	blockSizeInBits   INTEGER (64, 128),
+ *	iv                OCTET STRING OPTIONAL
+ *	}
+ */
+#define SN_rc5_cbc			"RC5-CBC"
+#define LN_rc5_cbc			"rc5-cbc"
+#define NID_rc5_cbc			120
+#define OBJ_rc5_cbc			OBJ_rsadsi,3L,8L
+
+#define SN_rc5_ecb			"RC5-ECB"
+#define LN_rc5_ecb			"rc5-ecb"
+#define NID_rc5_ecb			121
+
+#define SN_rc5_cfb64			"RC5-CFB"
+#define LN_rc5_cfb64			"rc5-cfb"
+#define NID_rc5_cfb64			122
+
+#define SN_rc5_ofb64			"RC5-OFB"
+#define LN_rc5_ofb64			"rc5-ofb"
+#define NID_rc5_ofb64			123
+
+#define SN_rle_compression		"RLE"
+#define LN_rle_compression		"run length compression"
+#define NID_rle_compression		124
+#define OBJ_rle_compression		1L,1L,1L,1L,666L,1L
+
+#define SN_zlib_compression		"ZLIB"
+#define LN_zlib_compression		"zlib compression"
+#define NID_zlib_compression		125
+#define OBJ_zlib_compression		1L,1L,1L,1L,666L,2L
+
+#define SN_ext_key_usage		"extendedKeyUsage"
+#define LN_ext_key_usage		"X509v3 Extended Key Usage"
+#define NID_ext_key_usage		126
+#define OBJ_ext_key_usage		OBJ_id_ce,37
+
+#define SN_id_pkix			"PKIX"
+#define NID_id_pkix			127
+#define OBJ_id_pkix			1L,3L,6L,1L,5L,5L,7L
+
+#define SN_id_kp			"id-kp"
+#define NID_id_kp			128
+#define OBJ_id_kp			OBJ_id_pkix,3L
+
+/* PKIX extended key usage OIDs */
+
+#define SN_server_auth			"serverAuth"
+#define LN_server_auth			"TLS Web Server Authentication"
+#define NID_server_auth			129
+#define OBJ_server_auth			OBJ_id_kp,1L
+
+#define SN_client_auth			"clientAuth"
+#define LN_client_auth			"TLS Web Client Authentication"
+#define NID_client_auth			130
+#define OBJ_client_auth			OBJ_id_kp,2L
+
+#define SN_code_sign			"codeSigning"
+#define LN_code_sign			"Code Signing"
+#define NID_code_sign			131
+#define OBJ_code_sign			OBJ_id_kp,3L
+
+#define SN_email_protect		"emailProtection"
+#define LN_email_protect		"E-mail Protection"
+#define NID_email_protect		132
+#define OBJ_email_protect		OBJ_id_kp,4L
+
+#define SN_time_stamp			"timeStamping"
+#define LN_time_stamp			"Time Stamping"
+#define NID_time_stamp			133
+#define OBJ_time_stamp			OBJ_id_kp,8L
+
+/* Additional extended key usage OIDs: Microsoft */
+
+#define SN_ms_code_ind			"msCodeInd"
+#define LN_ms_code_ind			"Microsoft Individual Code Signing"
+#define NID_ms_code_ind			134
+#define OBJ_ms_code_ind			1L,3L,6L,1L,4L,1L,311L,2L,1L,21L
+
+#define SN_ms_code_com			"msCodeCom"
+#define LN_ms_code_com			"Microsoft Commercial Code Signing"
+#define NID_ms_code_com			135
+#define OBJ_ms_code_com			1L,3L,6L,1L,4L,1L,311L,2L,1L,22L
+
+#define SN_ms_ctl_sign			"msCTLSign"
+#define LN_ms_ctl_sign			"Microsoft Trust List Signing"
+#define NID_ms_ctl_sign			136
+#define OBJ_ms_ctl_sign			1L,3L,6L,1L,4L,1L,311L,10L,3L,1L
+
+#define SN_ms_sgc			"msSGC"
+#define LN_ms_sgc			"Microsoft Server Gated Crypto"
+#define NID_ms_sgc			137
+#define OBJ_ms_sgc			1L,3L,6L,1L,4L,1L,311L,10L,3L,3L
+
+#define SN_ms_efs			"msEFS"
+#define LN_ms_efs			"Microsoft Encrypted File System"
+#define NID_ms_efs			138
+#define OBJ_ms_efs			1L,3L,6L,1L,4L,1L,311L,10L,3L,4L
+
+/* Additional usage: Netscape */
+
+#define SN_ns_sgc			"nsSGC"
+#define LN_ns_sgc			"Netscape Server Gated Crypto"
+#define NID_ns_sgc			139
+#define OBJ_ns_sgc			OBJ_netscape,4L,1L
+
+#define SN_delta_crl			"deltaCRL"
+#define LN_delta_crl			"X509v3 Delta CRL Indicator"
+#define NID_delta_crl			140
+#define OBJ_delta_crl			OBJ_id_ce,27L
+
+#define SN_crl_reason			"CRLReason"
+#define LN_crl_reason			"CRL Reason Code"
+#define NID_crl_reason			141
+#define OBJ_crl_reason			OBJ_id_ce,21L
+
+#define SN_invalidity_date		"invalidityDate"
+#define LN_invalidity_date		"Invalidity Date"
+#define NID_invalidity_date		142
+#define OBJ_invalidity_date		OBJ_id_ce,24L
+
+#define SN_sxnet			"SXNetID"
+#define LN_sxnet			"Strong Extranet ID"
+#define NID_sxnet			143
+#define OBJ_sxnet			1L,3L,101L,1L,4L,1L
+
+/* PKCS12 and related OBJECT IDENTIFIERS */
+
+#define OBJ_pkcs12			OBJ_pkcs,12L
+#define OBJ_pkcs12_pbeids		OBJ_pkcs12, 1
+
+#define SN_pbe_WithSHA1And128BitRC4	"PBE-SHA1-RC4-128"
+#define LN_pbe_WithSHA1And128BitRC4	"pbeWithSHA1And128BitRC4"
+#define NID_pbe_WithSHA1And128BitRC4	144
+#define OBJ_pbe_WithSHA1And128BitRC4	OBJ_pkcs12_pbeids, 1L
+
+#define SN_pbe_WithSHA1And40BitRC4	"PBE-SHA1-RC4-40"
+#define LN_pbe_WithSHA1And40BitRC4	"pbeWithSHA1And40BitRC4"
+#define NID_pbe_WithSHA1And40BitRC4	145
+#define OBJ_pbe_WithSHA1And40BitRC4	OBJ_pkcs12_pbeids, 2L
+
+#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC	"PBE-SHA1-3DES"
+#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC	"pbeWithSHA1And3-KeyTripleDES-CBC"
+#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC	146
+#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC	OBJ_pkcs12_pbeids, 3L
+
+#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC	"PBE-SHA1-2DES"
+#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC	"pbeWithSHA1And2-KeyTripleDES-CBC"
+#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC	147
+#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC	OBJ_pkcs12_pbeids, 4L
+
+#define SN_pbe_WithSHA1And128BitRC2_CBC		"PBE-SHA1-RC2-128"
+#define LN_pbe_WithSHA1And128BitRC2_CBC		"pbeWithSHA1And128BitRC2-CBC"
+#define NID_pbe_WithSHA1And128BitRC2_CBC	148
+#define OBJ_pbe_WithSHA1And128BitRC2_CBC	OBJ_pkcs12_pbeids, 5L
+
+#define SN_pbe_WithSHA1And40BitRC2_CBC	"PBE-SHA1-RC2-40"
+#define LN_pbe_WithSHA1And40BitRC2_CBC	"pbeWithSHA1And40BitRC2-CBC"
+#define NID_pbe_WithSHA1And40BitRC2_CBC	149
+#define OBJ_pbe_WithSHA1And40BitRC2_CBC	OBJ_pkcs12_pbeids, 6L
+
+#define OBJ_pkcs12_Version1	OBJ_pkcs12, 10L
+
+#define OBJ_pkcs12_BagIds	OBJ_pkcs12_Version1, 1L
+
+#define LN_keyBag		"keyBag"
+#define NID_keyBag		150
+#define OBJ_keyBag		OBJ_pkcs12_BagIds, 1L
+
+#define LN_pkcs8ShroudedKeyBag	"pkcs8ShroudedKeyBag"
+#define NID_pkcs8ShroudedKeyBag	151
+#define OBJ_pkcs8ShroudedKeyBag	OBJ_pkcs12_BagIds, 2L
+
+#define LN_certBag		"certBag"
+#define NID_certBag		152
+#define OBJ_certBag		OBJ_pkcs12_BagIds, 3L
+
+#define LN_crlBag		"crlBag"
+#define NID_crlBag		153
+#define OBJ_crlBag		OBJ_pkcs12_BagIds, 4L
+
+#define LN_secretBag		"secretBag"
+#define NID_secretBag		154
+#define OBJ_secretBag		OBJ_pkcs12_BagIds, 5L
+
+#define LN_safeContentsBag	"safeContentsBag"
+#define NID_safeContentsBag	155
+#define OBJ_safeContentsBag	OBJ_pkcs12_BagIds, 6L
+
+#define LN_friendlyName		"friendlyName"
+#define	NID_friendlyName	156
+#define OBJ_friendlyName	OBJ_pkcs9, 20L
+
+#define LN_localKeyID		"localKeyID"
+#define	NID_localKeyID		157
+#define OBJ_localKeyID		OBJ_pkcs9, 21L
+
+#define OBJ_certTypes		OBJ_pkcs9, 22L
+
+#define LN_x509Certificate	"x509Certificate"
+#define	NID_x509Certificate	158
+#define OBJ_x509Certificate	OBJ_certTypes, 1L
+
+#define LN_sdsiCertificate	"sdsiCertificate"
+#define	NID_sdsiCertificate	159
+#define OBJ_sdsiCertificate	OBJ_certTypes, 2L
+
+#define OBJ_crlTypes		OBJ_pkcs9, 23L
+
+#define LN_x509Crl		"x509Crl"
+#define	NID_x509Crl		160
+#define OBJ_x509Crl		OBJ_crlTypes, 1L
+
+/* PKCS#5 v2 OIDs */
+
+#define LN_pbes2		"PBES2"
+#define NID_pbes2		161
+#define OBJ_pbes2		OBJ_pkcs,5L,13L
+
+#define LN_pbmac1		"PBMAC1"
+#define NID_pbmac1		162
+#define OBJ_pbmac1		OBJ_pkcs,5L,14L
+
+#define LN_hmacWithSHA1		"hmacWithSHA1"
+#define NID_hmacWithSHA1	163
+#define OBJ_hmacWithSHA1	OBJ_rsadsi,2L,7L
+
+/* Policy Qualifier Ids */
+
+#define LN_id_qt_cps		"Policy Qualifier CPS"
+#define SN_id_qt_cps		"id-qt-cps"
+#define NID_id_qt_cps		164
+#define OBJ_id_qt_cps		OBJ_id_pkix,2L,1L
+
+#define LN_id_qt_unotice	"Policy Qualifier User Notice"
+#define SN_id_qt_unotice	"id-qt-unotice"
+#define NID_id_qt_unotice	165
+#define OBJ_id_qt_unotice	OBJ_id_pkix,2L,2L
+
+#define SN_rc2_64_cbc			"RC2-64-CBC"
+#define LN_rc2_64_cbc			"rc2-64-cbc"
+#define NID_rc2_64_cbc			166
+
+#define SN_SMIMECapabilities		"SMIME-CAPS"
+#define LN_SMIMECapabilities		"S/MIME Capabilities"
+#define NID_SMIMECapabilities		167
+#define OBJ_SMIMECapabilities		OBJ_pkcs9,15L
+
+#define SN_pbeWithMD2AndRC2_CBC		"PBE-MD2-RC2-64"
+#define LN_pbeWithMD2AndRC2_CBC		"pbeWithMD2AndRC2-CBC"
+#define NID_pbeWithMD2AndRC2_CBC	168
+#define OBJ_pbeWithMD2AndRC2_CBC	OBJ_pkcs,5L,4L
+
+#define SN_pbeWithMD5AndRC2_CBC		"PBE-MD5-RC2-64"
+#define LN_pbeWithMD5AndRC2_CBC		"pbeWithMD5AndRC2-CBC"
+#define NID_pbeWithMD5AndRC2_CBC	169
+#define OBJ_pbeWithMD5AndRC2_CBC	OBJ_pkcs,5L,6L
+
+#define SN_pbeWithSHA1AndDES_CBC	"PBE-SHA1-DES"
+#define LN_pbeWithSHA1AndDES_CBC	"pbeWithSHA1AndDES-CBC"
+#define NID_pbeWithSHA1AndDES_CBC	170
+#define OBJ_pbeWithSHA1AndDES_CBC	OBJ_pkcs,5L,10L
+
+/* Extension request OIDs */
+
+#define LN_ms_ext_req			"Microsoft Extension Request"
+#define SN_ms_ext_req			"msExtReq"
+#define NID_ms_ext_req			171
+#define OBJ_ms_ext_req			1L,3L,6L,1L,4L,1L,311L,2L,1L,14L
+
+#define LN_ext_req			"Extension Request"
+#define SN_ext_req			"extReq"
+#define NID_ext_req			172
+#define OBJ_ext_req			OBJ_pkcs9,14L
+
+#define SN_name				"name"
+#define LN_name				"name"
+#define NID_name			173
+#define OBJ_name			OBJ_X509,41L
+
+#define SN_dnQualifier			"dnQualifier"
+#define LN_dnQualifier			"dnQualifier"
+#define NID_dnQualifier			174
+#define OBJ_dnQualifier			OBJ_X509,46L
+
+#define SN_id_pe			"id-pe"
+#define NID_id_pe			175
+#define OBJ_id_pe			OBJ_id_pkix,1L
+
+#define SN_id_ad			"id-ad"
+#define NID_id_ad			176
+#define OBJ_id_ad			OBJ_id_pkix,48L
+
+#define SN_info_access			"authorityInfoAccess"
+#define LN_info_access			"Authority Information Access"
+#define NID_info_access			177
+#define OBJ_info_access			OBJ_id_pe,1L
+
+#define SN_ad_OCSP			"OCSP"
+#define LN_ad_OCSP			"OCSP"
+#define NID_ad_OCSP			178
+#define OBJ_ad_OCSP			OBJ_id_ad,1L
+
+#define SN_ad_ca_issuers		"caIssuers"
+#define LN_ad_ca_issuers		"CA Issuers"
+#define NID_ad_ca_issuers		179
+#define OBJ_ad_ca_issuers		OBJ_id_ad,2L
+
+#define SN_OCSP_sign			"OCSPSigning"
+#define LN_OCSP_sign			"OCSP Signing"
+#define NID_OCSP_sign			180
+#define OBJ_OCSP_sign			OBJ_id_kp,9L
+#endif /* USE_OBJ_MAC */
+
+#include <openssl/bio.h>
+#include <openssl/asn1.h>
+
+#define	OBJ_NAME_TYPE_UNDEF		0x00
+#define	OBJ_NAME_TYPE_MD_METH		0x01
+#define	OBJ_NAME_TYPE_CIPHER_METH	0x02
+#define	OBJ_NAME_TYPE_PKEY_METH		0x03
+#define	OBJ_NAME_TYPE_COMP_METH		0x04
+#define	OBJ_NAME_TYPE_NUM		0x05
+
+#define	OBJ_NAME_ALIAS			0x8000
+
+#define OBJ_BSEARCH_VALUE_ON_NOMATCH		0x01
+#define OBJ_BSEARCH_FIRST_VALUE_ON_MATCH	0x02
+
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct obj_name_st
+	{
+	int type;
+	int alias;
+	const char *name;
+	const char *data;
+	} OBJ_NAME;
+
+#define		OBJ_create_and_add_object(a,b,c) OBJ_create(a,b,c)
+
+
+int OBJ_NAME_init(void);
+int OBJ_NAME_new_index(unsigned long (*hash_func)(const char *),
+		       int (*cmp_func)(const char *, const char *),
+		       void (*free_func)(const char *, int, const char *));
+const char *OBJ_NAME_get(const char *name,int type);
+int OBJ_NAME_add(const char *name,int type,const char *data);
+int OBJ_NAME_remove(const char *name,int type);
+void OBJ_NAME_cleanup(int type); /* -1 for everything */
+void OBJ_NAME_do_all(int type,void (*fn)(const OBJ_NAME *,void *arg),
+		     void *arg);
+void OBJ_NAME_do_all_sorted(int type,void (*fn)(const OBJ_NAME *,void *arg),
+			    void *arg);
+
+ASN1_OBJECT *	OBJ_dup(const ASN1_OBJECT *o);
+ASN1_OBJECT *	OBJ_nid2obj(int n);
+const char *	OBJ_nid2ln(int n);
+const char *	OBJ_nid2sn(int n);
+int		OBJ_obj2nid(const ASN1_OBJECT *o);
+ASN1_OBJECT *	OBJ_txt2obj(const char *s, int no_name);
+int	OBJ_obj2txt(char *buf, int buf_len, const ASN1_OBJECT *a, int no_name);
+int		OBJ_txt2nid(const char *s);
+int		OBJ_ln2nid(const char *s);
+int		OBJ_sn2nid(const char *s);
+int		OBJ_cmp(const ASN1_OBJECT *a,const ASN1_OBJECT *b);
+const char *	OBJ_bsearch(const char *key,const char *base,int num,int size,
+	int (*cmp)(const void *, const void *));
+const char *	OBJ_bsearch_ex(const char *key,const char *base,int num,
+	int size, int (*cmp)(const void *, const void *), int flags);
+
+int		OBJ_new_nid(int num);
+int		OBJ_add_object(const ASN1_OBJECT *obj);
+int		OBJ_create(const char *oid,const char *sn,const char *ln);
+void		OBJ_cleanup(void );
+int		OBJ_create_objects(BIO *in);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_OBJ_strings(void);
+
+/* Error codes for the OBJ functions. */
+
+/* Function codes. */
+#define OBJ_F_OBJ_ADD_OBJECT				 105
+#define OBJ_F_OBJ_CREATE				 100
+#define OBJ_F_OBJ_DUP					 101
+#define OBJ_F_OBJ_NAME_NEW_INDEX			 106
+#define OBJ_F_OBJ_NID2LN				 102
+#define OBJ_F_OBJ_NID2OBJ				 103
+#define OBJ_F_OBJ_NID2SN				 104
+
+/* Reason codes. */
+#define OBJ_R_MALLOC_FAILURE				 100
+#define OBJ_R_UNKNOWN_NID				 101
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ocsp.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ocsp.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ocsp.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,614 @@
+/* ocsp.h */
+/* Written by Tom Titchener <Tom_Titchener@groove.net> for the OpenSSL
+ * project. */
+
+/* History:
+   This file was transfered to Richard Levitte from CertCo by Kathy
+   Weinhold in mid-spring 2000 to be included in OpenSSL or released
+   as a patch kit. */
+
+/* ====================================================================
+ * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_OCSP_H
+#define HEADER_OCSP_H
+
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/safestack.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Various flags and values */
+
+#define OCSP_DEFAULT_NONCE_LENGTH	16
+
+#define OCSP_NOCERTS			0x1
+#define OCSP_NOINTERN			0x2
+#define OCSP_NOSIGS			0x4
+#define OCSP_NOCHAIN			0x8
+#define OCSP_NOVERIFY			0x10
+#define OCSP_NOEXPLICIT			0x20
+#define OCSP_NOCASIGN			0x40
+#define OCSP_NODELEGATED		0x80
+#define OCSP_NOCHECKS			0x100
+#define OCSP_TRUSTOTHER			0x200
+#define OCSP_RESPID_KEY			0x400
+#define OCSP_NOTIME			0x800
+
+/*   CertID ::= SEQUENCE {
+ *       hashAlgorithm            AlgorithmIdentifier,
+ *       issuerNameHash     OCTET STRING, -- Hash of Issuer's DN
+ *       issuerKeyHash      OCTET STRING, -- Hash of Issuers public key (excluding the tag & length fields)
+ *       serialNumber       CertificateSerialNumber }
+ */
+typedef struct ocsp_cert_id_st
+	{
+	X509_ALGOR *hashAlgorithm;
+	ASN1_OCTET_STRING *issuerNameHash;
+	ASN1_OCTET_STRING *issuerKeyHash;
+	ASN1_INTEGER *serialNumber;
+	} OCSP_CERTID;
+
+DECLARE_STACK_OF(OCSP_CERTID)
+
+/*   Request ::=     SEQUENCE {
+ *       reqCert                    CertID,
+ *       singleRequestExtensions    [0] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct ocsp_one_request_st
+	{
+	OCSP_CERTID *reqCert;
+	STACK_OF(X509_EXTENSION) *singleRequestExtensions;
+	} OCSP_ONEREQ;
+
+DECLARE_STACK_OF(OCSP_ONEREQ)
+DECLARE_ASN1_SET_OF(OCSP_ONEREQ)
+
+
+/*   TBSRequest      ::=     SEQUENCE {
+ *       version             [0] EXPLICIT Version DEFAULT v1,
+ *       requestorName       [1] EXPLICIT GeneralName OPTIONAL,
+ *       requestList             SEQUENCE OF Request,
+ *       requestExtensions   [2] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct ocsp_req_info_st
+	{
+	ASN1_INTEGER *version;
+	GENERAL_NAME *requestorName;
+	STACK_OF(OCSP_ONEREQ) *requestList;
+	STACK_OF(X509_EXTENSION) *requestExtensions;
+	} OCSP_REQINFO;
+
+/*   Signature       ::=     SEQUENCE {
+ *       signatureAlgorithm   AlgorithmIdentifier,
+ *       signature            BIT STRING,
+ *       certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+typedef struct ocsp_signature_st
+	{
+	X509_ALGOR *signatureAlgorithm;
+	ASN1_BIT_STRING *signature;
+	STACK_OF(X509) *certs;
+	} OCSP_SIGNATURE;
+
+/*   OCSPRequest     ::=     SEQUENCE {
+ *       tbsRequest                  TBSRequest,
+ *       optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+ */
+typedef struct ocsp_request_st
+	{
+	OCSP_REQINFO *tbsRequest;
+	OCSP_SIGNATURE *optionalSignature; /* OPTIONAL */
+	} OCSP_REQUEST;
+
+/*   OCSPResponseStatus ::= ENUMERATED {
+ *       successful            (0),      --Response has valid confirmations
+ *       malformedRequest      (1),      --Illegal confirmation request
+ *       internalError         (2),      --Internal error in issuer
+ *       tryLater              (3),      --Try again later
+ *                                       --(4) is not used
+ *       sigRequired           (5),      --Must sign the request
+ *       unauthorized          (6)       --Request unauthorized
+ *   }
+ */
+#define OCSP_RESPONSE_STATUS_SUCCESSFUL          0
+#define OCSP_RESPONSE_STATUS_MALFORMEDREQUEST     1
+#define OCSP_RESPONSE_STATUS_INTERNALERROR        2
+#define OCSP_RESPONSE_STATUS_TRYLATER             3
+#define OCSP_RESPONSE_STATUS_SIGREQUIRED          5
+#define OCSP_RESPONSE_STATUS_UNAUTHORIZED         6
+
+/*   ResponseBytes ::=       SEQUENCE {
+ *       responseType   OBJECT IDENTIFIER,
+ *       response       OCTET STRING }
+ */
+typedef struct ocsp_resp_bytes_st
+	{
+	ASN1_OBJECT *responseType;
+	ASN1_OCTET_STRING *response;
+	} OCSP_RESPBYTES;
+
+/*   OCSPResponse ::= SEQUENCE {
+ *      responseStatus         OCSPResponseStatus,
+ *      responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+typedef struct ocsp_response_st
+	{
+	ASN1_ENUMERATED *responseStatus;
+	OCSP_RESPBYTES  *responseBytes;
+	} OCSP_RESPONSE;
+
+/*   ResponderID ::= CHOICE {
+ *      byName   [1] Name,
+ *      byKey    [2] KeyHash }
+ */
+#define V_OCSP_RESPID_NAME 0
+#define V_OCSP_RESPID_KEY  1
+typedef struct ocsp_responder_id_st
+	{
+	int type;
+	union   {
+		X509_NAME* byName;
+        	ASN1_OCTET_STRING *byKey;
+		} value;
+	} OCSP_RESPID;
+/*   KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key
+ *                            --(excluding the tag and length fields)
+ */
+
+/*   RevokedInfo ::= SEQUENCE {
+ *       revocationTime              GeneralizedTime,
+ *       revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+ */
+typedef struct ocsp_revoked_info_st
+	{
+	ASN1_GENERALIZEDTIME *revocationTime;
+	ASN1_ENUMERATED *revocationReason;
+	} OCSP_REVOKEDINFO;
+
+/*   CertStatus ::= CHOICE {
+ *       good                [0]     IMPLICIT NULL,
+ *       revoked             [1]     IMPLICIT RevokedInfo,
+ *       unknown             [2]     IMPLICIT UnknownInfo }
+ */
+#define V_OCSP_CERTSTATUS_GOOD    0
+#define V_OCSP_CERTSTATUS_REVOKED 1
+#define V_OCSP_CERTSTATUS_UNKNOWN 2
+typedef struct ocsp_cert_status_st
+	{
+	int type;
+	union	{
+		ASN1_NULL *good;
+		OCSP_REVOKEDINFO *revoked;
+		ASN1_NULL *unknown;
+		} value;
+	} OCSP_CERTSTATUS;
+
+/*   SingleResponse ::= SEQUENCE {
+ *      certID                       CertID,
+ *      certStatus                   CertStatus,
+ *      thisUpdate                   GeneralizedTime,
+ *      nextUpdate           [0]     EXPLICIT GeneralizedTime OPTIONAL,
+ *      singleExtensions     [1]     EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct ocsp_single_response_st
+	{
+	OCSP_CERTID *certId;
+	OCSP_CERTSTATUS *certStatus;
+	ASN1_GENERALIZEDTIME *thisUpdate;
+	ASN1_GENERALIZEDTIME *nextUpdate;
+	STACK_OF(X509_EXTENSION) *singleExtensions;
+	} OCSP_SINGLERESP;
+
+DECLARE_STACK_OF(OCSP_SINGLERESP)
+DECLARE_ASN1_SET_OF(OCSP_SINGLERESP)
+
+/*   ResponseData ::= SEQUENCE {
+ *      version              [0] EXPLICIT Version DEFAULT v1,
+ *      responderID              ResponderID,
+ *      producedAt               GeneralizedTime,
+ *      responses                SEQUENCE OF SingleResponse,
+ *      responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+ */
+typedef struct ocsp_response_data_st
+	{
+	ASN1_INTEGER *version;
+	OCSP_RESPID  *responderId;
+	ASN1_GENERALIZEDTIME *producedAt;
+	STACK_OF(OCSP_SINGLERESP) *responses;
+	STACK_OF(X509_EXTENSION) *responseExtensions;
+	} OCSP_RESPDATA;
+
+/*   BasicOCSPResponse       ::= SEQUENCE {
+ *      tbsResponseData      ResponseData,
+ *      signatureAlgorithm   AlgorithmIdentifier,
+ *      signature            BIT STRING,
+ *      certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+  /* Note 1:
+     The value for "signature" is specified in the OCSP rfc2560 as follows:
+     "The value for the signature SHALL be computed on the hash of the DER
+     encoding ResponseData."  This means that you must hash the DER-encoded
+     tbsResponseData, and then run it through a crypto-signing function, which
+     will (at least w/RSA) do a hash-'n'-private-encrypt operation.  This seems
+     a bit odd, but that's the spec.  Also note that the data structures do not
+     leave anywhere to independently specify the algorithm used for the initial
+     hash. So, we look at the signature-specification algorithm, and try to do
+     something intelligent.	-- Kathy Weinhold, CertCo */
+  /* Note 2:
+     It seems that the mentioned passage from RFC 2560 (section 4.2.1) is open
+     for interpretation.  I've done tests against another responder, and found
+     that it doesn't do the double hashing that the RFC seems to say one
+     should.  Therefore, all relevant functions take a flag saying which
+     variant should be used.	-- Richard Levitte, OpenSSL team and CeloCom */
+typedef struct ocsp_basic_response_st
+	{
+	OCSP_RESPDATA *tbsResponseData;
+	X509_ALGOR *signatureAlgorithm;
+	ASN1_BIT_STRING *signature;
+	STACK_OF(X509) *certs;
+	} OCSP_BASICRESP;
+
+/*
+ *   CRLReason ::= ENUMERATED {
+ *        unspecified             (0),
+ *        keyCompromise           (1),
+ *        cACompromise            (2),
+ *        affiliationChanged      (3),
+ *        superseded              (4),
+ *        cessationOfOperation    (5),
+ *        certificateHold         (6),
+ *        removeFromCRL           (8) }
+ */
+#define OCSP_REVOKED_STATUS_NOSTATUS               -1
+#define OCSP_REVOKED_STATUS_UNSPECIFIED             0
+#define OCSP_REVOKED_STATUS_KEYCOMPROMISE           1
+#define OCSP_REVOKED_STATUS_CACOMPROMISE            2
+#define OCSP_REVOKED_STATUS_AFFILIATIONCHANGED      3
+#define OCSP_REVOKED_STATUS_SUPERSEDED              4
+#define OCSP_REVOKED_STATUS_CESSATIONOFOPERATION    5
+#define OCSP_REVOKED_STATUS_CERTIFICATEHOLD         6
+#define OCSP_REVOKED_STATUS_REMOVEFROMCRL           8
+
+/* CrlID ::= SEQUENCE {
+ *     crlUrl               [0]     EXPLICIT IA5String OPTIONAL,
+ *     crlNum               [1]     EXPLICIT INTEGER OPTIONAL,
+ *     crlTime              [2]     EXPLICIT GeneralizedTime OPTIONAL }
+ */
+typedef struct ocsp_crl_id_st
+        {
+	ASN1_IA5STRING *crlUrl;
+	ASN1_INTEGER *crlNum;
+	ASN1_GENERALIZEDTIME *crlTime;
+        } OCSP_CRLID;
+
+/* ServiceLocator ::= SEQUENCE {
+ *      issuer    Name,
+ *      locator   AuthorityInfoAccessSyntax OPTIONAL }
+ */
+typedef struct ocsp_service_locator_st
+        {
+	X509_NAME* issuer;
+	STACK_OF(ACCESS_DESCRIPTION) *locator;
+        } OCSP_SERVICELOC;
+ 
+#define PEM_STRING_OCSP_REQUEST	"OCSP REQUEST"
+#define PEM_STRING_OCSP_RESPONSE "OCSP RESPONSE"
+
+#define d2i_OCSP_REQUEST_bio(bp,p) ASN1_d2i_bio_of(OCSP_REQUEST,OCSP_REQUEST_new,d2i_OCSP_REQUEST,bp,p)
+
+#define d2i_OCSP_RESPONSE_bio(bp,p) ASN1_d2i_bio_of(OCSP_RESPONSE,OCSP_RESPONSE_new,d2i_OCSP_RESPONSE,bp,p)
+
+#define	PEM_read_bio_OCSP_REQUEST(bp,x,cb) (OCSP_REQUEST *)PEM_ASN1_read_bio( \
+     (char *(*)())d2i_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,bp,(char **)x,cb,NULL)
+
+#define	PEM_read_bio_OCSP_RESPONSE(bp,x,cb)(OCSP_RESPONSE *)PEM_ASN1_read_bio(\
+     (char *(*)())d2i_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,bp,(char **)x,cb,NULL)
+
+#define PEM_write_bio_OCSP_REQUEST(bp,o) \
+    PEM_ASN1_write_bio((int (*)())i2d_OCSP_REQUEST,PEM_STRING_OCSP_REQUEST,\
+			bp,(char *)o, NULL,NULL,0,NULL,NULL)
+
+#define PEM_write_bio_OCSP_RESPONSE(bp,o) \
+    PEM_ASN1_write_bio((int (*)())i2d_OCSP_RESPONSE,PEM_STRING_OCSP_RESPONSE,\
+			bp,(char *)o, NULL,NULL,0,NULL,NULL)
+
+#define i2d_OCSP_RESPONSE_bio(bp,o) ASN1_i2d_bio_of(OCSP_RESPONSE,i2d_OCSP_RESPONSE,bp,o)
+
+#define i2d_OCSP_REQUEST_bio(bp,o) ASN1_i2d_bio_of(OCSP_REQUEST,i2d_OCSP_REQUEST,bp,o)
+
+#define OCSP_REQUEST_sign(o,pkey,md) \
+	ASN1_item_sign(ASN1_ITEM_rptr(OCSP_REQINFO),\
+		o->optionalSignature->signatureAlgorithm,NULL,\
+	        o->optionalSignature->signature,o->tbsRequest,pkey,md)
+
+#define OCSP_BASICRESP_sign(o,pkey,md,d) \
+	ASN1_item_sign(ASN1_ITEM_rptr(OCSP_RESPDATA),o->signatureAlgorithm,NULL,\
+		o->signature,o->tbsResponseData,pkey,md)
+
+#define OCSP_REQUEST_verify(a,r) ASN1_item_verify(ASN1_ITEM_rptr(OCSP_REQINFO),\
+        a->optionalSignature->signatureAlgorithm,\
+	a->optionalSignature->signature,a->tbsRequest,r)
+
+#define OCSP_BASICRESP_verify(a,r,d) ASN1_item_verify(ASN1_ITEM_rptr(OCSP_RESPDATA),\
+	a->signatureAlgorithm,a->signature,a->tbsResponseData,r)
+
+#define ASN1_BIT_STRING_digest(data,type,md,len) \
+	ASN1_item_digest(ASN1_ITEM_rptr(ASN1_BIT_STRING),type,data,md,len)
+
+#define OCSP_CERTID_dup(cid) ASN1_dup_of(OCSP_CERTID,i2d_OCSP_CERTID,d2i_OCSP_CERTID,cid)
+
+#define OCSP_CERTSTATUS_dup(cs)\
+                (OCSP_CERTSTATUS*)ASN1_dup((int(*)())i2d_OCSP_CERTSTATUS,\
+		(char *(*)())d2i_OCSP_CERTSTATUS,(char *)(cs))
+
+OCSP_RESPONSE *OCSP_sendreq_bio(BIO *b, char *path, OCSP_REQUEST *req);
+
+OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *dgst, X509 *subject, X509 *issuer);
+
+OCSP_CERTID *OCSP_cert_id_new(const EVP_MD *dgst, 
+			      X509_NAME *issuerName, 
+			      ASN1_BIT_STRING* issuerKey, 
+			      ASN1_INTEGER *serialNumber);
+
+OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *req, OCSP_CERTID *cid);
+
+int OCSP_request_add1_nonce(OCSP_REQUEST *req, unsigned char *val, int len);
+int OCSP_basic_add1_nonce(OCSP_BASICRESP *resp, unsigned char *val, int len);
+int OCSP_check_nonce(OCSP_REQUEST *req, OCSP_BASICRESP *bs);
+int OCSP_copy_nonce(OCSP_BASICRESP *resp, OCSP_REQUEST *req);
+
+int OCSP_request_set1_name(OCSP_REQUEST *req, X509_NAME *nm);
+int OCSP_request_add1_cert(OCSP_REQUEST *req, X509 *cert);
+
+int OCSP_request_sign(OCSP_REQUEST   *req,
+		      X509           *signer,
+		      EVP_PKEY       *key,
+		      const EVP_MD   *dgst,
+		      STACK_OF(X509) *certs,
+		      unsigned long flags);
+
+int OCSP_response_status(OCSP_RESPONSE *resp);
+OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *resp);
+
+int OCSP_resp_count(OCSP_BASICRESP *bs);
+OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *bs, int idx);
+int OCSP_resp_find(OCSP_BASICRESP *bs, OCSP_CERTID *id, int last);
+int OCSP_single_get0_status(OCSP_SINGLERESP *single, int *reason,
+				ASN1_GENERALIZEDTIME **revtime,
+				ASN1_GENERALIZEDTIME **thisupd,
+				ASN1_GENERALIZEDTIME **nextupd);
+int OCSP_resp_find_status(OCSP_BASICRESP *bs, OCSP_CERTID *id, int *status,
+				int *reason,
+				ASN1_GENERALIZEDTIME **revtime,
+				ASN1_GENERALIZEDTIME **thisupd,
+				ASN1_GENERALIZEDTIME **nextupd);
+int OCSP_check_validity(ASN1_GENERALIZEDTIME *thisupd,
+			ASN1_GENERALIZEDTIME *nextupd,
+			long sec, long maxsec);
+
+int OCSP_request_verify(OCSP_REQUEST *req, STACK_OF(X509) *certs, X509_STORE *store, unsigned long flags);
+
+int OCSP_parse_url(char *url, char **phost, char **pport, char **ppath, int *pssl);
+
+int OCSP_id_issuer_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
+int OCSP_id_cmp(OCSP_CERTID *a, OCSP_CERTID *b);
+
+int OCSP_request_onereq_count(OCSP_REQUEST *req);
+OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *req, int i);
+OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *one);
+int OCSP_id_get0_info(ASN1_OCTET_STRING **piNameHash, ASN1_OBJECT **pmd,
+			ASN1_OCTET_STRING **pikeyHash,
+			ASN1_INTEGER **pserial, OCSP_CERTID *cid);
+int OCSP_request_is_signed(OCSP_REQUEST *req);
+OCSP_RESPONSE *OCSP_response_create(int status, OCSP_BASICRESP *bs);
+OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *rsp,
+						OCSP_CERTID *cid,
+						int status, int reason,
+						ASN1_TIME *revtime,
+					ASN1_TIME *thisupd, ASN1_TIME *nextupd);
+int OCSP_basic_add1_cert(OCSP_BASICRESP *resp, X509 *cert);
+int OCSP_basic_sign(OCSP_BASICRESP *brsp, 
+			X509 *signer, EVP_PKEY *key, const EVP_MD *dgst,
+			STACK_OF(X509) *certs, unsigned long flags);
+
+ASN1_STRING *ASN1_STRING_encode(ASN1_STRING *s, i2d_of_void *i2d,
+				void *data, STACK_OF(ASN1_OBJECT) *sk);
+#define ASN1_STRING_encode_of(type,s,i2d,data,sk) \
+((ASN1_STRING *(*)(ASN1_STRING *,I2D_OF(type),type *,STACK_OF(ASN1_OBJECT) *))openssl_fcast(ASN1_STRING_encode))(s,i2d,data,sk)
+
+X509_EXTENSION *OCSP_crlID_new(char *url, long *n, char *tim);
+
+X509_EXTENSION *OCSP_accept_responses_new(char **oids);
+
+X509_EXTENSION *OCSP_archive_cutoff_new(char* tim);
+
+X509_EXTENSION *OCSP_url_svcloc_new(X509_NAME* issuer, char **urls);
+
+int OCSP_REQUEST_get_ext_count(OCSP_REQUEST *x);
+int OCSP_REQUEST_get_ext_by_NID(OCSP_REQUEST *x, int nid, int lastpos);
+int OCSP_REQUEST_get_ext_by_OBJ(OCSP_REQUEST *x, ASN1_OBJECT *obj, int lastpos);
+int OCSP_REQUEST_get_ext_by_critical(OCSP_REQUEST *x, int crit, int lastpos);
+X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *x, int loc);
+X509_EXTENSION *OCSP_REQUEST_delete_ext(OCSP_REQUEST *x, int loc);
+void *OCSP_REQUEST_get1_ext_d2i(OCSP_REQUEST *x, int nid, int *crit, int *idx);
+int OCSP_REQUEST_add1_ext_i2d(OCSP_REQUEST *x, int nid, void *value, int crit,
+							unsigned long flags);
+int OCSP_REQUEST_add_ext(OCSP_REQUEST *x, X509_EXTENSION *ex, int loc);
+
+int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *x);
+int OCSP_ONEREQ_get_ext_by_NID(OCSP_ONEREQ *x, int nid, int lastpos);
+int OCSP_ONEREQ_get_ext_by_OBJ(OCSP_ONEREQ *x, ASN1_OBJECT *obj, int lastpos);
+int OCSP_ONEREQ_get_ext_by_critical(OCSP_ONEREQ *x, int crit, int lastpos);
+X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *x, int loc);
+X509_EXTENSION *OCSP_ONEREQ_delete_ext(OCSP_ONEREQ *x, int loc);
+void *OCSP_ONEREQ_get1_ext_d2i(OCSP_ONEREQ *x, int nid, int *crit, int *idx);
+int OCSP_ONEREQ_add1_ext_i2d(OCSP_ONEREQ *x, int nid, void *value, int crit,
+							unsigned long flags);
+int OCSP_ONEREQ_add_ext(OCSP_ONEREQ *x, X509_EXTENSION *ex, int loc);
+
+int OCSP_BASICRESP_get_ext_count(OCSP_BASICRESP *x);
+int OCSP_BASICRESP_get_ext_by_NID(OCSP_BASICRESP *x, int nid, int lastpos);
+int OCSP_BASICRESP_get_ext_by_OBJ(OCSP_BASICRESP *x, ASN1_OBJECT *obj, int lastpos);
+int OCSP_BASICRESP_get_ext_by_critical(OCSP_BASICRESP *x, int crit, int lastpos);
+X509_EXTENSION *OCSP_BASICRESP_get_ext(OCSP_BASICRESP *x, int loc);
+X509_EXTENSION *OCSP_BASICRESP_delete_ext(OCSP_BASICRESP *x, int loc);
+void *OCSP_BASICRESP_get1_ext_d2i(OCSP_BASICRESP *x, int nid, int *crit, int *idx);
+int OCSP_BASICRESP_add1_ext_i2d(OCSP_BASICRESP *x, int nid, void *value, int crit,
+							unsigned long flags);
+int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *x, X509_EXTENSION *ex, int loc);
+
+int OCSP_SINGLERESP_get_ext_count(OCSP_SINGLERESP *x);
+int OCSP_SINGLERESP_get_ext_by_NID(OCSP_SINGLERESP *x, int nid, int lastpos);
+int OCSP_SINGLERESP_get_ext_by_OBJ(OCSP_SINGLERESP *x, ASN1_OBJECT *obj, int lastpos);
+int OCSP_SINGLERESP_get_ext_by_critical(OCSP_SINGLERESP *x, int crit, int lastpos);
+X509_EXTENSION *OCSP_SINGLERESP_get_ext(OCSP_SINGLERESP *x, int loc);
+X509_EXTENSION *OCSP_SINGLERESP_delete_ext(OCSP_SINGLERESP *x, int loc);
+void *OCSP_SINGLERESP_get1_ext_d2i(OCSP_SINGLERESP *x, int nid, int *crit, int *idx);
+int OCSP_SINGLERESP_add1_ext_i2d(OCSP_SINGLERESP *x, int nid, void *value, int crit,
+							unsigned long flags);
+int OCSP_SINGLERESP_add_ext(OCSP_SINGLERESP *x, X509_EXTENSION *ex, int loc);
+
+DECLARE_ASN1_FUNCTIONS(OCSP_SINGLERESP)
+DECLARE_ASN1_FUNCTIONS(OCSP_CERTSTATUS)
+DECLARE_ASN1_FUNCTIONS(OCSP_REVOKEDINFO)
+DECLARE_ASN1_FUNCTIONS(OCSP_BASICRESP)
+DECLARE_ASN1_FUNCTIONS(OCSP_RESPDATA)
+DECLARE_ASN1_FUNCTIONS(OCSP_RESPID)
+DECLARE_ASN1_FUNCTIONS(OCSP_RESPONSE)
+DECLARE_ASN1_FUNCTIONS(OCSP_RESPBYTES)
+DECLARE_ASN1_FUNCTIONS(OCSP_ONEREQ)
+DECLARE_ASN1_FUNCTIONS(OCSP_CERTID)
+DECLARE_ASN1_FUNCTIONS(OCSP_REQUEST)
+DECLARE_ASN1_FUNCTIONS(OCSP_SIGNATURE)
+DECLARE_ASN1_FUNCTIONS(OCSP_REQINFO)
+DECLARE_ASN1_FUNCTIONS(OCSP_CRLID)
+DECLARE_ASN1_FUNCTIONS(OCSP_SERVICELOC)
+
+char *OCSP_response_status_str(long s);
+char *OCSP_cert_status_str(long s);
+char *OCSP_crl_reason_str(long s);
+
+int OCSP_REQUEST_print(BIO *bp, OCSP_REQUEST* a, unsigned long flags);
+int OCSP_RESPONSE_print(BIO *bp, OCSP_RESPONSE* o, unsigned long flags);
+
+int OCSP_basic_verify(OCSP_BASICRESP *bs, STACK_OF(X509) *certs,
+				X509_STORE *st, unsigned long flags);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_OCSP_strings(void);
+
+/* Error codes for the OCSP functions. */
+
+/* Function codes. */
+#define OCSP_F_ASN1_STRING_ENCODE			 100
+#define OCSP_F_D2I_OCSP_NONCE				 102
+#define OCSP_F_OCSP_BASIC_ADD1_STATUS			 103
+#define OCSP_F_OCSP_BASIC_SIGN				 104
+#define OCSP_F_OCSP_BASIC_VERIFY			 105
+#define OCSP_F_OCSP_CERT_ID_NEW				 101
+#define OCSP_F_OCSP_CHECK_DELEGATED			 106
+#define OCSP_F_OCSP_CHECK_IDS				 107
+#define OCSP_F_OCSP_CHECK_ISSUER			 108
+#define OCSP_F_OCSP_CHECK_VALIDITY			 115
+#define OCSP_F_OCSP_MATCH_ISSUERID			 109
+#define OCSP_F_OCSP_PARSE_URL				 114
+#define OCSP_F_OCSP_REQUEST_SIGN			 110
+#define OCSP_F_OCSP_REQUEST_VERIFY			 116
+#define OCSP_F_OCSP_RESPONSE_GET1_BASIC			 111
+#define OCSP_F_OCSP_SENDREQ_BIO				 112
+#define OCSP_F_REQUEST_VERIFY				 113
+
+/* Reason codes. */
+#define OCSP_R_BAD_DATA					 100
+#define OCSP_R_CERTIFICATE_VERIFY_ERROR			 101
+#define OCSP_R_DIGEST_ERR				 102
+#define OCSP_R_ERROR_IN_NEXTUPDATE_FIELD		 122
+#define OCSP_R_ERROR_IN_THISUPDATE_FIELD		 123
+#define OCSP_R_ERROR_PARSING_URL			 121
+#define OCSP_R_MISSING_OCSPSIGNING_USAGE		 103
+#define OCSP_R_NEXTUPDATE_BEFORE_THISUPDATE		 124
+#define OCSP_R_NOT_BASIC_RESPONSE			 104
+#define OCSP_R_NO_CERTIFICATES_IN_CHAIN			 105
+#define OCSP_R_NO_CONTENT				 106
+#define OCSP_R_NO_PUBLIC_KEY				 107
+#define OCSP_R_NO_RESPONSE_DATA				 108
+#define OCSP_R_NO_REVOKED_TIME				 109
+#define OCSP_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE	 110
+#define OCSP_R_REQUEST_NOT_SIGNED			 128
+#define OCSP_R_RESPONSE_CONTAINS_NO_REVOCATION_DATA	 111
+#define OCSP_R_ROOT_CA_NOT_TRUSTED			 112
+#define OCSP_R_SERVER_READ_ERROR			 113
+#define OCSP_R_SERVER_RESPONSE_ERROR			 114
+#define OCSP_R_SERVER_RESPONSE_PARSE_ERROR		 115
+#define OCSP_R_SERVER_WRITE_ERROR			 116
+#define OCSP_R_SIGNATURE_FAILURE			 117
+#define OCSP_R_SIGNER_CERTIFICATE_NOT_FOUND		 118
+#define OCSP_R_STATUS_EXPIRED				 125
+#define OCSP_R_STATUS_NOT_YET_VALID			 126
+#define OCSP_R_STATUS_TOO_OLD				 127
+#define OCSP_R_UNKNOWN_MESSAGE_DIGEST			 119
+#define OCSP_R_UNKNOWN_NID				 120
+#define OCSP_R_UNSUPPORTED_REQUESTORNAME_TYPE		 129
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/opensslconf.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/opensslconf.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/opensslconf.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,202 @@
+/* opensslconf.h */
+/* WARNING: Generated automatically from opensslconf.h.in by Configure. */
+
+/* OpenSSL was configured with the following options: */
+#ifndef OPENSSL_DOING_MAKEDEPEND
+
+#ifndef OPENSSL_NO_GMP
+# define OPENSSL_NO_GMP
+#endif
+#ifndef OPENSSL_NO_KRB5
+# define OPENSSL_NO_KRB5
+#endif
+#ifndef OPENSSL_NO_MDC2
+# define OPENSSL_NO_MDC2
+#endif
+#ifndef OPENSSL_NO_RC5
+# define OPENSSL_NO_RC5
+#endif
+
+#endif /* OPENSSL_DOING_MAKEDEPEND */
+#ifndef OPENSSL_NO_DYNAMIC_ENGINE
+# define OPENSSL_NO_DYNAMIC_ENGINE
+#endif
+
+/* The OPENSSL_NO_* macros are also defined as NO_* if the application
+   asks for it.  This is a transient feature that is provided for those
+   who haven't had the time to do the appropriate changes in their
+   applications.  */
+#ifdef OPENSSL_ALGORITHM_DEFINES
+# if defined(OPENSSL_NO_GMP) && !defined(NO_GMP)
+#  define NO_GMP
+# endif
+# if defined(OPENSSL_NO_KRB5) && !defined(NO_KRB5)
+#  define NO_KRB5
+# endif
+# if defined(OPENSSL_NO_MDC2) && !defined(NO_MDC2)
+#  define NO_MDC2
+# endif
+# if defined(OPENSSL_NO_RC5) && !defined(NO_RC5)
+#  define NO_RC5
+# endif
+#endif
+
+/* crypto/opensslconf.h.in */
+
+/* Generate 80386 code? */
+#undef I386_ONLY
+
+#if !(defined(VMS) || defined(__VMS)) /* VMS uses logical names instead */
+#if defined(HEADER_CRYPTLIB_H) && !defined(OPENSSLDIR)
+#define ENGINESDIR "/usr/local/ssl/lib/engines"
+#define OPENSSLDIR "/usr/local/ssl"
+#endif
+#endif
+
+#undef OPENSSL_UNISTD
+#define OPENSSL_UNISTD <unistd.h>
+
+#undef OPENSSL_EXPORT_VAR_AS_FUNCTION
+
+#if defined(HEADER_IDEA_H) && !defined(IDEA_INT)
+#define IDEA_INT unsigned int
+#endif
+
+#if defined(HEADER_MD2_H) && !defined(MD2_INT)
+#define MD2_INT unsigned int
+#endif
+
+#if defined(HEADER_RC2_H) && !defined(RC2_INT)
+/* I need to put in a mod for the alpha - eay */
+#define RC2_INT unsigned int
+#endif
+
+#if defined(HEADER_RC4_H)
+#if !defined(RC4_INT)
+/* using int types make the structure larger but make the code faster
+ * on most boxes I have tested - up to %20 faster. */
+/*
+ * I don't know what does "most" mean, but declaring "int" is a must on:
+ * - Intel P6 because partial register stalls are very expensive;
+ * - elder Alpha because it lacks byte load/store instructions;
+ */
+#define RC4_INT unsigned int
+#endif
+#if !defined(RC4_CHUNK)
+/*
+ * This enables code handling data aligned at natural CPU word
+ * boundary. See crypto/rc4/rc4_enc.c for further details.
+ */
+#undef RC4_CHUNK
+#endif
+#endif
+
+#if (defined(HEADER_NEW_DES_H) || defined(HEADER_DES_H)) && !defined(DES_LONG)
+/* If this is set to 'unsigned int' on a DEC Alpha, this gives about a
+ * %20 speed up (longs are 8 bytes, int's are 4). */
+#ifndef DES_LONG
+#define DES_LONG unsigned long
+#endif
+#endif
+
+#if defined(HEADER_BN_H) && !defined(CONFIG_HEADER_BN_H)
+#define CONFIG_HEADER_BN_H
+#undef BN_LLONG
+
+/* Should we define BN_DIV2W here? */
+
+/* Only one for the following should be defined */
+/* The prime number generation stuff may not work when
+ * EIGHT_BIT but I don't care since I've only used this mode
+ * for debuging the bignum libraries */
+#undef SIXTY_FOUR_BIT_LONG
+#undef SIXTY_FOUR_BIT
+#define THIRTY_TWO_BIT
+#undef SIXTEEN_BIT
+#undef EIGHT_BIT
+#endif
+
+#if defined(HEADER_RC4_LOCL_H) && !defined(CONFIG_HEADER_RC4_LOCL_H)
+#define CONFIG_HEADER_RC4_LOCL_H
+/* if this is defined data[i] is used instead of *data, this is a %20
+ * speedup on x86 */
+#undef RC4_INDEX
+#endif
+
+#if defined(HEADER_BF_LOCL_H) && !defined(CONFIG_HEADER_BF_LOCL_H)
+#define CONFIG_HEADER_BF_LOCL_H
+#undef BF_PTR
+#endif /* HEADER_BF_LOCL_H */
+
+#if defined(HEADER_DES_LOCL_H) && !defined(CONFIG_HEADER_DES_LOCL_H)
+#define CONFIG_HEADER_DES_LOCL_H
+#ifndef DES_DEFAULT_OPTIONS
+/* the following is tweaked from a config script, that is why it is a
+ * protected undef/define */
+#ifndef DES_PTR
+#undef DES_PTR
+#endif
+
+/* This helps C compiler generate the correct code for multiple functional
+ * units.  It reduces register dependancies at the expense of 2 more
+ * registers */
+#ifndef DES_RISC1
+#undef DES_RISC1
+#endif
+
+#ifndef DES_RISC2
+#undef DES_RISC2
+#endif
+
+#if defined(DES_RISC1) && defined(DES_RISC2)
+YOU SHOULD NOT HAVE BOTH DES_RISC1 AND DES_RISC2 DEFINED!!!!!
+#endif
+
+/* Unroll the inner loop, this sometimes helps, sometimes hinders.
+ * Very mucy CPU dependant */
+#ifndef DES_UNROLL
+#undef DES_UNROLL
+#endif
+
+/* These default values were supplied by
+ * Peter Gutman <pgut001@cs.auckland.ac.nz>
+ * They are only used if nothing else has been defined */
+#if !defined(DES_PTR) && !defined(DES_RISC1) && !defined(DES_RISC2) && !defined(DES_UNROLL)
+/* Special defines which change the way the code is built depending on the
+   CPU and OS.  For SGI machines you can use _MIPS_SZLONG (32 or 64) to find
+   even newer MIPS CPU's, but at the moment one size fits all for
+   optimization options.  Older Sparc's work better with only UNROLL, but
+   there's no way to tell at compile time what it is you're running on */
+ 
+#if defined( sun )		/* Newer Sparc's */
+#  define DES_PTR
+#  define DES_RISC1
+#  define DES_UNROLL
+#elif defined( __ultrix )	/* Older MIPS */
+#  define DES_PTR
+#  define DES_RISC2
+#  define DES_UNROLL
+#elif defined( __osf1__ )	/* Alpha */
+#  define DES_PTR
+#  define DES_RISC2
+#elif defined ( _AIX )		/* RS6000 */
+  /* Unknown */
+#elif defined( __hpux )		/* HP-PA */
+  /* Unknown */
+#elif defined( __aux )		/* 68K */
+  /* Unknown */
+#elif defined( __dgux )		/* 88K (but P6 in latest boxes) */
+#  define DES_UNROLL
+#elif defined( __sgi )		/* Newer MIPS */
+#  define DES_PTR
+#  define DES_RISC2
+#  define DES_UNROLL
+#elif defined(i386) || defined(__i386__)	/* x86 boxes, should be gcc */
+#  define DES_PTR
+#  define DES_RISC1
+#  define DES_UNROLL
+#endif /* Systems-specific speed defines */
+#endif
+
+#endif /* DES_DEFAULT_OPTIONS */
+#endif /* HEADER_DES_LOCL_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/opensslv.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/opensslv.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/opensslv.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,89 @@
+#ifndef HEADER_OPENSSLV_H
+#define HEADER_OPENSSLV_H
+
+/* Numeric release version identifier:
+ * MNNFFPPS: major minor fix patch status
+ * The status nibble has one of the values 0 for development, 1 to e for betas
+ * 1 to 14, and f for release.  The patch level is exactly that.
+ * For example:
+ * 0.9.3-dev	  0x00903000
+ * 0.9.3-beta1	  0x00903001
+ * 0.9.3-beta2-dev 0x00903002
+ * 0.9.3-beta2    0x00903002 (same as ...beta2-dev)
+ * 0.9.3	  0x0090300f
+ * 0.9.3a	  0x0090301f
+ * 0.9.4	  0x0090400f
+ * 1.2.3z	  0x102031af
+ *
+ * For continuity reasons (because 0.9.5 is already out, and is coded
+ * 0x00905100), between 0.9.5 and 0.9.6 the coding of the patch level
+ * part is slightly different, by setting the highest bit.  This means
+ * that 0.9.5a looks like this: 0x0090581f.  At 0.9.6, we can start
+ * with 0x0090600S...
+ *
+ * (Prior to 0.9.3-dev a different scheme was used: 0.9.2b is 0x0922.)
+ * (Prior to 0.9.5a beta1, a different scheme was used: MMNNFFRBB for
+ *  major minor fix final patch/beta)
+ */
+#define OPENSSL_VERSION_NUMBER	0x0090800fL
+#ifdef OPENSSL_FIPS
+#define OPENSSL_VERSION_TEXT	"OpenSSL 0.9.8-fips 05 Jul 2005"
+#else
+#define OPENSSL_VERSION_TEXT	"OpenSSL 0.9.8 05 Jul 2005"
+#endif
+#define OPENSSL_VERSION_PTEXT	" part of " OPENSSL_VERSION_TEXT
+
+
+/* The macros below are to be used for shared library (.so, .dll, ...)
+ * versioning.  That kind of versioning works a bit differently between
+ * operating systems.  The most usual scheme is to set a major and a minor
+ * number, and have the runtime loader check that the major number is equal
+ * to what it was at application link time, while the minor number has to
+ * be greater or equal to what it was at application link time.  With this
+ * scheme, the version number is usually part of the file name, like this:
+ *
+ *	libcrypto.so.0.9
+ *
+ * Some unixen also make a softlink with the major verson number only:
+ *
+ *	libcrypto.so.0
+ *
+ * On Tru64 and IRIX 6.x it works a little bit differently.  There, the
+ * shared library version is stored in the file, and is actually a series
+ * of versions, separated by colons.  The rightmost version present in the
+ * library when linking an application is stored in the application to be
+ * matched at run time.  When the application is run, a check is done to
+ * see if the library version stored in the application matches any of the
+ * versions in the version string of the library itself.
+ * This version string can be constructed in any way, depending on what
+ * kind of matching is desired.  However, to implement the same scheme as
+ * the one used in the other unixen, all compatible versions, from lowest
+ * to highest, should be part of the string.  Consecutive builds would
+ * give the following versions strings:
+ *
+ *	3.0
+ *	3.0:3.1
+ *	3.0:3.1:3.2
+ *	4.0
+ *	4.0:4.1
+ *
+ * Notice how version 4 is completely incompatible with version, and
+ * therefore give the breach you can see.
+ *
+ * There may be other schemes as well that I haven't yet discovered.
+ *
+ * So, here's the way it works here: first of all, the library version
+ * number doesn't need at all to match the overall OpenSSL version.
+ * However, it's nice and more understandable if it actually does.
+ * The current library version is stored in the macro SHLIB_VERSION_NUMBER,
+ * which is just a piece of text in the format "M.m.e" (Major, minor, edit).
+ * For the sake of Tru64, IRIX, and any other OS that behaves in similar ways,
+ * we need to keep a history of version numbers, which is done in the
+ * macro SHLIB_VERSION_HISTORY.  The numbers are separated by colons and
+ * should only keep the versions that are binary compatible with the current.
+ */
+#define SHLIB_VERSION_HISTORY ""
+#define SHLIB_VERSION_NUMBER "0.9.8"
+
+
+#endif /* HEADER_OPENSSLV_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ossl_typ.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ossl_typ.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ossl_typ.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,174 @@
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_OPENSSL_TYPES_H
+#define HEADER_OPENSSL_TYPES_H
+
+#include <openssl/e_os2.h>
+
+#ifdef NO_ASN1_TYPEDEFS
+#define ASN1_INTEGER		ASN1_STRING
+#define ASN1_ENUMERATED		ASN1_STRING
+#define ASN1_BIT_STRING		ASN1_STRING
+#define ASN1_OCTET_STRING	ASN1_STRING
+#define ASN1_PRINTABLESTRING	ASN1_STRING
+#define ASN1_T61STRING		ASN1_STRING
+#define ASN1_IA5STRING		ASN1_STRING
+#define ASN1_UTCTIME		ASN1_STRING
+#define ASN1_GENERALIZEDTIME	ASN1_STRING
+#define ASN1_TIME		ASN1_STRING
+#define ASN1_GENERALSTRING	ASN1_STRING
+#define ASN1_UNIVERSALSTRING	ASN1_STRING
+#define ASN1_BMPSTRING		ASN1_STRING
+#define ASN1_VISIBLESTRING	ASN1_STRING
+#define ASN1_UTF8STRING		ASN1_STRING
+#define ASN1_BOOLEAN		int
+#define ASN1_NULL		int
+#else
+typedef struct asn1_string_st ASN1_INTEGER;
+typedef struct asn1_string_st ASN1_ENUMERATED;
+typedef struct asn1_string_st ASN1_BIT_STRING;
+typedef struct asn1_string_st ASN1_OCTET_STRING;
+typedef struct asn1_string_st ASN1_PRINTABLESTRING;
+typedef struct asn1_string_st ASN1_T61STRING;
+typedef struct asn1_string_st ASN1_IA5STRING;
+typedef struct asn1_string_st ASN1_GENERALSTRING;
+typedef struct asn1_string_st ASN1_UNIVERSALSTRING;
+typedef struct asn1_string_st ASN1_BMPSTRING;
+typedef struct asn1_string_st ASN1_UTCTIME;
+typedef struct asn1_string_st ASN1_TIME;
+typedef struct asn1_string_st ASN1_GENERALIZEDTIME;
+typedef struct asn1_string_st ASN1_VISIBLESTRING;
+typedef struct asn1_string_st ASN1_UTF8STRING;
+typedef int ASN1_BOOLEAN;
+typedef int ASN1_NULL;
+#endif
+
+#ifdef OPENSSL_SYS_WIN32
+#undef X509_NAME
+#undef X509_CERT_PAIR
+#undef PKCS7_ISSUER_AND_SERIAL
+#endif
+
+#ifdef BIGNUM
+#undef BIGNUM
+#endif
+typedef struct bignum_st BIGNUM;
+typedef struct bignum_ctx BN_CTX;
+typedef struct bn_blinding_st BN_BLINDING;
+typedef struct bn_mont_ctx_st BN_MONT_CTX;
+typedef struct bn_recp_ctx_st BN_RECP_CTX;
+typedef struct bn_gencb_st BN_GENCB;
+
+typedef struct buf_mem_st BUF_MEM;
+
+typedef struct evp_cipher_st EVP_CIPHER;
+typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
+typedef struct env_md_st EVP_MD;
+typedef struct env_md_ctx_st EVP_MD_CTX;
+typedef struct evp_pkey_st EVP_PKEY;
+
+typedef struct dh_st DH;
+typedef struct dh_method DH_METHOD;
+
+typedef struct dsa_st DSA;
+typedef struct dsa_method DSA_METHOD;
+
+typedef struct rsa_st RSA;
+typedef struct rsa_meth_st RSA_METHOD;
+
+typedef struct rand_meth_st RAND_METHOD;
+
+typedef struct ecdh_method ECDH_METHOD;
+typedef struct ecdsa_method ECDSA_METHOD;
+
+typedef struct x509_st X509;
+typedef struct X509_algor_st X509_ALGOR;
+typedef struct X509_crl_st X509_CRL;
+typedef struct X509_name_st X509_NAME;
+typedef struct x509_store_st X509_STORE;
+typedef struct x509_store_ctx_st X509_STORE_CTX;
+
+typedef struct v3_ext_ctx X509V3_CTX;
+typedef struct conf_st CONF;
+
+typedef struct store_st STORE;
+typedef struct store_method_st STORE_METHOD;
+
+typedef struct ui_st UI;
+typedef struct ui_method_st UI_METHOD;
+
+typedef struct st_ERR_FNS ERR_FNS;
+
+typedef struct engine_st ENGINE;
+
+typedef struct X509_POLICY_NODE_st X509_POLICY_NODE;
+typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL;
+typedef struct X509_POLICY_TREE_st X509_POLICY_TREE;
+typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE;
+
+  /* If placed in pkcs12.h, we end up with a circular depency with pkcs7.h */
+#define DECLARE_PKCS12_STACK_OF(type) /* Nothing */
+#define IMPLEMENT_PKCS12_STACK_OF(type) /* Nothing */
+
+typedef struct crypto_ex_data_st CRYPTO_EX_DATA;
+/* Callback types for crypto.h */
+typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+					int idx, long argl, void *argp);
+typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
+					int idx, long argl, void *argp);
+typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d, 
+					int idx, long argl, void *argp);
+
+#endif /* def HEADER_OPENSSL_TYPES_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pem.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pem.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pem.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,737 @@
+/* crypto/pem/pem.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_PEM_H
+#define HEADER_PEM_H
+
+#include <openssl/e_os2.h>
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#ifndef OPENSSL_NO_STACK
+#include <openssl/stack.h>
+#endif
+#include <openssl/evp.h>
+#include <openssl/x509.h>
+#include <openssl/pem2.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define PEM_BUFSIZE		1024
+
+#define PEM_OBJ_UNDEF		0
+#define PEM_OBJ_X509		1
+#define PEM_OBJ_X509_REQ	2
+#define PEM_OBJ_CRL		3
+#define PEM_OBJ_SSL_SESSION	4
+#define PEM_OBJ_PRIV_KEY	10
+#define PEM_OBJ_PRIV_RSA	11
+#define PEM_OBJ_PRIV_DSA	12
+#define PEM_OBJ_PRIV_DH		13
+#define PEM_OBJ_PUB_RSA		14
+#define PEM_OBJ_PUB_DSA		15
+#define PEM_OBJ_PUB_DH		16
+#define PEM_OBJ_DHPARAMS	17
+#define PEM_OBJ_DSAPARAMS	18
+#define PEM_OBJ_PRIV_RSA_PUBLIC	19
+#define PEM_OBJ_PRIV_ECDSA	20
+#define PEM_OBJ_PUB_ECDSA	21
+#define PEM_OBJ_ECPARAMETERS	22
+
+#define PEM_ERROR		30
+#define PEM_DEK_DES_CBC         40
+#define PEM_DEK_IDEA_CBC        45
+#define PEM_DEK_DES_EDE         50
+#define PEM_DEK_DES_ECB         60
+#define PEM_DEK_RSA             70
+#define PEM_DEK_RSA_MD2         80
+#define PEM_DEK_RSA_MD5         90
+
+#define PEM_MD_MD2		NID_md2
+#define PEM_MD_MD5		NID_md5
+#define PEM_MD_SHA		NID_sha
+#define PEM_MD_MD2_RSA		NID_md2WithRSAEncryption
+#define PEM_MD_MD5_RSA		NID_md5WithRSAEncryption
+#define PEM_MD_SHA_RSA		NID_sha1WithRSAEncryption
+
+#define PEM_STRING_X509_OLD	"X509 CERTIFICATE"
+#define PEM_STRING_X509		"CERTIFICATE"
+#define PEM_STRING_X509_PAIR	"CERTIFICATE PAIR"
+#define PEM_STRING_X509_TRUSTED	"TRUSTED CERTIFICATE"
+#define PEM_STRING_X509_REQ_OLD	"NEW CERTIFICATE REQUEST"
+#define PEM_STRING_X509_REQ	"CERTIFICATE REQUEST"
+#define PEM_STRING_X509_CRL	"X509 CRL"
+#define PEM_STRING_EVP_PKEY	"ANY PRIVATE KEY"
+#define PEM_STRING_PUBLIC	"PUBLIC KEY"
+#define PEM_STRING_RSA		"RSA PRIVATE KEY"
+#define PEM_STRING_RSA_PUBLIC	"RSA PUBLIC KEY"
+#define PEM_STRING_DSA		"DSA PRIVATE KEY"
+#define PEM_STRING_DSA_PUBLIC	"DSA PUBLIC KEY"
+#define PEM_STRING_PKCS7	"PKCS7"
+#define PEM_STRING_PKCS8	"ENCRYPTED PRIVATE KEY"
+#define PEM_STRING_PKCS8INF	"PRIVATE KEY"
+#define PEM_STRING_DHPARAMS	"DH PARAMETERS"
+#define PEM_STRING_SSL_SESSION	"SSL SESSION PARAMETERS"
+#define PEM_STRING_DSAPARAMS	"DSA PARAMETERS"
+#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY"
+#define PEM_STRING_ECPARAMETERS "EC PARAMETERS"
+#define PEM_STRING_ECPRIVATEKEY	"EC PRIVATE KEY"
+
+  /* Note that this structure is initialised by PEM_SealInit and cleaned up
+     by PEM_SealFinal (at least for now) */
+typedef struct PEM_Encode_Seal_st
+	{
+	EVP_ENCODE_CTX encode;
+	EVP_MD_CTX md;
+	EVP_CIPHER_CTX cipher;
+	} PEM_ENCODE_SEAL_CTX;
+
+/* enc_type is one off */
+#define PEM_TYPE_ENCRYPTED      10
+#define PEM_TYPE_MIC_ONLY       20
+#define PEM_TYPE_MIC_CLEAR      30
+#define PEM_TYPE_CLEAR		40
+
+typedef struct pem_recip_st
+	{
+	char *name;
+	X509_NAME *dn;
+
+	int cipher;
+	int key_enc;
+	/*	char iv[8]; unused and wrong size */
+	} PEM_USER;
+
+typedef struct pem_ctx_st
+	{
+	int type;		/* what type of object */
+
+	struct	{
+		int version;	
+		int mode;		
+		} proc_type;
+
+	char *domain;
+
+	struct	{
+		int cipher;
+	/* unused, and wrong size
+	   unsigned char iv[8]; */
+		} DEK_info;
+		
+	PEM_USER *originator;
+
+	int num_recipient;
+	PEM_USER **recipient;
+
+#ifndef OPENSSL_NO_STACK
+	STACK *x509_chain;	/* certificate chain */
+#else
+	char *x509_chain;	/* certificate chain */
+#endif
+	EVP_MD *md;		/* signature type */
+
+	int md_enc;		/* is the md encrypted or not? */
+	int md_len;		/* length of md_data */
+	char *md_data;		/* message digest, could be pkey encrypted */
+
+	EVP_CIPHER *dec;	/* date encryption cipher */
+	int key_len;		/* key length */
+	unsigned char *key;	/* key */
+	/* unused, and wrong size
+	   unsigned char iv[8]; */
+
+	
+	int  data_enc;		/* is the data encrypted */
+	int data_len;
+	unsigned char *data;
+	} PEM_CTX;
+
+/* These macros make the PEM_read/PEM_write functions easier to maintain and
+ * write. Now they are all implemented with either:
+ * IMPLEMENT_PEM_rw(...) or IMPLEMENT_PEM_rw_cb(...)
+ */
+
+#ifdef OPENSSL_NO_FP_API
+
+#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) /**/
+#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) /**/
+#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) /**/
+
+#else
+
+#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \
+type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\
+{ \
+return(((type *(*)(D2I_OF(type),char *,FILE *,type **,pem_password_cb *,void *))openssl_fcast(PEM_ASN1_read))(d2i_##asn1, str,fp,x,cb,u)); \
+} \
+
+#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \
+int PEM_write_##name(FILE *fp, type *x) \
+{ \
+return(((int (*)(I2D_OF(type),const char *,FILE *,type *, const EVP_CIPHER *,unsigned char *,int, pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write))(i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL)); \
+}
+
+#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \
+int PEM_write_##name(FILE *fp, const type *x) \
+{ \
+return(((int (*)(I2D_OF_const(type),const char *,FILE *, const type *, const EVP_CIPHER *,unsigned char *,int, pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write))(i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL)); \
+}
+
+#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \
+int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
+	     unsigned char *kstr, int klen, pem_password_cb *cb, \
+		  void *u) \
+	{ \
+	return(((int (*)(I2D_OF(type),const char *,FILE *,type *, const EVP_CIPHER *,unsigned char *,int, pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write))(i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u)); \
+	}
+
+#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \
+int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
+	     unsigned char *kstr, int klen, pem_password_cb *cb, \
+		  void *u) \
+	{ \
+	return(((int (*)(I2D_OF_const(type),const char *,FILE *,type *, const EVP_CIPHER *,unsigned char *,int, pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write))(i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u)); \
+	}
+
+#endif
+
+#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
+type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\
+{ \
+return(((type *(*)(D2I_OF(type),const char *,BIO *,type **,pem_password_cb *,void *))openssl_fcast(PEM_ASN1_read_bio))(d2i_##asn1, str,bp,x,cb,u)); \
+}
+
+#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \
+int PEM_write_bio_##name(BIO *bp, type *x) \
+{ \
+return(((int (*)(I2D_OF(type),const char *,BIO *,type *, const EVP_CIPHER *,unsigned char *,int, pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write_bio))(i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL)); \
+}
+
+#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \
+int PEM_write_bio_##name(BIO *bp, const type *x) \
+{ \
+return(((int (*)(I2D_OF_const(type),const char *,BIO *,const type *, const EVP_CIPHER *,unsigned char *,int, pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write_bio))(i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL)); \
+}
+
+#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \
+int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
+	     unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \
+	{ \
+	return(((int (*)(I2D_OF(type),const char *,BIO *,type *,const EVP_CIPHER *,unsigned char *,int,pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write_bio))(i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u)); \
+	}
+
+#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \
+int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
+	     unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \
+	{ \
+	return(((int (*)(I2D_OF_const(type),const char *,BIO *,type *,const EVP_CIPHER *,unsigned char *,int,pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write_bio))(i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u)); \
+	}
+
+#define IMPLEMENT_PEM_write(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_bio(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_fp(name, type, str, asn1) 
+
+#define IMPLEMENT_PEM_write_const(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) 
+
+#define IMPLEMENT_PEM_write_cb(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) 
+
+#define IMPLEMENT_PEM_write_cb_const(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) 
+
+#define IMPLEMENT_PEM_read(name, type, str, asn1) \
+	IMPLEMENT_PEM_read_bio(name, type, str, asn1) \
+	IMPLEMENT_PEM_read_fp(name, type, str, asn1) 
+
+#define IMPLEMENT_PEM_rw(name, type, str, asn1) \
+	IMPLEMENT_PEM_read(name, type, str, asn1) \
+	IMPLEMENT_PEM_write(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \
+	IMPLEMENT_PEM_read(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_const(name, type, str, asn1)
+
+#define IMPLEMENT_PEM_rw_cb(name, type, str, asn1) \
+	IMPLEMENT_PEM_read(name, type, str, asn1) \
+	IMPLEMENT_PEM_write_cb(name, type, str, asn1)
+
+/* These are the same except they are for the declarations */
+
+#if defined(OPENSSL_SYS_WIN16) || defined(OPENSSL_NO_FP_API)
+
+#define DECLARE_PEM_read_fp(name, type) /**/
+#define DECLARE_PEM_write_fp(name, type) /**/
+#define DECLARE_PEM_write_cb_fp(name, type) /**/
+
+#else
+
+#define DECLARE_PEM_read_fp(name, type) \
+	type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u);
+
+#define DECLARE_PEM_write_fp(name, type) \
+	int PEM_write_##name(FILE *fp, type *x);
+
+#define DECLARE_PEM_write_fp_const(name, type) \
+	int PEM_write_##name(FILE *fp, const type *x);
+
+#define DECLARE_PEM_write_cb_fp(name, type) \
+	int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \
+	     unsigned char *kstr, int klen, pem_password_cb *cb, void *u);
+
+#endif
+
+#ifndef OPENSSL_NO_BIO
+#define DECLARE_PEM_read_bio(name, type) \
+	type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u);
+
+#define DECLARE_PEM_write_bio(name, type) \
+	int PEM_write_bio_##name(BIO *bp, type *x);
+
+#define DECLARE_PEM_write_bio_const(name, type) \
+	int PEM_write_bio_##name(BIO *bp, const type *x);
+
+#define DECLARE_PEM_write_cb_bio(name, type) \
+	int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \
+	     unsigned char *kstr, int klen, pem_password_cb *cb, void *u);
+
+#else
+
+#define DECLARE_PEM_read_bio(name, type) /**/
+#define DECLARE_PEM_write_bio(name, type) /**/
+#define DECLARE_PEM_write_cb_bio(name, type) /**/
+
+#endif
+
+#define DECLARE_PEM_write(name, type) \
+	DECLARE_PEM_write_bio(name, type) \
+	DECLARE_PEM_write_fp(name, type) 
+
+#define DECLARE_PEM_write_const(name, type) \
+	DECLARE_PEM_write_bio_const(name, type) \
+	DECLARE_PEM_write_fp_const(name, type)
+
+#define DECLARE_PEM_write_cb(name, type) \
+	DECLARE_PEM_write_cb_bio(name, type) \
+	DECLARE_PEM_write_cb_fp(name, type) 
+
+#define DECLARE_PEM_read(name, type) \
+	DECLARE_PEM_read_bio(name, type) \
+	DECLARE_PEM_read_fp(name, type)
+
+#define DECLARE_PEM_rw(name, type) \
+	DECLARE_PEM_read(name, type) \
+	DECLARE_PEM_write(name, type)
+
+#define DECLARE_PEM_rw_const(name, type) \
+	DECLARE_PEM_read(name, type) \
+	DECLARE_PEM_write_const(name, type)
+
+#define DECLARE_PEM_rw_cb(name, type) \
+	DECLARE_PEM_read(name, type) \
+	DECLARE_PEM_write_cb(name, type)
+
+#ifdef SSLEAY_MACROS
+
+#define PEM_write_SSL_SESSION(fp,x) \
+		PEM_ASN1_write((int (*)())i2d_SSL_SESSION, \
+			PEM_STRING_SSL_SESSION,fp, (char *)x, NULL,NULL,0,NULL,NULL)
+#define PEM_write_X509(fp,x) \
+		PEM_ASN1_write((int (*)())i2d_X509,PEM_STRING_X509,fp, \
+			(char *)x, NULL,NULL,0,NULL,NULL)
+#define PEM_write_X509_REQ(fp,x) PEM_ASN1_write( \
+		(int (*)())i2d_X509_REQ,PEM_STRING_X509_REQ,fp,(char *)x, \
+			NULL,NULL,0,NULL,NULL)
+#define PEM_write_X509_CRL(fp,x) \
+		PEM_ASN1_write((int (*)())i2d_X509_CRL,PEM_STRING_X509_CRL, \
+			fp,(char *)x, NULL,NULL,0,NULL,NULL)
+#define	PEM_write_RSAPrivateKey(fp,x,enc,kstr,klen,cb,u) \
+		PEM_ASN1_write((int (*)())i2d_RSAPrivateKey,PEM_STRING_RSA,fp,\
+			(char *)x,enc,kstr,klen,cb,u)
+#define	PEM_write_RSAPublicKey(fp,x) \
+		PEM_ASN1_write((int (*)())i2d_RSAPublicKey,\
+			PEM_STRING_RSA_PUBLIC,fp,(char *)x,NULL,NULL,0,NULL,NULL)
+#define	PEM_write_DSAPrivateKey(fp,x,enc,kstr,klen,cb,u) \
+		PEM_ASN1_write((int (*)())i2d_DSAPrivateKey,PEM_STRING_DSA,fp,\
+			(char *)x,enc,kstr,klen,cb,u)
+#define	PEM_write_PrivateKey(bp,x,enc,kstr,klen,cb,u) \
+		PEM_ASN1_write((int (*)())i2d_PrivateKey,\
+		(((x)->type == EVP_PKEY_DSA)?PEM_STRING_DSA:PEM_STRING_RSA),\
+			bp,(char *)x,enc,kstr,klen,cb,u)
+#define PEM_write_PKCS7(fp,x) \
+		PEM_ASN1_write((int (*)())i2d_PKCS7,PEM_STRING_PKCS7,fp, \
+			(char *)x, NULL,NULL,0,NULL,NULL)
+#define PEM_write_DHparams(fp,x) \
+		PEM_ASN1_write((int (*)())i2d_DHparams,PEM_STRING_DHPARAMS,fp,\
+			(char *)x,NULL,NULL,0,NULL,NULL)
+
+#define PEM_write_NETSCAPE_CERT_SEQUENCE(fp,x) \
+                PEM_ASN1_write((int (*)())i2d_NETSCAPE_CERT_SEQUENCE, \
+			PEM_STRING_X509,fp, \
+                        (char *)x, NULL,NULL,0,NULL,NULL)
+
+#define	PEM_read_SSL_SESSION(fp,x,cb,u) (SSL_SESSION *)PEM_ASN1_read( \
+	(char *(*)())d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,fp,(char **)x,cb,u)
+#define	PEM_read_X509(fp,x,cb,u) (X509 *)PEM_ASN1_read( \
+	(char *(*)())d2i_X509,PEM_STRING_X509,fp,(char **)x,cb,u)
+#define	PEM_read_X509_REQ(fp,x,cb,u) (X509_REQ *)PEM_ASN1_read( \
+	(char *(*)())d2i_X509_REQ,PEM_STRING_X509_REQ,fp,(char **)x,cb,u)
+#define	PEM_read_X509_CRL(fp,x,cb,u) (X509_CRL *)PEM_ASN1_read( \
+	(char *(*)())d2i_X509_CRL,PEM_STRING_X509_CRL,fp,(char **)x,cb,u)
+#define	PEM_read_RSAPrivateKey(fp,x,cb,u) (RSA *)PEM_ASN1_read( \
+	(char *(*)())d2i_RSAPrivateKey,PEM_STRING_RSA,fp,(char **)x,cb,u)
+#define	PEM_read_RSAPublicKey(fp,x,cb,u) (RSA *)PEM_ASN1_read( \
+	(char *(*)())d2i_RSAPublicKey,PEM_STRING_RSA_PUBLIC,fp,(char **)x,cb,u)
+#define	PEM_read_DSAPrivateKey(fp,x,cb,u) (DSA *)PEM_ASN1_read( \
+	(char *(*)())d2i_DSAPrivateKey,PEM_STRING_DSA,fp,(char **)x,cb,u)
+#define	PEM_read_PrivateKey(fp,x,cb,u) (EVP_PKEY *)PEM_ASN1_read( \
+	(char *(*)())d2i_PrivateKey,PEM_STRING_EVP_PKEY,fp,(char **)x,cb,u)
+#define	PEM_read_PKCS7(fp,x,cb,u) (PKCS7 *)PEM_ASN1_read( \
+	(char *(*)())d2i_PKCS7,PEM_STRING_PKCS7,fp,(char **)x,cb,u)
+#define	PEM_read_DHparams(fp,x,cb,u) (DH *)PEM_ASN1_read( \
+	(char *(*)())d2i_DHparams,PEM_STRING_DHPARAMS,fp,(char **)x,cb,u)
+
+#define PEM_read_NETSCAPE_CERT_SEQUENCE(fp,x,cb,u) \
+		(NETSCAPE_CERT_SEQUENCE *)PEM_ASN1_read( \
+        (char *(*)())d2i_NETSCAPE_CERT_SEQUENCE,PEM_STRING_X509,fp,\
+							(char **)x,cb,u)
+
+#define PEM_write_bio_X509(bp,x) \
+		PEM_ASN1_write_bio((int (*)())i2d_X509,PEM_STRING_X509,bp, \
+			(char *)x, NULL,NULL,0,NULL,NULL)
+#define PEM_write_bio_X509_REQ(bp,x) PEM_ASN1_write_bio( \
+		(int (*)())i2d_X509_REQ,PEM_STRING_X509_REQ,bp,(char *)x, \
+			NULL,NULL,0,NULL,NULL)
+#define PEM_write_bio_X509_CRL(bp,x) \
+		PEM_ASN1_write_bio((int (*)())i2d_X509_CRL,PEM_STRING_X509_CRL,\
+			bp,(char *)x, NULL,NULL,0,NULL,NULL)
+#define	PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
+		PEM_ASN1_write_bio((int (*)())i2d_RSAPrivateKey,PEM_STRING_RSA,\
+			bp,(char *)x,enc,kstr,klen,cb,u)
+#define	PEM_write_bio_RSAPublicKey(bp,x) \
+		PEM_ASN1_write_bio((int (*)())i2d_RSAPublicKey, \
+			PEM_STRING_RSA_PUBLIC,\
+			bp,(char *)x,NULL,NULL,0,NULL,NULL)
+#define	PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
+		PEM_ASN1_write_bio((int (*)())i2d_DSAPrivateKey,PEM_STRING_DSA,\
+			bp,(char *)x,enc,kstr,klen,cb,u)
+#define	PEM_write_bio_PrivateKey(bp,x,enc,kstr,klen,cb,u) \
+		PEM_ASN1_write_bio((int (*)())i2d_PrivateKey,\
+		(((x)->type == EVP_PKEY_DSA)?PEM_STRING_DSA:PEM_STRING_RSA),\
+			bp,(char *)x,enc,kstr,klen,cb,u)
+#define PEM_write_bio_PKCS7(bp,x) \
+		PEM_ASN1_write_bio((int (*)())i2d_PKCS7,PEM_STRING_PKCS7,bp, \
+			(char *)x, NULL,NULL,0,NULL,NULL)
+#define PEM_write_bio_DHparams(bp,x) \
+		PEM_ASN1_write_bio((int (*)())i2d_DHparams,PEM_STRING_DHPARAMS,\
+			bp,(char *)x,NULL,NULL,0,NULL,NULL)
+#define PEM_write_bio_DSAparams(bp,x) \
+		PEM_ASN1_write_bio((int (*)())i2d_DSAparams, \
+			PEM_STRING_DSAPARAMS,bp,(char *)x,NULL,NULL,0,NULL,NULL)
+
+#define PEM_write_bio_NETSCAPE_CERT_SEQUENCE(bp,x) \
+                PEM_ASN1_write_bio((int (*)())i2d_NETSCAPE_CERT_SEQUENCE, \
+			PEM_STRING_X509,bp, \
+                        (char *)x, NULL,NULL,0,NULL,NULL)
+
+#define	PEM_read_bio_X509(bp,x,cb,u) (X509 *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_X509,PEM_STRING_X509,bp,(char **)x,cb,u)
+#define	PEM_read_bio_X509_REQ(bp,x,cb,u) (X509_REQ *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_X509_REQ,PEM_STRING_X509_REQ,bp,(char **)x,cb,u)
+#define	PEM_read_bio_X509_CRL(bp,x,cb,u) (X509_CRL *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_X509_CRL,PEM_STRING_X509_CRL,bp,(char **)x,cb,u)
+#define	PEM_read_bio_RSAPrivateKey(bp,x,cb,u) (RSA *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_RSAPrivateKey,PEM_STRING_RSA,bp,(char **)x,cb,u)
+#define	PEM_read_bio_RSAPublicKey(bp,x,cb,u) (RSA *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_RSAPublicKey,PEM_STRING_RSA_PUBLIC,bp,(char **)x,cb,u)
+#define	PEM_read_bio_DSAPrivateKey(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_DSAPrivateKey,PEM_STRING_DSA,bp,(char **)x,cb,u)
+#define	PEM_read_bio_PrivateKey(bp,x,cb,u) (EVP_PKEY *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_PrivateKey,PEM_STRING_EVP_PKEY,bp,(char **)x,cb,u)
+
+#define	PEM_read_bio_PKCS7(bp,x,cb,u) (PKCS7 *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_PKCS7,PEM_STRING_PKCS7,bp,(char **)x,cb,u)
+#define	PEM_read_bio_DHparams(bp,x,cb,u) (DH *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_DHparams,PEM_STRING_DHPARAMS,bp,(char **)x,cb,u)
+#define	PEM_read_bio_DSAparams(bp,x,cb,u) (DSA *)PEM_ASN1_read_bio( \
+	(char *(*)())d2i_DSAparams,PEM_STRING_DSAPARAMS,bp,(char **)x,cb,u)
+
+#define PEM_read_bio_NETSCAPE_CERT_SEQUENCE(bp,x,cb,u) \
+		(NETSCAPE_CERT_SEQUENCE *)PEM_ASN1_read_bio( \
+        (char *(*)())d2i_NETSCAPE_CERT_SEQUENCE,PEM_STRING_X509,bp,\
+							(char **)x,cb,u)
+
+#endif
+
+#if 1
+/* "userdata": new with OpenSSL 0.9.4 */
+typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
+#else
+/* OpenSSL 0.9.3, 0.9.3a */
+typedef int pem_password_cb(char *buf, int size, int rwflag);
+#endif
+
+int	PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher);
+int	PEM_do_header (EVP_CIPHER_INFO *cipher, unsigned char *data,long *len,
+	pem_password_cb *callback,void *u);
+
+#ifndef OPENSSL_NO_BIO
+int	PEM_read_bio(BIO *bp, char **name, char **header,
+		unsigned char **data,long *len);
+int	PEM_write_bio(BIO *bp,const char *name,char *hdr,unsigned char *data,
+		long len);
+int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp,
+	     pem_password_cb *cb, void *u);
+void *	PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp,
+			  void **x, pem_password_cb *cb, void *u);
+#define PEM_ASN1_read_bio_of(type,d2i,name,bp,x,cb,u) \
+((type *(*)(D2I_OF(type),const char *,BIO *,type **,pem_password_cb *,void *))openssl_fcast(PEM_ASN1_read_bio))(d2i,name,bp,x,cb,u)
+int	PEM_ASN1_write_bio(i2d_of_void *i2d,const char *name,BIO *bp,char *x,
+			   const EVP_CIPHER *enc,unsigned char *kstr,int klen,
+			   pem_password_cb *cb, void *u);
+#define PEM_ASN1_write_bio_of(type,i2d,name,bp,x,enc,kstr,klen,cb,u) \
+	((int (*)(I2D_OF(type),const char *,BIO *,type *, const EVP_CIPHER *,unsigned char *,int, pem_password_cb *,void *))openssl_fcast(PEM_ASN1_write_bio))(i2d,name,bp,x,enc,kstr,klen,cb,u)
+
+STACK_OF(X509_INFO) *	PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u);
+int	PEM_X509_INFO_write_bio(BIO *bp,X509_INFO *xi, EVP_CIPHER *enc,
+		unsigned char *kstr, int klen, pem_password_cb *cd, void *u);
+#endif
+
+#ifndef OPENSSL_SYS_WIN16
+int	PEM_read(FILE *fp, char **name, char **header,
+		unsigned char **data,long *len);
+int	PEM_write(FILE *fp,char *name,char *hdr,unsigned char *data,long len);
+void *  PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
+		      pem_password_cb *cb, void *u);
+int	PEM_ASN1_write(i2d_of_void *i2d,const char *name,FILE *fp,
+		       char *x,const EVP_CIPHER *enc,unsigned char *kstr,
+		       int klen,pem_password_cb *callback, void *u);
+STACK_OF(X509_INFO) *	PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk,
+	pem_password_cb *cb, void *u);
+#endif
+
+int	PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type,
+		EVP_MD *md_type, unsigned char **ek, int *ekl,
+		unsigned char *iv, EVP_PKEY **pubk, int npubk);
+void	PEM_SealUpdate(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *out, int *outl,
+		unsigned char *in, int inl);
+int	PEM_SealFinal(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *sig,int *sigl,
+		unsigned char *out, int *outl, EVP_PKEY *priv);
+
+void    PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type);
+void    PEM_SignUpdate(EVP_MD_CTX *ctx,unsigned char *d,unsigned int cnt);
+int	PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
+		unsigned int *siglen, EVP_PKEY *pkey);
+
+int	PEM_def_callback(char *buf, int num, int w, void *key);
+void	PEM_proc_type(char *buf, int type);
+void	PEM_dek_info(char *buf, const char *type, int len, char *str);
+
+#ifndef SSLEAY_MACROS
+
+#include <openssl/symhacks.h>
+
+DECLARE_PEM_rw(X509, X509)
+
+DECLARE_PEM_rw(X509_AUX, X509)
+
+DECLARE_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR)
+
+DECLARE_PEM_rw(X509_REQ, X509_REQ)
+DECLARE_PEM_write(X509_REQ_NEW, X509_REQ)
+
+DECLARE_PEM_rw(X509_CRL, X509_CRL)
+
+DECLARE_PEM_rw(PKCS7, PKCS7)
+
+DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE)
+
+DECLARE_PEM_rw(PKCS8, X509_SIG)
+
+DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO)
+
+#ifndef OPENSSL_NO_RSA
+
+DECLARE_PEM_rw_cb(RSAPrivateKey, RSA)
+
+DECLARE_PEM_rw_const(RSAPublicKey, RSA)
+DECLARE_PEM_rw(RSA_PUBKEY, RSA)
+
+#endif
+
+#ifndef OPENSSL_NO_DSA
+
+DECLARE_PEM_rw_cb(DSAPrivateKey, DSA)
+
+DECLARE_PEM_rw(DSA_PUBKEY, DSA)
+
+DECLARE_PEM_rw_const(DSAparams, DSA)
+
+#endif
+
+#ifndef OPENSSL_NO_EC
+DECLARE_PEM_rw_const(ECPKParameters, EC_GROUP)
+DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY)
+DECLARE_PEM_rw(EC_PUBKEY, EC_KEY)
+#endif
+
+#ifndef OPENSSL_NO_DH
+
+DECLARE_PEM_rw_const(DHparams, DH)
+
+#endif
+
+DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY)
+
+DECLARE_PEM_rw(PUBKEY, EVP_PKEY)
+
+int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid,
+				  char *kstr, int klen,
+				  pem_password_cb *cb, void *u);
+int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *,
+                                  char *, int, pem_password_cb *, void *);
+int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc,
+				  char *kstr, int klen,
+				  pem_password_cb *cb, void *u);
+int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid,
+				  char *kstr, int klen,
+				  pem_password_cb *cb, void *u);
+EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);
+
+int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc,
+				  char *kstr, int klen,
+				  pem_password_cb *cb, void *u);
+int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid,
+				  char *kstr, int klen,
+				  pem_password_cb *cb, void *u);
+int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid,
+				  char *kstr, int klen,
+				  pem_password_cb *cb, void *u);
+
+EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u);
+
+int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc,
+			      char *kstr,int klen, pem_password_cb *cd, void *u);
+
+#endif /* SSLEAY_MACROS */
+
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_PEM_strings(void);
+
+/* Error codes for the PEM functions. */
+
+/* Function codes. */
+#define PEM_F_D2I_PKCS8PRIVATEKEY_BIO			 120
+#define PEM_F_D2I_PKCS8PRIVATEKEY_FP			 121
+#define PEM_F_DO_PK8PKEY				 126
+#define PEM_F_DO_PK8PKEY_FP				 125
+#define PEM_F_LOAD_IV					 101
+#define PEM_F_PEM_ASN1_READ				 102
+#define PEM_F_PEM_ASN1_READ_BIO				 103
+#define PEM_F_PEM_ASN1_WRITE				 104
+#define PEM_F_PEM_ASN1_WRITE_BIO			 105
+#define PEM_F_PEM_DEF_CALLBACK				 100
+#define PEM_F_PEM_DO_HEADER				 106
+#define PEM_F_PEM_F_PEM_WRITE_PKCS8PRIVATEKEY		 118
+#define PEM_F_PEM_GET_EVP_CIPHER_INFO			 107
+#define PEM_F_PEM_PK8PKEY				 119
+#define PEM_F_PEM_READ					 108
+#define PEM_F_PEM_READ_BIO				 109
+#define PEM_F_PEM_READ_BIO_PRIVATEKEY			 123
+#define PEM_F_PEM_READ_PRIVATEKEY			 124
+#define PEM_F_PEM_SEALFINAL				 110
+#define PEM_F_PEM_SEALINIT				 111
+#define PEM_F_PEM_SIGNFINAL				 112
+#define PEM_F_PEM_WRITE					 113
+#define PEM_F_PEM_WRITE_BIO				 114
+#define PEM_F_PEM_X509_INFO_READ			 115
+#define PEM_F_PEM_X509_INFO_READ_BIO			 116
+#define PEM_F_PEM_X509_INFO_WRITE_BIO			 117
+
+/* Reason codes. */
+#define PEM_R_BAD_BASE64_DECODE				 100
+#define PEM_R_BAD_DECRYPT				 101
+#define PEM_R_BAD_END_LINE				 102
+#define PEM_R_BAD_IV_CHARS				 103
+#define PEM_R_BAD_PASSWORD_READ				 104
+#define PEM_R_ERROR_CONVERTING_PRIVATE_KEY		 115
+#define PEM_R_NOT_DEK_INFO				 105
+#define PEM_R_NOT_ENCRYPTED				 106
+#define PEM_R_NOT_PROC_TYPE				 107
+#define PEM_R_NO_START_LINE				 108
+#define PEM_R_PROBLEMS_GETTING_PASSWORD			 109
+#define PEM_R_PUBLIC_KEY_NO_RSA				 110
+#define PEM_R_READ_KEY					 111
+#define PEM_R_SHORT_HEADER				 112
+#define PEM_R_UNSUPPORTED_CIPHER			 113
+#define PEM_R_UNSUPPORTED_ENCRYPTION			 114
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pem2.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pem2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pem2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,70 @@
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+/*
+ * This header only exists to break a circular dependency between pem and err
+ * Ben 30 Jan 1999.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HEADER_PEM_H
+void ERR_load_PEM_strings(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pkcs12.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pkcs12.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pkcs12.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,333 @@
+/* pkcs12.h */
+/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_PKCS12_H
+#define HEADER_PKCS12_H
+
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PKCS12_KEY_ID	1
+#define PKCS12_IV_ID	2
+#define PKCS12_MAC_ID	3
+
+/* Default iteration count */
+#ifndef PKCS12_DEFAULT_ITER
+#define PKCS12_DEFAULT_ITER	PKCS5_DEFAULT_ITER
+#endif
+
+#define PKCS12_MAC_KEY_LENGTH 20
+
+#define PKCS12_SALT_LEN	8
+
+/* Uncomment out next line for unicode password and names, otherwise ASCII */
+
+/*#define PBE_UNICODE*/
+
+#ifdef PBE_UNICODE
+#define PKCS12_key_gen PKCS12_key_gen_uni
+#define PKCS12_add_friendlyname PKCS12_add_friendlyname_uni
+#else
+#define PKCS12_key_gen PKCS12_key_gen_asc
+#define PKCS12_add_friendlyname PKCS12_add_friendlyname_asc
+#endif
+
+/* MS key usage constants */
+
+#define KEY_EX	0x10
+#define KEY_SIG 0x80
+
+typedef struct {
+X509_SIG *dinfo;
+ASN1_OCTET_STRING *salt;
+ASN1_INTEGER *iter;	/* defaults to 1 */
+} PKCS12_MAC_DATA;
+
+typedef struct {
+ASN1_INTEGER *version;
+PKCS12_MAC_DATA *mac;
+PKCS7 *authsafes;
+} PKCS12;
+
+PREDECLARE_STACK_OF(PKCS12_SAFEBAG)
+
+typedef struct {
+ASN1_OBJECT *type;
+union {
+	struct pkcs12_bag_st *bag; /* secret, crl and certbag */
+	struct pkcs8_priv_key_info_st	*keybag; /* keybag */
+	X509_SIG *shkeybag; /* shrouded key bag */
+	STACK_OF(PKCS12_SAFEBAG) *safes;
+	ASN1_TYPE *other;
+}value;
+STACK_OF(X509_ATTRIBUTE) *attrib;
+} PKCS12_SAFEBAG;
+
+DECLARE_STACK_OF(PKCS12_SAFEBAG)
+DECLARE_ASN1_SET_OF(PKCS12_SAFEBAG)
+DECLARE_PKCS12_STACK_OF(PKCS12_SAFEBAG)
+
+typedef struct pkcs12_bag_st {
+ASN1_OBJECT *type;
+union {
+	ASN1_OCTET_STRING *x509cert;
+	ASN1_OCTET_STRING *x509crl;
+	ASN1_OCTET_STRING *octet;
+	ASN1_IA5STRING *sdsicert;
+	ASN1_TYPE *other; /* Secret or other bag */
+}value;
+} PKCS12_BAGS;
+
+#define PKCS12_ERROR	0
+#define PKCS12_OK	1
+
+/* Compatibility macros */
+
+#define M_PKCS12_x5092certbag PKCS12_x5092certbag
+#define M_PKCS12_x509crl2certbag PKCS12_x509crl2certbag
+
+#define M_PKCS12_certbag2x509 PKCS12_certbag2x509
+#define M_PKCS12_certbag2x509crl PKCS12_certbag2x509crl 
+
+#define M_PKCS12_unpack_p7data PKCS12_unpack_p7data
+#define M_PKCS12_pack_authsafes PKCS12_pack_authsafes
+#define M_PKCS12_unpack_authsafes PKCS12_unpack_authsafes
+#define M_PKCS12_unpack_p7encdata PKCS12_unpack_p7encdata
+
+#define M_PKCS12_decrypt_skey PKCS12_decrypt_skey
+#define M_PKCS8_decrypt PKCS8_decrypt
+
+#define M_PKCS12_bag_type(bg) OBJ_obj2nid((bg)->type)
+#define M_PKCS12_cert_bag_type(bg) OBJ_obj2nid((bg)->value.bag->type)
+#define M_PKCS12_crl_bag_type M_PKCS12_cert_bag_type
+
+#define PKCS12_get_attr(bag, attr_nid) \
+			 PKCS12_get_attr_gen(bag->attrib, attr_nid)
+
+#define PKCS8_get_attr(p8, attr_nid) \
+		PKCS12_get_attr_gen(p8->attributes, attr_nid)
+
+#define PKCS12_mac_present(p12) ((p12)->mac ? 1 : 0)
+
+
+PKCS12_SAFEBAG *PKCS12_x5092certbag(X509 *x509);
+PKCS12_SAFEBAG *PKCS12_x509crl2certbag(X509_CRL *crl);
+X509 *PKCS12_certbag2x509(PKCS12_SAFEBAG *bag);
+X509_CRL *PKCS12_certbag2x509crl(PKCS12_SAFEBAG *bag);
+
+PKCS12_SAFEBAG *PKCS12_item_pack_safebag(void *obj, const ASN1_ITEM *it, int nid1,
+	     int nid2);
+PKCS12_SAFEBAG *PKCS12_MAKE_KEYBAG(PKCS8_PRIV_KEY_INFO *p8);
+PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *p8, const char *pass, int passlen);
+PKCS8_PRIV_KEY_INFO *PKCS12_decrypt_skey(PKCS12_SAFEBAG *bag, const char *pass,
+								int passlen);
+X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, 
+			const char *pass, int passlen,
+			unsigned char *salt, int saltlen, int iter,
+			PKCS8_PRIV_KEY_INFO *p8);
+PKCS12_SAFEBAG *PKCS12_MAKE_SHKEYBAG(int pbe_nid, const char *pass,
+				     int passlen, unsigned char *salt,
+				     int saltlen, int iter,
+				     PKCS8_PRIV_KEY_INFO *p8);
+PKCS7 *PKCS12_pack_p7data(STACK_OF(PKCS12_SAFEBAG) *sk);
+STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7data(PKCS7 *p7);
+PKCS7 *PKCS12_pack_p7encdata(int pbe_nid, const char *pass, int passlen,
+			     unsigned char *salt, int saltlen, int iter,
+			     STACK_OF(PKCS12_SAFEBAG) *bags);
+STACK_OF(PKCS12_SAFEBAG) *PKCS12_unpack_p7encdata(PKCS7 *p7, const char *pass, int passlen);
+
+int PKCS12_pack_authsafes(PKCS12 *p12, STACK_OF(PKCS7) *safes);
+STACK_OF(PKCS7) *PKCS12_unpack_authsafes(PKCS12 *p12);
+
+int PKCS12_add_localkeyid(PKCS12_SAFEBAG *bag, unsigned char *name, int namelen);
+int PKCS12_add_friendlyname_asc(PKCS12_SAFEBAG *bag, const char *name,
+				int namelen);
+int PKCS12_add_CSPName_asc(PKCS12_SAFEBAG *bag, const char *name,
+				int namelen);
+int PKCS12_add_friendlyname_uni(PKCS12_SAFEBAG *bag, const unsigned char *name,
+				int namelen);
+int PKCS8_add_keyusage(PKCS8_PRIV_KEY_INFO *p8, int usage);
+ASN1_TYPE *PKCS12_get_attr_gen(STACK_OF(X509_ATTRIBUTE) *attrs, int attr_nid);
+char *PKCS12_get_friendlyname(PKCS12_SAFEBAG *bag);
+unsigned char *PKCS12_pbe_crypt(X509_ALGOR *algor, const char *pass,
+				int passlen, unsigned char *in, int inlen,
+				unsigned char **data, int *datalen, int en_de);
+void * PKCS12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it,
+	     const char *pass, int passlen, ASN1_OCTET_STRING *oct, int zbuf);
+ASN1_OCTET_STRING *PKCS12_item_i2d_encrypt(X509_ALGOR *algor, const ASN1_ITEM *it,
+				       const char *pass, int passlen,
+				       void *obj, int zbuf);
+PKCS12 *PKCS12_init(int mode);
+int PKCS12_key_gen_asc(const char *pass, int passlen, unsigned char *salt,
+		       int saltlen, int id, int iter, int n,
+		       unsigned char *out, const EVP_MD *md_type);
+int PKCS12_key_gen_uni(unsigned char *pass, int passlen, unsigned char *salt, int saltlen, int id, int iter, int n, unsigned char *out, const EVP_MD *md_type);
+int PKCS12_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, int passlen,
+			 ASN1_TYPE *param, const EVP_CIPHER *cipher, const EVP_MD *md_type,
+			 int en_de);
+int PKCS12_gen_mac(PKCS12 *p12, const char *pass, int passlen,
+			 unsigned char *mac, unsigned int *maclen);
+int PKCS12_verify_mac(PKCS12 *p12, const char *pass, int passlen);
+int PKCS12_set_mac(PKCS12 *p12, const char *pass, int passlen,
+		   unsigned char *salt, int saltlen, int iter,
+		   const EVP_MD *md_type);
+int PKCS12_setup_mac(PKCS12 *p12, int iter, unsigned char *salt,
+					 int saltlen, const EVP_MD *md_type);
+unsigned char *asc2uni(const char *asc, int asclen, unsigned char **uni, int *unilen);
+char *uni2asc(unsigned char *uni, int unilen);
+
+DECLARE_ASN1_FUNCTIONS(PKCS12)
+DECLARE_ASN1_FUNCTIONS(PKCS12_MAC_DATA)
+DECLARE_ASN1_FUNCTIONS(PKCS12_SAFEBAG)
+DECLARE_ASN1_FUNCTIONS(PKCS12_BAGS)
+
+DECLARE_ASN1_ITEM(PKCS12_SAFEBAGS)
+DECLARE_ASN1_ITEM(PKCS12_AUTHSAFES)
+
+void PKCS12_PBE_add(void);
+int PKCS12_parse(PKCS12 *p12, const char *pass, EVP_PKEY **pkey, X509 **cert,
+		 STACK_OF(X509) **ca);
+PKCS12 *PKCS12_create(char *pass, char *name, EVP_PKEY *pkey, X509 *cert,
+			 STACK_OF(X509) *ca, int nid_key, int nid_cert, int iter,
+						 int mac_iter, int keytype);
+
+PKCS12_SAFEBAG *PKCS12_add_cert(STACK_OF(PKCS12_SAFEBAG) **pbags, X509 *cert);
+PKCS12_SAFEBAG *PKCS12_add_key(STACK_OF(PKCS12_SAFEBAG) **pbags, EVP_PKEY *key,
+						int key_usage, int iter,
+						int key_nid, char *pass);
+int PKCS12_add_safe(STACK_OF(PKCS7) **psafes, STACK_OF(PKCS12_SAFEBAG) *bags,
+					int safe_nid, int iter, char *pass);
+PKCS12 *PKCS12_add_safes(STACK_OF(PKCS7) *safes, int p7_nid);
+
+int i2d_PKCS12_bio(BIO *bp, PKCS12 *p12);
+int i2d_PKCS12_fp(FILE *fp, PKCS12 *p12);
+PKCS12 *d2i_PKCS12_bio(BIO *bp, PKCS12 **p12);
+PKCS12 *d2i_PKCS12_fp(FILE *fp, PKCS12 **p12);
+int PKCS12_newpass(PKCS12 *p12, char *oldpass, char *newpass);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_PKCS12_strings(void);
+
+/* Error codes for the PKCS12 functions. */
+
+/* Function codes. */
+#define PKCS12_F_PARSE_BAG				 129
+#define PKCS12_F_PARSE_BAGS				 103
+#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME		 100
+#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME_ASC		 127
+#define PKCS12_F_PKCS12_ADD_FRIENDLYNAME_UNI		 102
+#define PKCS12_F_PKCS12_ADD_LOCALKEYID			 104
+#define PKCS12_F_PKCS12_CREATE				 105
+#define PKCS12_F_PKCS12_GEN_MAC				 107
+#define PKCS12_F_PKCS12_INIT				 109
+#define PKCS12_F_PKCS12_ITEM_DECRYPT_D2I		 106
+#define PKCS12_F_PKCS12_ITEM_I2D_ENCRYPT		 108
+#define PKCS12_F_PKCS12_ITEM_PACK_SAFEBAG		 117
+#define PKCS12_F_PKCS12_KEY_GEN_ASC			 110
+#define PKCS12_F_PKCS12_KEY_GEN_UNI			 111
+#define PKCS12_F_PKCS12_MAKE_KEYBAG			 112
+#define PKCS12_F_PKCS12_MAKE_SHKEYBAG			 113
+#define PKCS12_F_PKCS12_NEWPASS				 128
+#define PKCS12_F_PKCS12_PACK_P7DATA			 114
+#define PKCS12_F_PKCS12_PACK_P7ENCDATA			 115
+#define PKCS12_F_PKCS12_PARSE				 118
+#define PKCS12_F_PKCS12_PBE_CRYPT			 119
+#define PKCS12_F_PKCS12_PBE_KEYIVGEN			 120
+#define PKCS12_F_PKCS12_SETUP_MAC			 122
+#define PKCS12_F_PKCS12_SET_MAC				 123
+#define PKCS12_F_PKCS12_UNPACK_AUTHSAFES		 130
+#define PKCS12_F_PKCS12_UNPACK_P7DATA			 131
+#define PKCS12_F_PKCS12_VERIFY_MAC			 126
+#define PKCS12_F_PKCS8_ADD_KEYUSAGE			 124
+#define PKCS12_F_PKCS8_ENCRYPT				 125
+
+/* Reason codes. */
+#define PKCS12_R_CANT_PACK_STRUCTURE			 100
+#define PKCS12_R_CONTENT_TYPE_NOT_DATA			 121
+#define PKCS12_R_DECODE_ERROR				 101
+#define PKCS12_R_ENCODE_ERROR				 102
+#define PKCS12_R_ENCRYPT_ERROR				 103
+#define PKCS12_R_ERROR_SETTING_ENCRYPTED_DATA_TYPE	 120
+#define PKCS12_R_INVALID_NULL_ARGUMENT			 104
+#define PKCS12_R_INVALID_NULL_PKCS12_POINTER		 105
+#define PKCS12_R_IV_GEN_ERROR				 106
+#define PKCS12_R_KEY_GEN_ERROR				 107
+#define PKCS12_R_MAC_ABSENT				 108
+#define PKCS12_R_MAC_GENERATION_ERROR			 109
+#define PKCS12_R_MAC_SETUP_ERROR			 110
+#define PKCS12_R_MAC_STRING_SET_ERROR			 111
+#define PKCS12_R_MAC_VERIFY_ERROR			 112
+#define PKCS12_R_MAC_VERIFY_FAILURE			 113
+#define PKCS12_R_PARSE_ERROR				 114
+#define PKCS12_R_PKCS12_ALGOR_CIPHERINIT_ERROR		 115
+#define PKCS12_R_PKCS12_CIPHERFINAL_ERROR		 116
+#define PKCS12_R_PKCS12_PBE_CRYPT_ERROR			 117
+#define PKCS12_R_UNKNOWN_DIGEST_ALGORITHM		 118
+#define PKCS12_R_UNSUPPORTED_PKCS12_MODE		 119
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pkcs7.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pkcs7.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pkcs7.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,463 @@
+/* crypto/pkcs7/pkcs7.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_PKCS7_H
+#define HEADER_PKCS7_H
+
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/e_os2.h>
+
+#include <openssl/symhacks.h>
+#include <openssl/ossl_typ.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_SYS_WIN32
+/* Under Win32 thes are defined in wincrypt.h */
+#undef PKCS7_ISSUER_AND_SERIAL
+#undef PKCS7_SIGNER_INFO
+#endif
+
+/*
+Encryption_ID		DES-CBC
+Digest_ID		MD5
+Digest_Encryption_ID	rsaEncryption
+Key_Encryption_ID	rsaEncryption
+*/
+
+typedef struct pkcs7_issuer_and_serial_st
+	{
+	X509_NAME *issuer;
+	ASN1_INTEGER *serial;
+	} PKCS7_ISSUER_AND_SERIAL;
+
+typedef struct pkcs7_signer_info_st
+	{
+	ASN1_INTEGER 			*version;	/* version 1 */
+	PKCS7_ISSUER_AND_SERIAL		*issuer_and_serial;
+	X509_ALGOR			*digest_alg;
+	STACK_OF(X509_ATTRIBUTE)	*auth_attr;	/* [ 0 ] */
+	X509_ALGOR			*digest_enc_alg;
+	ASN1_OCTET_STRING		*enc_digest;
+	STACK_OF(X509_ATTRIBUTE)	*unauth_attr;	/* [ 1 ] */
+
+	/* The private key to sign with */
+	EVP_PKEY			*pkey;
+	} PKCS7_SIGNER_INFO;
+
+DECLARE_STACK_OF(PKCS7_SIGNER_INFO)
+DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO)
+
+typedef struct pkcs7_recip_info_st
+	{
+	ASN1_INTEGER			*version;	/* version 0 */
+	PKCS7_ISSUER_AND_SERIAL		*issuer_and_serial;
+	X509_ALGOR			*key_enc_algor;
+	ASN1_OCTET_STRING		*enc_key;
+	X509				*cert; /* get the pub-key from this */
+	} PKCS7_RECIP_INFO;
+
+DECLARE_STACK_OF(PKCS7_RECIP_INFO)
+DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO)
+
+typedef struct pkcs7_signed_st
+	{
+	ASN1_INTEGER			*version;	/* version 1 */
+	STACK_OF(X509_ALGOR)		*md_algs;	/* md used */
+	STACK_OF(X509)			*cert;		/* [ 0 ] */
+	STACK_OF(X509_CRL)		*crl;		/* [ 1 ] */
+	STACK_OF(PKCS7_SIGNER_INFO)	*signer_info;
+
+	struct pkcs7_st			*contents;
+	} PKCS7_SIGNED;
+/* The above structure is very very similar to PKCS7_SIGN_ENVELOPE.
+ * How about merging the two */
+
+typedef struct pkcs7_enc_content_st
+	{
+	ASN1_OBJECT			*content_type;
+	X509_ALGOR			*algorithm;
+	ASN1_OCTET_STRING		*enc_data;	/* [ 0 ] */
+	const EVP_CIPHER		*cipher;
+	} PKCS7_ENC_CONTENT;
+
+typedef struct pkcs7_enveloped_st
+	{
+	ASN1_INTEGER			*version;	/* version 0 */
+	STACK_OF(PKCS7_RECIP_INFO)	*recipientinfo;
+	PKCS7_ENC_CONTENT		*enc_data;
+	} PKCS7_ENVELOPE;
+
+typedef struct pkcs7_signedandenveloped_st
+	{
+	ASN1_INTEGER			*version;	/* version 1 */
+	STACK_OF(X509_ALGOR)		*md_algs;	/* md used */
+	STACK_OF(X509)			*cert;		/* [ 0 ] */
+	STACK_OF(X509_CRL)		*crl;		/* [ 1 ] */
+	STACK_OF(PKCS7_SIGNER_INFO)	*signer_info;
+
+	PKCS7_ENC_CONTENT		*enc_data;
+	STACK_OF(PKCS7_RECIP_INFO)	*recipientinfo;
+	} PKCS7_SIGN_ENVELOPE;
+
+typedef struct pkcs7_digest_st
+	{
+	ASN1_INTEGER			*version;	/* version 0 */
+	X509_ALGOR			*md;		/* md used */
+	struct pkcs7_st 		*contents;
+	ASN1_OCTET_STRING		*digest;
+	} PKCS7_DIGEST;
+
+typedef struct pkcs7_encrypted_st
+	{
+	ASN1_INTEGER			*version;	/* version 0 */
+	PKCS7_ENC_CONTENT		*enc_data;
+	} PKCS7_ENCRYPT;
+
+typedef struct pkcs7_st
+	{
+	/* The following is non NULL if it contains ASN1 encoding of
+	 * this structure */
+	unsigned char *asn1;
+	long length;
+
+#define PKCS7_S_HEADER	0
+#define PKCS7_S_BODY	1
+#define PKCS7_S_TAIL	2
+	int state; /* used during processing */
+
+	int detached;
+
+	ASN1_OBJECT *type;
+	/* content as defined by the type */
+	/* all encryption/message digests are applied to the 'contents',
+	 * leaving out the 'type' field. */
+	union	{
+		char *ptr;
+
+		/* NID_pkcs7_data */
+		ASN1_OCTET_STRING *data;
+
+		/* NID_pkcs7_signed */
+		PKCS7_SIGNED *sign;
+
+		/* NID_pkcs7_enveloped */
+		PKCS7_ENVELOPE *enveloped;
+
+		/* NID_pkcs7_signedAndEnveloped */
+		PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
+
+		/* NID_pkcs7_digest */
+		PKCS7_DIGEST *digest;
+
+		/* NID_pkcs7_encrypted */
+		PKCS7_ENCRYPT *encrypted;
+
+		/* Anything else */
+		ASN1_TYPE *other;
+		} d;
+	} PKCS7;
+
+DECLARE_STACK_OF(PKCS7)
+DECLARE_ASN1_SET_OF(PKCS7)
+DECLARE_PKCS12_STACK_OF(PKCS7)
+
+#define PKCS7_OP_SET_DETACHED_SIGNATURE	1
+#define PKCS7_OP_GET_DETACHED_SIGNATURE	2
+
+#define PKCS7_get_signed_attributes(si)	((si)->auth_attr)
+#define PKCS7_get_attributes(si)	((si)->unauth_attr)
+
+#define PKCS7_type_is_signed(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_signed)
+#define PKCS7_type_is_encrypted(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_encrypted)
+#define PKCS7_type_is_enveloped(a) (OBJ_obj2nid((a)->type) == NID_pkcs7_enveloped)
+#define PKCS7_type_is_signedAndEnveloped(a) \
+		(OBJ_obj2nid((a)->type) == NID_pkcs7_signedAndEnveloped)
+#define PKCS7_type_is_data(a)   (OBJ_obj2nid((a)->type) == NID_pkcs7_data)
+
+#define PKCS7_type_is_digest(a)   (OBJ_obj2nid((a)->type) == NID_pkcs7_digest)
+
+#define PKCS7_set_detached(p,v) \
+		PKCS7_ctrl(p,PKCS7_OP_SET_DETACHED_SIGNATURE,v,NULL)
+#define PKCS7_get_detached(p) \
+		PKCS7_ctrl(p,PKCS7_OP_GET_DETACHED_SIGNATURE,0,NULL)
+
+#define PKCS7_is_detached(p7) (PKCS7_type_is_signed(p7) && PKCS7_get_detached(p7))
+
+#ifdef SSLEAY_MACROS
+#ifndef PKCS7_ISSUER_AND_SERIAL_digest
+#define PKCS7_ISSUER_AND_SERIAL_digest(data,type,md,len) \
+        ASN1_digest((int (*)())i2d_PKCS7_ISSUER_AND_SERIAL,type,\
+	                (char *)data,md,len)
+#endif
+#endif
+
+/* S/MIME related flags */
+
+#define PKCS7_TEXT		0x1
+#define PKCS7_NOCERTS		0x2
+#define PKCS7_NOSIGS		0x4
+#define PKCS7_NOCHAIN		0x8
+#define PKCS7_NOINTERN		0x10
+#define PKCS7_NOVERIFY		0x20
+#define PKCS7_DETACHED		0x40
+#define PKCS7_BINARY		0x80
+#define PKCS7_NOATTR		0x100
+#define	PKCS7_NOSMIMECAP	0x200
+#define PKCS7_NOOLDMIMETYPE	0x400
+#define PKCS7_CRLFEOL		0x800
+#define PKCS7_STREAM		0x1000
+#define PKCS7_NOCRL		0x2000
+
+/* Flags: for compatibility with older code */
+
+#define SMIME_TEXT	PKCS7_TEXT
+#define SMIME_NOCERTS	PKCS7_NOCERTS
+#define SMIME_NOSIGS	PKCS7_NOSIGS
+#define SMIME_NOCHAIN	PKCS7_NOCHAIN
+#define SMIME_NOINTERN	PKCS7_NOINTERN
+#define SMIME_NOVERIFY	PKCS7_NOVERIFY
+#define SMIME_DETACHED	PKCS7_DETACHED
+#define SMIME_BINARY	PKCS7_BINARY
+#define SMIME_NOATTR	PKCS7_NOATTR
+
+DECLARE_ASN1_FUNCTIONS(PKCS7_ISSUER_AND_SERIAL)
+
+#ifndef SSLEAY_MACROS
+int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data,const EVP_MD *type,
+	unsigned char *md,unsigned int *len);
+#ifndef OPENSSL_NO_FP_API
+PKCS7 *d2i_PKCS7_fp(FILE *fp,PKCS7 **p7);
+int i2d_PKCS7_fp(FILE *fp,PKCS7 *p7);
+#endif
+PKCS7 *PKCS7_dup(PKCS7 *p7);
+PKCS7 *d2i_PKCS7_bio(BIO *bp,PKCS7 **p7);
+int i2d_PKCS7_bio(BIO *bp,PKCS7 *p7);
+#endif
+
+DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNER_INFO)
+DECLARE_ASN1_FUNCTIONS(PKCS7_RECIP_INFO)
+DECLARE_ASN1_FUNCTIONS(PKCS7_SIGNED)
+DECLARE_ASN1_FUNCTIONS(PKCS7_ENC_CONTENT)
+DECLARE_ASN1_FUNCTIONS(PKCS7_ENVELOPE)
+DECLARE_ASN1_FUNCTIONS(PKCS7_SIGN_ENVELOPE)
+DECLARE_ASN1_FUNCTIONS(PKCS7_DIGEST)
+DECLARE_ASN1_FUNCTIONS(PKCS7_ENCRYPT)
+DECLARE_ASN1_FUNCTIONS(PKCS7)
+
+DECLARE_ASN1_ITEM(PKCS7_ATTR_SIGN)
+DECLARE_ASN1_ITEM(PKCS7_ATTR_VERIFY)
+
+DECLARE_ASN1_NDEF_FUNCTION(PKCS7)
+
+long PKCS7_ctrl(PKCS7 *p7, int cmd, long larg, char *parg);
+
+int PKCS7_set_type(PKCS7 *p7, int type);
+int PKCS7_set0_type_other(PKCS7 *p7, int type, ASN1_TYPE *other);
+int PKCS7_set_content(PKCS7 *p7, PKCS7 *p7_data);
+int PKCS7_SIGNER_INFO_set(PKCS7_SIGNER_INFO *p7i, X509 *x509, EVP_PKEY *pkey,
+	const EVP_MD *dgst);
+int PKCS7_add_signer(PKCS7 *p7, PKCS7_SIGNER_INFO *p7i);
+int PKCS7_add_certificate(PKCS7 *p7, X509 *x509);
+int PKCS7_add_crl(PKCS7 *p7, X509_CRL *x509);
+int PKCS7_content_new(PKCS7 *p7, int nid);
+int PKCS7_dataVerify(X509_STORE *cert_store, X509_STORE_CTX *ctx,
+	BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si); 
+int PKCS7_signatureVerify(BIO *bio, PKCS7 *p7, PKCS7_SIGNER_INFO *si,
+								X509 *x509);
+
+BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio);
+int PKCS7_dataFinal(PKCS7 *p7, BIO *bio);
+BIO *PKCS7_dataDecode(PKCS7 *p7, EVP_PKEY *pkey, BIO *in_bio, X509 *pcert);
+
+
+PKCS7_SIGNER_INFO *PKCS7_add_signature(PKCS7 *p7, X509 *x509,
+	EVP_PKEY *pkey, const EVP_MD *dgst);
+X509 *PKCS7_cert_from_signer_info(PKCS7 *p7, PKCS7_SIGNER_INFO *si);
+int PKCS7_set_digest(PKCS7 *p7, const EVP_MD *md);
+STACK_OF(PKCS7_SIGNER_INFO) *PKCS7_get_signer_info(PKCS7 *p7);
+
+PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509);
+int PKCS7_add_recipient_info(PKCS7 *p7, PKCS7_RECIP_INFO *ri);
+int PKCS7_RECIP_INFO_set(PKCS7_RECIP_INFO *p7i, X509 *x509);
+int PKCS7_set_cipher(PKCS7 *p7, const EVP_CIPHER *cipher);
+
+PKCS7_ISSUER_AND_SERIAL *PKCS7_get_issuer_and_serial(PKCS7 *p7, int idx);
+ASN1_OCTET_STRING *PKCS7_digest_from_attributes(STACK_OF(X509_ATTRIBUTE) *sk);
+int PKCS7_add_signed_attribute(PKCS7_SIGNER_INFO *p7si,int nid,int type,
+	void *data);
+int PKCS7_add_attribute (PKCS7_SIGNER_INFO *p7si, int nid, int atrtype,
+	void *value);
+ASN1_TYPE *PKCS7_get_attribute(PKCS7_SIGNER_INFO *si, int nid);
+ASN1_TYPE *PKCS7_get_signed_attribute(PKCS7_SIGNER_INFO *si, int nid);
+int PKCS7_set_signed_attributes(PKCS7_SIGNER_INFO *p7si,
+				STACK_OF(X509_ATTRIBUTE) *sk);
+int PKCS7_set_attributes(PKCS7_SIGNER_INFO *p7si,STACK_OF(X509_ATTRIBUTE) *sk);
+
+
+PKCS7 *PKCS7_sign(X509 *signcert, EVP_PKEY *pkey, STACK_OF(X509) *certs,
+							BIO *data, int flags);
+int PKCS7_verify(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store,
+					BIO *indata, BIO *out, int flags);
+STACK_OF(X509) *PKCS7_get0_signers(PKCS7 *p7, STACK_OF(X509) *certs, int flags);
+PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher,
+								int flags);
+int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags);
+
+int PKCS7_add_attrib_smimecap(PKCS7_SIGNER_INFO *si,
+			      STACK_OF(X509_ALGOR) *cap);
+STACK_OF(X509_ALGOR) *PKCS7_get_smimecap(PKCS7_SIGNER_INFO *si);
+int PKCS7_simple_smimecap(STACK_OF(X509_ALGOR) *sk, int nid, int arg);
+
+int SMIME_write_PKCS7(BIO *bio, PKCS7 *p7, BIO *data, int flags);
+PKCS7 *SMIME_read_PKCS7(BIO *bio, BIO **bcont);
+int SMIME_crlf_copy(BIO *in, BIO *out, int flags);
+int SMIME_text(BIO *in, BIO *out);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_PKCS7_strings(void);
+
+/* Error codes for the PKCS7 functions. */
+
+/* Function codes. */
+#define PKCS7_F_B64_READ_PKCS7				 120
+#define PKCS7_F_B64_WRITE_PKCS7				 121
+#define PKCS7_F_PKCS7_ADD_ATTRIB_SMIMECAP		 118
+#define PKCS7_F_PKCS7_ADD_CERTIFICATE			 100
+#define PKCS7_F_PKCS7_ADD_CRL				 101
+#define PKCS7_F_PKCS7_ADD_RECIPIENT_INFO		 102
+#define PKCS7_F_PKCS7_ADD_SIGNER			 103
+#define PKCS7_F_PKCS7_BIO_ADD_DIGEST			 125
+#define PKCS7_F_PKCS7_CTRL				 104
+#define PKCS7_F_PKCS7_DATADECODE			 112
+#define PKCS7_F_PKCS7_DATAFINAL				 128
+#define PKCS7_F_PKCS7_DATAINIT				 105
+#define PKCS7_F_PKCS7_DATASIGN				 106
+#define PKCS7_F_PKCS7_DATAVERIFY			 107
+#define PKCS7_F_PKCS7_DECRYPT				 114
+#define PKCS7_F_PKCS7_ENCRYPT				 115
+#define PKCS7_F_PKCS7_FIND_DIGEST			 127
+#define PKCS7_F_PKCS7_GET0_SIGNERS			 124
+#define PKCS7_F_PKCS7_SET_CIPHER			 108
+#define PKCS7_F_PKCS7_SET_CONTENT			 109
+#define PKCS7_F_PKCS7_SET_DIGEST			 126
+#define PKCS7_F_PKCS7_SET_TYPE				 110
+#define PKCS7_F_PKCS7_SIGN				 116
+#define PKCS7_F_PKCS7_SIGNATUREVERIFY			 113
+#define PKCS7_F_PKCS7_SIMPLE_SMIMECAP			 119
+#define PKCS7_F_PKCS7_VERIFY				 117
+#define PKCS7_F_SMIME_READ_PKCS7			 122
+#define PKCS7_F_SMIME_TEXT				 123
+
+/* Reason codes. */
+#define PKCS7_R_CERTIFICATE_VERIFY_ERROR		 117
+#define PKCS7_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER		 144
+#define PKCS7_R_CIPHER_NOT_INITIALIZED			 116
+#define PKCS7_R_CONTENT_AND_DATA_PRESENT		 118
+#define PKCS7_R_DECODE_ERROR				 130
+#define PKCS7_R_DECRYPTED_KEY_IS_WRONG_LENGTH		 100
+#define PKCS7_R_DECRYPT_ERROR				 119
+#define PKCS7_R_DIGEST_FAILURE				 101
+#define PKCS7_R_ERROR_ADDING_RECIPIENT			 120
+#define PKCS7_R_ERROR_SETTING_CIPHER			 121
+#define PKCS7_R_INVALID_MIME_TYPE			 131
+#define PKCS7_R_INVALID_NULL_POINTER			 143
+#define PKCS7_R_MIME_NO_CONTENT_TYPE			 132
+#define PKCS7_R_MIME_PARSE_ERROR			 133
+#define PKCS7_R_MIME_SIG_PARSE_ERROR			 134
+#define PKCS7_R_MISSING_CERIPEND_INFO			 103
+#define PKCS7_R_NO_CONTENT				 122
+#define PKCS7_R_NO_CONTENT_TYPE				 135
+#define PKCS7_R_NO_MULTIPART_BODY_FAILURE		 136
+#define PKCS7_R_NO_MULTIPART_BOUNDARY			 137
+#define PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE	 115
+#define PKCS7_R_NO_SIGNATURES_ON_DATA			 123
+#define PKCS7_R_NO_SIGNERS				 142
+#define PKCS7_R_NO_SIG_CONTENT_TYPE			 138
+#define PKCS7_R_OPERATION_NOT_SUPPORTED_ON_THIS_TYPE	 104
+#define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR		 124
+#define PKCS7_R_PKCS7_DATAFINAL				 126
+#define PKCS7_R_PKCS7_DATAFINAL_ERROR			 125
+#define PKCS7_R_PKCS7_DATASIGN				 145
+#define PKCS7_R_PKCS7_PARSE_ERROR			 139
+#define PKCS7_R_PKCS7_SIG_PARSE_ERROR			 140
+#define PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE	 127
+#define PKCS7_R_SIGNATURE_FAILURE			 105
+#define PKCS7_R_SIGNER_CERTIFICATE_NOT_FOUND		 128
+#define PKCS7_R_SIG_INVALID_MIME_TYPE			 141
+#define PKCS7_R_SMIME_TEXT_ERROR			 129
+#define PKCS7_R_UNABLE_TO_FIND_CERTIFICATE		 106
+#define PKCS7_R_UNABLE_TO_FIND_MEM_BIO			 107
+#define PKCS7_R_UNABLE_TO_FIND_MESSAGE_DIGEST		 108
+#define PKCS7_R_UNKNOWN_DIGEST_TYPE			 109
+#define PKCS7_R_UNKNOWN_OPERATION			 110
+#define PKCS7_R_UNSUPPORTED_CIPHER_TYPE			 111
+#define PKCS7_R_UNSUPPORTED_CONTENT_TYPE		 112
+#define PKCS7_R_WRONG_CONTENT_TYPE			 113
+#define PKCS7_R_WRONG_PKCS7_TYPE			 114
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pq_compat.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pq_compat.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pq_compat.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,147 @@
+/* crypto/pqueue/pqueue_compat.h */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#include "opensslconf.h"
+#include <openssl/bn.h>
+
+/* 
+ * The purpose of this header file is for supporting 64-bit integer
+ * manipulation on 32-bit (and lower) machines.  Currently the only
+ * such environment is VMS, Utrix and those with smaller default integer
+ * sizes than 32 bits.  For all such environment, we fall back to using
+ * BIGNUM.  We may need to fine tune the conditions for systems that
+ * are incorrectly configured.
+ *
+ * The only clients of this code are (1) pqueue for priority, and
+ * (2) DTLS, for sequence number manipulation.
+ */
+
+#if (defined(THIRTY_TWO_BIT) && !defined(BN_LLONG)) || defined(SIXTEEN_BIT) || defined(EIGHT_BIT)
+
+#define PQ_64BIT_IS_INTEGER 0
+#define PQ_64BIT_IS_BIGNUM 1
+
+#define PQ_64BIT     BIGNUM
+#define PQ_64BIT_CTX BN_CTX
+
+#define pq_64bit_init(x)           BN_init(x)
+#define pq_64bit_free(x)           BN_free(x)
+
+#define pq_64bit_ctx_new(ctx)      BN_CTX_new()
+#define pq_64bit_ctx_free(x)       BN_CTX_free(x)
+
+#define pq_64bit_assign(x, y)      BN_copy(x, y)
+#define pq_64bit_assign_word(x, y) BN_set_word(x, y)
+#define pq_64bit_gt(x, y)          BN_ucmp(x, y) >= 1 ? 1 : 0
+#define pq_64bit_eq(x, y)          BN_ucmp(x, y) == 0 ? 1 : 0
+#define pq_64bit_add_word(x, w)    BN_add_word(x, w)
+#define pq_64bit_sub(r, x, y)      BN_sub(r, x, y)
+#define pq_64bit_sub_word(x, w)    BN_sub_word(x, w)
+#define pq_64bit_mod(r, x, n, ctx) BN_mod(r, x, n, ctx)
+
+#define pq_64bit_bin2num(bn, bytes, len)   BN_bin2bn(bytes, len, bn)
+#define pq_64bit_num2bin(bn, bytes)        BN_bn2bin(bn, bytes)
+#define pq_64bit_get_word(x)               BN_get_word(x)
+#define pq_64bit_is_bit_set(x, offset)     BN_is_bit_set(x, offset)
+#define pq_64bit_lshift(r, x, shift)       BN_lshift(r, x, shift)
+#define pq_64bit_set_bit(x, num)           BN_set_bit(x, num)
+#define pq_64bit_get_length(x)             BN_num_bits((x))
+
+#else
+
+#define PQ_64BIT_IS_INTEGER 1
+#define PQ_64BIT_IS_BIGNUM 0
+
+#if defined(SIXTY_FOUR_BIT)
+#define PQ_64BIT BN_ULONG
+#define PQ_64BIT_PRINT "%lld"
+#elif defined(SIXTY_FOUR_BIT_LONG)
+#define PQ_64BIT BN_ULONG
+#define PQ_64BIT_PRINT "%ld"
+#elif defined(THIRTY_TWO_BIT)
+#define PQ_64BIT BN_ULLONG
+#define PQ_64BIT_PRINT "%lld"
+#endif
+
+#define PQ_64BIT_CTX      void
+
+#define pq_64bit_init(x)
+#define pq_64bit_free(x)
+#define pq_64bit_ctx_new(ctx)        (ctx)
+#define pq_64bit_ctx_free(x)
+
+#define pq_64bit_assign(x, y)        (*(x) = *(y))
+#define pq_64bit_assign_word(x, y)   (*(x) = y)
+#define pq_64bit_gt(x, y)	         (*(x) > *(y))
+#define pq_64bit_eq(x, y)            (*(x) == *(y))
+#define pq_64bit_add_word(x, w)      (*(x) = (*(x) + (w)))
+#define pq_64bit_sub(r, x, y)        (*(r) = (*(x) - *(y)))
+#define pq_64bit_sub_word(x, w)      (*(x) = (*(x) - (w)))
+#define pq_64bit_mod(r, x, n, ctx)
+
+#define pq_64bit_bin2num(num, bytes, len) bytes_to_long_long(bytes, num)
+#define pq_64bit_num2bin(num, bytes)      long_long_to_bytes(num, bytes)
+#define pq_64bit_get_word(x)              *(x)
+#define pq_64bit_lshift(r, x, shift)      (*(r) = (*(x) << (shift)))
+#define pq_64bit_set_bit(x, num)          do { \
+                                              PQ_64BIT mask = 1; \
+                                              mask = mask << (num); \
+                                              *(x) |= mask; \
+                                          } while(0)
+#endif /* OPENSSL_SYS_VMS */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pqueue.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pqueue.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/pqueue.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,95 @@
+/* crypto/pqueue/pqueue.h */
+/* 
+ * DTLS implementation written by Nagendra Modadugu
+ * (nagendra@cs.stanford.edu) for the OpenSSL project 2005.  
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2005 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_PQUEUE_H
+#define HEADER_PQUEUE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/pq_compat.h>
+
+typedef struct _pqueue *pqueue;
+
+typedef struct _pitem
+	{
+	PQ_64BIT priority;
+	void *data;
+	struct _pitem *next;
+	} pitem;
+
+typedef struct _pitem *piterator;
+
+pitem *pitem_new(PQ_64BIT priority, void *data);
+void   pitem_free(pitem *item);
+
+pqueue pqueue_new(void);
+void   pqueue_free(pqueue pq);
+
+pitem *pqueue_insert(pqueue pq, pitem *item);
+pitem *pqueue_peek(pqueue pq);
+pitem *pqueue_pop(pqueue pq);
+pitem *pqueue_find(pqueue pq, PQ_64BIT priority);
+pitem *pqueue_iterator(pqueue pq);
+pitem *pqueue_next(piterator *iter);
+
+void   pqueue_print(pqueue pq);
+
+#endif /* ! HEADER_PQUEUE_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rand.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rand.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rand.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,140 @@
+/* crypto/rand/rand.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_RAND_H
+#define HEADER_RAND_H
+
+#include <stdlib.h>
+#include <openssl/ossl_typ.h>
+#include <openssl/e_os2.h>
+
+#if defined(OPENSSL_SYS_WINDOWS)
+#include <windows.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#if defined(OPENSSL_FIPS)
+#define FIPS_RAND_SIZE_T size_t
+#endif
+
+/* Already defined in ossl_typ.h */
+/* typedef struct rand_meth_st RAND_METHOD; */
+
+struct rand_meth_st
+	{
+	void (*seed)(const void *buf, int num);
+	int (*bytes)(unsigned char *buf, int num);
+	void (*cleanup)(void);
+	void (*add)(const void *buf, int num, double entropy);
+	int (*pseudorand)(unsigned char *buf, int num);
+	int (*status)(void);
+	};
+
+#ifdef BN_DEBUG
+extern int rand_predictable;
+#endif
+
+int RAND_set_rand_method(const RAND_METHOD *meth);
+const RAND_METHOD *RAND_get_rand_method(void);
+#ifndef OPENSSL_NO_ENGINE
+int RAND_set_rand_engine(ENGINE *engine);
+#endif
+RAND_METHOD *RAND_SSLeay(void);
+void RAND_cleanup(void );
+int  RAND_bytes(unsigned char *buf,int num);
+int  RAND_pseudo_bytes(unsigned char *buf,int num);
+void RAND_seed(const void *buf,int num);
+void RAND_add(const void *buf,int num,double entropy);
+int  RAND_load_file(const char *file,long max_bytes);
+int  RAND_write_file(const char *file);
+const char *RAND_file_name(char *file,size_t num);
+int RAND_status(void);
+int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes);
+int RAND_egd(const char *path);
+int RAND_egd_bytes(const char *path,int bytes);
+int RAND_poll(void);
+
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
+
+void RAND_screen(void);
+int RAND_event(UINT, WPARAM, LPARAM);
+
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_RAND_strings(void);
+
+/* Error codes for the RAND functions. */
+
+/* Function codes. */
+#define RAND_F_RAND_GET_RAND_METHOD			 101
+#define RAND_F_SSLEAY_RAND_BYTES			 100
+
+/* Reason codes. */
+#define RAND_R_PRNG_NOT_SEEDED				 100
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc2.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,101 @@
+/* crypto/rc2/rc2.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_RC2_H
+#define HEADER_RC2_H
+
+#include <openssl/opensslconf.h> /* OPENSSL_NO_RC2, RC2_INT */
+#ifdef OPENSSL_NO_RC2
+#error RC2 is disabled.
+#endif
+
+#define RC2_ENCRYPT	1
+#define RC2_DECRYPT	0
+
+#define RC2_BLOCK	8
+#define RC2_KEY_LENGTH	16
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct rc2_key_st
+	{
+	RC2_INT data[64];
+	} RC2_KEY;
+
+ 
+void RC2_set_key(RC2_KEY *key, int len, const unsigned char *data,int bits);
+void RC2_ecb_encrypt(const unsigned char *in,unsigned char *out,RC2_KEY *key,
+		     int enc);
+void RC2_encrypt(unsigned long *data,RC2_KEY *key);
+void RC2_decrypt(unsigned long *data,RC2_KEY *key);
+void RC2_cbc_encrypt(const unsigned char *in, unsigned char *out, long length,
+	RC2_KEY *ks, unsigned char *iv, int enc);
+void RC2_cfb64_encrypt(const unsigned char *in, unsigned char *out,
+		       long length, RC2_KEY *schedule, unsigned char *ivec,
+		       int *num, int enc);
+void RC2_ofb64_encrypt(const unsigned char *in, unsigned char *out,
+		       long length, RC2_KEY *schedule, unsigned char *ivec,
+		       int *num);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc4.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc4.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc4.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,87 @@
+/* crypto/rc4/rc4.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_RC4_H
+#define HEADER_RC4_H
+
+#include <openssl/opensslconf.h> /* OPENSSL_NO_RC4, RC4_INT */
+#ifdef OPENSSL_NO_RC4
+#error RC4 is disabled.
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct rc4_key_st
+	{
+	RC4_INT x,y;
+	RC4_INT data[256];
+	} RC4_KEY;
+
+ 
+const char *RC4_options(void);
+void RC4_set_key(RC4_KEY *key, int len, const unsigned char *data);
+void RC4(RC4_KEY *key, unsigned long len, const unsigned char *indata,
+		unsigned char *outdata);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc5.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc5.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rc5.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,120 @@
+/* crypto/rc5/rc5.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_RC5_H
+#define HEADER_RC5_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_NO_RC5
+#error RC5 is disabled.
+#endif
+
+#define RC5_ENCRYPT	1
+#define RC5_DECRYPT	0
+
+/* 32 bit.  For Alpha, things may get weird */
+#define RC5_32_INT unsigned long
+
+#define RC5_32_BLOCK		8
+#define RC5_32_KEY_LENGTH	16 /* This is a default, max is 255 */
+
+/* This are the only values supported.  Tweak the code if you want more
+ * The most supported modes will be
+ * RC5-32/12/16
+ * RC5-32/16/8
+ */
+#define RC5_8_ROUNDS	8
+#define RC5_12_ROUNDS	12
+#define RC5_16_ROUNDS	16
+
+typedef struct rc5_key_st
+	{
+	/* Number of rounds */
+	int rounds;
+	RC5_32_INT data[2*(RC5_16_ROUNDS+1)];
+	} RC5_32_KEY;
+
+#ifdef OPENSSL_FIPS 
+void private_RC5_32_set_key(RC5_32_KEY *key, int len, const unsigned char *data,
+	int rounds);
+#endif
+void RC5_32_set_key(RC5_32_KEY *key, int len, const unsigned char *data,
+	int rounds);
+void RC5_32_ecb_encrypt(const unsigned char *in,unsigned char *out,RC5_32_KEY *key,
+	int enc);
+void RC5_32_encrypt(unsigned long *data,RC5_32_KEY *key);
+void RC5_32_decrypt(unsigned long *data,RC5_32_KEY *key);
+void RC5_32_cbc_encrypt(const unsigned char *in, unsigned char *out,
+			long length, RC5_32_KEY *ks, unsigned char *iv,
+			int enc);
+void RC5_32_cfb64_encrypt(const unsigned char *in, unsigned char *out,
+			  long length, RC5_32_KEY *schedule,
+			  unsigned char *ivec, int *num, int enc);
+void RC5_32_ofb64_encrypt(const unsigned char *in, unsigned char *out,
+			  long length, RC5_32_KEY *schedule,
+			  unsigned char *ivec, int *num);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ripemd.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ripemd.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ripemd.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,103 @@
+/* crypto/ripemd/ripemd.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_RIPEMD_H
+#define HEADER_RIPEMD_H
+
+#include <openssl/e_os2.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_NO_RIPEMD
+#error RIPEMD is disabled.
+#endif
+
+#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__)
+#define RIPEMD160_LONG unsigned long
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
+#define RIPEMD160_LONG unsigned long
+#define RIPEMD160_LONG_LOG2 3
+#else
+#define RIPEMD160_LONG unsigned int
+#endif
+
+#define RIPEMD160_CBLOCK	64
+#define RIPEMD160_LBLOCK	(RIPEMD160_CBLOCK/4)
+#define RIPEMD160_DIGEST_LENGTH	20
+
+typedef struct RIPEMD160state_st
+	{
+	RIPEMD160_LONG A,B,C,D,E;
+	RIPEMD160_LONG Nl,Nh;
+	RIPEMD160_LONG data[RIPEMD160_LBLOCK];
+	unsigned int   num;
+	} RIPEMD160_CTX;
+
+int RIPEMD160_Init(RIPEMD160_CTX *c);
+int RIPEMD160_Update(RIPEMD160_CTX *c, const void *data, size_t len);
+int RIPEMD160_Final(unsigned char *md, RIPEMD160_CTX *c);
+unsigned char *RIPEMD160(const unsigned char *d, size_t n,
+	unsigned char *md);
+void RIPEMD160_Transform(RIPEMD160_CTX *c, const unsigned char *b);
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rsa.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rsa.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/rsa.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,429 @@
+/* crypto/rsa/rsa.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_RSA_H
+#define HEADER_RSA_H
+
+#include <openssl/asn1.h>
+
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/crypto.h>
+#include <openssl/ossl_typ.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/bn.h>
+#endif
+
+#ifdef OPENSSL_NO_RSA
+#error RSA is disabled.
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Declared already in ossl_typ.h */
+/* typedef struct rsa_st RSA; */
+/* typedef struct rsa_meth_st RSA_METHOD; */
+
+struct rsa_meth_st
+	{
+	const char *name;
+	int (*rsa_pub_enc)(int flen,const unsigned char *from,
+			   unsigned char *to,
+			   RSA *rsa,int padding);
+	int (*rsa_pub_dec)(int flen,const unsigned char *from,
+			   unsigned char *to,
+			   RSA *rsa,int padding);
+	int (*rsa_priv_enc)(int flen,const unsigned char *from,
+			    unsigned char *to,
+			    RSA *rsa,int padding);
+	int (*rsa_priv_dec)(int flen,const unsigned char *from,
+			    unsigned char *to,
+			    RSA *rsa,int padding);
+	int (*rsa_mod_exp)(BIGNUM *r0,const BIGNUM *I,RSA *rsa,BN_CTX *ctx); /* Can be null */
+	int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p,
+			  const BIGNUM *m, BN_CTX *ctx,
+			  BN_MONT_CTX *m_ctx); /* Can be null */
+	int (*init)(RSA *rsa);		/* called at new */
+	int (*finish)(RSA *rsa);	/* called at free */
+	int flags;			/* RSA_METHOD_FLAG_* things */
+	char *app_data;			/* may be needed! */
+/* New sign and verify functions: some libraries don't allow arbitrary data
+ * to be signed/verified: this allows them to be used. Note: for this to work
+ * the RSA_public_decrypt() and RSA_private_encrypt() should *NOT* be used
+ * RSA_sign(), RSA_verify() should be used instead. Note: for backwards
+ * compatibility this functionality is only enabled if the RSA_FLAG_SIGN_VER
+ * option is set in 'flags'.
+ */
+	int (*rsa_sign)(int type,
+		const unsigned char *m, unsigned int m_length,
+		unsigned char *sigret, unsigned int *siglen, const RSA *rsa);
+	int (*rsa_verify)(int dtype,
+		const unsigned char *m, unsigned int m_length,
+		unsigned char *sigbuf, unsigned int siglen, const RSA *rsa);
+/* If this callback is NULL, the builtin software RSA key-gen will be used. This
+ * is for behavioural compatibility whilst the code gets rewired, but one day
+ * it would be nice to assume there are no such things as "builtin software"
+ * implementations. */
+	int (*rsa_keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+	};
+
+struct rsa_st
+	{
+	/* The first parameter is used to pickup errors where
+	 * this is passed instead of aEVP_PKEY, it is set to 0 */
+	int pad;
+	long version;
+	const RSA_METHOD *meth;
+	/* functional reference if 'meth' is ENGINE-provided */
+	ENGINE *engine;
+	BIGNUM *n;
+	BIGNUM *e;
+	BIGNUM *d;
+	BIGNUM *p;
+	BIGNUM *q;
+	BIGNUM *dmp1;
+	BIGNUM *dmq1;
+	BIGNUM *iqmp;
+	/* be careful using this if the RSA structure is shared */
+	CRYPTO_EX_DATA ex_data;
+	int references;
+	int flags;
+
+	/* Used to cache montgomery values */
+	BN_MONT_CTX *_method_mod_n;
+	BN_MONT_CTX *_method_mod_p;
+	BN_MONT_CTX *_method_mod_q;
+
+	/* all BIGNUM values are actually in the following data, if it is not
+	 * NULL */
+	char *bignum_data;
+	BN_BLINDING *blinding;
+	BN_BLINDING *mt_blinding;
+	};
+
+#define RSA_3	0x3L
+#define RSA_F4	0x10001L
+
+#define RSA_METHOD_FLAG_NO_CHECK	0x0001 /* don't check pub/private match */
+
+#define RSA_FLAG_CACHE_PUBLIC		0x0002
+#define RSA_FLAG_CACHE_PRIVATE		0x0004
+#define RSA_FLAG_BLINDING		0x0008
+#define RSA_FLAG_THREAD_SAFE		0x0010
+/* This flag means the private key operations will be handled by rsa_mod_exp
+ * and that they do not depend on the private key components being present:
+ * for example a key stored in external hardware. Without this flag bn_mod_exp
+ * gets called when private key components are absent.
+ */
+#define RSA_FLAG_EXT_PKEY		0x0020
+
+/* This flag in the RSA_METHOD enables the new rsa_sign, rsa_verify functions.
+ */
+#define RSA_FLAG_SIGN_VER		0x0040
+
+#define RSA_FLAG_NO_BLINDING		0x0080 /* new with 0.9.6j and 0.9.7b; the built-in
+                                                * RSA implementation now uses blinding by
+                                                * default (ignoring RSA_FLAG_BLINDING),
+                                                * but other engines might not need it
+                                                */
+#define RSA_FLAG_NO_EXP_CONSTTIME	0x0100 /* new with 0.9.7h; the built-in RSA
+                                                * implementation now uses constant time
+                                                * modular exponentiation for secret exponents
+                                                * by default. This flag causes the
+                                                * faster variable sliding window method to
+                                                * be used for all exponents.
+                                                */
+
+#define RSA_PKCS1_PADDING	1
+#define RSA_SSLV23_PADDING	2
+#define RSA_NO_PADDING		3
+#define RSA_PKCS1_OAEP_PADDING	4
+#define RSA_X931_PADDING	5
+
+#define RSA_PKCS1_PADDING_SIZE	11
+
+#define RSA_set_app_data(s,arg)         RSA_set_ex_data(s,0,arg)
+#define RSA_get_app_data(s)             RSA_get_ex_data(s,0)
+
+RSA *	RSA_new(void);
+RSA *	RSA_new_method(ENGINE *engine);
+int	RSA_size(const RSA *);
+
+/* Deprecated version */
+#ifndef OPENSSL_NO_DEPRECATED
+RSA *	RSA_generate_key(int bits, unsigned long e,void
+		(*callback)(int,int,void *),void *cb_arg);
+#endif /* !defined(OPENSSL_NO_DEPRECATED) */
+
+/* New version */
+int	RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb);
+
+int	RSA_check_key(const RSA *);
+	/* next 4 return -1 on error */
+int	RSA_public_encrypt(int flen, const unsigned char *from,
+		unsigned char *to, RSA *rsa,int padding);
+int	RSA_private_encrypt(int flen, const unsigned char *from,
+		unsigned char *to, RSA *rsa,int padding);
+int	RSA_public_decrypt(int flen, const unsigned char *from, 
+		unsigned char *to, RSA *rsa,int padding);
+int	RSA_private_decrypt(int flen, const unsigned char *from, 
+		unsigned char *to, RSA *rsa,int padding);
+void	RSA_free (RSA *r);
+/* "up" the RSA object's reference count */
+int	RSA_up_ref(RSA *r);
+
+int	RSA_flags(const RSA *r);
+
+void RSA_set_default_method(const RSA_METHOD *meth);
+const RSA_METHOD *RSA_get_default_method(void);
+const RSA_METHOD *RSA_get_method(const RSA *rsa);
+int RSA_set_method(RSA *rsa, const RSA_METHOD *meth);
+
+/* This function needs the memory locking malloc callbacks to be installed */
+int RSA_memory_lock(RSA *r);
+
+/* these are the actual SSLeay RSA functions */
+const RSA_METHOD *RSA_PKCS1_SSLeay(void);
+
+const RSA_METHOD *RSA_null_method(void);
+
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPublicKey)
+DECLARE_ASN1_ENCODE_FUNCTIONS_const(RSA, RSAPrivateKey)
+
+#ifndef OPENSSL_NO_FP_API
+int	RSA_print_fp(FILE *fp, const RSA *r,int offset);
+#endif
+
+#ifndef OPENSSL_NO_BIO
+int	RSA_print(BIO *bp, const RSA *r,int offset);
+#endif
+
+int i2d_RSA_NET(const RSA *a, unsigned char **pp,
+		int (*cb)(char *buf, int len, const char *prompt, int verify),
+		int sgckey);
+RSA *d2i_RSA_NET(RSA **a, const unsigned char **pp, long length,
+		 int (*cb)(char *buf, int len, const char *prompt, int verify),
+		 int sgckey);
+
+int i2d_Netscape_RSA(const RSA *a, unsigned char **pp,
+		     int (*cb)(char *buf, int len, const char *prompt,
+			       int verify));
+RSA *d2i_Netscape_RSA(RSA **a, const unsigned char **pp, long length,
+		      int (*cb)(char *buf, int len, const char *prompt,
+				int verify));
+
+/* The following 2 functions sign and verify a X509_SIG ASN1 object
+ * inside PKCS#1 padded RSA encryption */
+int RSA_sign(int type, const unsigned char *m, unsigned int m_length,
+	unsigned char *sigret, unsigned int *siglen, RSA *rsa);
+int RSA_verify(int type, const unsigned char *m, unsigned int m_length,
+	unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
+
+/* The following 2 function sign and verify a ASN1_OCTET_STRING
+ * object inside PKCS#1 padded RSA encryption */
+int RSA_sign_ASN1_OCTET_STRING(int type,
+	const unsigned char *m, unsigned int m_length,
+	unsigned char *sigret, unsigned int *siglen, RSA *rsa);
+int RSA_verify_ASN1_OCTET_STRING(int type,
+	const unsigned char *m, unsigned int m_length,
+	unsigned char *sigbuf, unsigned int siglen, RSA *rsa);
+
+int RSA_blinding_on(RSA *rsa, BN_CTX *ctx);
+void RSA_blinding_off(RSA *rsa);
+BN_BLINDING *RSA_setup_blinding(RSA *rsa, BN_CTX *ctx);
+
+int RSA_padding_add_PKCS1_type_1(unsigned char *to,int tlen,
+	const unsigned char *f,int fl);
+int RSA_padding_check_PKCS1_type_1(unsigned char *to,int tlen,
+	const unsigned char *f,int fl,int rsa_len);
+int RSA_padding_add_PKCS1_type_2(unsigned char *to,int tlen,
+	const unsigned char *f,int fl);
+int RSA_padding_check_PKCS1_type_2(unsigned char *to,int tlen,
+	const unsigned char *f,int fl,int rsa_len);
+int PKCS1_MGF1(unsigned char *mask, long len,
+	const unsigned char *seed, long seedlen, const EVP_MD *dgst);
+int RSA_padding_add_PKCS1_OAEP(unsigned char *to,int tlen,
+	const unsigned char *f,int fl,
+	const unsigned char *p,int pl);
+int RSA_padding_check_PKCS1_OAEP(unsigned char *to,int tlen,
+	const unsigned char *f,int fl,int rsa_len,
+	const unsigned char *p,int pl);
+int RSA_padding_add_SSLv23(unsigned char *to,int tlen,
+	const unsigned char *f,int fl);
+int RSA_padding_check_SSLv23(unsigned char *to,int tlen,
+	const unsigned char *f,int fl,int rsa_len);
+int RSA_padding_add_none(unsigned char *to,int tlen,
+	const unsigned char *f,int fl);
+int RSA_padding_check_none(unsigned char *to,int tlen,
+	const unsigned char *f,int fl,int rsa_len);
+int RSA_padding_add_X931(unsigned char *to,int tlen,
+	const unsigned char *f,int fl);
+int RSA_padding_check_X931(unsigned char *to,int tlen,
+	const unsigned char *f,int fl,int rsa_len);
+int RSA_X931_hash_id(int nid);
+
+int RSA_verify_PKCS1_PSS(RSA *rsa, const unsigned char *mHash,
+			const EVP_MD *Hash, const unsigned char *EM, int sLen);
+int RSA_padding_add_PKCS1_PSS(RSA *rsa, unsigned char *EM,
+			const unsigned char *mHash,
+			const EVP_MD *Hash, int sLen);
+
+int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int RSA_set_ex_data(RSA *r,int idx,void *arg);
+void *RSA_get_ex_data(const RSA *r, int idx);
+
+RSA *RSAPublicKey_dup(RSA *rsa);
+RSA *RSAPrivateKey_dup(RSA *rsa);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_RSA_strings(void);
+
+/* Error codes for the RSA functions. */
+
+/* Function codes. */
+#define RSA_F_MEMORY_LOCK				 100
+#define RSA_F_RSA_BUILTIN_KEYGEN			 129
+#define RSA_F_RSA_CHECK_KEY				 123
+#define RSA_F_RSA_EAY_PRIVATE_DECRYPT			 101
+#define RSA_F_RSA_EAY_PRIVATE_ENCRYPT			 102
+#define RSA_F_RSA_EAY_PUBLIC_DECRYPT			 103
+#define RSA_F_RSA_EAY_PUBLIC_ENCRYPT			 104
+#define RSA_F_RSA_GENERATE_KEY				 105
+#define RSA_F_RSA_MEMORY_LOCK				 130
+#define RSA_F_RSA_NEW_METHOD				 106
+#define RSA_F_RSA_NULL					 124
+#define RSA_F_RSA_NULL_MOD_EXP				 131
+#define RSA_F_RSA_NULL_PRIVATE_DECRYPT			 132
+#define RSA_F_RSA_NULL_PRIVATE_ENCRYPT			 133
+#define RSA_F_RSA_NULL_PUBLIC_DECRYPT			 134
+#define RSA_F_RSA_NULL_PUBLIC_ENCRYPT			 135
+#define RSA_F_RSA_PADDING_ADD_NONE			 107
+#define RSA_F_RSA_PADDING_ADD_PKCS1_OAEP		 121
+#define RSA_F_RSA_PADDING_ADD_PKCS1_PSS			 125
+#define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_1		 108
+#define RSA_F_RSA_PADDING_ADD_PKCS1_TYPE_2		 109
+#define RSA_F_RSA_PADDING_ADD_SSLV23			 110
+#define RSA_F_RSA_PADDING_ADD_X931			 127
+#define RSA_F_RSA_PADDING_CHECK_NONE			 111
+#define RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP		 122
+#define RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_1		 112
+#define RSA_F_RSA_PADDING_CHECK_PKCS1_TYPE_2		 113
+#define RSA_F_RSA_PADDING_CHECK_SSLV23			 114
+#define RSA_F_RSA_PADDING_CHECK_X931			 128
+#define RSA_F_RSA_PRINT					 115
+#define RSA_F_RSA_PRINT_FP				 116
+#define RSA_F_RSA_SETUP_BLINDING			 136
+#define RSA_F_RSA_SIGN					 117
+#define RSA_F_RSA_SIGN_ASN1_OCTET_STRING		 118
+#define RSA_F_RSA_VERIFY				 119
+#define RSA_F_RSA_VERIFY_ASN1_OCTET_STRING		 120
+#define RSA_F_RSA_VERIFY_PKCS1_PSS			 126
+
+/* Reason codes. */
+#define RSA_R_ALGORITHM_MISMATCH			 100
+#define RSA_R_BAD_E_VALUE				 101
+#define RSA_R_BAD_FIXED_HEADER_DECRYPT			 102
+#define RSA_R_BAD_PAD_BYTE_COUNT			 103
+#define RSA_R_BAD_SIGNATURE				 104
+#define RSA_R_BLOCK_TYPE_IS_NOT_01			 106
+#define RSA_R_BLOCK_TYPE_IS_NOT_02			 107
+#define RSA_R_DATA_GREATER_THAN_MOD_LEN			 108
+#define RSA_R_DATA_TOO_LARGE				 109
+#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE		 110
+#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS		 132
+#define RSA_R_DATA_TOO_SMALL				 111
+#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE		 122
+#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY		 112
+#define RSA_R_DMP1_NOT_CONGRUENT_TO_D			 124
+#define RSA_R_DMQ1_NOT_CONGRUENT_TO_D			 125
+#define RSA_R_D_E_NOT_CONGRUENT_TO_1			 123
+#define RSA_R_FIRST_OCTET_INVALID			 133
+#define RSA_R_INVALID_HEADER				 137
+#define RSA_R_INVALID_MESSAGE_LENGTH			 131
+#define RSA_R_INVALID_PADDING				 138
+#define RSA_R_INVALID_TRAILER				 139
+#define RSA_R_IQMP_NOT_INVERSE_OF_Q			 126
+#define RSA_R_KEY_SIZE_TOO_SMALL			 120
+#define RSA_R_LAST_OCTET_INVALID			 134
+#define RSA_R_NO_PUBLIC_EXPONENT			 140
+#define RSA_R_NULL_BEFORE_BLOCK_MISSING			 113
+#define RSA_R_N_DOES_NOT_EQUAL_P_Q			 127
+#define RSA_R_OAEP_DECODING_ERROR			 121
+#define RSA_R_SLEN_RECOVERY_FAILED			 135
+#define RSA_R_PADDING_CHECK_FAILED			 114
+#define RSA_R_P_NOT_PRIME				 128
+#define RSA_R_Q_NOT_PRIME				 129
+#define RSA_R_RSA_OPERATIONS_NOT_SUPPORTED		 130
+#define RSA_R_SSLV3_ROLLBACK_ATTACK			 115
+#define RSA_R_THE_ASN1_OBJECT_IDENTIFIER_IS_NOT_KNOWN_FOR_THIS_MD 116
+#define RSA_R_UNKNOWN_ALGORITHM_TYPE			 117
+#define RSA_R_UNKNOWN_PADDING_TYPE			 118
+#define RSA_R_WRONG_SIGNATURE_LENGTH			 119
+#define RSA_R_SLEN_CHECK_FAILED				 136
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/safestack.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/safestack.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/safestack.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1784 @@
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_SAFESTACK_H
+#define HEADER_SAFESTACK_H
+
+#include <openssl/stack.h>
+
+typedef void (*openssl_fptr)(void);
+#define openssl_fcast(f) ((openssl_fptr)f)
+
+#ifdef DEBUG_SAFESTACK
+
+#define STACK_OF(type) struct stack_st_##type
+#define PREDECLARE_STACK_OF(type) STACK_OF(type);
+
+#define DECLARE_STACK_OF(type) \
+STACK_OF(type) \
+    { \
+    STACK stack; \
+    };
+
+#define IMPLEMENT_STACK_OF(type) /* nada (obsolete in new safestack approach)*/
+
+/* SKM_sk_... stack macros are internal to safestack.h:
+ * never use them directly, use sk_<type>_... instead */
+#define SKM_sk_new(type, cmp) \
+	((STACK_OF(type) * (*)(int (*)(const type * const *, const type * const *)))openssl_fcast(sk_new))(cmp)
+#define SKM_sk_new_null(type) \
+	((STACK_OF(type) * (*)(void))openssl_fcast(sk_new_null))()
+#define SKM_sk_free(type, st) \
+	((void (*)(STACK_OF(type) *))openssl_fcast(sk_free))(st)
+#define SKM_sk_num(type, st) \
+	((int (*)(const STACK_OF(type) *))openssl_fcast(sk_num))(st)
+#define SKM_sk_value(type, st,i) \
+	((type * (*)(const STACK_OF(type) *, int))openssl_fcast(sk_value))(st, i)
+#define SKM_sk_set(type, st,i,val) \
+	((type * (*)(STACK_OF(type) *, int, type *))openssl_fcast(sk_set))(st, i, val)
+#define SKM_sk_zero(type, st) \
+	((void (*)(STACK_OF(type) *))openssl_fcast(sk_zero))(st)
+#define SKM_sk_push(type, st,val) \
+	((int (*)(STACK_OF(type) *, type *))openssl_fcast(sk_push))(st, val)
+#define SKM_sk_unshift(type, st,val) \
+	((int (*)(STACK_OF(type) *, type *))openssl_fcast(sk_unshift))(st, val)
+#define SKM_sk_find(type, st,val) \
+	((int (*)(STACK_OF(type) *, type *))openssl_fcast(sk_find))(st, val)
+#define SKM_sk_delete(type, st,i) \
+	((type * (*)(STACK_OF(type) *, int))openssl_fcast(sk_delete))(st, i)
+#define SKM_sk_delete_ptr(type, st,ptr) \
+	((type * (*)(STACK_OF(type) *, type *))openssl_fcast(sk_delete_ptr))(st, ptr)
+#define SKM_sk_insert(type, st,val,i) \
+	((int (*)(STACK_OF(type) *, type *, int))openssl_fcast(sk_insert))(st, val, i)
+#define SKM_sk_set_cmp_func(type, st,cmp) \
+	((int (*(*)(STACK_OF(type) *, int (*)(const type * const *, const type * const *))) \
+	  (const type * const *, const type * const *))openssl_fcast(sk_set_cmp_func))\
+	(st, cmp)
+#define SKM_sk_dup(type, st) \
+	((STACK_OF(type) *(*)(STACK_OF(type) *))openssl_fcast(sk_dup))(st)
+#define SKM_sk_pop_free(type, st,free_func) \
+	((void (*)(STACK_OF(type) *, void (*)(type *)))openssl_fcast(sk_pop_free))\
+	(st, free_func)
+#define SKM_sk_shift(type, st) \
+	((type * (*)(STACK_OF(type) *))openssl_fcast(sk_shift))(st)
+#define SKM_sk_pop(type, st) \
+	((type * (*)(STACK_OF(type) *))openssl_fcast(sk_pop))(st)
+#define SKM_sk_sort(type, st) \
+	((void (*)(STACK_OF(type) *))openssl_fcast(sk_sort))(st)
+#define SKM_sk_is_sorted(type, st) \
+	((int (*)(const STACK_OF(type) *))openssl_fcast(sk_is_sorted))(st)
+
+#define	SKM_ASN1_SET_OF_d2i(type, st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+((STACK_OF(type) * (*) (STACK_OF(type) **,const unsigned char **, long , \
+                         type *(*)(type **, const unsigned char **,long), \
+                                void (*)(type *), int ,int )) openssl_fcast(d2i_ASN1_SET)) \
+			(st,pp,length, d2i_func, free_func, ex_tag,ex_class)
+#define	SKM_ASN1_SET_OF_i2d(type, st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	((int (*)(STACK_OF(type) *,unsigned char **, \
+        int (*)(type *,unsigned char **), int , int , int)) openssl_fcast(i2d_ASN1_SET)) \
+						(st,pp,i2d_func,ex_tag,ex_class,is_set)
+
+#define	SKM_ASN1_seq_pack(type, st, i2d_func, buf, len) \
+	((unsigned char *(*)(STACK_OF(type) *, \
+        int (*)(type *,unsigned char **), unsigned char **,int *)) openssl_fcast(ASN1_seq_pack)) \
+				(st, i2d_func, buf, len)
+#define	SKM_ASN1_seq_unpack(type, buf, len, d2i_func, free_func) \
+	((STACK_OF(type) * (*)(const unsigned char *,int, \
+                              type *(*)(type **,const unsigned char **, long), \
+                              void (*)(type *)))openssl_fcast(ASN1_seq_unpack)) \
+					(buf,len,d2i_func, free_func)
+
+#define SKM_PKCS12_decrypt_d2i(type, algor, d2i_func, free_func, pass, passlen, oct, seq) \
+	((STACK_OF(type) * (*)(X509_ALGOR *, \
+            		type *(*)(type **, const unsigned char **, long), \
+				void (*)(type *), \
+                                const char *, int, \
+                                ASN1_STRING *, int))PKCS12_decrypt_d2i) \
+				(algor,d2i_func,free_func,pass,passlen,oct,seq)
+
+#else
+
+#define STACK_OF(type) STACK
+#define PREDECLARE_STACK_OF(type) /* nada */
+#define DECLARE_STACK_OF(type)    /* nada */
+#define IMPLEMENT_STACK_OF(type)  /* nada */
+
+#define SKM_sk_new(type, cmp) \
+	sk_new((int (*)(const char * const *, const char * const *))(cmp))
+#define SKM_sk_new_null(type) \
+	sk_new_null()
+#define SKM_sk_free(type, st) \
+	sk_free(st)
+#define SKM_sk_num(type, st) \
+	sk_num(st)
+#define SKM_sk_value(type, st,i) \
+	((type *)sk_value(st, i))
+#define SKM_sk_set(type, st,i,val) \
+	((type *)sk_set(st, i,(char *)val))
+#define SKM_sk_zero(type, st) \
+	sk_zero(st)
+#define SKM_sk_push(type, st,val) \
+	sk_push(st, (char *)val)
+#define SKM_sk_unshift(type, st,val) \
+	sk_unshift(st, val)
+#define SKM_sk_find(type, st,val) \
+	sk_find(st, (char *)val)
+#define SKM_sk_delete(type, st,i) \
+	((type *)sk_delete(st, i))
+#define SKM_sk_delete_ptr(type, st,ptr) \
+	((type *)sk_delete_ptr(st,(char *)ptr))
+#define SKM_sk_insert(type, st,val,i) \
+	sk_insert(st, (char *)val, i)
+#define SKM_sk_set_cmp_func(type, st,cmp) \
+	((int (*)(const type * const *,const type * const *)) \
+	sk_set_cmp_func(st, (int (*)(const char * const *, const char * const *))(cmp)))
+#define SKM_sk_dup(type, st) \
+	sk_dup(st)
+#define SKM_sk_pop_free(type, st,free_func) \
+	sk_pop_free(st, (void (*)(void *))free_func)
+#define SKM_sk_shift(type, st) \
+	((type *)sk_shift(st))
+#define SKM_sk_pop(type, st) \
+	((type *)sk_pop(st))
+#define SKM_sk_sort(type, st) \
+	sk_sort(st)
+#define SKM_sk_is_sorted(type, st) \
+	sk_is_sorted(st)
+
+#define	SKM_ASN1_SET_OF_d2i(type, st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	d2i_ASN1_SET(st,pp,length, (void *(*)(void ** ,const unsigned char ** ,long))d2i_func, (void (*)(void *))free_func, ex_tag,ex_class)
+#define	SKM_ASN1_SET_OF_i2d(type, st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	i2d_ASN1_SET(st,pp,(int (*)(void *, unsigned char **))i2d_func,ex_tag,ex_class,is_set)
+
+#define	SKM_ASN1_seq_pack(type, st, i2d_func, buf, len) \
+	ASN1_seq_pack(st, (int (*)(void *, unsigned char **))i2d_func, buf, len)
+#define	SKM_ASN1_seq_unpack(type, buf, len, d2i_func, free_func) \
+	ASN1_seq_unpack(buf,len,(void *(*)(void **,const unsigned char **,long))d2i_func, (void(*)(void *))free_func)
+
+#define SKM_PKCS12_decrypt_d2i(type, algor, d2i_func, free_func, pass, passlen, oct, seq) \
+	((STACK *)PKCS12_decrypt_d2i(algor,(char *(*)())d2i_func, (void(*)(void *))free_func,pass,passlen,oct,seq))
+
+#endif
+
+/* This block of defines is updated by util/mkstack.pl, please do not touch! */
+#define sk_ACCESS_DESCRIPTION_new(st) SKM_sk_new(ACCESS_DESCRIPTION, (st))
+#define sk_ACCESS_DESCRIPTION_new_null() SKM_sk_new_null(ACCESS_DESCRIPTION)
+#define sk_ACCESS_DESCRIPTION_free(st) SKM_sk_free(ACCESS_DESCRIPTION, (st))
+#define sk_ACCESS_DESCRIPTION_num(st) SKM_sk_num(ACCESS_DESCRIPTION, (st))
+#define sk_ACCESS_DESCRIPTION_value(st, i) SKM_sk_value(ACCESS_DESCRIPTION, (st), (i))
+#define sk_ACCESS_DESCRIPTION_set(st, i, val) SKM_sk_set(ACCESS_DESCRIPTION, (st), (i), (val))
+#define sk_ACCESS_DESCRIPTION_zero(st) SKM_sk_zero(ACCESS_DESCRIPTION, (st))
+#define sk_ACCESS_DESCRIPTION_push(st, val) SKM_sk_push(ACCESS_DESCRIPTION, (st), (val))
+#define sk_ACCESS_DESCRIPTION_unshift(st, val) SKM_sk_unshift(ACCESS_DESCRIPTION, (st), (val))
+#define sk_ACCESS_DESCRIPTION_find(st, val) SKM_sk_find(ACCESS_DESCRIPTION, (st), (val))
+#define sk_ACCESS_DESCRIPTION_find_ex(st, val) SKM_sk_find_ex(ACCESS_DESCRIPTION, (st), (val))
+#define sk_ACCESS_DESCRIPTION_delete(st, i) SKM_sk_delete(ACCESS_DESCRIPTION, (st), (i))
+#define sk_ACCESS_DESCRIPTION_delete_ptr(st, ptr) SKM_sk_delete_ptr(ACCESS_DESCRIPTION, (st), (ptr))
+#define sk_ACCESS_DESCRIPTION_insert(st, val, i) SKM_sk_insert(ACCESS_DESCRIPTION, (st), (val), (i))
+#define sk_ACCESS_DESCRIPTION_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ACCESS_DESCRIPTION, (st), (cmp))
+#define sk_ACCESS_DESCRIPTION_dup(st) SKM_sk_dup(ACCESS_DESCRIPTION, st)
+#define sk_ACCESS_DESCRIPTION_pop_free(st, free_func) SKM_sk_pop_free(ACCESS_DESCRIPTION, (st), (free_func))
+#define sk_ACCESS_DESCRIPTION_shift(st) SKM_sk_shift(ACCESS_DESCRIPTION, (st))
+#define sk_ACCESS_DESCRIPTION_pop(st) SKM_sk_pop(ACCESS_DESCRIPTION, (st))
+#define sk_ACCESS_DESCRIPTION_sort(st) SKM_sk_sort(ACCESS_DESCRIPTION, (st))
+#define sk_ACCESS_DESCRIPTION_is_sorted(st) SKM_sk_is_sorted(ACCESS_DESCRIPTION, (st))
+
+#define sk_ASN1_GENERALSTRING_new(st) SKM_sk_new(ASN1_GENERALSTRING, (st))
+#define sk_ASN1_GENERALSTRING_new_null() SKM_sk_new_null(ASN1_GENERALSTRING)
+#define sk_ASN1_GENERALSTRING_free(st) SKM_sk_free(ASN1_GENERALSTRING, (st))
+#define sk_ASN1_GENERALSTRING_num(st) SKM_sk_num(ASN1_GENERALSTRING, (st))
+#define sk_ASN1_GENERALSTRING_value(st, i) SKM_sk_value(ASN1_GENERALSTRING, (st), (i))
+#define sk_ASN1_GENERALSTRING_set(st, i, val) SKM_sk_set(ASN1_GENERALSTRING, (st), (i), (val))
+#define sk_ASN1_GENERALSTRING_zero(st) SKM_sk_zero(ASN1_GENERALSTRING, (st))
+#define sk_ASN1_GENERALSTRING_push(st, val) SKM_sk_push(ASN1_GENERALSTRING, (st), (val))
+#define sk_ASN1_GENERALSTRING_unshift(st, val) SKM_sk_unshift(ASN1_GENERALSTRING, (st), (val))
+#define sk_ASN1_GENERALSTRING_find(st, val) SKM_sk_find(ASN1_GENERALSTRING, (st), (val))
+#define sk_ASN1_GENERALSTRING_find_ex(st, val) SKM_sk_find_ex(ASN1_GENERALSTRING, (st), (val))
+#define sk_ASN1_GENERALSTRING_delete(st, i) SKM_sk_delete(ASN1_GENERALSTRING, (st), (i))
+#define sk_ASN1_GENERALSTRING_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_GENERALSTRING, (st), (ptr))
+#define sk_ASN1_GENERALSTRING_insert(st, val, i) SKM_sk_insert(ASN1_GENERALSTRING, (st), (val), (i))
+#define sk_ASN1_GENERALSTRING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_GENERALSTRING, (st), (cmp))
+#define sk_ASN1_GENERALSTRING_dup(st) SKM_sk_dup(ASN1_GENERALSTRING, st)
+#define sk_ASN1_GENERALSTRING_pop_free(st, free_func) SKM_sk_pop_free(ASN1_GENERALSTRING, (st), (free_func))
+#define sk_ASN1_GENERALSTRING_shift(st) SKM_sk_shift(ASN1_GENERALSTRING, (st))
+#define sk_ASN1_GENERALSTRING_pop(st) SKM_sk_pop(ASN1_GENERALSTRING, (st))
+#define sk_ASN1_GENERALSTRING_sort(st) SKM_sk_sort(ASN1_GENERALSTRING, (st))
+#define sk_ASN1_GENERALSTRING_is_sorted(st) SKM_sk_is_sorted(ASN1_GENERALSTRING, (st))
+
+#define sk_ASN1_INTEGER_new(st) SKM_sk_new(ASN1_INTEGER, (st))
+#define sk_ASN1_INTEGER_new_null() SKM_sk_new_null(ASN1_INTEGER)
+#define sk_ASN1_INTEGER_free(st) SKM_sk_free(ASN1_INTEGER, (st))
+#define sk_ASN1_INTEGER_num(st) SKM_sk_num(ASN1_INTEGER, (st))
+#define sk_ASN1_INTEGER_value(st, i) SKM_sk_value(ASN1_INTEGER, (st), (i))
+#define sk_ASN1_INTEGER_set(st, i, val) SKM_sk_set(ASN1_INTEGER, (st), (i), (val))
+#define sk_ASN1_INTEGER_zero(st) SKM_sk_zero(ASN1_INTEGER, (st))
+#define sk_ASN1_INTEGER_push(st, val) SKM_sk_push(ASN1_INTEGER, (st), (val))
+#define sk_ASN1_INTEGER_unshift(st, val) SKM_sk_unshift(ASN1_INTEGER, (st), (val))
+#define sk_ASN1_INTEGER_find(st, val) SKM_sk_find(ASN1_INTEGER, (st), (val))
+#define sk_ASN1_INTEGER_find_ex(st, val) SKM_sk_find_ex(ASN1_INTEGER, (st), (val))
+#define sk_ASN1_INTEGER_delete(st, i) SKM_sk_delete(ASN1_INTEGER, (st), (i))
+#define sk_ASN1_INTEGER_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_INTEGER, (st), (ptr))
+#define sk_ASN1_INTEGER_insert(st, val, i) SKM_sk_insert(ASN1_INTEGER, (st), (val), (i))
+#define sk_ASN1_INTEGER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_INTEGER, (st), (cmp))
+#define sk_ASN1_INTEGER_dup(st) SKM_sk_dup(ASN1_INTEGER, st)
+#define sk_ASN1_INTEGER_pop_free(st, free_func) SKM_sk_pop_free(ASN1_INTEGER, (st), (free_func))
+#define sk_ASN1_INTEGER_shift(st) SKM_sk_shift(ASN1_INTEGER, (st))
+#define sk_ASN1_INTEGER_pop(st) SKM_sk_pop(ASN1_INTEGER, (st))
+#define sk_ASN1_INTEGER_sort(st) SKM_sk_sort(ASN1_INTEGER, (st))
+#define sk_ASN1_INTEGER_is_sorted(st) SKM_sk_is_sorted(ASN1_INTEGER, (st))
+
+#define sk_ASN1_OBJECT_new(st) SKM_sk_new(ASN1_OBJECT, (st))
+#define sk_ASN1_OBJECT_new_null() SKM_sk_new_null(ASN1_OBJECT)
+#define sk_ASN1_OBJECT_free(st) SKM_sk_free(ASN1_OBJECT, (st))
+#define sk_ASN1_OBJECT_num(st) SKM_sk_num(ASN1_OBJECT, (st))
+#define sk_ASN1_OBJECT_value(st, i) SKM_sk_value(ASN1_OBJECT, (st), (i))
+#define sk_ASN1_OBJECT_set(st, i, val) SKM_sk_set(ASN1_OBJECT, (st), (i), (val))
+#define sk_ASN1_OBJECT_zero(st) SKM_sk_zero(ASN1_OBJECT, (st))
+#define sk_ASN1_OBJECT_push(st, val) SKM_sk_push(ASN1_OBJECT, (st), (val))
+#define sk_ASN1_OBJECT_unshift(st, val) SKM_sk_unshift(ASN1_OBJECT, (st), (val))
+#define sk_ASN1_OBJECT_find(st, val) SKM_sk_find(ASN1_OBJECT, (st), (val))
+#define sk_ASN1_OBJECT_find_ex(st, val) SKM_sk_find_ex(ASN1_OBJECT, (st), (val))
+#define sk_ASN1_OBJECT_delete(st, i) SKM_sk_delete(ASN1_OBJECT, (st), (i))
+#define sk_ASN1_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_OBJECT, (st), (ptr))
+#define sk_ASN1_OBJECT_insert(st, val, i) SKM_sk_insert(ASN1_OBJECT, (st), (val), (i))
+#define sk_ASN1_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_OBJECT, (st), (cmp))
+#define sk_ASN1_OBJECT_dup(st) SKM_sk_dup(ASN1_OBJECT, st)
+#define sk_ASN1_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(ASN1_OBJECT, (st), (free_func))
+#define sk_ASN1_OBJECT_shift(st) SKM_sk_shift(ASN1_OBJECT, (st))
+#define sk_ASN1_OBJECT_pop(st) SKM_sk_pop(ASN1_OBJECT, (st))
+#define sk_ASN1_OBJECT_sort(st) SKM_sk_sort(ASN1_OBJECT, (st))
+#define sk_ASN1_OBJECT_is_sorted(st) SKM_sk_is_sorted(ASN1_OBJECT, (st))
+
+#define sk_ASN1_STRING_TABLE_new(st) SKM_sk_new(ASN1_STRING_TABLE, (st))
+#define sk_ASN1_STRING_TABLE_new_null() SKM_sk_new_null(ASN1_STRING_TABLE)
+#define sk_ASN1_STRING_TABLE_free(st) SKM_sk_free(ASN1_STRING_TABLE, (st))
+#define sk_ASN1_STRING_TABLE_num(st) SKM_sk_num(ASN1_STRING_TABLE, (st))
+#define sk_ASN1_STRING_TABLE_value(st, i) SKM_sk_value(ASN1_STRING_TABLE, (st), (i))
+#define sk_ASN1_STRING_TABLE_set(st, i, val) SKM_sk_set(ASN1_STRING_TABLE, (st), (i), (val))
+#define sk_ASN1_STRING_TABLE_zero(st) SKM_sk_zero(ASN1_STRING_TABLE, (st))
+#define sk_ASN1_STRING_TABLE_push(st, val) SKM_sk_push(ASN1_STRING_TABLE, (st), (val))
+#define sk_ASN1_STRING_TABLE_unshift(st, val) SKM_sk_unshift(ASN1_STRING_TABLE, (st), (val))
+#define sk_ASN1_STRING_TABLE_find(st, val) SKM_sk_find(ASN1_STRING_TABLE, (st), (val))
+#define sk_ASN1_STRING_TABLE_find_ex(st, val) SKM_sk_find_ex(ASN1_STRING_TABLE, (st), (val))
+#define sk_ASN1_STRING_TABLE_delete(st, i) SKM_sk_delete(ASN1_STRING_TABLE, (st), (i))
+#define sk_ASN1_STRING_TABLE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_STRING_TABLE, (st), (ptr))
+#define sk_ASN1_STRING_TABLE_insert(st, val, i) SKM_sk_insert(ASN1_STRING_TABLE, (st), (val), (i))
+#define sk_ASN1_STRING_TABLE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_STRING_TABLE, (st), (cmp))
+#define sk_ASN1_STRING_TABLE_dup(st) SKM_sk_dup(ASN1_STRING_TABLE, st)
+#define sk_ASN1_STRING_TABLE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_STRING_TABLE, (st), (free_func))
+#define sk_ASN1_STRING_TABLE_shift(st) SKM_sk_shift(ASN1_STRING_TABLE, (st))
+#define sk_ASN1_STRING_TABLE_pop(st) SKM_sk_pop(ASN1_STRING_TABLE, (st))
+#define sk_ASN1_STRING_TABLE_sort(st) SKM_sk_sort(ASN1_STRING_TABLE, (st))
+#define sk_ASN1_STRING_TABLE_is_sorted(st) SKM_sk_is_sorted(ASN1_STRING_TABLE, (st))
+
+#define sk_ASN1_TYPE_new(st) SKM_sk_new(ASN1_TYPE, (st))
+#define sk_ASN1_TYPE_new_null() SKM_sk_new_null(ASN1_TYPE)
+#define sk_ASN1_TYPE_free(st) SKM_sk_free(ASN1_TYPE, (st))
+#define sk_ASN1_TYPE_num(st) SKM_sk_num(ASN1_TYPE, (st))
+#define sk_ASN1_TYPE_value(st, i) SKM_sk_value(ASN1_TYPE, (st), (i))
+#define sk_ASN1_TYPE_set(st, i, val) SKM_sk_set(ASN1_TYPE, (st), (i), (val))
+#define sk_ASN1_TYPE_zero(st) SKM_sk_zero(ASN1_TYPE, (st))
+#define sk_ASN1_TYPE_push(st, val) SKM_sk_push(ASN1_TYPE, (st), (val))
+#define sk_ASN1_TYPE_unshift(st, val) SKM_sk_unshift(ASN1_TYPE, (st), (val))
+#define sk_ASN1_TYPE_find(st, val) SKM_sk_find(ASN1_TYPE, (st), (val))
+#define sk_ASN1_TYPE_find_ex(st, val) SKM_sk_find_ex(ASN1_TYPE, (st), (val))
+#define sk_ASN1_TYPE_delete(st, i) SKM_sk_delete(ASN1_TYPE, (st), (i))
+#define sk_ASN1_TYPE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_TYPE, (st), (ptr))
+#define sk_ASN1_TYPE_insert(st, val, i) SKM_sk_insert(ASN1_TYPE, (st), (val), (i))
+#define sk_ASN1_TYPE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_TYPE, (st), (cmp))
+#define sk_ASN1_TYPE_dup(st) SKM_sk_dup(ASN1_TYPE, st)
+#define sk_ASN1_TYPE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_TYPE, (st), (free_func))
+#define sk_ASN1_TYPE_shift(st) SKM_sk_shift(ASN1_TYPE, (st))
+#define sk_ASN1_TYPE_pop(st) SKM_sk_pop(ASN1_TYPE, (st))
+#define sk_ASN1_TYPE_sort(st) SKM_sk_sort(ASN1_TYPE, (st))
+#define sk_ASN1_TYPE_is_sorted(st) SKM_sk_is_sorted(ASN1_TYPE, (st))
+
+#define sk_ASN1_VALUE_new(st) SKM_sk_new(ASN1_VALUE, (st))
+#define sk_ASN1_VALUE_new_null() SKM_sk_new_null(ASN1_VALUE)
+#define sk_ASN1_VALUE_free(st) SKM_sk_free(ASN1_VALUE, (st))
+#define sk_ASN1_VALUE_num(st) SKM_sk_num(ASN1_VALUE, (st))
+#define sk_ASN1_VALUE_value(st, i) SKM_sk_value(ASN1_VALUE, (st), (i))
+#define sk_ASN1_VALUE_set(st, i, val) SKM_sk_set(ASN1_VALUE, (st), (i), (val))
+#define sk_ASN1_VALUE_zero(st) SKM_sk_zero(ASN1_VALUE, (st))
+#define sk_ASN1_VALUE_push(st, val) SKM_sk_push(ASN1_VALUE, (st), (val))
+#define sk_ASN1_VALUE_unshift(st, val) SKM_sk_unshift(ASN1_VALUE, (st), (val))
+#define sk_ASN1_VALUE_find(st, val) SKM_sk_find(ASN1_VALUE, (st), (val))
+#define sk_ASN1_VALUE_find_ex(st, val) SKM_sk_find_ex(ASN1_VALUE, (st), (val))
+#define sk_ASN1_VALUE_delete(st, i) SKM_sk_delete(ASN1_VALUE, (st), (i))
+#define sk_ASN1_VALUE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ASN1_VALUE, (st), (ptr))
+#define sk_ASN1_VALUE_insert(st, val, i) SKM_sk_insert(ASN1_VALUE, (st), (val), (i))
+#define sk_ASN1_VALUE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ASN1_VALUE, (st), (cmp))
+#define sk_ASN1_VALUE_dup(st) SKM_sk_dup(ASN1_VALUE, st)
+#define sk_ASN1_VALUE_pop_free(st, free_func) SKM_sk_pop_free(ASN1_VALUE, (st), (free_func))
+#define sk_ASN1_VALUE_shift(st) SKM_sk_shift(ASN1_VALUE, (st))
+#define sk_ASN1_VALUE_pop(st) SKM_sk_pop(ASN1_VALUE, (st))
+#define sk_ASN1_VALUE_sort(st) SKM_sk_sort(ASN1_VALUE, (st))
+#define sk_ASN1_VALUE_is_sorted(st) SKM_sk_is_sorted(ASN1_VALUE, (st))
+
+#define sk_BIO_new(st) SKM_sk_new(BIO, (st))
+#define sk_BIO_new_null() SKM_sk_new_null(BIO)
+#define sk_BIO_free(st) SKM_sk_free(BIO, (st))
+#define sk_BIO_num(st) SKM_sk_num(BIO, (st))
+#define sk_BIO_value(st, i) SKM_sk_value(BIO, (st), (i))
+#define sk_BIO_set(st, i, val) SKM_sk_set(BIO, (st), (i), (val))
+#define sk_BIO_zero(st) SKM_sk_zero(BIO, (st))
+#define sk_BIO_push(st, val) SKM_sk_push(BIO, (st), (val))
+#define sk_BIO_unshift(st, val) SKM_sk_unshift(BIO, (st), (val))
+#define sk_BIO_find(st, val) SKM_sk_find(BIO, (st), (val))
+#define sk_BIO_find_ex(st, val) SKM_sk_find_ex(BIO, (st), (val))
+#define sk_BIO_delete(st, i) SKM_sk_delete(BIO, (st), (i))
+#define sk_BIO_delete_ptr(st, ptr) SKM_sk_delete_ptr(BIO, (st), (ptr))
+#define sk_BIO_insert(st, val, i) SKM_sk_insert(BIO, (st), (val), (i))
+#define sk_BIO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(BIO, (st), (cmp))
+#define sk_BIO_dup(st) SKM_sk_dup(BIO, st)
+#define sk_BIO_pop_free(st, free_func) SKM_sk_pop_free(BIO, (st), (free_func))
+#define sk_BIO_shift(st) SKM_sk_shift(BIO, (st))
+#define sk_BIO_pop(st) SKM_sk_pop(BIO, (st))
+#define sk_BIO_sort(st) SKM_sk_sort(BIO, (st))
+#define sk_BIO_is_sorted(st) SKM_sk_is_sorted(BIO, (st))
+
+#define sk_CONF_IMODULE_new(st) SKM_sk_new(CONF_IMODULE, (st))
+#define sk_CONF_IMODULE_new_null() SKM_sk_new_null(CONF_IMODULE)
+#define sk_CONF_IMODULE_free(st) SKM_sk_free(CONF_IMODULE, (st))
+#define sk_CONF_IMODULE_num(st) SKM_sk_num(CONF_IMODULE, (st))
+#define sk_CONF_IMODULE_value(st, i) SKM_sk_value(CONF_IMODULE, (st), (i))
+#define sk_CONF_IMODULE_set(st, i, val) SKM_sk_set(CONF_IMODULE, (st), (i), (val))
+#define sk_CONF_IMODULE_zero(st) SKM_sk_zero(CONF_IMODULE, (st))
+#define sk_CONF_IMODULE_push(st, val) SKM_sk_push(CONF_IMODULE, (st), (val))
+#define sk_CONF_IMODULE_unshift(st, val) SKM_sk_unshift(CONF_IMODULE, (st), (val))
+#define sk_CONF_IMODULE_find(st, val) SKM_sk_find(CONF_IMODULE, (st), (val))
+#define sk_CONF_IMODULE_find_ex(st, val) SKM_sk_find_ex(CONF_IMODULE, (st), (val))
+#define sk_CONF_IMODULE_delete(st, i) SKM_sk_delete(CONF_IMODULE, (st), (i))
+#define sk_CONF_IMODULE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_IMODULE, (st), (ptr))
+#define sk_CONF_IMODULE_insert(st, val, i) SKM_sk_insert(CONF_IMODULE, (st), (val), (i))
+#define sk_CONF_IMODULE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_IMODULE, (st), (cmp))
+#define sk_CONF_IMODULE_dup(st) SKM_sk_dup(CONF_IMODULE, st)
+#define sk_CONF_IMODULE_pop_free(st, free_func) SKM_sk_pop_free(CONF_IMODULE, (st), (free_func))
+#define sk_CONF_IMODULE_shift(st) SKM_sk_shift(CONF_IMODULE, (st))
+#define sk_CONF_IMODULE_pop(st) SKM_sk_pop(CONF_IMODULE, (st))
+#define sk_CONF_IMODULE_sort(st) SKM_sk_sort(CONF_IMODULE, (st))
+#define sk_CONF_IMODULE_is_sorted(st) SKM_sk_is_sorted(CONF_IMODULE, (st))
+
+#define sk_CONF_MODULE_new(st) SKM_sk_new(CONF_MODULE, (st))
+#define sk_CONF_MODULE_new_null() SKM_sk_new_null(CONF_MODULE)
+#define sk_CONF_MODULE_free(st) SKM_sk_free(CONF_MODULE, (st))
+#define sk_CONF_MODULE_num(st) SKM_sk_num(CONF_MODULE, (st))
+#define sk_CONF_MODULE_value(st, i) SKM_sk_value(CONF_MODULE, (st), (i))
+#define sk_CONF_MODULE_set(st, i, val) SKM_sk_set(CONF_MODULE, (st), (i), (val))
+#define sk_CONF_MODULE_zero(st) SKM_sk_zero(CONF_MODULE, (st))
+#define sk_CONF_MODULE_push(st, val) SKM_sk_push(CONF_MODULE, (st), (val))
+#define sk_CONF_MODULE_unshift(st, val) SKM_sk_unshift(CONF_MODULE, (st), (val))
+#define sk_CONF_MODULE_find(st, val) SKM_sk_find(CONF_MODULE, (st), (val))
+#define sk_CONF_MODULE_find_ex(st, val) SKM_sk_find_ex(CONF_MODULE, (st), (val))
+#define sk_CONF_MODULE_delete(st, i) SKM_sk_delete(CONF_MODULE, (st), (i))
+#define sk_CONF_MODULE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_MODULE, (st), (ptr))
+#define sk_CONF_MODULE_insert(st, val, i) SKM_sk_insert(CONF_MODULE, (st), (val), (i))
+#define sk_CONF_MODULE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_MODULE, (st), (cmp))
+#define sk_CONF_MODULE_dup(st) SKM_sk_dup(CONF_MODULE, st)
+#define sk_CONF_MODULE_pop_free(st, free_func) SKM_sk_pop_free(CONF_MODULE, (st), (free_func))
+#define sk_CONF_MODULE_shift(st) SKM_sk_shift(CONF_MODULE, (st))
+#define sk_CONF_MODULE_pop(st) SKM_sk_pop(CONF_MODULE, (st))
+#define sk_CONF_MODULE_sort(st) SKM_sk_sort(CONF_MODULE, (st))
+#define sk_CONF_MODULE_is_sorted(st) SKM_sk_is_sorted(CONF_MODULE, (st))
+
+#define sk_CONF_VALUE_new(st) SKM_sk_new(CONF_VALUE, (st))
+#define sk_CONF_VALUE_new_null() SKM_sk_new_null(CONF_VALUE)
+#define sk_CONF_VALUE_free(st) SKM_sk_free(CONF_VALUE, (st))
+#define sk_CONF_VALUE_num(st) SKM_sk_num(CONF_VALUE, (st))
+#define sk_CONF_VALUE_value(st, i) SKM_sk_value(CONF_VALUE, (st), (i))
+#define sk_CONF_VALUE_set(st, i, val) SKM_sk_set(CONF_VALUE, (st), (i), (val))
+#define sk_CONF_VALUE_zero(st) SKM_sk_zero(CONF_VALUE, (st))
+#define sk_CONF_VALUE_push(st, val) SKM_sk_push(CONF_VALUE, (st), (val))
+#define sk_CONF_VALUE_unshift(st, val) SKM_sk_unshift(CONF_VALUE, (st), (val))
+#define sk_CONF_VALUE_find(st, val) SKM_sk_find(CONF_VALUE, (st), (val))
+#define sk_CONF_VALUE_find_ex(st, val) SKM_sk_find_ex(CONF_VALUE, (st), (val))
+#define sk_CONF_VALUE_delete(st, i) SKM_sk_delete(CONF_VALUE, (st), (i))
+#define sk_CONF_VALUE_delete_ptr(st, ptr) SKM_sk_delete_ptr(CONF_VALUE, (st), (ptr))
+#define sk_CONF_VALUE_insert(st, val, i) SKM_sk_insert(CONF_VALUE, (st), (val), (i))
+#define sk_CONF_VALUE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CONF_VALUE, (st), (cmp))
+#define sk_CONF_VALUE_dup(st) SKM_sk_dup(CONF_VALUE, st)
+#define sk_CONF_VALUE_pop_free(st, free_func) SKM_sk_pop_free(CONF_VALUE, (st), (free_func))
+#define sk_CONF_VALUE_shift(st) SKM_sk_shift(CONF_VALUE, (st))
+#define sk_CONF_VALUE_pop(st) SKM_sk_pop(CONF_VALUE, (st))
+#define sk_CONF_VALUE_sort(st) SKM_sk_sort(CONF_VALUE, (st))
+#define sk_CONF_VALUE_is_sorted(st) SKM_sk_is_sorted(CONF_VALUE, (st))
+
+#define sk_CRYPTO_EX_DATA_FUNCS_new(st) SKM_sk_new(CRYPTO_EX_DATA_FUNCS, (st))
+#define sk_CRYPTO_EX_DATA_FUNCS_new_null() SKM_sk_new_null(CRYPTO_EX_DATA_FUNCS)
+#define sk_CRYPTO_EX_DATA_FUNCS_free(st) SKM_sk_free(CRYPTO_EX_DATA_FUNCS, (st))
+#define sk_CRYPTO_EX_DATA_FUNCS_num(st) SKM_sk_num(CRYPTO_EX_DATA_FUNCS, (st))
+#define sk_CRYPTO_EX_DATA_FUNCS_value(st, i) SKM_sk_value(CRYPTO_EX_DATA_FUNCS, (st), (i))
+#define sk_CRYPTO_EX_DATA_FUNCS_set(st, i, val) SKM_sk_set(CRYPTO_EX_DATA_FUNCS, (st), (i), (val))
+#define sk_CRYPTO_EX_DATA_FUNCS_zero(st) SKM_sk_zero(CRYPTO_EX_DATA_FUNCS, (st))
+#define sk_CRYPTO_EX_DATA_FUNCS_push(st, val) SKM_sk_push(CRYPTO_EX_DATA_FUNCS, (st), (val))
+#define sk_CRYPTO_EX_DATA_FUNCS_unshift(st, val) SKM_sk_unshift(CRYPTO_EX_DATA_FUNCS, (st), (val))
+#define sk_CRYPTO_EX_DATA_FUNCS_find(st, val) SKM_sk_find(CRYPTO_EX_DATA_FUNCS, (st), (val))
+#define sk_CRYPTO_EX_DATA_FUNCS_find_ex(st, val) SKM_sk_find_ex(CRYPTO_EX_DATA_FUNCS, (st), (val))
+#define sk_CRYPTO_EX_DATA_FUNCS_delete(st, i) SKM_sk_delete(CRYPTO_EX_DATA_FUNCS, (st), (i))
+#define sk_CRYPTO_EX_DATA_FUNCS_delete_ptr(st, ptr) SKM_sk_delete_ptr(CRYPTO_EX_DATA_FUNCS, (st), (ptr))
+#define sk_CRYPTO_EX_DATA_FUNCS_insert(st, val, i) SKM_sk_insert(CRYPTO_EX_DATA_FUNCS, (st), (val), (i))
+#define sk_CRYPTO_EX_DATA_FUNCS_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CRYPTO_EX_DATA_FUNCS, (st), (cmp))
+#define sk_CRYPTO_EX_DATA_FUNCS_dup(st) SKM_sk_dup(CRYPTO_EX_DATA_FUNCS, st)
+#define sk_CRYPTO_EX_DATA_FUNCS_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_EX_DATA_FUNCS, (st), (free_func))
+#define sk_CRYPTO_EX_DATA_FUNCS_shift(st) SKM_sk_shift(CRYPTO_EX_DATA_FUNCS, (st))
+#define sk_CRYPTO_EX_DATA_FUNCS_pop(st) SKM_sk_pop(CRYPTO_EX_DATA_FUNCS, (st))
+#define sk_CRYPTO_EX_DATA_FUNCS_sort(st) SKM_sk_sort(CRYPTO_EX_DATA_FUNCS, (st))
+#define sk_CRYPTO_EX_DATA_FUNCS_is_sorted(st) SKM_sk_is_sorted(CRYPTO_EX_DATA_FUNCS, (st))
+
+#define sk_CRYPTO_dynlock_new(st) SKM_sk_new(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_new_null() SKM_sk_new_null(CRYPTO_dynlock)
+#define sk_CRYPTO_dynlock_free(st) SKM_sk_free(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_num(st) SKM_sk_num(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_value(st, i) SKM_sk_value(CRYPTO_dynlock, (st), (i))
+#define sk_CRYPTO_dynlock_set(st, i, val) SKM_sk_set(CRYPTO_dynlock, (st), (i), (val))
+#define sk_CRYPTO_dynlock_zero(st) SKM_sk_zero(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_push(st, val) SKM_sk_push(CRYPTO_dynlock, (st), (val))
+#define sk_CRYPTO_dynlock_unshift(st, val) SKM_sk_unshift(CRYPTO_dynlock, (st), (val))
+#define sk_CRYPTO_dynlock_find(st, val) SKM_sk_find(CRYPTO_dynlock, (st), (val))
+#define sk_CRYPTO_dynlock_find_ex(st, val) SKM_sk_find_ex(CRYPTO_dynlock, (st), (val))
+#define sk_CRYPTO_dynlock_delete(st, i) SKM_sk_delete(CRYPTO_dynlock, (st), (i))
+#define sk_CRYPTO_dynlock_delete_ptr(st, ptr) SKM_sk_delete_ptr(CRYPTO_dynlock, (st), (ptr))
+#define sk_CRYPTO_dynlock_insert(st, val, i) SKM_sk_insert(CRYPTO_dynlock, (st), (val), (i))
+#define sk_CRYPTO_dynlock_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(CRYPTO_dynlock, (st), (cmp))
+#define sk_CRYPTO_dynlock_dup(st) SKM_sk_dup(CRYPTO_dynlock, st)
+#define sk_CRYPTO_dynlock_pop_free(st, free_func) SKM_sk_pop_free(CRYPTO_dynlock, (st), (free_func))
+#define sk_CRYPTO_dynlock_shift(st) SKM_sk_shift(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_pop(st) SKM_sk_pop(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_sort(st) SKM_sk_sort(CRYPTO_dynlock, (st))
+#define sk_CRYPTO_dynlock_is_sorted(st) SKM_sk_is_sorted(CRYPTO_dynlock, (st))
+
+#define sk_DIST_POINT_new(st) SKM_sk_new(DIST_POINT, (st))
+#define sk_DIST_POINT_new_null() SKM_sk_new_null(DIST_POINT)
+#define sk_DIST_POINT_free(st) SKM_sk_free(DIST_POINT, (st))
+#define sk_DIST_POINT_num(st) SKM_sk_num(DIST_POINT, (st))
+#define sk_DIST_POINT_value(st, i) SKM_sk_value(DIST_POINT, (st), (i))
+#define sk_DIST_POINT_set(st, i, val) SKM_sk_set(DIST_POINT, (st), (i), (val))
+#define sk_DIST_POINT_zero(st) SKM_sk_zero(DIST_POINT, (st))
+#define sk_DIST_POINT_push(st, val) SKM_sk_push(DIST_POINT, (st), (val))
+#define sk_DIST_POINT_unshift(st, val) SKM_sk_unshift(DIST_POINT, (st), (val))
+#define sk_DIST_POINT_find(st, val) SKM_sk_find(DIST_POINT, (st), (val))
+#define sk_DIST_POINT_find_ex(st, val) SKM_sk_find_ex(DIST_POINT, (st), (val))
+#define sk_DIST_POINT_delete(st, i) SKM_sk_delete(DIST_POINT, (st), (i))
+#define sk_DIST_POINT_delete_ptr(st, ptr) SKM_sk_delete_ptr(DIST_POINT, (st), (ptr))
+#define sk_DIST_POINT_insert(st, val, i) SKM_sk_insert(DIST_POINT, (st), (val), (i))
+#define sk_DIST_POINT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(DIST_POINT, (st), (cmp))
+#define sk_DIST_POINT_dup(st) SKM_sk_dup(DIST_POINT, st)
+#define sk_DIST_POINT_pop_free(st, free_func) SKM_sk_pop_free(DIST_POINT, (st), (free_func))
+#define sk_DIST_POINT_shift(st) SKM_sk_shift(DIST_POINT, (st))
+#define sk_DIST_POINT_pop(st) SKM_sk_pop(DIST_POINT, (st))
+#define sk_DIST_POINT_sort(st) SKM_sk_sort(DIST_POINT, (st))
+#define sk_DIST_POINT_is_sorted(st) SKM_sk_is_sorted(DIST_POINT, (st))
+
+#define sk_ENGINE_new(st) SKM_sk_new(ENGINE, (st))
+#define sk_ENGINE_new_null() SKM_sk_new_null(ENGINE)
+#define sk_ENGINE_free(st) SKM_sk_free(ENGINE, (st))
+#define sk_ENGINE_num(st) SKM_sk_num(ENGINE, (st))
+#define sk_ENGINE_value(st, i) SKM_sk_value(ENGINE, (st), (i))
+#define sk_ENGINE_set(st, i, val) SKM_sk_set(ENGINE, (st), (i), (val))
+#define sk_ENGINE_zero(st) SKM_sk_zero(ENGINE, (st))
+#define sk_ENGINE_push(st, val) SKM_sk_push(ENGINE, (st), (val))
+#define sk_ENGINE_unshift(st, val) SKM_sk_unshift(ENGINE, (st), (val))
+#define sk_ENGINE_find(st, val) SKM_sk_find(ENGINE, (st), (val))
+#define sk_ENGINE_find_ex(st, val) SKM_sk_find_ex(ENGINE, (st), (val))
+#define sk_ENGINE_delete(st, i) SKM_sk_delete(ENGINE, (st), (i))
+#define sk_ENGINE_delete_ptr(st, ptr) SKM_sk_delete_ptr(ENGINE, (st), (ptr))
+#define sk_ENGINE_insert(st, val, i) SKM_sk_insert(ENGINE, (st), (val), (i))
+#define sk_ENGINE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ENGINE, (st), (cmp))
+#define sk_ENGINE_dup(st) SKM_sk_dup(ENGINE, st)
+#define sk_ENGINE_pop_free(st, free_func) SKM_sk_pop_free(ENGINE, (st), (free_func))
+#define sk_ENGINE_shift(st) SKM_sk_shift(ENGINE, (st))
+#define sk_ENGINE_pop(st) SKM_sk_pop(ENGINE, (st))
+#define sk_ENGINE_sort(st) SKM_sk_sort(ENGINE, (st))
+#define sk_ENGINE_is_sorted(st) SKM_sk_is_sorted(ENGINE, (st))
+
+#define sk_ENGINE_CLEANUP_ITEM_new(st) SKM_sk_new(ENGINE_CLEANUP_ITEM, (st))
+#define sk_ENGINE_CLEANUP_ITEM_new_null() SKM_sk_new_null(ENGINE_CLEANUP_ITEM)
+#define sk_ENGINE_CLEANUP_ITEM_free(st) SKM_sk_free(ENGINE_CLEANUP_ITEM, (st))
+#define sk_ENGINE_CLEANUP_ITEM_num(st) SKM_sk_num(ENGINE_CLEANUP_ITEM, (st))
+#define sk_ENGINE_CLEANUP_ITEM_value(st, i) SKM_sk_value(ENGINE_CLEANUP_ITEM, (st), (i))
+#define sk_ENGINE_CLEANUP_ITEM_set(st, i, val) SKM_sk_set(ENGINE_CLEANUP_ITEM, (st), (i), (val))
+#define sk_ENGINE_CLEANUP_ITEM_zero(st) SKM_sk_zero(ENGINE_CLEANUP_ITEM, (st))
+#define sk_ENGINE_CLEANUP_ITEM_push(st, val) SKM_sk_push(ENGINE_CLEANUP_ITEM, (st), (val))
+#define sk_ENGINE_CLEANUP_ITEM_unshift(st, val) SKM_sk_unshift(ENGINE_CLEANUP_ITEM, (st), (val))
+#define sk_ENGINE_CLEANUP_ITEM_find(st, val) SKM_sk_find(ENGINE_CLEANUP_ITEM, (st), (val))
+#define sk_ENGINE_CLEANUP_ITEM_find_ex(st, val) SKM_sk_find_ex(ENGINE_CLEANUP_ITEM, (st), (val))
+#define sk_ENGINE_CLEANUP_ITEM_delete(st, i) SKM_sk_delete(ENGINE_CLEANUP_ITEM, (st), (i))
+#define sk_ENGINE_CLEANUP_ITEM_delete_ptr(st, ptr) SKM_sk_delete_ptr(ENGINE_CLEANUP_ITEM, (st), (ptr))
+#define sk_ENGINE_CLEANUP_ITEM_insert(st, val, i) SKM_sk_insert(ENGINE_CLEANUP_ITEM, (st), (val), (i))
+#define sk_ENGINE_CLEANUP_ITEM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(ENGINE_CLEANUP_ITEM, (st), (cmp))
+#define sk_ENGINE_CLEANUP_ITEM_dup(st) SKM_sk_dup(ENGINE_CLEANUP_ITEM, st)
+#define sk_ENGINE_CLEANUP_ITEM_pop_free(st, free_func) SKM_sk_pop_free(ENGINE_CLEANUP_ITEM, (st), (free_func))
+#define sk_ENGINE_CLEANUP_ITEM_shift(st) SKM_sk_shift(ENGINE_CLEANUP_ITEM, (st))
+#define sk_ENGINE_CLEANUP_ITEM_pop(st) SKM_sk_pop(ENGINE_CLEANUP_ITEM, (st))
+#define sk_ENGINE_CLEANUP_ITEM_sort(st) SKM_sk_sort(ENGINE_CLEANUP_ITEM, (st))
+#define sk_ENGINE_CLEANUP_ITEM_is_sorted(st) SKM_sk_is_sorted(ENGINE_CLEANUP_ITEM, (st))
+
+#define sk_GENERAL_NAME_new(st) SKM_sk_new(GENERAL_NAME, (st))
+#define sk_GENERAL_NAME_new_null() SKM_sk_new_null(GENERAL_NAME)
+#define sk_GENERAL_NAME_free(st) SKM_sk_free(GENERAL_NAME, (st))
+#define sk_GENERAL_NAME_num(st) SKM_sk_num(GENERAL_NAME, (st))
+#define sk_GENERAL_NAME_value(st, i) SKM_sk_value(GENERAL_NAME, (st), (i))
+#define sk_GENERAL_NAME_set(st, i, val) SKM_sk_set(GENERAL_NAME, (st), (i), (val))
+#define sk_GENERAL_NAME_zero(st) SKM_sk_zero(GENERAL_NAME, (st))
+#define sk_GENERAL_NAME_push(st, val) SKM_sk_push(GENERAL_NAME, (st), (val))
+#define sk_GENERAL_NAME_unshift(st, val) SKM_sk_unshift(GENERAL_NAME, (st), (val))
+#define sk_GENERAL_NAME_find(st, val) SKM_sk_find(GENERAL_NAME, (st), (val))
+#define sk_GENERAL_NAME_find_ex(st, val) SKM_sk_find_ex(GENERAL_NAME, (st), (val))
+#define sk_GENERAL_NAME_delete(st, i) SKM_sk_delete(GENERAL_NAME, (st), (i))
+#define sk_GENERAL_NAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_NAME, (st), (ptr))
+#define sk_GENERAL_NAME_insert(st, val, i) SKM_sk_insert(GENERAL_NAME, (st), (val), (i))
+#define sk_GENERAL_NAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_NAME, (st), (cmp))
+#define sk_GENERAL_NAME_dup(st) SKM_sk_dup(GENERAL_NAME, st)
+#define sk_GENERAL_NAME_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_NAME, (st), (free_func))
+#define sk_GENERAL_NAME_shift(st) SKM_sk_shift(GENERAL_NAME, (st))
+#define sk_GENERAL_NAME_pop(st) SKM_sk_pop(GENERAL_NAME, (st))
+#define sk_GENERAL_NAME_sort(st) SKM_sk_sort(GENERAL_NAME, (st))
+#define sk_GENERAL_NAME_is_sorted(st) SKM_sk_is_sorted(GENERAL_NAME, (st))
+
+#define sk_GENERAL_SUBTREE_new(st) SKM_sk_new(GENERAL_SUBTREE, (st))
+#define sk_GENERAL_SUBTREE_new_null() SKM_sk_new_null(GENERAL_SUBTREE)
+#define sk_GENERAL_SUBTREE_free(st) SKM_sk_free(GENERAL_SUBTREE, (st))
+#define sk_GENERAL_SUBTREE_num(st) SKM_sk_num(GENERAL_SUBTREE, (st))
+#define sk_GENERAL_SUBTREE_value(st, i) SKM_sk_value(GENERAL_SUBTREE, (st), (i))
+#define sk_GENERAL_SUBTREE_set(st, i, val) SKM_sk_set(GENERAL_SUBTREE, (st), (i), (val))
+#define sk_GENERAL_SUBTREE_zero(st) SKM_sk_zero(GENERAL_SUBTREE, (st))
+#define sk_GENERAL_SUBTREE_push(st, val) SKM_sk_push(GENERAL_SUBTREE, (st), (val))
+#define sk_GENERAL_SUBTREE_unshift(st, val) SKM_sk_unshift(GENERAL_SUBTREE, (st), (val))
+#define sk_GENERAL_SUBTREE_find(st, val) SKM_sk_find(GENERAL_SUBTREE, (st), (val))
+#define sk_GENERAL_SUBTREE_find_ex(st, val) SKM_sk_find_ex(GENERAL_SUBTREE, (st), (val))
+#define sk_GENERAL_SUBTREE_delete(st, i) SKM_sk_delete(GENERAL_SUBTREE, (st), (i))
+#define sk_GENERAL_SUBTREE_delete_ptr(st, ptr) SKM_sk_delete_ptr(GENERAL_SUBTREE, (st), (ptr))
+#define sk_GENERAL_SUBTREE_insert(st, val, i) SKM_sk_insert(GENERAL_SUBTREE, (st), (val), (i))
+#define sk_GENERAL_SUBTREE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(GENERAL_SUBTREE, (st), (cmp))
+#define sk_GENERAL_SUBTREE_dup(st) SKM_sk_dup(GENERAL_SUBTREE, st)
+#define sk_GENERAL_SUBTREE_pop_free(st, free_func) SKM_sk_pop_free(GENERAL_SUBTREE, (st), (free_func))
+#define sk_GENERAL_SUBTREE_shift(st) SKM_sk_shift(GENERAL_SUBTREE, (st))
+#define sk_GENERAL_SUBTREE_pop(st) SKM_sk_pop(GENERAL_SUBTREE, (st))
+#define sk_GENERAL_SUBTREE_sort(st) SKM_sk_sort(GENERAL_SUBTREE, (st))
+#define sk_GENERAL_SUBTREE_is_sorted(st) SKM_sk_is_sorted(GENERAL_SUBTREE, (st))
+
+#define sk_KRB5_APREQBODY_new(st) SKM_sk_new(KRB5_APREQBODY, (st))
+#define sk_KRB5_APREQBODY_new_null() SKM_sk_new_null(KRB5_APREQBODY)
+#define sk_KRB5_APREQBODY_free(st) SKM_sk_free(KRB5_APREQBODY, (st))
+#define sk_KRB5_APREQBODY_num(st) SKM_sk_num(KRB5_APREQBODY, (st))
+#define sk_KRB5_APREQBODY_value(st, i) SKM_sk_value(KRB5_APREQBODY, (st), (i))
+#define sk_KRB5_APREQBODY_set(st, i, val) SKM_sk_set(KRB5_APREQBODY, (st), (i), (val))
+#define sk_KRB5_APREQBODY_zero(st) SKM_sk_zero(KRB5_APREQBODY, (st))
+#define sk_KRB5_APREQBODY_push(st, val) SKM_sk_push(KRB5_APREQBODY, (st), (val))
+#define sk_KRB5_APREQBODY_unshift(st, val) SKM_sk_unshift(KRB5_APREQBODY, (st), (val))
+#define sk_KRB5_APREQBODY_find(st, val) SKM_sk_find(KRB5_APREQBODY, (st), (val))
+#define sk_KRB5_APREQBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_APREQBODY, (st), (val))
+#define sk_KRB5_APREQBODY_delete(st, i) SKM_sk_delete(KRB5_APREQBODY, (st), (i))
+#define sk_KRB5_APREQBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_APREQBODY, (st), (ptr))
+#define sk_KRB5_APREQBODY_insert(st, val, i) SKM_sk_insert(KRB5_APREQBODY, (st), (val), (i))
+#define sk_KRB5_APREQBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_APREQBODY, (st), (cmp))
+#define sk_KRB5_APREQBODY_dup(st) SKM_sk_dup(KRB5_APREQBODY, st)
+#define sk_KRB5_APREQBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_APREQBODY, (st), (free_func))
+#define sk_KRB5_APREQBODY_shift(st) SKM_sk_shift(KRB5_APREQBODY, (st))
+#define sk_KRB5_APREQBODY_pop(st) SKM_sk_pop(KRB5_APREQBODY, (st))
+#define sk_KRB5_APREQBODY_sort(st) SKM_sk_sort(KRB5_APREQBODY, (st))
+#define sk_KRB5_APREQBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_APREQBODY, (st))
+
+#define sk_KRB5_AUTHDATA_new(st) SKM_sk_new(KRB5_AUTHDATA, (st))
+#define sk_KRB5_AUTHDATA_new_null() SKM_sk_new_null(KRB5_AUTHDATA)
+#define sk_KRB5_AUTHDATA_free(st) SKM_sk_free(KRB5_AUTHDATA, (st))
+#define sk_KRB5_AUTHDATA_num(st) SKM_sk_num(KRB5_AUTHDATA, (st))
+#define sk_KRB5_AUTHDATA_value(st, i) SKM_sk_value(KRB5_AUTHDATA, (st), (i))
+#define sk_KRB5_AUTHDATA_set(st, i, val) SKM_sk_set(KRB5_AUTHDATA, (st), (i), (val))
+#define sk_KRB5_AUTHDATA_zero(st) SKM_sk_zero(KRB5_AUTHDATA, (st))
+#define sk_KRB5_AUTHDATA_push(st, val) SKM_sk_push(KRB5_AUTHDATA, (st), (val))
+#define sk_KRB5_AUTHDATA_unshift(st, val) SKM_sk_unshift(KRB5_AUTHDATA, (st), (val))
+#define sk_KRB5_AUTHDATA_find(st, val) SKM_sk_find(KRB5_AUTHDATA, (st), (val))
+#define sk_KRB5_AUTHDATA_find_ex(st, val) SKM_sk_find_ex(KRB5_AUTHDATA, (st), (val))
+#define sk_KRB5_AUTHDATA_delete(st, i) SKM_sk_delete(KRB5_AUTHDATA, (st), (i))
+#define sk_KRB5_AUTHDATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_AUTHDATA, (st), (ptr))
+#define sk_KRB5_AUTHDATA_insert(st, val, i) SKM_sk_insert(KRB5_AUTHDATA, (st), (val), (i))
+#define sk_KRB5_AUTHDATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_AUTHDATA, (st), (cmp))
+#define sk_KRB5_AUTHDATA_dup(st) SKM_sk_dup(KRB5_AUTHDATA, st)
+#define sk_KRB5_AUTHDATA_pop_free(st, free_func) SKM_sk_pop_free(KRB5_AUTHDATA, (st), (free_func))
+#define sk_KRB5_AUTHDATA_shift(st) SKM_sk_shift(KRB5_AUTHDATA, (st))
+#define sk_KRB5_AUTHDATA_pop(st) SKM_sk_pop(KRB5_AUTHDATA, (st))
+#define sk_KRB5_AUTHDATA_sort(st) SKM_sk_sort(KRB5_AUTHDATA, (st))
+#define sk_KRB5_AUTHDATA_is_sorted(st) SKM_sk_is_sorted(KRB5_AUTHDATA, (st))
+
+#define sk_KRB5_AUTHENTBODY_new(st) SKM_sk_new(KRB5_AUTHENTBODY, (st))
+#define sk_KRB5_AUTHENTBODY_new_null() SKM_sk_new_null(KRB5_AUTHENTBODY)
+#define sk_KRB5_AUTHENTBODY_free(st) SKM_sk_free(KRB5_AUTHENTBODY, (st))
+#define sk_KRB5_AUTHENTBODY_num(st) SKM_sk_num(KRB5_AUTHENTBODY, (st))
+#define sk_KRB5_AUTHENTBODY_value(st, i) SKM_sk_value(KRB5_AUTHENTBODY, (st), (i))
+#define sk_KRB5_AUTHENTBODY_set(st, i, val) SKM_sk_set(KRB5_AUTHENTBODY, (st), (i), (val))
+#define sk_KRB5_AUTHENTBODY_zero(st) SKM_sk_zero(KRB5_AUTHENTBODY, (st))
+#define sk_KRB5_AUTHENTBODY_push(st, val) SKM_sk_push(KRB5_AUTHENTBODY, (st), (val))
+#define sk_KRB5_AUTHENTBODY_unshift(st, val) SKM_sk_unshift(KRB5_AUTHENTBODY, (st), (val))
+#define sk_KRB5_AUTHENTBODY_find(st, val) SKM_sk_find(KRB5_AUTHENTBODY, (st), (val))
+#define sk_KRB5_AUTHENTBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_AUTHENTBODY, (st), (val))
+#define sk_KRB5_AUTHENTBODY_delete(st, i) SKM_sk_delete(KRB5_AUTHENTBODY, (st), (i))
+#define sk_KRB5_AUTHENTBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_AUTHENTBODY, (st), (ptr))
+#define sk_KRB5_AUTHENTBODY_insert(st, val, i) SKM_sk_insert(KRB5_AUTHENTBODY, (st), (val), (i))
+#define sk_KRB5_AUTHENTBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_AUTHENTBODY, (st), (cmp))
+#define sk_KRB5_AUTHENTBODY_dup(st) SKM_sk_dup(KRB5_AUTHENTBODY, st)
+#define sk_KRB5_AUTHENTBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_AUTHENTBODY, (st), (free_func))
+#define sk_KRB5_AUTHENTBODY_shift(st) SKM_sk_shift(KRB5_AUTHENTBODY, (st))
+#define sk_KRB5_AUTHENTBODY_pop(st) SKM_sk_pop(KRB5_AUTHENTBODY, (st))
+#define sk_KRB5_AUTHENTBODY_sort(st) SKM_sk_sort(KRB5_AUTHENTBODY, (st))
+#define sk_KRB5_AUTHENTBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_AUTHENTBODY, (st))
+
+#define sk_KRB5_CHECKSUM_new(st) SKM_sk_new(KRB5_CHECKSUM, (st))
+#define sk_KRB5_CHECKSUM_new_null() SKM_sk_new_null(KRB5_CHECKSUM)
+#define sk_KRB5_CHECKSUM_free(st) SKM_sk_free(KRB5_CHECKSUM, (st))
+#define sk_KRB5_CHECKSUM_num(st) SKM_sk_num(KRB5_CHECKSUM, (st))
+#define sk_KRB5_CHECKSUM_value(st, i) SKM_sk_value(KRB5_CHECKSUM, (st), (i))
+#define sk_KRB5_CHECKSUM_set(st, i, val) SKM_sk_set(KRB5_CHECKSUM, (st), (i), (val))
+#define sk_KRB5_CHECKSUM_zero(st) SKM_sk_zero(KRB5_CHECKSUM, (st))
+#define sk_KRB5_CHECKSUM_push(st, val) SKM_sk_push(KRB5_CHECKSUM, (st), (val))
+#define sk_KRB5_CHECKSUM_unshift(st, val) SKM_sk_unshift(KRB5_CHECKSUM, (st), (val))
+#define sk_KRB5_CHECKSUM_find(st, val) SKM_sk_find(KRB5_CHECKSUM, (st), (val))
+#define sk_KRB5_CHECKSUM_find_ex(st, val) SKM_sk_find_ex(KRB5_CHECKSUM, (st), (val))
+#define sk_KRB5_CHECKSUM_delete(st, i) SKM_sk_delete(KRB5_CHECKSUM, (st), (i))
+#define sk_KRB5_CHECKSUM_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_CHECKSUM, (st), (ptr))
+#define sk_KRB5_CHECKSUM_insert(st, val, i) SKM_sk_insert(KRB5_CHECKSUM, (st), (val), (i))
+#define sk_KRB5_CHECKSUM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_CHECKSUM, (st), (cmp))
+#define sk_KRB5_CHECKSUM_dup(st) SKM_sk_dup(KRB5_CHECKSUM, st)
+#define sk_KRB5_CHECKSUM_pop_free(st, free_func) SKM_sk_pop_free(KRB5_CHECKSUM, (st), (free_func))
+#define sk_KRB5_CHECKSUM_shift(st) SKM_sk_shift(KRB5_CHECKSUM, (st))
+#define sk_KRB5_CHECKSUM_pop(st) SKM_sk_pop(KRB5_CHECKSUM, (st))
+#define sk_KRB5_CHECKSUM_sort(st) SKM_sk_sort(KRB5_CHECKSUM, (st))
+#define sk_KRB5_CHECKSUM_is_sorted(st) SKM_sk_is_sorted(KRB5_CHECKSUM, (st))
+
+#define sk_KRB5_ENCDATA_new(st) SKM_sk_new(KRB5_ENCDATA, (st))
+#define sk_KRB5_ENCDATA_new_null() SKM_sk_new_null(KRB5_ENCDATA)
+#define sk_KRB5_ENCDATA_free(st) SKM_sk_free(KRB5_ENCDATA, (st))
+#define sk_KRB5_ENCDATA_num(st) SKM_sk_num(KRB5_ENCDATA, (st))
+#define sk_KRB5_ENCDATA_value(st, i) SKM_sk_value(KRB5_ENCDATA, (st), (i))
+#define sk_KRB5_ENCDATA_set(st, i, val) SKM_sk_set(KRB5_ENCDATA, (st), (i), (val))
+#define sk_KRB5_ENCDATA_zero(st) SKM_sk_zero(KRB5_ENCDATA, (st))
+#define sk_KRB5_ENCDATA_push(st, val) SKM_sk_push(KRB5_ENCDATA, (st), (val))
+#define sk_KRB5_ENCDATA_unshift(st, val) SKM_sk_unshift(KRB5_ENCDATA, (st), (val))
+#define sk_KRB5_ENCDATA_find(st, val) SKM_sk_find(KRB5_ENCDATA, (st), (val))
+#define sk_KRB5_ENCDATA_find_ex(st, val) SKM_sk_find_ex(KRB5_ENCDATA, (st), (val))
+#define sk_KRB5_ENCDATA_delete(st, i) SKM_sk_delete(KRB5_ENCDATA, (st), (i))
+#define sk_KRB5_ENCDATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_ENCDATA, (st), (ptr))
+#define sk_KRB5_ENCDATA_insert(st, val, i) SKM_sk_insert(KRB5_ENCDATA, (st), (val), (i))
+#define sk_KRB5_ENCDATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_ENCDATA, (st), (cmp))
+#define sk_KRB5_ENCDATA_dup(st) SKM_sk_dup(KRB5_ENCDATA, st)
+#define sk_KRB5_ENCDATA_pop_free(st, free_func) SKM_sk_pop_free(KRB5_ENCDATA, (st), (free_func))
+#define sk_KRB5_ENCDATA_shift(st) SKM_sk_shift(KRB5_ENCDATA, (st))
+#define sk_KRB5_ENCDATA_pop(st) SKM_sk_pop(KRB5_ENCDATA, (st))
+#define sk_KRB5_ENCDATA_sort(st) SKM_sk_sort(KRB5_ENCDATA, (st))
+#define sk_KRB5_ENCDATA_is_sorted(st) SKM_sk_is_sorted(KRB5_ENCDATA, (st))
+
+#define sk_KRB5_ENCKEY_new(st) SKM_sk_new(KRB5_ENCKEY, (st))
+#define sk_KRB5_ENCKEY_new_null() SKM_sk_new_null(KRB5_ENCKEY)
+#define sk_KRB5_ENCKEY_free(st) SKM_sk_free(KRB5_ENCKEY, (st))
+#define sk_KRB5_ENCKEY_num(st) SKM_sk_num(KRB5_ENCKEY, (st))
+#define sk_KRB5_ENCKEY_value(st, i) SKM_sk_value(KRB5_ENCKEY, (st), (i))
+#define sk_KRB5_ENCKEY_set(st, i, val) SKM_sk_set(KRB5_ENCKEY, (st), (i), (val))
+#define sk_KRB5_ENCKEY_zero(st) SKM_sk_zero(KRB5_ENCKEY, (st))
+#define sk_KRB5_ENCKEY_push(st, val) SKM_sk_push(KRB5_ENCKEY, (st), (val))
+#define sk_KRB5_ENCKEY_unshift(st, val) SKM_sk_unshift(KRB5_ENCKEY, (st), (val))
+#define sk_KRB5_ENCKEY_find(st, val) SKM_sk_find(KRB5_ENCKEY, (st), (val))
+#define sk_KRB5_ENCKEY_find_ex(st, val) SKM_sk_find_ex(KRB5_ENCKEY, (st), (val))
+#define sk_KRB5_ENCKEY_delete(st, i) SKM_sk_delete(KRB5_ENCKEY, (st), (i))
+#define sk_KRB5_ENCKEY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_ENCKEY, (st), (ptr))
+#define sk_KRB5_ENCKEY_insert(st, val, i) SKM_sk_insert(KRB5_ENCKEY, (st), (val), (i))
+#define sk_KRB5_ENCKEY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_ENCKEY, (st), (cmp))
+#define sk_KRB5_ENCKEY_dup(st) SKM_sk_dup(KRB5_ENCKEY, st)
+#define sk_KRB5_ENCKEY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_ENCKEY, (st), (free_func))
+#define sk_KRB5_ENCKEY_shift(st) SKM_sk_shift(KRB5_ENCKEY, (st))
+#define sk_KRB5_ENCKEY_pop(st) SKM_sk_pop(KRB5_ENCKEY, (st))
+#define sk_KRB5_ENCKEY_sort(st) SKM_sk_sort(KRB5_ENCKEY, (st))
+#define sk_KRB5_ENCKEY_is_sorted(st) SKM_sk_is_sorted(KRB5_ENCKEY, (st))
+
+#define sk_KRB5_PRINCNAME_new(st) SKM_sk_new(KRB5_PRINCNAME, (st))
+#define sk_KRB5_PRINCNAME_new_null() SKM_sk_new_null(KRB5_PRINCNAME)
+#define sk_KRB5_PRINCNAME_free(st) SKM_sk_free(KRB5_PRINCNAME, (st))
+#define sk_KRB5_PRINCNAME_num(st) SKM_sk_num(KRB5_PRINCNAME, (st))
+#define sk_KRB5_PRINCNAME_value(st, i) SKM_sk_value(KRB5_PRINCNAME, (st), (i))
+#define sk_KRB5_PRINCNAME_set(st, i, val) SKM_sk_set(KRB5_PRINCNAME, (st), (i), (val))
+#define sk_KRB5_PRINCNAME_zero(st) SKM_sk_zero(KRB5_PRINCNAME, (st))
+#define sk_KRB5_PRINCNAME_push(st, val) SKM_sk_push(KRB5_PRINCNAME, (st), (val))
+#define sk_KRB5_PRINCNAME_unshift(st, val) SKM_sk_unshift(KRB5_PRINCNAME, (st), (val))
+#define sk_KRB5_PRINCNAME_find(st, val) SKM_sk_find(KRB5_PRINCNAME, (st), (val))
+#define sk_KRB5_PRINCNAME_find_ex(st, val) SKM_sk_find_ex(KRB5_PRINCNAME, (st), (val))
+#define sk_KRB5_PRINCNAME_delete(st, i) SKM_sk_delete(KRB5_PRINCNAME, (st), (i))
+#define sk_KRB5_PRINCNAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_PRINCNAME, (st), (ptr))
+#define sk_KRB5_PRINCNAME_insert(st, val, i) SKM_sk_insert(KRB5_PRINCNAME, (st), (val), (i))
+#define sk_KRB5_PRINCNAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_PRINCNAME, (st), (cmp))
+#define sk_KRB5_PRINCNAME_dup(st) SKM_sk_dup(KRB5_PRINCNAME, st)
+#define sk_KRB5_PRINCNAME_pop_free(st, free_func) SKM_sk_pop_free(KRB5_PRINCNAME, (st), (free_func))
+#define sk_KRB5_PRINCNAME_shift(st) SKM_sk_shift(KRB5_PRINCNAME, (st))
+#define sk_KRB5_PRINCNAME_pop(st) SKM_sk_pop(KRB5_PRINCNAME, (st))
+#define sk_KRB5_PRINCNAME_sort(st) SKM_sk_sort(KRB5_PRINCNAME, (st))
+#define sk_KRB5_PRINCNAME_is_sorted(st) SKM_sk_is_sorted(KRB5_PRINCNAME, (st))
+
+#define sk_KRB5_TKTBODY_new(st) SKM_sk_new(KRB5_TKTBODY, (st))
+#define sk_KRB5_TKTBODY_new_null() SKM_sk_new_null(KRB5_TKTBODY)
+#define sk_KRB5_TKTBODY_free(st) SKM_sk_free(KRB5_TKTBODY, (st))
+#define sk_KRB5_TKTBODY_num(st) SKM_sk_num(KRB5_TKTBODY, (st))
+#define sk_KRB5_TKTBODY_value(st, i) SKM_sk_value(KRB5_TKTBODY, (st), (i))
+#define sk_KRB5_TKTBODY_set(st, i, val) SKM_sk_set(KRB5_TKTBODY, (st), (i), (val))
+#define sk_KRB5_TKTBODY_zero(st) SKM_sk_zero(KRB5_TKTBODY, (st))
+#define sk_KRB5_TKTBODY_push(st, val) SKM_sk_push(KRB5_TKTBODY, (st), (val))
+#define sk_KRB5_TKTBODY_unshift(st, val) SKM_sk_unshift(KRB5_TKTBODY, (st), (val))
+#define sk_KRB5_TKTBODY_find(st, val) SKM_sk_find(KRB5_TKTBODY, (st), (val))
+#define sk_KRB5_TKTBODY_find_ex(st, val) SKM_sk_find_ex(KRB5_TKTBODY, (st), (val))
+#define sk_KRB5_TKTBODY_delete(st, i) SKM_sk_delete(KRB5_TKTBODY, (st), (i))
+#define sk_KRB5_TKTBODY_delete_ptr(st, ptr) SKM_sk_delete_ptr(KRB5_TKTBODY, (st), (ptr))
+#define sk_KRB5_TKTBODY_insert(st, val, i) SKM_sk_insert(KRB5_TKTBODY, (st), (val), (i))
+#define sk_KRB5_TKTBODY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(KRB5_TKTBODY, (st), (cmp))
+#define sk_KRB5_TKTBODY_dup(st) SKM_sk_dup(KRB5_TKTBODY, st)
+#define sk_KRB5_TKTBODY_pop_free(st, free_func) SKM_sk_pop_free(KRB5_TKTBODY, (st), (free_func))
+#define sk_KRB5_TKTBODY_shift(st) SKM_sk_shift(KRB5_TKTBODY, (st))
+#define sk_KRB5_TKTBODY_pop(st) SKM_sk_pop(KRB5_TKTBODY, (st))
+#define sk_KRB5_TKTBODY_sort(st) SKM_sk_sort(KRB5_TKTBODY, (st))
+#define sk_KRB5_TKTBODY_is_sorted(st) SKM_sk_is_sorted(KRB5_TKTBODY, (st))
+
+#define sk_MIME_HEADER_new(st) SKM_sk_new(MIME_HEADER, (st))
+#define sk_MIME_HEADER_new_null() SKM_sk_new_null(MIME_HEADER)
+#define sk_MIME_HEADER_free(st) SKM_sk_free(MIME_HEADER, (st))
+#define sk_MIME_HEADER_num(st) SKM_sk_num(MIME_HEADER, (st))
+#define sk_MIME_HEADER_value(st, i) SKM_sk_value(MIME_HEADER, (st), (i))
+#define sk_MIME_HEADER_set(st, i, val) SKM_sk_set(MIME_HEADER, (st), (i), (val))
+#define sk_MIME_HEADER_zero(st) SKM_sk_zero(MIME_HEADER, (st))
+#define sk_MIME_HEADER_push(st, val) SKM_sk_push(MIME_HEADER, (st), (val))
+#define sk_MIME_HEADER_unshift(st, val) SKM_sk_unshift(MIME_HEADER, (st), (val))
+#define sk_MIME_HEADER_find(st, val) SKM_sk_find(MIME_HEADER, (st), (val))
+#define sk_MIME_HEADER_find_ex(st, val) SKM_sk_find_ex(MIME_HEADER, (st), (val))
+#define sk_MIME_HEADER_delete(st, i) SKM_sk_delete(MIME_HEADER, (st), (i))
+#define sk_MIME_HEADER_delete_ptr(st, ptr) SKM_sk_delete_ptr(MIME_HEADER, (st), (ptr))
+#define sk_MIME_HEADER_insert(st, val, i) SKM_sk_insert(MIME_HEADER, (st), (val), (i))
+#define sk_MIME_HEADER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(MIME_HEADER, (st), (cmp))
+#define sk_MIME_HEADER_dup(st) SKM_sk_dup(MIME_HEADER, st)
+#define sk_MIME_HEADER_pop_free(st, free_func) SKM_sk_pop_free(MIME_HEADER, (st), (free_func))
+#define sk_MIME_HEADER_shift(st) SKM_sk_shift(MIME_HEADER, (st))
+#define sk_MIME_HEADER_pop(st) SKM_sk_pop(MIME_HEADER, (st))
+#define sk_MIME_HEADER_sort(st) SKM_sk_sort(MIME_HEADER, (st))
+#define sk_MIME_HEADER_is_sorted(st) SKM_sk_is_sorted(MIME_HEADER, (st))
+
+#define sk_MIME_PARAM_new(st) SKM_sk_new(MIME_PARAM, (st))
+#define sk_MIME_PARAM_new_null() SKM_sk_new_null(MIME_PARAM)
+#define sk_MIME_PARAM_free(st) SKM_sk_free(MIME_PARAM, (st))
+#define sk_MIME_PARAM_num(st) SKM_sk_num(MIME_PARAM, (st))
+#define sk_MIME_PARAM_value(st, i) SKM_sk_value(MIME_PARAM, (st), (i))
+#define sk_MIME_PARAM_set(st, i, val) SKM_sk_set(MIME_PARAM, (st), (i), (val))
+#define sk_MIME_PARAM_zero(st) SKM_sk_zero(MIME_PARAM, (st))
+#define sk_MIME_PARAM_push(st, val) SKM_sk_push(MIME_PARAM, (st), (val))
+#define sk_MIME_PARAM_unshift(st, val) SKM_sk_unshift(MIME_PARAM, (st), (val))
+#define sk_MIME_PARAM_find(st, val) SKM_sk_find(MIME_PARAM, (st), (val))
+#define sk_MIME_PARAM_find_ex(st, val) SKM_sk_find_ex(MIME_PARAM, (st), (val))
+#define sk_MIME_PARAM_delete(st, i) SKM_sk_delete(MIME_PARAM, (st), (i))
+#define sk_MIME_PARAM_delete_ptr(st, ptr) SKM_sk_delete_ptr(MIME_PARAM, (st), (ptr))
+#define sk_MIME_PARAM_insert(st, val, i) SKM_sk_insert(MIME_PARAM, (st), (val), (i))
+#define sk_MIME_PARAM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(MIME_PARAM, (st), (cmp))
+#define sk_MIME_PARAM_dup(st) SKM_sk_dup(MIME_PARAM, st)
+#define sk_MIME_PARAM_pop_free(st, free_func) SKM_sk_pop_free(MIME_PARAM, (st), (free_func))
+#define sk_MIME_PARAM_shift(st) SKM_sk_shift(MIME_PARAM, (st))
+#define sk_MIME_PARAM_pop(st) SKM_sk_pop(MIME_PARAM, (st))
+#define sk_MIME_PARAM_sort(st) SKM_sk_sort(MIME_PARAM, (st))
+#define sk_MIME_PARAM_is_sorted(st) SKM_sk_is_sorted(MIME_PARAM, (st))
+
+#define sk_NAME_FUNCS_new(st) SKM_sk_new(NAME_FUNCS, (st))
+#define sk_NAME_FUNCS_new_null() SKM_sk_new_null(NAME_FUNCS)
+#define sk_NAME_FUNCS_free(st) SKM_sk_free(NAME_FUNCS, (st))
+#define sk_NAME_FUNCS_num(st) SKM_sk_num(NAME_FUNCS, (st))
+#define sk_NAME_FUNCS_value(st, i) SKM_sk_value(NAME_FUNCS, (st), (i))
+#define sk_NAME_FUNCS_set(st, i, val) SKM_sk_set(NAME_FUNCS, (st), (i), (val))
+#define sk_NAME_FUNCS_zero(st) SKM_sk_zero(NAME_FUNCS, (st))
+#define sk_NAME_FUNCS_push(st, val) SKM_sk_push(NAME_FUNCS, (st), (val))
+#define sk_NAME_FUNCS_unshift(st, val) SKM_sk_unshift(NAME_FUNCS, (st), (val))
+#define sk_NAME_FUNCS_find(st, val) SKM_sk_find(NAME_FUNCS, (st), (val))
+#define sk_NAME_FUNCS_find_ex(st, val) SKM_sk_find_ex(NAME_FUNCS, (st), (val))
+#define sk_NAME_FUNCS_delete(st, i) SKM_sk_delete(NAME_FUNCS, (st), (i))
+#define sk_NAME_FUNCS_delete_ptr(st, ptr) SKM_sk_delete_ptr(NAME_FUNCS, (st), (ptr))
+#define sk_NAME_FUNCS_insert(st, val, i) SKM_sk_insert(NAME_FUNCS, (st), (val), (i))
+#define sk_NAME_FUNCS_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(NAME_FUNCS, (st), (cmp))
+#define sk_NAME_FUNCS_dup(st) SKM_sk_dup(NAME_FUNCS, st)
+#define sk_NAME_FUNCS_pop_free(st, free_func) SKM_sk_pop_free(NAME_FUNCS, (st), (free_func))
+#define sk_NAME_FUNCS_shift(st) SKM_sk_shift(NAME_FUNCS, (st))
+#define sk_NAME_FUNCS_pop(st) SKM_sk_pop(NAME_FUNCS, (st))
+#define sk_NAME_FUNCS_sort(st) SKM_sk_sort(NAME_FUNCS, (st))
+#define sk_NAME_FUNCS_is_sorted(st) SKM_sk_is_sorted(NAME_FUNCS, (st))
+
+#define sk_OCSP_CERTID_new(st) SKM_sk_new(OCSP_CERTID, (st))
+#define sk_OCSP_CERTID_new_null() SKM_sk_new_null(OCSP_CERTID)
+#define sk_OCSP_CERTID_free(st) SKM_sk_free(OCSP_CERTID, (st))
+#define sk_OCSP_CERTID_num(st) SKM_sk_num(OCSP_CERTID, (st))
+#define sk_OCSP_CERTID_value(st, i) SKM_sk_value(OCSP_CERTID, (st), (i))
+#define sk_OCSP_CERTID_set(st, i, val) SKM_sk_set(OCSP_CERTID, (st), (i), (val))
+#define sk_OCSP_CERTID_zero(st) SKM_sk_zero(OCSP_CERTID, (st))
+#define sk_OCSP_CERTID_push(st, val) SKM_sk_push(OCSP_CERTID, (st), (val))
+#define sk_OCSP_CERTID_unshift(st, val) SKM_sk_unshift(OCSP_CERTID, (st), (val))
+#define sk_OCSP_CERTID_find(st, val) SKM_sk_find(OCSP_CERTID, (st), (val))
+#define sk_OCSP_CERTID_find_ex(st, val) SKM_sk_find_ex(OCSP_CERTID, (st), (val))
+#define sk_OCSP_CERTID_delete(st, i) SKM_sk_delete(OCSP_CERTID, (st), (i))
+#define sk_OCSP_CERTID_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_CERTID, (st), (ptr))
+#define sk_OCSP_CERTID_insert(st, val, i) SKM_sk_insert(OCSP_CERTID, (st), (val), (i))
+#define sk_OCSP_CERTID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_CERTID, (st), (cmp))
+#define sk_OCSP_CERTID_dup(st) SKM_sk_dup(OCSP_CERTID, st)
+#define sk_OCSP_CERTID_pop_free(st, free_func) SKM_sk_pop_free(OCSP_CERTID, (st), (free_func))
+#define sk_OCSP_CERTID_shift(st) SKM_sk_shift(OCSP_CERTID, (st))
+#define sk_OCSP_CERTID_pop(st) SKM_sk_pop(OCSP_CERTID, (st))
+#define sk_OCSP_CERTID_sort(st) SKM_sk_sort(OCSP_CERTID, (st))
+#define sk_OCSP_CERTID_is_sorted(st) SKM_sk_is_sorted(OCSP_CERTID, (st))
+
+#define sk_OCSP_ONEREQ_new(st) SKM_sk_new(OCSP_ONEREQ, (st))
+#define sk_OCSP_ONEREQ_new_null() SKM_sk_new_null(OCSP_ONEREQ)
+#define sk_OCSP_ONEREQ_free(st) SKM_sk_free(OCSP_ONEREQ, (st))
+#define sk_OCSP_ONEREQ_num(st) SKM_sk_num(OCSP_ONEREQ, (st))
+#define sk_OCSP_ONEREQ_value(st, i) SKM_sk_value(OCSP_ONEREQ, (st), (i))
+#define sk_OCSP_ONEREQ_set(st, i, val) SKM_sk_set(OCSP_ONEREQ, (st), (i), (val))
+#define sk_OCSP_ONEREQ_zero(st) SKM_sk_zero(OCSP_ONEREQ, (st))
+#define sk_OCSP_ONEREQ_push(st, val) SKM_sk_push(OCSP_ONEREQ, (st), (val))
+#define sk_OCSP_ONEREQ_unshift(st, val) SKM_sk_unshift(OCSP_ONEREQ, (st), (val))
+#define sk_OCSP_ONEREQ_find(st, val) SKM_sk_find(OCSP_ONEREQ, (st), (val))
+#define sk_OCSP_ONEREQ_find_ex(st, val) SKM_sk_find_ex(OCSP_ONEREQ, (st), (val))
+#define sk_OCSP_ONEREQ_delete(st, i) SKM_sk_delete(OCSP_ONEREQ, (st), (i))
+#define sk_OCSP_ONEREQ_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_ONEREQ, (st), (ptr))
+#define sk_OCSP_ONEREQ_insert(st, val, i) SKM_sk_insert(OCSP_ONEREQ, (st), (val), (i))
+#define sk_OCSP_ONEREQ_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_ONEREQ, (st), (cmp))
+#define sk_OCSP_ONEREQ_dup(st) SKM_sk_dup(OCSP_ONEREQ, st)
+#define sk_OCSP_ONEREQ_pop_free(st, free_func) SKM_sk_pop_free(OCSP_ONEREQ, (st), (free_func))
+#define sk_OCSP_ONEREQ_shift(st) SKM_sk_shift(OCSP_ONEREQ, (st))
+#define sk_OCSP_ONEREQ_pop(st) SKM_sk_pop(OCSP_ONEREQ, (st))
+#define sk_OCSP_ONEREQ_sort(st) SKM_sk_sort(OCSP_ONEREQ, (st))
+#define sk_OCSP_ONEREQ_is_sorted(st) SKM_sk_is_sorted(OCSP_ONEREQ, (st))
+
+#define sk_OCSP_SINGLERESP_new(st) SKM_sk_new(OCSP_SINGLERESP, (st))
+#define sk_OCSP_SINGLERESP_new_null() SKM_sk_new_null(OCSP_SINGLERESP)
+#define sk_OCSP_SINGLERESP_free(st) SKM_sk_free(OCSP_SINGLERESP, (st))
+#define sk_OCSP_SINGLERESP_num(st) SKM_sk_num(OCSP_SINGLERESP, (st))
+#define sk_OCSP_SINGLERESP_value(st, i) SKM_sk_value(OCSP_SINGLERESP, (st), (i))
+#define sk_OCSP_SINGLERESP_set(st, i, val) SKM_sk_set(OCSP_SINGLERESP, (st), (i), (val))
+#define sk_OCSP_SINGLERESP_zero(st) SKM_sk_zero(OCSP_SINGLERESP, (st))
+#define sk_OCSP_SINGLERESP_push(st, val) SKM_sk_push(OCSP_SINGLERESP, (st), (val))
+#define sk_OCSP_SINGLERESP_unshift(st, val) SKM_sk_unshift(OCSP_SINGLERESP, (st), (val))
+#define sk_OCSP_SINGLERESP_find(st, val) SKM_sk_find(OCSP_SINGLERESP, (st), (val))
+#define sk_OCSP_SINGLERESP_find_ex(st, val) SKM_sk_find_ex(OCSP_SINGLERESP, (st), (val))
+#define sk_OCSP_SINGLERESP_delete(st, i) SKM_sk_delete(OCSP_SINGLERESP, (st), (i))
+#define sk_OCSP_SINGLERESP_delete_ptr(st, ptr) SKM_sk_delete_ptr(OCSP_SINGLERESP, (st), (ptr))
+#define sk_OCSP_SINGLERESP_insert(st, val, i) SKM_sk_insert(OCSP_SINGLERESP, (st), (val), (i))
+#define sk_OCSP_SINGLERESP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(OCSP_SINGLERESP, (st), (cmp))
+#define sk_OCSP_SINGLERESP_dup(st) SKM_sk_dup(OCSP_SINGLERESP, st)
+#define sk_OCSP_SINGLERESP_pop_free(st, free_func) SKM_sk_pop_free(OCSP_SINGLERESP, (st), (free_func))
+#define sk_OCSP_SINGLERESP_shift(st) SKM_sk_shift(OCSP_SINGLERESP, (st))
+#define sk_OCSP_SINGLERESP_pop(st) SKM_sk_pop(OCSP_SINGLERESP, (st))
+#define sk_OCSP_SINGLERESP_sort(st) SKM_sk_sort(OCSP_SINGLERESP, (st))
+#define sk_OCSP_SINGLERESP_is_sorted(st) SKM_sk_is_sorted(OCSP_SINGLERESP, (st))
+
+#define sk_PKCS12_SAFEBAG_new(st) SKM_sk_new(PKCS12_SAFEBAG, (st))
+#define sk_PKCS12_SAFEBAG_new_null() SKM_sk_new_null(PKCS12_SAFEBAG)
+#define sk_PKCS12_SAFEBAG_free(st) SKM_sk_free(PKCS12_SAFEBAG, (st))
+#define sk_PKCS12_SAFEBAG_num(st) SKM_sk_num(PKCS12_SAFEBAG, (st))
+#define sk_PKCS12_SAFEBAG_value(st, i) SKM_sk_value(PKCS12_SAFEBAG, (st), (i))
+#define sk_PKCS12_SAFEBAG_set(st, i, val) SKM_sk_set(PKCS12_SAFEBAG, (st), (i), (val))
+#define sk_PKCS12_SAFEBAG_zero(st) SKM_sk_zero(PKCS12_SAFEBAG, (st))
+#define sk_PKCS12_SAFEBAG_push(st, val) SKM_sk_push(PKCS12_SAFEBAG, (st), (val))
+#define sk_PKCS12_SAFEBAG_unshift(st, val) SKM_sk_unshift(PKCS12_SAFEBAG, (st), (val))
+#define sk_PKCS12_SAFEBAG_find(st, val) SKM_sk_find(PKCS12_SAFEBAG, (st), (val))
+#define sk_PKCS12_SAFEBAG_find_ex(st, val) SKM_sk_find_ex(PKCS12_SAFEBAG, (st), (val))
+#define sk_PKCS12_SAFEBAG_delete(st, i) SKM_sk_delete(PKCS12_SAFEBAG, (st), (i))
+#define sk_PKCS12_SAFEBAG_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS12_SAFEBAG, (st), (ptr))
+#define sk_PKCS12_SAFEBAG_insert(st, val, i) SKM_sk_insert(PKCS12_SAFEBAG, (st), (val), (i))
+#define sk_PKCS12_SAFEBAG_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS12_SAFEBAG, (st), (cmp))
+#define sk_PKCS12_SAFEBAG_dup(st) SKM_sk_dup(PKCS12_SAFEBAG, st)
+#define sk_PKCS12_SAFEBAG_pop_free(st, free_func) SKM_sk_pop_free(PKCS12_SAFEBAG, (st), (free_func))
+#define sk_PKCS12_SAFEBAG_shift(st) SKM_sk_shift(PKCS12_SAFEBAG, (st))
+#define sk_PKCS12_SAFEBAG_pop(st) SKM_sk_pop(PKCS12_SAFEBAG, (st))
+#define sk_PKCS12_SAFEBAG_sort(st) SKM_sk_sort(PKCS12_SAFEBAG, (st))
+#define sk_PKCS12_SAFEBAG_is_sorted(st) SKM_sk_is_sorted(PKCS12_SAFEBAG, (st))
+
+#define sk_PKCS7_new(st) SKM_sk_new(PKCS7, (st))
+#define sk_PKCS7_new_null() SKM_sk_new_null(PKCS7)
+#define sk_PKCS7_free(st) SKM_sk_free(PKCS7, (st))
+#define sk_PKCS7_num(st) SKM_sk_num(PKCS7, (st))
+#define sk_PKCS7_value(st, i) SKM_sk_value(PKCS7, (st), (i))
+#define sk_PKCS7_set(st, i, val) SKM_sk_set(PKCS7, (st), (i), (val))
+#define sk_PKCS7_zero(st) SKM_sk_zero(PKCS7, (st))
+#define sk_PKCS7_push(st, val) SKM_sk_push(PKCS7, (st), (val))
+#define sk_PKCS7_unshift(st, val) SKM_sk_unshift(PKCS7, (st), (val))
+#define sk_PKCS7_find(st, val) SKM_sk_find(PKCS7, (st), (val))
+#define sk_PKCS7_find_ex(st, val) SKM_sk_find_ex(PKCS7, (st), (val))
+#define sk_PKCS7_delete(st, i) SKM_sk_delete(PKCS7, (st), (i))
+#define sk_PKCS7_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7, (st), (ptr))
+#define sk_PKCS7_insert(st, val, i) SKM_sk_insert(PKCS7, (st), (val), (i))
+#define sk_PKCS7_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7, (st), (cmp))
+#define sk_PKCS7_dup(st) SKM_sk_dup(PKCS7, st)
+#define sk_PKCS7_pop_free(st, free_func) SKM_sk_pop_free(PKCS7, (st), (free_func))
+#define sk_PKCS7_shift(st) SKM_sk_shift(PKCS7, (st))
+#define sk_PKCS7_pop(st) SKM_sk_pop(PKCS7, (st))
+#define sk_PKCS7_sort(st) SKM_sk_sort(PKCS7, (st))
+#define sk_PKCS7_is_sorted(st) SKM_sk_is_sorted(PKCS7, (st))
+
+#define sk_PKCS7_RECIP_INFO_new(st) SKM_sk_new(PKCS7_RECIP_INFO, (st))
+#define sk_PKCS7_RECIP_INFO_new_null() SKM_sk_new_null(PKCS7_RECIP_INFO)
+#define sk_PKCS7_RECIP_INFO_free(st) SKM_sk_free(PKCS7_RECIP_INFO, (st))
+#define sk_PKCS7_RECIP_INFO_num(st) SKM_sk_num(PKCS7_RECIP_INFO, (st))
+#define sk_PKCS7_RECIP_INFO_value(st, i) SKM_sk_value(PKCS7_RECIP_INFO, (st), (i))
+#define sk_PKCS7_RECIP_INFO_set(st, i, val) SKM_sk_set(PKCS7_RECIP_INFO, (st), (i), (val))
+#define sk_PKCS7_RECIP_INFO_zero(st) SKM_sk_zero(PKCS7_RECIP_INFO, (st))
+#define sk_PKCS7_RECIP_INFO_push(st, val) SKM_sk_push(PKCS7_RECIP_INFO, (st), (val))
+#define sk_PKCS7_RECIP_INFO_unshift(st, val) SKM_sk_unshift(PKCS7_RECIP_INFO, (st), (val))
+#define sk_PKCS7_RECIP_INFO_find(st, val) SKM_sk_find(PKCS7_RECIP_INFO, (st), (val))
+#define sk_PKCS7_RECIP_INFO_find_ex(st, val) SKM_sk_find_ex(PKCS7_RECIP_INFO, (st), (val))
+#define sk_PKCS7_RECIP_INFO_delete(st, i) SKM_sk_delete(PKCS7_RECIP_INFO, (st), (i))
+#define sk_PKCS7_RECIP_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7_RECIP_INFO, (st), (ptr))
+#define sk_PKCS7_RECIP_INFO_insert(st, val, i) SKM_sk_insert(PKCS7_RECIP_INFO, (st), (val), (i))
+#define sk_PKCS7_RECIP_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7_RECIP_INFO, (st), (cmp))
+#define sk_PKCS7_RECIP_INFO_dup(st) SKM_sk_dup(PKCS7_RECIP_INFO, st)
+#define sk_PKCS7_RECIP_INFO_pop_free(st, free_func) SKM_sk_pop_free(PKCS7_RECIP_INFO, (st), (free_func))
+#define sk_PKCS7_RECIP_INFO_shift(st) SKM_sk_shift(PKCS7_RECIP_INFO, (st))
+#define sk_PKCS7_RECIP_INFO_pop(st) SKM_sk_pop(PKCS7_RECIP_INFO, (st))
+#define sk_PKCS7_RECIP_INFO_sort(st) SKM_sk_sort(PKCS7_RECIP_INFO, (st))
+#define sk_PKCS7_RECIP_INFO_is_sorted(st) SKM_sk_is_sorted(PKCS7_RECIP_INFO, (st))
+
+#define sk_PKCS7_SIGNER_INFO_new(st) SKM_sk_new(PKCS7_SIGNER_INFO, (st))
+#define sk_PKCS7_SIGNER_INFO_new_null() SKM_sk_new_null(PKCS7_SIGNER_INFO)
+#define sk_PKCS7_SIGNER_INFO_free(st) SKM_sk_free(PKCS7_SIGNER_INFO, (st))
+#define sk_PKCS7_SIGNER_INFO_num(st) SKM_sk_num(PKCS7_SIGNER_INFO, (st))
+#define sk_PKCS7_SIGNER_INFO_value(st, i) SKM_sk_value(PKCS7_SIGNER_INFO, (st), (i))
+#define sk_PKCS7_SIGNER_INFO_set(st, i, val) SKM_sk_set(PKCS7_SIGNER_INFO, (st), (i), (val))
+#define sk_PKCS7_SIGNER_INFO_zero(st) SKM_sk_zero(PKCS7_SIGNER_INFO, (st))
+#define sk_PKCS7_SIGNER_INFO_push(st, val) SKM_sk_push(PKCS7_SIGNER_INFO, (st), (val))
+#define sk_PKCS7_SIGNER_INFO_unshift(st, val) SKM_sk_unshift(PKCS7_SIGNER_INFO, (st), (val))
+#define sk_PKCS7_SIGNER_INFO_find(st, val) SKM_sk_find(PKCS7_SIGNER_INFO, (st), (val))
+#define sk_PKCS7_SIGNER_INFO_find_ex(st, val) SKM_sk_find_ex(PKCS7_SIGNER_INFO, (st), (val))
+#define sk_PKCS7_SIGNER_INFO_delete(st, i) SKM_sk_delete(PKCS7_SIGNER_INFO, (st), (i))
+#define sk_PKCS7_SIGNER_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(PKCS7_SIGNER_INFO, (st), (ptr))
+#define sk_PKCS7_SIGNER_INFO_insert(st, val, i) SKM_sk_insert(PKCS7_SIGNER_INFO, (st), (val), (i))
+#define sk_PKCS7_SIGNER_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(PKCS7_SIGNER_INFO, (st), (cmp))
+#define sk_PKCS7_SIGNER_INFO_dup(st) SKM_sk_dup(PKCS7_SIGNER_INFO, st)
+#define sk_PKCS7_SIGNER_INFO_pop_free(st, free_func) SKM_sk_pop_free(PKCS7_SIGNER_INFO, (st), (free_func))
+#define sk_PKCS7_SIGNER_INFO_shift(st) SKM_sk_shift(PKCS7_SIGNER_INFO, (st))
+#define sk_PKCS7_SIGNER_INFO_pop(st) SKM_sk_pop(PKCS7_SIGNER_INFO, (st))
+#define sk_PKCS7_SIGNER_INFO_sort(st) SKM_sk_sort(PKCS7_SIGNER_INFO, (st))
+#define sk_PKCS7_SIGNER_INFO_is_sorted(st) SKM_sk_is_sorted(PKCS7_SIGNER_INFO, (st))
+
+#define sk_POLICYINFO_new(st) SKM_sk_new(POLICYINFO, (st))
+#define sk_POLICYINFO_new_null() SKM_sk_new_null(POLICYINFO)
+#define sk_POLICYINFO_free(st) SKM_sk_free(POLICYINFO, (st))
+#define sk_POLICYINFO_num(st) SKM_sk_num(POLICYINFO, (st))
+#define sk_POLICYINFO_value(st, i) SKM_sk_value(POLICYINFO, (st), (i))
+#define sk_POLICYINFO_set(st, i, val) SKM_sk_set(POLICYINFO, (st), (i), (val))
+#define sk_POLICYINFO_zero(st) SKM_sk_zero(POLICYINFO, (st))
+#define sk_POLICYINFO_push(st, val) SKM_sk_push(POLICYINFO, (st), (val))
+#define sk_POLICYINFO_unshift(st, val) SKM_sk_unshift(POLICYINFO, (st), (val))
+#define sk_POLICYINFO_find(st, val) SKM_sk_find(POLICYINFO, (st), (val))
+#define sk_POLICYINFO_find_ex(st, val) SKM_sk_find_ex(POLICYINFO, (st), (val))
+#define sk_POLICYINFO_delete(st, i) SKM_sk_delete(POLICYINFO, (st), (i))
+#define sk_POLICYINFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICYINFO, (st), (ptr))
+#define sk_POLICYINFO_insert(st, val, i) SKM_sk_insert(POLICYINFO, (st), (val), (i))
+#define sk_POLICYINFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICYINFO, (st), (cmp))
+#define sk_POLICYINFO_dup(st) SKM_sk_dup(POLICYINFO, st)
+#define sk_POLICYINFO_pop_free(st, free_func) SKM_sk_pop_free(POLICYINFO, (st), (free_func))
+#define sk_POLICYINFO_shift(st) SKM_sk_shift(POLICYINFO, (st))
+#define sk_POLICYINFO_pop(st) SKM_sk_pop(POLICYINFO, (st))
+#define sk_POLICYINFO_sort(st) SKM_sk_sort(POLICYINFO, (st))
+#define sk_POLICYINFO_is_sorted(st) SKM_sk_is_sorted(POLICYINFO, (st))
+
+#define sk_POLICYQUALINFO_new(st) SKM_sk_new(POLICYQUALINFO, (st))
+#define sk_POLICYQUALINFO_new_null() SKM_sk_new_null(POLICYQUALINFO)
+#define sk_POLICYQUALINFO_free(st) SKM_sk_free(POLICYQUALINFO, (st))
+#define sk_POLICYQUALINFO_num(st) SKM_sk_num(POLICYQUALINFO, (st))
+#define sk_POLICYQUALINFO_value(st, i) SKM_sk_value(POLICYQUALINFO, (st), (i))
+#define sk_POLICYQUALINFO_set(st, i, val) SKM_sk_set(POLICYQUALINFO, (st), (i), (val))
+#define sk_POLICYQUALINFO_zero(st) SKM_sk_zero(POLICYQUALINFO, (st))
+#define sk_POLICYQUALINFO_push(st, val) SKM_sk_push(POLICYQUALINFO, (st), (val))
+#define sk_POLICYQUALINFO_unshift(st, val) SKM_sk_unshift(POLICYQUALINFO, (st), (val))
+#define sk_POLICYQUALINFO_find(st, val) SKM_sk_find(POLICYQUALINFO, (st), (val))
+#define sk_POLICYQUALINFO_find_ex(st, val) SKM_sk_find_ex(POLICYQUALINFO, (st), (val))
+#define sk_POLICYQUALINFO_delete(st, i) SKM_sk_delete(POLICYQUALINFO, (st), (i))
+#define sk_POLICYQUALINFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICYQUALINFO, (st), (ptr))
+#define sk_POLICYQUALINFO_insert(st, val, i) SKM_sk_insert(POLICYQUALINFO, (st), (val), (i))
+#define sk_POLICYQUALINFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICYQUALINFO, (st), (cmp))
+#define sk_POLICYQUALINFO_dup(st) SKM_sk_dup(POLICYQUALINFO, st)
+#define sk_POLICYQUALINFO_pop_free(st, free_func) SKM_sk_pop_free(POLICYQUALINFO, (st), (free_func))
+#define sk_POLICYQUALINFO_shift(st) SKM_sk_shift(POLICYQUALINFO, (st))
+#define sk_POLICYQUALINFO_pop(st) SKM_sk_pop(POLICYQUALINFO, (st))
+#define sk_POLICYQUALINFO_sort(st) SKM_sk_sort(POLICYQUALINFO, (st))
+#define sk_POLICYQUALINFO_is_sorted(st) SKM_sk_is_sorted(POLICYQUALINFO, (st))
+
+#define sk_POLICY_MAPPING_new(st) SKM_sk_new(POLICY_MAPPING, (st))
+#define sk_POLICY_MAPPING_new_null() SKM_sk_new_null(POLICY_MAPPING)
+#define sk_POLICY_MAPPING_free(st) SKM_sk_free(POLICY_MAPPING, (st))
+#define sk_POLICY_MAPPING_num(st) SKM_sk_num(POLICY_MAPPING, (st))
+#define sk_POLICY_MAPPING_value(st, i) SKM_sk_value(POLICY_MAPPING, (st), (i))
+#define sk_POLICY_MAPPING_set(st, i, val) SKM_sk_set(POLICY_MAPPING, (st), (i), (val))
+#define sk_POLICY_MAPPING_zero(st) SKM_sk_zero(POLICY_MAPPING, (st))
+#define sk_POLICY_MAPPING_push(st, val) SKM_sk_push(POLICY_MAPPING, (st), (val))
+#define sk_POLICY_MAPPING_unshift(st, val) SKM_sk_unshift(POLICY_MAPPING, (st), (val))
+#define sk_POLICY_MAPPING_find(st, val) SKM_sk_find(POLICY_MAPPING, (st), (val))
+#define sk_POLICY_MAPPING_find_ex(st, val) SKM_sk_find_ex(POLICY_MAPPING, (st), (val))
+#define sk_POLICY_MAPPING_delete(st, i) SKM_sk_delete(POLICY_MAPPING, (st), (i))
+#define sk_POLICY_MAPPING_delete_ptr(st, ptr) SKM_sk_delete_ptr(POLICY_MAPPING, (st), (ptr))
+#define sk_POLICY_MAPPING_insert(st, val, i) SKM_sk_insert(POLICY_MAPPING, (st), (val), (i))
+#define sk_POLICY_MAPPING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(POLICY_MAPPING, (st), (cmp))
+#define sk_POLICY_MAPPING_dup(st) SKM_sk_dup(POLICY_MAPPING, st)
+#define sk_POLICY_MAPPING_pop_free(st, free_func) SKM_sk_pop_free(POLICY_MAPPING, (st), (free_func))
+#define sk_POLICY_MAPPING_shift(st) SKM_sk_shift(POLICY_MAPPING, (st))
+#define sk_POLICY_MAPPING_pop(st) SKM_sk_pop(POLICY_MAPPING, (st))
+#define sk_POLICY_MAPPING_sort(st) SKM_sk_sort(POLICY_MAPPING, (st))
+#define sk_POLICY_MAPPING_is_sorted(st) SKM_sk_is_sorted(POLICY_MAPPING, (st))
+
+#define sk_SSL_CIPHER_new(st) SKM_sk_new(SSL_CIPHER, (st))
+#define sk_SSL_CIPHER_new_null() SKM_sk_new_null(SSL_CIPHER)
+#define sk_SSL_CIPHER_free(st) SKM_sk_free(SSL_CIPHER, (st))
+#define sk_SSL_CIPHER_num(st) SKM_sk_num(SSL_CIPHER, (st))
+#define sk_SSL_CIPHER_value(st, i) SKM_sk_value(SSL_CIPHER, (st), (i))
+#define sk_SSL_CIPHER_set(st, i, val) SKM_sk_set(SSL_CIPHER, (st), (i), (val))
+#define sk_SSL_CIPHER_zero(st) SKM_sk_zero(SSL_CIPHER, (st))
+#define sk_SSL_CIPHER_push(st, val) SKM_sk_push(SSL_CIPHER, (st), (val))
+#define sk_SSL_CIPHER_unshift(st, val) SKM_sk_unshift(SSL_CIPHER, (st), (val))
+#define sk_SSL_CIPHER_find(st, val) SKM_sk_find(SSL_CIPHER, (st), (val))
+#define sk_SSL_CIPHER_find_ex(st, val) SKM_sk_find_ex(SSL_CIPHER, (st), (val))
+#define sk_SSL_CIPHER_delete(st, i) SKM_sk_delete(SSL_CIPHER, (st), (i))
+#define sk_SSL_CIPHER_delete_ptr(st, ptr) SKM_sk_delete_ptr(SSL_CIPHER, (st), (ptr))
+#define sk_SSL_CIPHER_insert(st, val, i) SKM_sk_insert(SSL_CIPHER, (st), (val), (i))
+#define sk_SSL_CIPHER_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SSL_CIPHER, (st), (cmp))
+#define sk_SSL_CIPHER_dup(st) SKM_sk_dup(SSL_CIPHER, st)
+#define sk_SSL_CIPHER_pop_free(st, free_func) SKM_sk_pop_free(SSL_CIPHER, (st), (free_func))
+#define sk_SSL_CIPHER_shift(st) SKM_sk_shift(SSL_CIPHER, (st))
+#define sk_SSL_CIPHER_pop(st) SKM_sk_pop(SSL_CIPHER, (st))
+#define sk_SSL_CIPHER_sort(st) SKM_sk_sort(SSL_CIPHER, (st))
+#define sk_SSL_CIPHER_is_sorted(st) SKM_sk_is_sorted(SSL_CIPHER, (st))
+
+#define sk_SSL_COMP_new(st) SKM_sk_new(SSL_COMP, (st))
+#define sk_SSL_COMP_new_null() SKM_sk_new_null(SSL_COMP)
+#define sk_SSL_COMP_free(st) SKM_sk_free(SSL_COMP, (st))
+#define sk_SSL_COMP_num(st) SKM_sk_num(SSL_COMP, (st))
+#define sk_SSL_COMP_value(st, i) SKM_sk_value(SSL_COMP, (st), (i))
+#define sk_SSL_COMP_set(st, i, val) SKM_sk_set(SSL_COMP, (st), (i), (val))
+#define sk_SSL_COMP_zero(st) SKM_sk_zero(SSL_COMP, (st))
+#define sk_SSL_COMP_push(st, val) SKM_sk_push(SSL_COMP, (st), (val))
+#define sk_SSL_COMP_unshift(st, val) SKM_sk_unshift(SSL_COMP, (st), (val))
+#define sk_SSL_COMP_find(st, val) SKM_sk_find(SSL_COMP, (st), (val))
+#define sk_SSL_COMP_find_ex(st, val) SKM_sk_find_ex(SSL_COMP, (st), (val))
+#define sk_SSL_COMP_delete(st, i) SKM_sk_delete(SSL_COMP, (st), (i))
+#define sk_SSL_COMP_delete_ptr(st, ptr) SKM_sk_delete_ptr(SSL_COMP, (st), (ptr))
+#define sk_SSL_COMP_insert(st, val, i) SKM_sk_insert(SSL_COMP, (st), (val), (i))
+#define sk_SSL_COMP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SSL_COMP, (st), (cmp))
+#define sk_SSL_COMP_dup(st) SKM_sk_dup(SSL_COMP, st)
+#define sk_SSL_COMP_pop_free(st, free_func) SKM_sk_pop_free(SSL_COMP, (st), (free_func))
+#define sk_SSL_COMP_shift(st) SKM_sk_shift(SSL_COMP, (st))
+#define sk_SSL_COMP_pop(st) SKM_sk_pop(SSL_COMP, (st))
+#define sk_SSL_COMP_sort(st) SKM_sk_sort(SSL_COMP, (st))
+#define sk_SSL_COMP_is_sorted(st) SKM_sk_is_sorted(SSL_COMP, (st))
+
+#define sk_STORE_OBJECT_new(st) SKM_sk_new(STORE_OBJECT, (st))
+#define sk_STORE_OBJECT_new_null() SKM_sk_new_null(STORE_OBJECT)
+#define sk_STORE_OBJECT_free(st) SKM_sk_free(STORE_OBJECT, (st))
+#define sk_STORE_OBJECT_num(st) SKM_sk_num(STORE_OBJECT, (st))
+#define sk_STORE_OBJECT_value(st, i) SKM_sk_value(STORE_OBJECT, (st), (i))
+#define sk_STORE_OBJECT_set(st, i, val) SKM_sk_set(STORE_OBJECT, (st), (i), (val))
+#define sk_STORE_OBJECT_zero(st) SKM_sk_zero(STORE_OBJECT, (st))
+#define sk_STORE_OBJECT_push(st, val) SKM_sk_push(STORE_OBJECT, (st), (val))
+#define sk_STORE_OBJECT_unshift(st, val) SKM_sk_unshift(STORE_OBJECT, (st), (val))
+#define sk_STORE_OBJECT_find(st, val) SKM_sk_find(STORE_OBJECT, (st), (val))
+#define sk_STORE_OBJECT_find_ex(st, val) SKM_sk_find_ex(STORE_OBJECT, (st), (val))
+#define sk_STORE_OBJECT_delete(st, i) SKM_sk_delete(STORE_OBJECT, (st), (i))
+#define sk_STORE_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(STORE_OBJECT, (st), (ptr))
+#define sk_STORE_OBJECT_insert(st, val, i) SKM_sk_insert(STORE_OBJECT, (st), (val), (i))
+#define sk_STORE_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(STORE_OBJECT, (st), (cmp))
+#define sk_STORE_OBJECT_dup(st) SKM_sk_dup(STORE_OBJECT, st)
+#define sk_STORE_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(STORE_OBJECT, (st), (free_func))
+#define sk_STORE_OBJECT_shift(st) SKM_sk_shift(STORE_OBJECT, (st))
+#define sk_STORE_OBJECT_pop(st) SKM_sk_pop(STORE_OBJECT, (st))
+#define sk_STORE_OBJECT_sort(st) SKM_sk_sort(STORE_OBJECT, (st))
+#define sk_STORE_OBJECT_is_sorted(st) SKM_sk_is_sorted(STORE_OBJECT, (st))
+
+#define sk_SXNETID_new(st) SKM_sk_new(SXNETID, (st))
+#define sk_SXNETID_new_null() SKM_sk_new_null(SXNETID)
+#define sk_SXNETID_free(st) SKM_sk_free(SXNETID, (st))
+#define sk_SXNETID_num(st) SKM_sk_num(SXNETID, (st))
+#define sk_SXNETID_value(st, i) SKM_sk_value(SXNETID, (st), (i))
+#define sk_SXNETID_set(st, i, val) SKM_sk_set(SXNETID, (st), (i), (val))
+#define sk_SXNETID_zero(st) SKM_sk_zero(SXNETID, (st))
+#define sk_SXNETID_push(st, val) SKM_sk_push(SXNETID, (st), (val))
+#define sk_SXNETID_unshift(st, val) SKM_sk_unshift(SXNETID, (st), (val))
+#define sk_SXNETID_find(st, val) SKM_sk_find(SXNETID, (st), (val))
+#define sk_SXNETID_find_ex(st, val) SKM_sk_find_ex(SXNETID, (st), (val))
+#define sk_SXNETID_delete(st, i) SKM_sk_delete(SXNETID, (st), (i))
+#define sk_SXNETID_delete_ptr(st, ptr) SKM_sk_delete_ptr(SXNETID, (st), (ptr))
+#define sk_SXNETID_insert(st, val, i) SKM_sk_insert(SXNETID, (st), (val), (i))
+#define sk_SXNETID_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(SXNETID, (st), (cmp))
+#define sk_SXNETID_dup(st) SKM_sk_dup(SXNETID, st)
+#define sk_SXNETID_pop_free(st, free_func) SKM_sk_pop_free(SXNETID, (st), (free_func))
+#define sk_SXNETID_shift(st) SKM_sk_shift(SXNETID, (st))
+#define sk_SXNETID_pop(st) SKM_sk_pop(SXNETID, (st))
+#define sk_SXNETID_sort(st) SKM_sk_sort(SXNETID, (st))
+#define sk_SXNETID_is_sorted(st) SKM_sk_is_sorted(SXNETID, (st))
+
+#define sk_UI_STRING_new(st) SKM_sk_new(UI_STRING, (st))
+#define sk_UI_STRING_new_null() SKM_sk_new_null(UI_STRING)
+#define sk_UI_STRING_free(st) SKM_sk_free(UI_STRING, (st))
+#define sk_UI_STRING_num(st) SKM_sk_num(UI_STRING, (st))
+#define sk_UI_STRING_value(st, i) SKM_sk_value(UI_STRING, (st), (i))
+#define sk_UI_STRING_set(st, i, val) SKM_sk_set(UI_STRING, (st), (i), (val))
+#define sk_UI_STRING_zero(st) SKM_sk_zero(UI_STRING, (st))
+#define sk_UI_STRING_push(st, val) SKM_sk_push(UI_STRING, (st), (val))
+#define sk_UI_STRING_unshift(st, val) SKM_sk_unshift(UI_STRING, (st), (val))
+#define sk_UI_STRING_find(st, val) SKM_sk_find(UI_STRING, (st), (val))
+#define sk_UI_STRING_find_ex(st, val) SKM_sk_find_ex(UI_STRING, (st), (val))
+#define sk_UI_STRING_delete(st, i) SKM_sk_delete(UI_STRING, (st), (i))
+#define sk_UI_STRING_delete_ptr(st, ptr) SKM_sk_delete_ptr(UI_STRING, (st), (ptr))
+#define sk_UI_STRING_insert(st, val, i) SKM_sk_insert(UI_STRING, (st), (val), (i))
+#define sk_UI_STRING_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(UI_STRING, (st), (cmp))
+#define sk_UI_STRING_dup(st) SKM_sk_dup(UI_STRING, st)
+#define sk_UI_STRING_pop_free(st, free_func) SKM_sk_pop_free(UI_STRING, (st), (free_func))
+#define sk_UI_STRING_shift(st) SKM_sk_shift(UI_STRING, (st))
+#define sk_UI_STRING_pop(st) SKM_sk_pop(UI_STRING, (st))
+#define sk_UI_STRING_sort(st) SKM_sk_sort(UI_STRING, (st))
+#define sk_UI_STRING_is_sorted(st) SKM_sk_is_sorted(UI_STRING, (st))
+
+#define sk_X509_new(st) SKM_sk_new(X509, (st))
+#define sk_X509_new_null() SKM_sk_new_null(X509)
+#define sk_X509_free(st) SKM_sk_free(X509, (st))
+#define sk_X509_num(st) SKM_sk_num(X509, (st))
+#define sk_X509_value(st, i) SKM_sk_value(X509, (st), (i))
+#define sk_X509_set(st, i, val) SKM_sk_set(X509, (st), (i), (val))
+#define sk_X509_zero(st) SKM_sk_zero(X509, (st))
+#define sk_X509_push(st, val) SKM_sk_push(X509, (st), (val))
+#define sk_X509_unshift(st, val) SKM_sk_unshift(X509, (st), (val))
+#define sk_X509_find(st, val) SKM_sk_find(X509, (st), (val))
+#define sk_X509_find_ex(st, val) SKM_sk_find_ex(X509, (st), (val))
+#define sk_X509_delete(st, i) SKM_sk_delete(X509, (st), (i))
+#define sk_X509_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509, (st), (ptr))
+#define sk_X509_insert(st, val, i) SKM_sk_insert(X509, (st), (val), (i))
+#define sk_X509_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509, (st), (cmp))
+#define sk_X509_dup(st) SKM_sk_dup(X509, st)
+#define sk_X509_pop_free(st, free_func) SKM_sk_pop_free(X509, (st), (free_func))
+#define sk_X509_shift(st) SKM_sk_shift(X509, (st))
+#define sk_X509_pop(st) SKM_sk_pop(X509, (st))
+#define sk_X509_sort(st) SKM_sk_sort(X509, (st))
+#define sk_X509_is_sorted(st) SKM_sk_is_sorted(X509, (st))
+
+#define sk_X509V3_EXT_METHOD_new(st) SKM_sk_new(X509V3_EXT_METHOD, (st))
+#define sk_X509V3_EXT_METHOD_new_null() SKM_sk_new_null(X509V3_EXT_METHOD)
+#define sk_X509V3_EXT_METHOD_free(st) SKM_sk_free(X509V3_EXT_METHOD, (st))
+#define sk_X509V3_EXT_METHOD_num(st) SKM_sk_num(X509V3_EXT_METHOD, (st))
+#define sk_X509V3_EXT_METHOD_value(st, i) SKM_sk_value(X509V3_EXT_METHOD, (st), (i))
+#define sk_X509V3_EXT_METHOD_set(st, i, val) SKM_sk_set(X509V3_EXT_METHOD, (st), (i), (val))
+#define sk_X509V3_EXT_METHOD_zero(st) SKM_sk_zero(X509V3_EXT_METHOD, (st))
+#define sk_X509V3_EXT_METHOD_push(st, val) SKM_sk_push(X509V3_EXT_METHOD, (st), (val))
+#define sk_X509V3_EXT_METHOD_unshift(st, val) SKM_sk_unshift(X509V3_EXT_METHOD, (st), (val))
+#define sk_X509V3_EXT_METHOD_find(st, val) SKM_sk_find(X509V3_EXT_METHOD, (st), (val))
+#define sk_X509V3_EXT_METHOD_find_ex(st, val) SKM_sk_find_ex(X509V3_EXT_METHOD, (st), (val))
+#define sk_X509V3_EXT_METHOD_delete(st, i) SKM_sk_delete(X509V3_EXT_METHOD, (st), (i))
+#define sk_X509V3_EXT_METHOD_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509V3_EXT_METHOD, (st), (ptr))
+#define sk_X509V3_EXT_METHOD_insert(st, val, i) SKM_sk_insert(X509V3_EXT_METHOD, (st), (val), (i))
+#define sk_X509V3_EXT_METHOD_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509V3_EXT_METHOD, (st), (cmp))
+#define sk_X509V3_EXT_METHOD_dup(st) SKM_sk_dup(X509V3_EXT_METHOD, st)
+#define sk_X509V3_EXT_METHOD_pop_free(st, free_func) SKM_sk_pop_free(X509V3_EXT_METHOD, (st), (free_func))
+#define sk_X509V3_EXT_METHOD_shift(st) SKM_sk_shift(X509V3_EXT_METHOD, (st))
+#define sk_X509V3_EXT_METHOD_pop(st) SKM_sk_pop(X509V3_EXT_METHOD, (st))
+#define sk_X509V3_EXT_METHOD_sort(st) SKM_sk_sort(X509V3_EXT_METHOD, (st))
+#define sk_X509V3_EXT_METHOD_is_sorted(st) SKM_sk_is_sorted(X509V3_EXT_METHOD, (st))
+
+#define sk_X509_ALGOR_new(st) SKM_sk_new(X509_ALGOR, (st))
+#define sk_X509_ALGOR_new_null() SKM_sk_new_null(X509_ALGOR)
+#define sk_X509_ALGOR_free(st) SKM_sk_free(X509_ALGOR, (st))
+#define sk_X509_ALGOR_num(st) SKM_sk_num(X509_ALGOR, (st))
+#define sk_X509_ALGOR_value(st, i) SKM_sk_value(X509_ALGOR, (st), (i))
+#define sk_X509_ALGOR_set(st, i, val) SKM_sk_set(X509_ALGOR, (st), (i), (val))
+#define sk_X509_ALGOR_zero(st) SKM_sk_zero(X509_ALGOR, (st))
+#define sk_X509_ALGOR_push(st, val) SKM_sk_push(X509_ALGOR, (st), (val))
+#define sk_X509_ALGOR_unshift(st, val) SKM_sk_unshift(X509_ALGOR, (st), (val))
+#define sk_X509_ALGOR_find(st, val) SKM_sk_find(X509_ALGOR, (st), (val))
+#define sk_X509_ALGOR_find_ex(st, val) SKM_sk_find_ex(X509_ALGOR, (st), (val))
+#define sk_X509_ALGOR_delete(st, i) SKM_sk_delete(X509_ALGOR, (st), (i))
+#define sk_X509_ALGOR_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_ALGOR, (st), (ptr))
+#define sk_X509_ALGOR_insert(st, val, i) SKM_sk_insert(X509_ALGOR, (st), (val), (i))
+#define sk_X509_ALGOR_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_ALGOR, (st), (cmp))
+#define sk_X509_ALGOR_dup(st) SKM_sk_dup(X509_ALGOR, st)
+#define sk_X509_ALGOR_pop_free(st, free_func) SKM_sk_pop_free(X509_ALGOR, (st), (free_func))
+#define sk_X509_ALGOR_shift(st) SKM_sk_shift(X509_ALGOR, (st))
+#define sk_X509_ALGOR_pop(st) SKM_sk_pop(X509_ALGOR, (st))
+#define sk_X509_ALGOR_sort(st) SKM_sk_sort(X509_ALGOR, (st))
+#define sk_X509_ALGOR_is_sorted(st) SKM_sk_is_sorted(X509_ALGOR, (st))
+
+#define sk_X509_ATTRIBUTE_new(st) SKM_sk_new(X509_ATTRIBUTE, (st))
+#define sk_X509_ATTRIBUTE_new_null() SKM_sk_new_null(X509_ATTRIBUTE)
+#define sk_X509_ATTRIBUTE_free(st) SKM_sk_free(X509_ATTRIBUTE, (st))
+#define sk_X509_ATTRIBUTE_num(st) SKM_sk_num(X509_ATTRIBUTE, (st))
+#define sk_X509_ATTRIBUTE_value(st, i) SKM_sk_value(X509_ATTRIBUTE, (st), (i))
+#define sk_X509_ATTRIBUTE_set(st, i, val) SKM_sk_set(X509_ATTRIBUTE, (st), (i), (val))
+#define sk_X509_ATTRIBUTE_zero(st) SKM_sk_zero(X509_ATTRIBUTE, (st))
+#define sk_X509_ATTRIBUTE_push(st, val) SKM_sk_push(X509_ATTRIBUTE, (st), (val))
+#define sk_X509_ATTRIBUTE_unshift(st, val) SKM_sk_unshift(X509_ATTRIBUTE, (st), (val))
+#define sk_X509_ATTRIBUTE_find(st, val) SKM_sk_find(X509_ATTRIBUTE, (st), (val))
+#define sk_X509_ATTRIBUTE_find_ex(st, val) SKM_sk_find_ex(X509_ATTRIBUTE, (st), (val))
+#define sk_X509_ATTRIBUTE_delete(st, i) SKM_sk_delete(X509_ATTRIBUTE, (st), (i))
+#define sk_X509_ATTRIBUTE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_ATTRIBUTE, (st), (ptr))
+#define sk_X509_ATTRIBUTE_insert(st, val, i) SKM_sk_insert(X509_ATTRIBUTE, (st), (val), (i))
+#define sk_X509_ATTRIBUTE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_ATTRIBUTE, (st), (cmp))
+#define sk_X509_ATTRIBUTE_dup(st) SKM_sk_dup(X509_ATTRIBUTE, st)
+#define sk_X509_ATTRIBUTE_pop_free(st, free_func) SKM_sk_pop_free(X509_ATTRIBUTE, (st), (free_func))
+#define sk_X509_ATTRIBUTE_shift(st) SKM_sk_shift(X509_ATTRIBUTE, (st))
+#define sk_X509_ATTRIBUTE_pop(st) SKM_sk_pop(X509_ATTRIBUTE, (st))
+#define sk_X509_ATTRIBUTE_sort(st) SKM_sk_sort(X509_ATTRIBUTE, (st))
+#define sk_X509_ATTRIBUTE_is_sorted(st) SKM_sk_is_sorted(X509_ATTRIBUTE, (st))
+
+#define sk_X509_CRL_new(st) SKM_sk_new(X509_CRL, (st))
+#define sk_X509_CRL_new_null() SKM_sk_new_null(X509_CRL)
+#define sk_X509_CRL_free(st) SKM_sk_free(X509_CRL, (st))
+#define sk_X509_CRL_num(st) SKM_sk_num(X509_CRL, (st))
+#define sk_X509_CRL_value(st, i) SKM_sk_value(X509_CRL, (st), (i))
+#define sk_X509_CRL_set(st, i, val) SKM_sk_set(X509_CRL, (st), (i), (val))
+#define sk_X509_CRL_zero(st) SKM_sk_zero(X509_CRL, (st))
+#define sk_X509_CRL_push(st, val) SKM_sk_push(X509_CRL, (st), (val))
+#define sk_X509_CRL_unshift(st, val) SKM_sk_unshift(X509_CRL, (st), (val))
+#define sk_X509_CRL_find(st, val) SKM_sk_find(X509_CRL, (st), (val))
+#define sk_X509_CRL_find_ex(st, val) SKM_sk_find_ex(X509_CRL, (st), (val))
+#define sk_X509_CRL_delete(st, i) SKM_sk_delete(X509_CRL, (st), (i))
+#define sk_X509_CRL_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_CRL, (st), (ptr))
+#define sk_X509_CRL_insert(st, val, i) SKM_sk_insert(X509_CRL, (st), (val), (i))
+#define sk_X509_CRL_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_CRL, (st), (cmp))
+#define sk_X509_CRL_dup(st) SKM_sk_dup(X509_CRL, st)
+#define sk_X509_CRL_pop_free(st, free_func) SKM_sk_pop_free(X509_CRL, (st), (free_func))
+#define sk_X509_CRL_shift(st) SKM_sk_shift(X509_CRL, (st))
+#define sk_X509_CRL_pop(st) SKM_sk_pop(X509_CRL, (st))
+#define sk_X509_CRL_sort(st) SKM_sk_sort(X509_CRL, (st))
+#define sk_X509_CRL_is_sorted(st) SKM_sk_is_sorted(X509_CRL, (st))
+
+#define sk_X509_EXTENSION_new(st) SKM_sk_new(X509_EXTENSION, (st))
+#define sk_X509_EXTENSION_new_null() SKM_sk_new_null(X509_EXTENSION)
+#define sk_X509_EXTENSION_free(st) SKM_sk_free(X509_EXTENSION, (st))
+#define sk_X509_EXTENSION_num(st) SKM_sk_num(X509_EXTENSION, (st))
+#define sk_X509_EXTENSION_value(st, i) SKM_sk_value(X509_EXTENSION, (st), (i))
+#define sk_X509_EXTENSION_set(st, i, val) SKM_sk_set(X509_EXTENSION, (st), (i), (val))
+#define sk_X509_EXTENSION_zero(st) SKM_sk_zero(X509_EXTENSION, (st))
+#define sk_X509_EXTENSION_push(st, val) SKM_sk_push(X509_EXTENSION, (st), (val))
+#define sk_X509_EXTENSION_unshift(st, val) SKM_sk_unshift(X509_EXTENSION, (st), (val))
+#define sk_X509_EXTENSION_find(st, val) SKM_sk_find(X509_EXTENSION, (st), (val))
+#define sk_X509_EXTENSION_find_ex(st, val) SKM_sk_find_ex(X509_EXTENSION, (st), (val))
+#define sk_X509_EXTENSION_delete(st, i) SKM_sk_delete(X509_EXTENSION, (st), (i))
+#define sk_X509_EXTENSION_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_EXTENSION, (st), (ptr))
+#define sk_X509_EXTENSION_insert(st, val, i) SKM_sk_insert(X509_EXTENSION, (st), (val), (i))
+#define sk_X509_EXTENSION_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_EXTENSION, (st), (cmp))
+#define sk_X509_EXTENSION_dup(st) SKM_sk_dup(X509_EXTENSION, st)
+#define sk_X509_EXTENSION_pop_free(st, free_func) SKM_sk_pop_free(X509_EXTENSION, (st), (free_func))
+#define sk_X509_EXTENSION_shift(st) SKM_sk_shift(X509_EXTENSION, (st))
+#define sk_X509_EXTENSION_pop(st) SKM_sk_pop(X509_EXTENSION, (st))
+#define sk_X509_EXTENSION_sort(st) SKM_sk_sort(X509_EXTENSION, (st))
+#define sk_X509_EXTENSION_is_sorted(st) SKM_sk_is_sorted(X509_EXTENSION, (st))
+
+#define sk_X509_INFO_new(st) SKM_sk_new(X509_INFO, (st))
+#define sk_X509_INFO_new_null() SKM_sk_new_null(X509_INFO)
+#define sk_X509_INFO_free(st) SKM_sk_free(X509_INFO, (st))
+#define sk_X509_INFO_num(st) SKM_sk_num(X509_INFO, (st))
+#define sk_X509_INFO_value(st, i) SKM_sk_value(X509_INFO, (st), (i))
+#define sk_X509_INFO_set(st, i, val) SKM_sk_set(X509_INFO, (st), (i), (val))
+#define sk_X509_INFO_zero(st) SKM_sk_zero(X509_INFO, (st))
+#define sk_X509_INFO_push(st, val) SKM_sk_push(X509_INFO, (st), (val))
+#define sk_X509_INFO_unshift(st, val) SKM_sk_unshift(X509_INFO, (st), (val))
+#define sk_X509_INFO_find(st, val) SKM_sk_find(X509_INFO, (st), (val))
+#define sk_X509_INFO_find_ex(st, val) SKM_sk_find_ex(X509_INFO, (st), (val))
+#define sk_X509_INFO_delete(st, i) SKM_sk_delete(X509_INFO, (st), (i))
+#define sk_X509_INFO_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_INFO, (st), (ptr))
+#define sk_X509_INFO_insert(st, val, i) SKM_sk_insert(X509_INFO, (st), (val), (i))
+#define sk_X509_INFO_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_INFO, (st), (cmp))
+#define sk_X509_INFO_dup(st) SKM_sk_dup(X509_INFO, st)
+#define sk_X509_INFO_pop_free(st, free_func) SKM_sk_pop_free(X509_INFO, (st), (free_func))
+#define sk_X509_INFO_shift(st) SKM_sk_shift(X509_INFO, (st))
+#define sk_X509_INFO_pop(st) SKM_sk_pop(X509_INFO, (st))
+#define sk_X509_INFO_sort(st) SKM_sk_sort(X509_INFO, (st))
+#define sk_X509_INFO_is_sorted(st) SKM_sk_is_sorted(X509_INFO, (st))
+
+#define sk_X509_LOOKUP_new(st) SKM_sk_new(X509_LOOKUP, (st))
+#define sk_X509_LOOKUP_new_null() SKM_sk_new_null(X509_LOOKUP)
+#define sk_X509_LOOKUP_free(st) SKM_sk_free(X509_LOOKUP, (st))
+#define sk_X509_LOOKUP_num(st) SKM_sk_num(X509_LOOKUP, (st))
+#define sk_X509_LOOKUP_value(st, i) SKM_sk_value(X509_LOOKUP, (st), (i))
+#define sk_X509_LOOKUP_set(st, i, val) SKM_sk_set(X509_LOOKUP, (st), (i), (val))
+#define sk_X509_LOOKUP_zero(st) SKM_sk_zero(X509_LOOKUP, (st))
+#define sk_X509_LOOKUP_push(st, val) SKM_sk_push(X509_LOOKUP, (st), (val))
+#define sk_X509_LOOKUP_unshift(st, val) SKM_sk_unshift(X509_LOOKUP, (st), (val))
+#define sk_X509_LOOKUP_find(st, val) SKM_sk_find(X509_LOOKUP, (st), (val))
+#define sk_X509_LOOKUP_find_ex(st, val) SKM_sk_find_ex(X509_LOOKUP, (st), (val))
+#define sk_X509_LOOKUP_delete(st, i) SKM_sk_delete(X509_LOOKUP, (st), (i))
+#define sk_X509_LOOKUP_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_LOOKUP, (st), (ptr))
+#define sk_X509_LOOKUP_insert(st, val, i) SKM_sk_insert(X509_LOOKUP, (st), (val), (i))
+#define sk_X509_LOOKUP_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_LOOKUP, (st), (cmp))
+#define sk_X509_LOOKUP_dup(st) SKM_sk_dup(X509_LOOKUP, st)
+#define sk_X509_LOOKUP_pop_free(st, free_func) SKM_sk_pop_free(X509_LOOKUP, (st), (free_func))
+#define sk_X509_LOOKUP_shift(st) SKM_sk_shift(X509_LOOKUP, (st))
+#define sk_X509_LOOKUP_pop(st) SKM_sk_pop(X509_LOOKUP, (st))
+#define sk_X509_LOOKUP_sort(st) SKM_sk_sort(X509_LOOKUP, (st))
+#define sk_X509_LOOKUP_is_sorted(st) SKM_sk_is_sorted(X509_LOOKUP, (st))
+
+#define sk_X509_NAME_new(st) SKM_sk_new(X509_NAME, (st))
+#define sk_X509_NAME_new_null() SKM_sk_new_null(X509_NAME)
+#define sk_X509_NAME_free(st) SKM_sk_free(X509_NAME, (st))
+#define sk_X509_NAME_num(st) SKM_sk_num(X509_NAME, (st))
+#define sk_X509_NAME_value(st, i) SKM_sk_value(X509_NAME, (st), (i))
+#define sk_X509_NAME_set(st, i, val) SKM_sk_set(X509_NAME, (st), (i), (val))
+#define sk_X509_NAME_zero(st) SKM_sk_zero(X509_NAME, (st))
+#define sk_X509_NAME_push(st, val) SKM_sk_push(X509_NAME, (st), (val))
+#define sk_X509_NAME_unshift(st, val) SKM_sk_unshift(X509_NAME, (st), (val))
+#define sk_X509_NAME_find(st, val) SKM_sk_find(X509_NAME, (st), (val))
+#define sk_X509_NAME_find_ex(st, val) SKM_sk_find_ex(X509_NAME, (st), (val))
+#define sk_X509_NAME_delete(st, i) SKM_sk_delete(X509_NAME, (st), (i))
+#define sk_X509_NAME_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_NAME, (st), (ptr))
+#define sk_X509_NAME_insert(st, val, i) SKM_sk_insert(X509_NAME, (st), (val), (i))
+#define sk_X509_NAME_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_NAME, (st), (cmp))
+#define sk_X509_NAME_dup(st) SKM_sk_dup(X509_NAME, st)
+#define sk_X509_NAME_pop_free(st, free_func) SKM_sk_pop_free(X509_NAME, (st), (free_func))
+#define sk_X509_NAME_shift(st) SKM_sk_shift(X509_NAME, (st))
+#define sk_X509_NAME_pop(st) SKM_sk_pop(X509_NAME, (st))
+#define sk_X509_NAME_sort(st) SKM_sk_sort(X509_NAME, (st))
+#define sk_X509_NAME_is_sorted(st) SKM_sk_is_sorted(X509_NAME, (st))
+
+#define sk_X509_NAME_ENTRY_new(st) SKM_sk_new(X509_NAME_ENTRY, (st))
+#define sk_X509_NAME_ENTRY_new_null() SKM_sk_new_null(X509_NAME_ENTRY)
+#define sk_X509_NAME_ENTRY_free(st) SKM_sk_free(X509_NAME_ENTRY, (st))
+#define sk_X509_NAME_ENTRY_num(st) SKM_sk_num(X509_NAME_ENTRY, (st))
+#define sk_X509_NAME_ENTRY_value(st, i) SKM_sk_value(X509_NAME_ENTRY, (st), (i))
+#define sk_X509_NAME_ENTRY_set(st, i, val) SKM_sk_set(X509_NAME_ENTRY, (st), (i), (val))
+#define sk_X509_NAME_ENTRY_zero(st) SKM_sk_zero(X509_NAME_ENTRY, (st))
+#define sk_X509_NAME_ENTRY_push(st, val) SKM_sk_push(X509_NAME_ENTRY, (st), (val))
+#define sk_X509_NAME_ENTRY_unshift(st, val) SKM_sk_unshift(X509_NAME_ENTRY, (st), (val))
+#define sk_X509_NAME_ENTRY_find(st, val) SKM_sk_find(X509_NAME_ENTRY, (st), (val))
+#define sk_X509_NAME_ENTRY_find_ex(st, val) SKM_sk_find_ex(X509_NAME_ENTRY, (st), (val))
+#define sk_X509_NAME_ENTRY_delete(st, i) SKM_sk_delete(X509_NAME_ENTRY, (st), (i))
+#define sk_X509_NAME_ENTRY_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_NAME_ENTRY, (st), (ptr))
+#define sk_X509_NAME_ENTRY_insert(st, val, i) SKM_sk_insert(X509_NAME_ENTRY, (st), (val), (i))
+#define sk_X509_NAME_ENTRY_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_NAME_ENTRY, (st), (cmp))
+#define sk_X509_NAME_ENTRY_dup(st) SKM_sk_dup(X509_NAME_ENTRY, st)
+#define sk_X509_NAME_ENTRY_pop_free(st, free_func) SKM_sk_pop_free(X509_NAME_ENTRY, (st), (free_func))
+#define sk_X509_NAME_ENTRY_shift(st) SKM_sk_shift(X509_NAME_ENTRY, (st))
+#define sk_X509_NAME_ENTRY_pop(st) SKM_sk_pop(X509_NAME_ENTRY, (st))
+#define sk_X509_NAME_ENTRY_sort(st) SKM_sk_sort(X509_NAME_ENTRY, (st))
+#define sk_X509_NAME_ENTRY_is_sorted(st) SKM_sk_is_sorted(X509_NAME_ENTRY, (st))
+
+#define sk_X509_OBJECT_new(st) SKM_sk_new(X509_OBJECT, (st))
+#define sk_X509_OBJECT_new_null() SKM_sk_new_null(X509_OBJECT)
+#define sk_X509_OBJECT_free(st) SKM_sk_free(X509_OBJECT, (st))
+#define sk_X509_OBJECT_num(st) SKM_sk_num(X509_OBJECT, (st))
+#define sk_X509_OBJECT_value(st, i) SKM_sk_value(X509_OBJECT, (st), (i))
+#define sk_X509_OBJECT_set(st, i, val) SKM_sk_set(X509_OBJECT, (st), (i), (val))
+#define sk_X509_OBJECT_zero(st) SKM_sk_zero(X509_OBJECT, (st))
+#define sk_X509_OBJECT_push(st, val) SKM_sk_push(X509_OBJECT, (st), (val))
+#define sk_X509_OBJECT_unshift(st, val) SKM_sk_unshift(X509_OBJECT, (st), (val))
+#define sk_X509_OBJECT_find(st, val) SKM_sk_find(X509_OBJECT, (st), (val))
+#define sk_X509_OBJECT_find_ex(st, val) SKM_sk_find_ex(X509_OBJECT, (st), (val))
+#define sk_X509_OBJECT_delete(st, i) SKM_sk_delete(X509_OBJECT, (st), (i))
+#define sk_X509_OBJECT_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_OBJECT, (st), (ptr))
+#define sk_X509_OBJECT_insert(st, val, i) SKM_sk_insert(X509_OBJECT, (st), (val), (i))
+#define sk_X509_OBJECT_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_OBJECT, (st), (cmp))
+#define sk_X509_OBJECT_dup(st) SKM_sk_dup(X509_OBJECT, st)
+#define sk_X509_OBJECT_pop_free(st, free_func) SKM_sk_pop_free(X509_OBJECT, (st), (free_func))
+#define sk_X509_OBJECT_shift(st) SKM_sk_shift(X509_OBJECT, (st))
+#define sk_X509_OBJECT_pop(st) SKM_sk_pop(X509_OBJECT, (st))
+#define sk_X509_OBJECT_sort(st) SKM_sk_sort(X509_OBJECT, (st))
+#define sk_X509_OBJECT_is_sorted(st) SKM_sk_is_sorted(X509_OBJECT, (st))
+
+#define sk_X509_POLICY_DATA_new(st) SKM_sk_new(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_new_null() SKM_sk_new_null(X509_POLICY_DATA)
+#define sk_X509_POLICY_DATA_free(st) SKM_sk_free(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_num(st) SKM_sk_num(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_value(st, i) SKM_sk_value(X509_POLICY_DATA, (st), (i))
+#define sk_X509_POLICY_DATA_set(st, i, val) SKM_sk_set(X509_POLICY_DATA, (st), (i), (val))
+#define sk_X509_POLICY_DATA_zero(st) SKM_sk_zero(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_push(st, val) SKM_sk_push(X509_POLICY_DATA, (st), (val))
+#define sk_X509_POLICY_DATA_unshift(st, val) SKM_sk_unshift(X509_POLICY_DATA, (st), (val))
+#define sk_X509_POLICY_DATA_find(st, val) SKM_sk_find(X509_POLICY_DATA, (st), (val))
+#define sk_X509_POLICY_DATA_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_DATA, (st), (val))
+#define sk_X509_POLICY_DATA_delete(st, i) SKM_sk_delete(X509_POLICY_DATA, (st), (i))
+#define sk_X509_POLICY_DATA_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_DATA, (st), (ptr))
+#define sk_X509_POLICY_DATA_insert(st, val, i) SKM_sk_insert(X509_POLICY_DATA, (st), (val), (i))
+#define sk_X509_POLICY_DATA_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_DATA, (st), (cmp))
+#define sk_X509_POLICY_DATA_dup(st) SKM_sk_dup(X509_POLICY_DATA, st)
+#define sk_X509_POLICY_DATA_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_DATA, (st), (free_func))
+#define sk_X509_POLICY_DATA_shift(st) SKM_sk_shift(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_pop(st) SKM_sk_pop(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_sort(st) SKM_sk_sort(X509_POLICY_DATA, (st))
+#define sk_X509_POLICY_DATA_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_DATA, (st))
+
+#define sk_X509_POLICY_NODE_new(st) SKM_sk_new(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_new_null() SKM_sk_new_null(X509_POLICY_NODE)
+#define sk_X509_POLICY_NODE_free(st) SKM_sk_free(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_num(st) SKM_sk_num(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_value(st, i) SKM_sk_value(X509_POLICY_NODE, (st), (i))
+#define sk_X509_POLICY_NODE_set(st, i, val) SKM_sk_set(X509_POLICY_NODE, (st), (i), (val))
+#define sk_X509_POLICY_NODE_zero(st) SKM_sk_zero(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_push(st, val) SKM_sk_push(X509_POLICY_NODE, (st), (val))
+#define sk_X509_POLICY_NODE_unshift(st, val) SKM_sk_unshift(X509_POLICY_NODE, (st), (val))
+#define sk_X509_POLICY_NODE_find(st, val) SKM_sk_find(X509_POLICY_NODE, (st), (val))
+#define sk_X509_POLICY_NODE_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_NODE, (st), (val))
+#define sk_X509_POLICY_NODE_delete(st, i) SKM_sk_delete(X509_POLICY_NODE, (st), (i))
+#define sk_X509_POLICY_NODE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_NODE, (st), (ptr))
+#define sk_X509_POLICY_NODE_insert(st, val, i) SKM_sk_insert(X509_POLICY_NODE, (st), (val), (i))
+#define sk_X509_POLICY_NODE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_NODE, (st), (cmp))
+#define sk_X509_POLICY_NODE_dup(st) SKM_sk_dup(X509_POLICY_NODE, st)
+#define sk_X509_POLICY_NODE_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_NODE, (st), (free_func))
+#define sk_X509_POLICY_NODE_shift(st) SKM_sk_shift(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_pop(st) SKM_sk_pop(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_sort(st) SKM_sk_sort(X509_POLICY_NODE, (st))
+#define sk_X509_POLICY_NODE_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_NODE, (st))
+
+#define sk_X509_POLICY_REF_new(st) SKM_sk_new(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_new_null() SKM_sk_new_null(X509_POLICY_REF)
+#define sk_X509_POLICY_REF_free(st) SKM_sk_free(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_num(st) SKM_sk_num(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_value(st, i) SKM_sk_value(X509_POLICY_REF, (st), (i))
+#define sk_X509_POLICY_REF_set(st, i, val) SKM_sk_set(X509_POLICY_REF, (st), (i), (val))
+#define sk_X509_POLICY_REF_zero(st) SKM_sk_zero(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_push(st, val) SKM_sk_push(X509_POLICY_REF, (st), (val))
+#define sk_X509_POLICY_REF_unshift(st, val) SKM_sk_unshift(X509_POLICY_REF, (st), (val))
+#define sk_X509_POLICY_REF_find(st, val) SKM_sk_find(X509_POLICY_REF, (st), (val))
+#define sk_X509_POLICY_REF_find_ex(st, val) SKM_sk_find_ex(X509_POLICY_REF, (st), (val))
+#define sk_X509_POLICY_REF_delete(st, i) SKM_sk_delete(X509_POLICY_REF, (st), (i))
+#define sk_X509_POLICY_REF_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_POLICY_REF, (st), (ptr))
+#define sk_X509_POLICY_REF_insert(st, val, i) SKM_sk_insert(X509_POLICY_REF, (st), (val), (i))
+#define sk_X509_POLICY_REF_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_POLICY_REF, (st), (cmp))
+#define sk_X509_POLICY_REF_dup(st) SKM_sk_dup(X509_POLICY_REF, st)
+#define sk_X509_POLICY_REF_pop_free(st, free_func) SKM_sk_pop_free(X509_POLICY_REF, (st), (free_func))
+#define sk_X509_POLICY_REF_shift(st) SKM_sk_shift(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_pop(st) SKM_sk_pop(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_sort(st) SKM_sk_sort(X509_POLICY_REF, (st))
+#define sk_X509_POLICY_REF_is_sorted(st) SKM_sk_is_sorted(X509_POLICY_REF, (st))
+
+#define sk_X509_PURPOSE_new(st) SKM_sk_new(X509_PURPOSE, (st))
+#define sk_X509_PURPOSE_new_null() SKM_sk_new_null(X509_PURPOSE)
+#define sk_X509_PURPOSE_free(st) SKM_sk_free(X509_PURPOSE, (st))
+#define sk_X509_PURPOSE_num(st) SKM_sk_num(X509_PURPOSE, (st))
+#define sk_X509_PURPOSE_value(st, i) SKM_sk_value(X509_PURPOSE, (st), (i))
+#define sk_X509_PURPOSE_set(st, i, val) SKM_sk_set(X509_PURPOSE, (st), (i), (val))
+#define sk_X509_PURPOSE_zero(st) SKM_sk_zero(X509_PURPOSE, (st))
+#define sk_X509_PURPOSE_push(st, val) SKM_sk_push(X509_PURPOSE, (st), (val))
+#define sk_X509_PURPOSE_unshift(st, val) SKM_sk_unshift(X509_PURPOSE, (st), (val))
+#define sk_X509_PURPOSE_find(st, val) SKM_sk_find(X509_PURPOSE, (st), (val))
+#define sk_X509_PURPOSE_find_ex(st, val) SKM_sk_find_ex(X509_PURPOSE, (st), (val))
+#define sk_X509_PURPOSE_delete(st, i) SKM_sk_delete(X509_PURPOSE, (st), (i))
+#define sk_X509_PURPOSE_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_PURPOSE, (st), (ptr))
+#define sk_X509_PURPOSE_insert(st, val, i) SKM_sk_insert(X509_PURPOSE, (st), (val), (i))
+#define sk_X509_PURPOSE_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_PURPOSE, (st), (cmp))
+#define sk_X509_PURPOSE_dup(st) SKM_sk_dup(X509_PURPOSE, st)
+#define sk_X509_PURPOSE_pop_free(st, free_func) SKM_sk_pop_free(X509_PURPOSE, (st), (free_func))
+#define sk_X509_PURPOSE_shift(st) SKM_sk_shift(X509_PURPOSE, (st))
+#define sk_X509_PURPOSE_pop(st) SKM_sk_pop(X509_PURPOSE, (st))
+#define sk_X509_PURPOSE_sort(st) SKM_sk_sort(X509_PURPOSE, (st))
+#define sk_X509_PURPOSE_is_sorted(st) SKM_sk_is_sorted(X509_PURPOSE, (st))
+
+#define sk_X509_REVOKED_new(st) SKM_sk_new(X509_REVOKED, (st))
+#define sk_X509_REVOKED_new_null() SKM_sk_new_null(X509_REVOKED)
+#define sk_X509_REVOKED_free(st) SKM_sk_free(X509_REVOKED, (st))
+#define sk_X509_REVOKED_num(st) SKM_sk_num(X509_REVOKED, (st))
+#define sk_X509_REVOKED_value(st, i) SKM_sk_value(X509_REVOKED, (st), (i))
+#define sk_X509_REVOKED_set(st, i, val) SKM_sk_set(X509_REVOKED, (st), (i), (val))
+#define sk_X509_REVOKED_zero(st) SKM_sk_zero(X509_REVOKED, (st))
+#define sk_X509_REVOKED_push(st, val) SKM_sk_push(X509_REVOKED, (st), (val))
+#define sk_X509_REVOKED_unshift(st, val) SKM_sk_unshift(X509_REVOKED, (st), (val))
+#define sk_X509_REVOKED_find(st, val) SKM_sk_find(X509_REVOKED, (st), (val))
+#define sk_X509_REVOKED_find_ex(st, val) SKM_sk_find_ex(X509_REVOKED, (st), (val))
+#define sk_X509_REVOKED_delete(st, i) SKM_sk_delete(X509_REVOKED, (st), (i))
+#define sk_X509_REVOKED_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_REVOKED, (st), (ptr))
+#define sk_X509_REVOKED_insert(st, val, i) SKM_sk_insert(X509_REVOKED, (st), (val), (i))
+#define sk_X509_REVOKED_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_REVOKED, (st), (cmp))
+#define sk_X509_REVOKED_dup(st) SKM_sk_dup(X509_REVOKED, st)
+#define sk_X509_REVOKED_pop_free(st, free_func) SKM_sk_pop_free(X509_REVOKED, (st), (free_func))
+#define sk_X509_REVOKED_shift(st) SKM_sk_shift(X509_REVOKED, (st))
+#define sk_X509_REVOKED_pop(st) SKM_sk_pop(X509_REVOKED, (st))
+#define sk_X509_REVOKED_sort(st) SKM_sk_sort(X509_REVOKED, (st))
+#define sk_X509_REVOKED_is_sorted(st) SKM_sk_is_sorted(X509_REVOKED, (st))
+
+#define sk_X509_TRUST_new(st) SKM_sk_new(X509_TRUST, (st))
+#define sk_X509_TRUST_new_null() SKM_sk_new_null(X509_TRUST)
+#define sk_X509_TRUST_free(st) SKM_sk_free(X509_TRUST, (st))
+#define sk_X509_TRUST_num(st) SKM_sk_num(X509_TRUST, (st))
+#define sk_X509_TRUST_value(st, i) SKM_sk_value(X509_TRUST, (st), (i))
+#define sk_X509_TRUST_set(st, i, val) SKM_sk_set(X509_TRUST, (st), (i), (val))
+#define sk_X509_TRUST_zero(st) SKM_sk_zero(X509_TRUST, (st))
+#define sk_X509_TRUST_push(st, val) SKM_sk_push(X509_TRUST, (st), (val))
+#define sk_X509_TRUST_unshift(st, val) SKM_sk_unshift(X509_TRUST, (st), (val))
+#define sk_X509_TRUST_find(st, val) SKM_sk_find(X509_TRUST, (st), (val))
+#define sk_X509_TRUST_find_ex(st, val) SKM_sk_find_ex(X509_TRUST, (st), (val))
+#define sk_X509_TRUST_delete(st, i) SKM_sk_delete(X509_TRUST, (st), (i))
+#define sk_X509_TRUST_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_TRUST, (st), (ptr))
+#define sk_X509_TRUST_insert(st, val, i) SKM_sk_insert(X509_TRUST, (st), (val), (i))
+#define sk_X509_TRUST_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_TRUST, (st), (cmp))
+#define sk_X509_TRUST_dup(st) SKM_sk_dup(X509_TRUST, st)
+#define sk_X509_TRUST_pop_free(st, free_func) SKM_sk_pop_free(X509_TRUST, (st), (free_func))
+#define sk_X509_TRUST_shift(st) SKM_sk_shift(X509_TRUST, (st))
+#define sk_X509_TRUST_pop(st) SKM_sk_pop(X509_TRUST, (st))
+#define sk_X509_TRUST_sort(st) SKM_sk_sort(X509_TRUST, (st))
+#define sk_X509_TRUST_is_sorted(st) SKM_sk_is_sorted(X509_TRUST, (st))
+
+#define sk_X509_VERIFY_PARAM_new(st) SKM_sk_new(X509_VERIFY_PARAM, (st))
+#define sk_X509_VERIFY_PARAM_new_null() SKM_sk_new_null(X509_VERIFY_PARAM)
+#define sk_X509_VERIFY_PARAM_free(st) SKM_sk_free(X509_VERIFY_PARAM, (st))
+#define sk_X509_VERIFY_PARAM_num(st) SKM_sk_num(X509_VERIFY_PARAM, (st))
+#define sk_X509_VERIFY_PARAM_value(st, i) SKM_sk_value(X509_VERIFY_PARAM, (st), (i))
+#define sk_X509_VERIFY_PARAM_set(st, i, val) SKM_sk_set(X509_VERIFY_PARAM, (st), (i), (val))
+#define sk_X509_VERIFY_PARAM_zero(st) SKM_sk_zero(X509_VERIFY_PARAM, (st))
+#define sk_X509_VERIFY_PARAM_push(st, val) SKM_sk_push(X509_VERIFY_PARAM, (st), (val))
+#define sk_X509_VERIFY_PARAM_unshift(st, val) SKM_sk_unshift(X509_VERIFY_PARAM, (st), (val))
+#define sk_X509_VERIFY_PARAM_find(st, val) SKM_sk_find(X509_VERIFY_PARAM, (st), (val))
+#define sk_X509_VERIFY_PARAM_find_ex(st, val) SKM_sk_find_ex(X509_VERIFY_PARAM, (st), (val))
+#define sk_X509_VERIFY_PARAM_delete(st, i) SKM_sk_delete(X509_VERIFY_PARAM, (st), (i))
+#define sk_X509_VERIFY_PARAM_delete_ptr(st, ptr) SKM_sk_delete_ptr(X509_VERIFY_PARAM, (st), (ptr))
+#define sk_X509_VERIFY_PARAM_insert(st, val, i) SKM_sk_insert(X509_VERIFY_PARAM, (st), (val), (i))
+#define sk_X509_VERIFY_PARAM_set_cmp_func(st, cmp) SKM_sk_set_cmp_func(X509_VERIFY_PARAM, (st), (cmp))
+#define sk_X509_VERIFY_PARAM_dup(st) SKM_sk_dup(X509_VERIFY_PARAM, st)
+#define sk_X509_VERIFY_PARAM_pop_free(st, free_func) SKM_sk_pop_free(X509_VERIFY_PARAM, (st), (free_func))
+#define sk_X509_VERIFY_PARAM_shift(st) SKM_sk_shift(X509_VERIFY_PARAM, (st))
+#define sk_X509_VERIFY_PARAM_pop(st) SKM_sk_pop(X509_VERIFY_PARAM, (st))
+#define sk_X509_VERIFY_PARAM_sort(st) SKM_sk_sort(X509_VERIFY_PARAM, (st))
+#define sk_X509_VERIFY_PARAM_is_sorted(st) SKM_sk_is_sorted(X509_VERIFY_PARAM, (st))
+
+#define d2i_ASN1_SET_OF_ACCESS_DESCRIPTION(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(ACCESS_DESCRIPTION, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_ACCESS_DESCRIPTION(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(ACCESS_DESCRIPTION, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_ACCESS_DESCRIPTION(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(ACCESS_DESCRIPTION, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_ACCESS_DESCRIPTION(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(ACCESS_DESCRIPTION, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_ASN1_INTEGER(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(ASN1_INTEGER, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_ASN1_INTEGER(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(ASN1_INTEGER, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_ASN1_INTEGER(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(ASN1_INTEGER, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_ASN1_INTEGER(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(ASN1_INTEGER, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_ASN1_OBJECT(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(ASN1_OBJECT, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_ASN1_OBJECT(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(ASN1_OBJECT, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_ASN1_OBJECT(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(ASN1_OBJECT, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_ASN1_OBJECT(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(ASN1_OBJECT, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_ASN1_TYPE(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(ASN1_TYPE, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_ASN1_TYPE(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(ASN1_TYPE, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_ASN1_TYPE(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(ASN1_TYPE, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_ASN1_TYPE(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(ASN1_TYPE, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_DIST_POINT(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(DIST_POINT, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_DIST_POINT(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(DIST_POINT, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_DIST_POINT(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(DIST_POINT, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_DIST_POINT(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(DIST_POINT, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_GENERAL_NAME(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(GENERAL_NAME, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_GENERAL_NAME(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(GENERAL_NAME, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_GENERAL_NAME(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(GENERAL_NAME, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_GENERAL_NAME(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(GENERAL_NAME, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_OCSP_ONEREQ(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(OCSP_ONEREQ, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_OCSP_ONEREQ(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(OCSP_ONEREQ, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_OCSP_ONEREQ(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(OCSP_ONEREQ, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_OCSP_ONEREQ(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(OCSP_ONEREQ, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_OCSP_SINGLERESP(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(OCSP_SINGLERESP, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_OCSP_SINGLERESP(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(OCSP_SINGLERESP, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_OCSP_SINGLERESP(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(OCSP_SINGLERESP, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_OCSP_SINGLERESP(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(OCSP_SINGLERESP, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_PKCS12_SAFEBAG(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(PKCS12_SAFEBAG, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_PKCS12_SAFEBAG(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(PKCS12_SAFEBAG, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_PKCS12_SAFEBAG(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(PKCS12_SAFEBAG, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_PKCS12_SAFEBAG(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(PKCS12_SAFEBAG, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_PKCS7(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(PKCS7, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_PKCS7(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(PKCS7, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_PKCS7(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(PKCS7, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_PKCS7(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(PKCS7, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_PKCS7_RECIP_INFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(PKCS7_RECIP_INFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_PKCS7_RECIP_INFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(PKCS7_RECIP_INFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_PKCS7_RECIP_INFO(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(PKCS7_RECIP_INFO, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_PKCS7_RECIP_INFO(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(PKCS7_RECIP_INFO, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(PKCS7_SIGNER_INFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(PKCS7_SIGNER_INFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_PKCS7_SIGNER_INFO(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(PKCS7_SIGNER_INFO, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_PKCS7_SIGNER_INFO(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(PKCS7_SIGNER_INFO, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_POLICYINFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(POLICYINFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_POLICYINFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(POLICYINFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_POLICYINFO(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(POLICYINFO, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_POLICYINFO(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(POLICYINFO, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_POLICYQUALINFO(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(POLICYQUALINFO, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_POLICYQUALINFO(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(POLICYQUALINFO, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_POLICYQUALINFO(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(POLICYQUALINFO, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_POLICYQUALINFO(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(POLICYQUALINFO, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_SXNETID(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(SXNETID, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_SXNETID(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(SXNETID, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_SXNETID(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(SXNETID, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_SXNETID(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(SXNETID, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_X509(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(X509, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_X509(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(X509, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_X509(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(X509, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_X509(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(X509, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_X509_ALGOR(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(X509_ALGOR, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_X509_ALGOR(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(X509_ALGOR, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_X509_ALGOR(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(X509_ALGOR, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_X509_ALGOR(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(X509_ALGOR, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_X509_ATTRIBUTE(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(X509_ATTRIBUTE, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_X509_ATTRIBUTE(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(X509_ATTRIBUTE, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_X509_ATTRIBUTE(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(X509_ATTRIBUTE, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_X509_ATTRIBUTE(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(X509_ATTRIBUTE, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_X509_CRL(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(X509_CRL, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_X509_CRL(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(X509_CRL, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_X509_CRL(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(X509_CRL, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_X509_CRL(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(X509_CRL, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_X509_EXTENSION(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(X509_EXTENSION, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_X509_EXTENSION(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(X509_EXTENSION, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_X509_EXTENSION(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(X509_EXTENSION, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_X509_EXTENSION(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(X509_EXTENSION, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_X509_NAME_ENTRY(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(X509_NAME_ENTRY, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_X509_NAME_ENTRY(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(X509_NAME_ENTRY, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_X509_NAME_ENTRY(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(X509_NAME_ENTRY, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_X509_NAME_ENTRY(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(X509_NAME_ENTRY, (buf), (len), (d2i_func), (free_func))
+
+#define d2i_ASN1_SET_OF_X509_REVOKED(st, pp, length, d2i_func, free_func, ex_tag, ex_class) \
+	SKM_ASN1_SET_OF_d2i(X509_REVOKED, (st), (pp), (length), (d2i_func), (free_func), (ex_tag), (ex_class)) 
+#define i2d_ASN1_SET_OF_X509_REVOKED(st, pp, i2d_func, ex_tag, ex_class, is_set) \
+	SKM_ASN1_SET_OF_i2d(X509_REVOKED, (st), (pp), (i2d_func), (ex_tag), (ex_class), (is_set))
+#define ASN1_seq_pack_X509_REVOKED(st, i2d_func, buf, len) \
+	SKM_ASN1_seq_pack(X509_REVOKED, (st), (i2d_func), (buf), (len))
+#define ASN1_seq_unpack_X509_REVOKED(buf, len, d2i_func, free_func) \
+	SKM_ASN1_seq_unpack(X509_REVOKED, (buf), (len), (d2i_func), (free_func))
+
+#define PKCS12_decrypt_d2i_PKCS12_SAFEBAG(algor, d2i_func, free_func, pass, passlen, oct, seq) \
+	SKM_PKCS12_decrypt_d2i(PKCS12_SAFEBAG, (algor), (d2i_func), (free_func), (pass), (passlen), (oct), (seq))
+
+#define PKCS12_decrypt_d2i_PKCS7(algor, d2i_func, free_func, pass, passlen, oct, seq) \
+	SKM_PKCS12_decrypt_d2i(PKCS7, (algor), (d2i_func), (free_func), (pass), (passlen), (oct), (seq))
+/* End of util/mkstack.pl block, you may now edit :-) */
+
+#endif /* !defined HEADER_SAFESTACK_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/sha.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/sha.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/sha.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,199 @@
+/* crypto/sha/sha.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_SHA_H
+#define HEADER_SHA_H
+
+#include <openssl/e_os2.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#if defined(OPENSSL_NO_SHA) || (defined(OPENSSL_NO_SHA0) && defined(OPENSSL_NO_SHA1))
+#error SHA is disabled.
+#endif
+
+#if defined(OPENSSL_FIPS)
+#define FIPS_SHA_SIZE_T size_t
+#endif
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * ! SHA_LONG has to be at least 32 bits wide. If it's wider, then !
+ * ! SHA_LONG_LOG2 has to be defined along.                        !
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ */
+
+#if defined(OPENSSL_SYS_WIN16) || defined(__LP32__)
+#define SHA_LONG unsigned long
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
+#define SHA_LONG unsigned long
+#define SHA_LONG_LOG2 3
+#else
+#define SHA_LONG unsigned int
+#endif
+
+#define SHA_LBLOCK	16
+#define SHA_CBLOCK	(SHA_LBLOCK*4)	/* SHA treats input data as a
+					 * contiguous array of 32 bit
+					 * wide big-endian values. */
+#define SHA_LAST_BLOCK  (SHA_CBLOCK-8)
+#define SHA_DIGEST_LENGTH 20
+
+typedef struct SHAstate_st
+	{
+	SHA_LONG h0,h1,h2,h3,h4;
+	SHA_LONG Nl,Nh;
+	SHA_LONG data[SHA_LBLOCK];
+	unsigned int num;
+	} SHA_CTX;
+
+#ifndef OPENSSL_NO_SHA0
+int SHA_Init(SHA_CTX *c);
+int SHA_Update(SHA_CTX *c, const void *data, size_t len);
+int SHA_Final(unsigned char *md, SHA_CTX *c);
+unsigned char *SHA(const unsigned char *d, size_t n, unsigned char *md);
+void SHA_Transform(SHA_CTX *c, const unsigned char *data);
+#endif
+#ifndef OPENSSL_NO_SHA1
+int SHA1_Init(SHA_CTX *c);
+int SHA1_Update(SHA_CTX *c, const void *data, size_t len);
+int SHA1_Final(unsigned char *md, SHA_CTX *c);
+unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md);
+void SHA1_Transform(SHA_CTX *c, const unsigned char *data);
+#endif
+
+#define SHA256_CBLOCK	(SHA_LBLOCK*4)	/* SHA-256 treats input data as a
+					 * contiguous array of 32 bit
+					 * wide big-endian values. */
+#define SHA224_DIGEST_LENGTH	28
+#define SHA256_DIGEST_LENGTH	32
+
+typedef struct SHA256state_st
+	{
+	SHA_LONG h[8];
+	SHA_LONG Nl,Nh;
+	SHA_LONG data[SHA_LBLOCK];
+	unsigned int num,md_len;
+	} SHA256_CTX;
+
+#ifndef OPENSSL_NO_SHA256
+int SHA224_Init(SHA256_CTX *c);
+int SHA224_Update(SHA256_CTX *c, const void *data, size_t len);
+int SHA224_Final(unsigned char *md, SHA256_CTX *c);
+unsigned char *SHA224(const unsigned char *d, size_t n,unsigned char *md);
+int SHA256_Init(SHA256_CTX *c);
+int SHA256_Update(SHA256_CTX *c, const void *data, size_t len);
+int SHA256_Final(unsigned char *md, SHA256_CTX *c);
+unsigned char *SHA256(const unsigned char *d, size_t n,unsigned char *md);
+void SHA256_Transform(SHA256_CTX *c, const unsigned char *data);
+#endif
+
+#define SHA384_DIGEST_LENGTH	48
+#define SHA512_DIGEST_LENGTH	64
+
+#ifndef OPENSSL_NO_SHA512
+/*
+ * Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64
+ * being exactly 64-bit wide. See Implementation Notes in sha512.c
+ * for further details.
+ */
+#define SHA512_CBLOCK	(SHA_LBLOCK*8)	/* SHA-512 treats input data as a
+					 * contiguous array of 64 bit
+					 * wide big-endian values. */
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
+#define SHA_LONG64 unsigned __int64
+#define U64(C)     C##UI64
+#elif defined(__arch64__)
+#define SHA_LONG64 unsigned long
+#define U64(C)     C##UL
+#else
+#define SHA_LONG64 unsigned long long
+#define U64(C)     C##ULL
+#endif
+
+typedef struct SHA512state_st
+	{
+	SHA_LONG64 h[8];
+	SHA_LONG64 Nl,Nh;
+	union {
+		SHA_LONG64	d[SHA_LBLOCK];
+		unsigned char	p[SHA512_CBLOCK];
+	} u;
+	unsigned int num,md_len;
+	} SHA512_CTX;
+#endif
+
+#ifndef OPENSSL_NO_SHA512
+int SHA384_Init(SHA512_CTX *c);
+int SHA384_Update(SHA512_CTX *c, const void *data, size_t len);
+int SHA384_Final(unsigned char *md, SHA512_CTX *c);
+unsigned char *SHA384(const unsigned char *d, size_t n,unsigned char *md);
+int SHA512_Init(SHA512_CTX *c);
+int SHA512_Update(SHA512_CTX *c, const void *data, size_t len);
+int SHA512_Final(unsigned char *md, SHA512_CTX *c);
+unsigned char *SHA512(const unsigned char *d, size_t n,unsigned char *md);
+void SHA512_Transform(SHA512_CTX *c, const unsigned char *data);
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1961 @@
+/* ssl/ssl.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#ifndef HEADER_SSL_H 
+#define HEADER_SSL_H 
+
+#include <openssl/e_os2.h>
+
+#ifndef OPENSSL_NO_COMP
+#include <openssl/comp.h>
+#endif
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#ifndef OPENSSL_NO_DEPRECATED
+#ifndef OPENSSL_NO_X509
+#include <openssl/x509.h>
+#endif
+#include <openssl/crypto.h>
+#include <openssl/lhash.h>
+#include <openssl/buffer.h>
+#endif
+#include <openssl/pem.h>
+
+#include <openssl/kssl.h>
+#include <openssl/safestack.h>
+#include <openssl/symhacks.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* SSLeay version number for ASN.1 encoding of the session information */
+/* Version 0 - initial version
+ * Version 1 - added the optional peer certificate
+ */
+#define SSL_SESSION_ASN1_VERSION 0x0001
+
+/* text strings for the ciphers */
+#define SSL_TXT_NULL_WITH_MD5		SSL2_TXT_NULL_WITH_MD5			
+#define SSL_TXT_RC4_128_WITH_MD5	SSL2_TXT_RC4_128_WITH_MD5		
+#define SSL_TXT_RC4_128_EXPORT40_WITH_MD5 SSL2_TXT_RC4_128_EXPORT40_WITH_MD5	
+#define SSL_TXT_RC2_128_CBC_WITH_MD5	SSL2_TXT_RC2_128_CBC_WITH_MD5		
+#define SSL_TXT_RC2_128_CBC_EXPORT40_WITH_MD5 SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5	
+#define SSL_TXT_IDEA_128_CBC_WITH_MD5	SSL2_TXT_IDEA_128_CBC_WITH_MD5		
+#define SSL_TXT_DES_64_CBC_WITH_MD5	SSL2_TXT_DES_64_CBC_WITH_MD5		
+#define SSL_TXT_DES_64_CBC_WITH_SHA	SSL2_TXT_DES_64_CBC_WITH_SHA		
+#define SSL_TXT_DES_192_EDE3_CBC_WITH_MD5 SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5	
+#define SSL_TXT_DES_192_EDE3_CBC_WITH_SHA SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA	
+
+/*    VRS Additional Kerberos5 entries
+ */
+#define SSL_TXT_KRB5_DES_64_CBC_SHA   SSL3_TXT_KRB5_DES_64_CBC_SHA
+#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
+#define SSL_TXT_KRB5_RC4_128_SHA      SSL3_TXT_KRB5_RC4_128_SHA
+#define SSL_TXT_KRB5_IDEA_128_CBC_SHA SSL3_TXT_KRB5_IDEA_128_CBC_SHA
+#define SSL_TXT_KRB5_DES_64_CBC_MD5   SSL3_TXT_KRB5_DES_64_CBC_MD5       
+#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5       
+#define SSL_TXT_KRB5_RC4_128_MD5      SSL3_TXT_KRB5_RC4_128_MD5
+#define SSL_TXT_KRB5_IDEA_128_CBC_MD5 SSL3_TXT_KRB5_IDEA_128_CBC_MD5 
+
+#define SSL_TXT_KRB5_DES_40_CBC_SHA   SSL3_TXT_KRB5_DES_40_CBC_SHA 
+#define SSL_TXT_KRB5_RC2_40_CBC_SHA   SSL3_TXT_KRB5_RC2_40_CBC_SHA 
+#define SSL_TXT_KRB5_RC4_40_SHA	      SSL3_TXT_KRB5_RC4_40_SHA
+#define SSL_TXT_KRB5_DES_40_CBC_MD5   SSL3_TXT_KRB5_DES_40_CBC_MD5 
+#define SSL_TXT_KRB5_RC2_40_CBC_MD5   SSL3_TXT_KRB5_RC2_40_CBC_MD5 
+#define SSL_TXT_KRB5_RC4_40_MD5	      SSL3_TXT_KRB5_RC4_40_MD5
+
+#define SSL_TXT_KRB5_DES_40_CBC_SHA   SSL3_TXT_KRB5_DES_40_CBC_SHA
+#define SSL_TXT_KRB5_DES_40_CBC_MD5   SSL3_TXT_KRB5_DES_40_CBC_MD5
+#define SSL_TXT_KRB5_DES_64_CBC_SHA   SSL3_TXT_KRB5_DES_64_CBC_SHA
+#define SSL_TXT_KRB5_DES_64_CBC_MD5   SSL3_TXT_KRB5_DES_64_CBC_MD5
+#define SSL_TXT_KRB5_DES_192_CBC3_SHA SSL3_TXT_KRB5_DES_192_CBC3_SHA
+#define SSL_TXT_KRB5_DES_192_CBC3_MD5 SSL3_TXT_KRB5_DES_192_CBC3_MD5
+#define SSL_MAX_KRB5_PRINCIPAL_LENGTH  256
+
+#define SSL_MAX_SSL_SESSION_ID_LENGTH		32
+#define SSL_MAX_SID_CTX_LENGTH			32
+
+#define SSL_MIN_RSA_MODULUS_LENGTH_IN_BYTES	(512/8)
+#define SSL_MAX_KEY_ARG_LENGTH			8
+#define SSL_MAX_MASTER_KEY_LENGTH		48
+
+/* These are used to specify which ciphers to use and not to use */
+#define SSL_TXT_LOW		"LOW"
+#define SSL_TXT_MEDIUM		"MEDIUM"
+#define SSL_TXT_HIGH		"HIGH"
+#define SSL_TXT_kFZA		"kFZA"
+#define	SSL_TXT_aFZA		"aFZA"
+#define SSL_TXT_eFZA		"eFZA"
+#define SSL_TXT_FZA		"FZA"
+
+#define	SSL_TXT_aNULL		"aNULL"
+#define	SSL_TXT_eNULL		"eNULL"
+#define	SSL_TXT_NULL		"NULL"
+
+#define SSL_TXT_kKRB5     	"kKRB5"
+#define SSL_TXT_aKRB5     	"aKRB5"
+#define SSL_TXT_KRB5      	"KRB5"
+
+#define SSL_TXT_kRSA		"kRSA"
+#define SSL_TXT_kDHr		"kDHr"
+#define SSL_TXT_kDHd		"kDHd"
+#define SSL_TXT_kEDH		"kEDH"
+#define	SSL_TXT_aRSA		"aRSA"
+#define	SSL_TXT_aDSS		"aDSS"
+#define	SSL_TXT_aDH		"aDH"
+#define	SSL_TXT_DSS		"DSS"
+#define SSL_TXT_DH		"DH"
+#define SSL_TXT_EDH		"EDH"
+#define SSL_TXT_ADH		"ADH"
+#define SSL_TXT_RSA		"RSA"
+#define SSL_TXT_DES		"DES"
+#define SSL_TXT_3DES		"3DES"
+#define SSL_TXT_RC4		"RC4"
+#define SSL_TXT_RC2		"RC2"
+#define SSL_TXT_IDEA		"IDEA"
+#define SSL_TXT_AES		"AES"
+#define SSL_TXT_MD5		"MD5"
+#define SSL_TXT_SHA1		"SHA1"
+#define SSL_TXT_SHA		"SHA"
+#define SSL_TXT_EXP		"EXP"
+#define SSL_TXT_EXPORT		"EXPORT"
+#define SSL_TXT_EXP40		"EXPORT40"
+#define SSL_TXT_EXP56		"EXPORT56"
+#define SSL_TXT_SSLV2		"SSLv2"
+#define SSL_TXT_SSLV3		"SSLv3"
+#define SSL_TXT_TLSV1		"TLSv1"
+#define SSL_TXT_ALL		"ALL"
+#define SSL_TXT_ECC		"ECCdraft" /* ECC ciphersuites are not yet official */
+
+/*
+ * COMPLEMENTOF* definitions. These identifiers are used to (de-select)
+ * ciphers normally not being used.
+ * Example: "RC4" will activate all ciphers using RC4 including ciphers
+ * without authentication, which would normally disabled by DEFAULT (due
+ * the "!ADH" being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT"
+ * will make sure that it is also disabled in the specific selection.
+ * COMPLEMENTOF* identifiers are portable between version, as adjustments
+ * to the default cipher setup will also be included here.
+ *
+ * COMPLEMENTOFDEFAULT does not experience the same special treatment that
+ * DEFAULT gets, as only selection is being done and no sorting as needed
+ * for DEFAULT.
+ */
+#define SSL_TXT_CMPALL		"COMPLEMENTOFALL"
+#define SSL_TXT_CMPDEF		"COMPLEMENTOFDEFAULT"
+
+/* The following cipher list is used by default.
+ * It also is substituted when an application-defined cipher list string
+ * starts with 'DEFAULT'. */
+#define SSL_DEFAULT_CIPHER_LIST	"ALL:!ADH:+RC4:@STRENGTH" /* low priority for RC4 */
+
+/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
+#define SSL_SENT_SHUTDOWN	1
+#define SSL_RECEIVED_SHUTDOWN	2
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#if (defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_MD5)) && !defined(OPENSSL_NO_SSL2)
+#define OPENSSL_NO_SSL2
+#endif
+
+#define SSL_FILETYPE_ASN1	X509_FILETYPE_ASN1
+#define SSL_FILETYPE_PEM	X509_FILETYPE_PEM
+
+/* This is needed to stop compilers complaining about the
+ * 'struct ssl_st *' function parameters used to prototype callbacks
+ * in SSL_CTX. */
+typedef struct ssl_st *ssl_crock_st;
+
+/* used to hold info on the particular ciphers used */
+typedef struct ssl_cipher_st
+	{
+	int valid;
+	const char *name;		/* text name */
+	unsigned long id;		/* id, 4 bytes, first is version */
+	unsigned long algorithms;	/* what ciphers are used */
+	unsigned long algo_strength;	/* strength and export flags */
+	unsigned long algorithm2;	/* Extra flags */
+	int strength_bits;		/* Number of bits really used */
+	int alg_bits;			/* Number of bits for algorithm */
+	unsigned long mask;		/* used for matching */
+	unsigned long mask_strength;	/* also used for matching */
+	} SSL_CIPHER;
+
+DECLARE_STACK_OF(SSL_CIPHER)
+
+typedef struct ssl_st SSL;
+typedef struct ssl_ctx_st SSL_CTX;
+
+/* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+typedef struct ssl_method_st
+	{
+	int version;
+	int (*ssl_new)(SSL *s);
+	void (*ssl_clear)(SSL *s);
+	void (*ssl_free)(SSL *s);
+	int (*ssl_accept)(SSL *s);
+	int (*ssl_connect)(SSL *s);
+	int (*ssl_read)(SSL *s,void *buf,int len);
+	int (*ssl_peek)(SSL *s,void *buf,int len);
+	int (*ssl_write)(SSL *s,const void *buf,int len);
+	int (*ssl_shutdown)(SSL *s);
+	int (*ssl_renegotiate)(SSL *s);
+	int (*ssl_renegotiate_check)(SSL *s);
+	long (*ssl_get_message)(SSL *s, int st1, int stn, int mt, long
+		max, int *ok);
+	int (*ssl_read_bytes)(SSL *s, int type, unsigned char *buf, int len, 
+		int peek);
+	int (*ssl_write_bytes)(SSL *s, int type, const void *buf_, int len);
+	int (*ssl_dispatch_alert)(SSL *s);
+	long (*ssl_ctrl)(SSL *s,int cmd,long larg,void *parg);
+	long (*ssl_ctx_ctrl)(SSL_CTX *ctx,int cmd,long larg,void *parg);
+	SSL_CIPHER *(*get_cipher_by_char)(const unsigned char *ptr);
+	int (*put_cipher_by_char)(const SSL_CIPHER *cipher,unsigned char *ptr);
+	int (*ssl_pending)(const SSL *s);
+	int (*num_ciphers)(void);
+	SSL_CIPHER *(*get_cipher)(unsigned ncipher);
+	struct ssl_method_st *(*get_ssl_method)(int version);
+	long (*get_timeout)(void);
+	struct ssl3_enc_method *ssl3_enc; /* Extra SSLv3/TLS stuff */
+	int (*ssl_version)(void);
+	long (*ssl_callback_ctrl)(SSL *s, int cb_id, void (*fp)(void));
+	long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void));
+	} SSL_METHOD;
+
+/* Lets make this into an ASN.1 type structure as follows
+ * SSL_SESSION_ID ::= SEQUENCE {
+ *	version 		INTEGER,	-- structure version number
+ *	SSLversion 		INTEGER,	-- SSL version number
+ *	Cipher 			OCTET_STRING,	-- the 3 byte cipher ID
+ *	Session_ID 		OCTET_STRING,	-- the Session ID
+ *	Master_key 		OCTET_STRING,	-- the master key
+ *	KRB5_principal		OCTET_STRING	-- optional Kerberos principal
+ *	Key_Arg [ 0 ] IMPLICIT	OCTET_STRING,	-- the optional Key argument
+ *	Time [ 1 ] EXPLICIT	INTEGER,	-- optional Start Time
+ *	Timeout [ 2 ] EXPLICIT	INTEGER,	-- optional Timeout ins seconds
+ *	Peer [ 3 ] EXPLICIT	X509,		-- optional Peer Certificate
+ *	Session_ID_context [ 4 ] EXPLICIT OCTET_STRING,   -- the Session ID context
+ *	Verify_result [ 5 ] EXPLICIT INTEGER    -- X509_V_... code for `Peer'
+ *	Compression [6] IMPLICIT ASN1_OBJECT	-- compression OID XXXXX
+ *	}
+ * Look in ssl/ssl_asn1.c for more details
+ * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-).
+ */
+typedef struct ssl_session_st
+	{
+	int ssl_version;	/* what ssl version session info is
+				 * being kept in here? */
+
+	/* only really used in SSLv2 */
+	unsigned int key_arg_length;
+	unsigned char key_arg[SSL_MAX_KEY_ARG_LENGTH];
+	int master_key_length;
+	unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
+	/* session_id - valid? */
+	unsigned int session_id_length;
+	unsigned char session_id[SSL_MAX_SSL_SESSION_ID_LENGTH];
+	/* this is used to determine whether the session is being reused in
+	 * the appropriate context. It is up to the application to set this,
+	 * via SSL_new */
+	unsigned int sid_ctx_length;
+	unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+
+#ifndef OPENSSL_NO_KRB5
+        unsigned int krb5_client_princ_len;
+        unsigned char krb5_client_princ[SSL_MAX_KRB5_PRINCIPAL_LENGTH];
+#endif /* OPENSSL_NO_KRB5 */
+
+	int not_resumable;
+
+	/* The cert is the certificate used to establish this connection */
+	struct sess_cert_st /* SESS_CERT */ *sess_cert;
+
+	/* This is the cert for the other end.
+	 * On clients, it will be the same as sess_cert->peer_key->x509
+	 * (the latter is not enough as sess_cert is not retained
+	 * in the external representation of sessions, see ssl_asn1.c). */
+	X509 *peer;
+	/* when app_verify_callback accepts a session where the peer's certificate
+	 * is not ok, we must remember the error for session reuse: */
+	long verify_result; /* only for servers */
+
+	int references;
+	long timeout;
+	long time;
+
+	int compress_meth;		/* Need to lookup the method */
+
+	SSL_CIPHER *cipher;
+	unsigned long cipher_id;	/* when ASN.1 loaded, this
+					 * needs to be used to load
+					 * the 'cipher' structure */
+
+	STACK_OF(SSL_CIPHER) *ciphers; /* shared ciphers? */
+
+	CRYPTO_EX_DATA ex_data; /* application specific data */
+
+	/* These are used to make removal of session-ids more
+	 * efficient and to implement a maximum cache size. */
+	struct ssl_session_st *prev,*next;
+	} SSL_SESSION;
+
+
+#define SSL_OP_MICROSOFT_SESS_ID_BUG			0x00000001L
+#define SSL_OP_NETSCAPE_CHALLENGE_BUG			0x00000002L
+#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG		0x00000008L
+#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG		0x00000010L
+#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER		0x00000020L
+#define SSL_OP_MSIE_SSLV2_RSA_PADDING			0x00000040L
+#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG			0x00000080L
+#define SSL_OP_TLS_D5_BUG				0x00000100L
+#define SSL_OP_TLS_BLOCK_PADDING_BUG			0x00000200L
+
+/* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added
+ * in OpenSSL 0.9.6d.  Usually (depending on the application protocol)
+ * the workaround is not needed.  Unfortunately some broken SSL/TLS
+ * implementations cannot handle it at all, which is why we include
+ * it in SSL_OP_ALL. */
+#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS              0x00000800L /* added in 0.9.6e */
+
+/* SSL_OP_ALL: various bug workarounds that should be rather harmless.
+ *             This used to be 0x000FFFFFL before 0.9.7. */
+#define SSL_OP_ALL					0x00000FFFL
+
+/* DTLS options */
+#define SSL_OP_NO_QUERY_MTU                 0x00001000L
+/* Turn on Cookie Exchange (on relevant for servers) */
+#define SSL_OP_COOKIE_EXCHANGE              0x00002000L
+
+/* As server, disallow session resumption on renegotiation */
+#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION	0x00010000L
+/* If set, always create a new key when using tmp_ecdh parameters */
+#define SSL_OP_SINGLE_ECDH_USE				0x00080000L
+/* If set, always create a new key when using tmp_dh parameters */
+#define SSL_OP_SINGLE_DH_USE				0x00100000L
+/* Set to always use the tmp_rsa key when doing RSA operations,
+ * even when this violates protocol specs */
+#define SSL_OP_EPHEMERAL_RSA				0x00200000L
+/* Set on servers to choose the cipher according to the server's
+ * preferences */
+#define SSL_OP_CIPHER_SERVER_PREFERENCE			0x00400000L
+/* If set, a server will allow a client to issue a SSLv3.0 version number
+ * as latest version supported in the premaster secret, even when TLSv1.0
+ * (version 3.1) was announced in the client hello. Normally this is
+ * forbidden to prevent version rollback attacks. */
+#define SSL_OP_TLS_ROLLBACK_BUG				0x00800000L
+
+#define SSL_OP_NO_SSLv2					0x01000000L
+#define SSL_OP_NO_SSLv3					0x02000000L
+#define SSL_OP_NO_TLSv1					0x04000000L
+
+/* The next flag deliberately changes the ciphertest, this is a check
+ * for the PKCS#1 attack */
+#define SSL_OP_PKCS1_CHECK_1				0x08000000L
+#define SSL_OP_PKCS1_CHECK_2				0x10000000L
+#define SSL_OP_NETSCAPE_CA_DN_BUG			0x20000000L
+#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG		0x40000000L
+
+
+/* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
+ * when just a single record has been written): */
+#define SSL_MODE_ENABLE_PARTIAL_WRITE       0x00000001L
+/* Make it possible to retry SSL_write() with changed buffer location
+ * (buffer contents must stay the same!); this is not the default to avoid
+ * the misconception that non-blocking SSL_write() behaves like
+ * non-blocking write(): */
+#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
+/* Never bother the application with retries if the transport
+ * is blocking: */
+#define SSL_MODE_AUTO_RETRY 0x00000004L
+/* Don't attempt to automatically build certificate chain */
+#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
+
+
+/* Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value,
+ * they cannot be used to clear bits. */
+
+#define SSL_CTX_set_options(ctx,op) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
+#define SSL_CTX_get_options(ctx) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,0,NULL)
+#define SSL_set_options(ssl,op) \
+	SSL_ctrl((ssl),SSL_CTRL_OPTIONS,(op),NULL)
+#define SSL_get_options(ssl) \
+        SSL_ctrl((ssl),SSL_CTRL_OPTIONS,0,NULL)
+
+#define SSL_CTX_set_mode(ctx,op) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
+#define SSL_CTX_get_mode(ctx) \
+	SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,0,NULL)
+#define SSL_set_mode(ssl,op) \
+	SSL_ctrl((ssl),SSL_CTRL_MODE,(op),NULL)
+#define SSL_get_mode(ssl) \
+        SSL_ctrl((ssl),SSL_CTRL_MODE,0,NULL)
+#define SSL_set_mtu(ssl, mtu) \
+        SSL_ctrl((ssl),SSL_CTRL_SET_MTU,(mtu),NULL)
+
+
+void SSL_CTX_set_msg_callback(SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
+void SSL_set_msg_callback(SSL *ssl, void (*cb)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg));
+#define SSL_CTX_set_msg_callback_arg(ctx, arg) SSL_CTX_ctrl((ctx), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
+#define SSL_set_msg_callback_arg(ssl, arg) SSL_ctrl((ssl), SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, (arg))
+
+
+
+#if defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32)
+#define SSL_MAX_CERT_LIST_DEFAULT 1024*30 /* 30k max cert list :-) */
+#else
+#define SSL_MAX_CERT_LIST_DEFAULT 1024*100 /* 100k max cert list :-) */
+#endif
+
+#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT	(1024*20)
+
+/* This callback type is used inside SSL_CTX, SSL, and in the functions that set
+ * them. It is used to override the generation of SSL/TLS session IDs in a
+ * server. Return value should be zero on an error, non-zero to proceed. Also,
+ * callbacks should themselves check if the id they generate is unique otherwise
+ * the SSL handshake will fail with an error - callbacks can do this using the
+ * 'ssl' value they're passed by;
+ *      SSL_has_matching_session_id(ssl, id, *id_len)
+ * The length value passed in is set at the maximum size the session ID can be.
+ * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback
+ * can alter this length to be less if desired, but under SSLv2 session IDs are
+ * supposed to be fixed at 16 bytes so the id will be padded after the callback
+ * returns in this case. It is also an error for the callback to set the size to
+ * zero. */
+typedef int (*GEN_SESSION_CB)(const SSL *ssl, unsigned char *id,
+				unsigned int *id_len);
+
+typedef struct ssl_comp_st
+	{
+	int id;
+	const char *name;
+#ifndef OPENSSL_NO_COMP
+	COMP_METHOD *method;
+#else
+	char *method;
+#endif
+	} SSL_COMP;
+
+DECLARE_STACK_OF(SSL_COMP)
+
+struct ssl_ctx_st
+	{
+	SSL_METHOD *method;
+
+	STACK_OF(SSL_CIPHER) *cipher_list;
+	/* same as above but sorted for lookup */
+	STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+
+	struct x509_store_st /* X509_STORE */ *cert_store;
+	struct lhash_st /* LHASH */ *sessions;	/* a set of SSL_SESSIONs */
+	/* Most session-ids that will be cached, default is
+	 * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */
+	unsigned long session_cache_size;
+	struct ssl_session_st *session_cache_head;
+	struct ssl_session_st *session_cache_tail;
+
+	/* This can have one of 2 values, ored together,
+	 * SSL_SESS_CACHE_CLIENT,
+	 * SSL_SESS_CACHE_SERVER,
+	 * Default is SSL_SESSION_CACHE_SERVER, which means only
+	 * SSL_accept which cache SSL_SESSIONS. */
+	int session_cache_mode;
+
+	/* If timeout is not 0, it is the default timeout value set
+	 * when SSL_new() is called.  This has been put in to make
+	 * life easier to set things up */
+	long session_timeout;
+
+	/* If this callback is not null, it will be called each
+	 * time a session id is added to the cache.  If this function
+	 * returns 1, it means that the callback will do a
+	 * SSL_SESSION_free() when it has finished using it.  Otherwise,
+	 * on 0, it means the callback has finished with it.
+	 * If remove_session_cb is not null, it will be called when
+	 * a session-id is removed from the cache.  After the call,
+	 * OpenSSL will SSL_SESSION_free() it. */
+	int (*new_session_cb)(struct ssl_st *ssl,SSL_SESSION *sess);
+	void (*remove_session_cb)(struct ssl_ctx_st *ctx,SSL_SESSION *sess);
+	SSL_SESSION *(*get_session_cb)(struct ssl_st *ssl,
+		unsigned char *data,int len,int *copy);
+
+	struct
+		{
+		int sess_connect;	/* SSL new conn - started */
+		int sess_connect_renegotiate;/* SSL reneg - requested */
+		int sess_connect_good;	/* SSL new conne/reneg - finished */
+		int sess_accept;	/* SSL new accept - started */
+		int sess_accept_renegotiate;/* SSL reneg - requested */
+		int sess_accept_good;	/* SSL accept/reneg - finished */
+		int sess_miss;		/* session lookup misses  */
+		int sess_timeout;	/* reuse attempt on timeouted session */
+		int sess_cache_full;	/* session removed due to full cache */
+		int sess_hit;		/* session reuse actually done */
+		int sess_cb_hit;	/* session-id that was not
+					 * in the cache was
+					 * passed back via the callback.  This
+					 * indicates that the application is
+					 * supplying session-id's from other
+					 * processes - spooky :-) */
+		} stats;
+
+	int references;
+
+	/* if defined, these override the X509_verify_cert() calls */
+	int (*app_verify_callback)(X509_STORE_CTX *, void *);
+	void *app_verify_arg;
+	/* before OpenSSL 0.9.7, 'app_verify_arg' was ignored
+	 * ('app_verify_callback' was called with just one argument) */
+
+	/* Default password callback. */
+	pem_password_cb *default_passwd_callback;
+
+	/* Default password callback user data. */
+	void *default_passwd_callback_userdata;
+
+	/* get client cert callback */
+	int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey);
+
+    /* cookie generate callback */
+    int (*app_gen_cookie_cb)(SSL *ssl, unsigned char *cookie, 
+        unsigned int *cookie_len);
+
+    /* verify cookie callback */
+    int (*app_verify_cookie_cb)(SSL *ssl, unsigned char *cookie, 
+        unsigned int cookie_len);
+
+	CRYPTO_EX_DATA ex_data;
+
+	const EVP_MD *rsa_md5;/* For SSLv2 - name is 'ssl2-md5' */
+	const EVP_MD *md5;	/* For SSLv3/TLSv1 'ssl3-md5' */
+	const EVP_MD *sha1;   /* For SSLv3/TLSv1 'ssl3->sha1' */
+
+	STACK_OF(X509) *extra_certs;
+	STACK_OF(SSL_COMP) *comp_methods; /* stack of SSL_COMP, SSLv3/TLSv1 */
+
+
+	/* Default values used when no per-SSL value is defined follow */
+
+	void (*info_callback)(const SSL *ssl,int type,int val); /* used if SSL's info_callback is NULL */
+
+	/* what we put in client cert requests */
+	STACK_OF(X509_NAME) *client_CA;
+
+
+	/* Default values to use in SSL structures follow (these are copied by SSL_new) */
+
+	unsigned long options;
+	unsigned long mode;
+	long max_cert_list;
+
+	struct cert_st /* CERT */ *cert;
+	int read_ahead;
+
+	/* callback that allows applications to peek at protocol messages */
+	void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
+	void *msg_callback_arg;
+
+	int verify_mode;
+	unsigned int sid_ctx_length;
+	unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+	int (*default_verify_callback)(int ok,X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */
+
+	/* Default generate session ID callback. */
+	GEN_SESSION_CB generate_session_id;
+
+	X509_VERIFY_PARAM *param;
+
+#if 0
+	int purpose;		/* Purpose setting */
+	int trust;		/* Trust setting */
+#endif
+
+	int quiet_shutdown;
+	};
+
+#define SSL_SESS_CACHE_OFF			0x0000
+#define SSL_SESS_CACHE_CLIENT			0x0001
+#define SSL_SESS_CACHE_SERVER			0x0002
+#define SSL_SESS_CACHE_BOTH	(SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_SERVER)
+#define SSL_SESS_CACHE_NO_AUTO_CLEAR		0x0080
+/* enough comments already ... see SSL_CTX_set_session_cache_mode(3) */
+#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP	0x0100
+#define SSL_SESS_CACHE_NO_INTERNAL_STORE	0x0200
+#define SSL_SESS_CACHE_NO_INTERNAL \
+	(SSL_SESS_CACHE_NO_INTERNAL_LOOKUP|SSL_SESS_CACHE_NO_INTERNAL_STORE)
+
+  struct lhash_st *SSL_CTX_sessions(SSL_CTX *ctx);
+#define SSL_CTX_sess_number(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_NUMBER,0,NULL)
+#define SSL_CTX_sess_connect(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT,0,NULL)
+#define SSL_CTX_sess_connect_good(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_GOOD,0,NULL)
+#define SSL_CTX_sess_connect_renegotiate(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CONNECT_RENEGOTIATE,0,NULL)
+#define SSL_CTX_sess_accept(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT,0,NULL)
+#define SSL_CTX_sess_accept_renegotiate(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_RENEGOTIATE,0,NULL)
+#define SSL_CTX_sess_accept_good(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_ACCEPT_GOOD,0,NULL)
+#define SSL_CTX_sess_hits(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_HIT,0,NULL)
+#define SSL_CTX_sess_cb_hits(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CB_HIT,0,NULL)
+#define SSL_CTX_sess_misses(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_MISSES,0,NULL)
+#define SSL_CTX_sess_timeouts(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_TIMEOUTS,0,NULL)
+#define SSL_CTX_sess_cache_full(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SESS_CACHE_FULL,0,NULL)
+
+#define SSL_CTX_sess_set_new_cb(ctx,cb)	((ctx)->new_session_cb=(cb))
+#define SSL_CTX_sess_get_new_cb(ctx)	((ctx)->new_session_cb)
+#define SSL_CTX_sess_set_remove_cb(ctx,cb)	((ctx)->remove_session_cb=(cb))
+#define SSL_CTX_sess_get_remove_cb(ctx)	((ctx)->remove_session_cb)
+#define SSL_CTX_sess_set_get_cb(ctx,cb)	((ctx)->get_session_cb=(cb))
+#define SSL_CTX_sess_get_get_cb(ctx)	((ctx)->get_session_cb)
+#define SSL_CTX_set_info_callback(ctx,cb)	((ctx)->info_callback=(cb))
+#define SSL_CTX_get_info_callback(ctx)		((ctx)->info_callback)
+#define SSL_CTX_set_client_cert_cb(ctx,cb)	((ctx)->client_cert_cb=(cb))
+#define SSL_CTX_get_client_cert_cb(ctx)		((ctx)->client_cert_cb)
+#define SSL_CTX_set_cookie_generate_cb(ctx,cb) ((ctx)->app_gen_cookie_cb=(cb))
+#define SSL_CTX_set_cookie_verify_cb(ctx,cb) ((ctx)->app_verify_cookie_cb=(cb))
+
+#define SSL_NOTHING	1
+#define SSL_WRITING	2
+#define SSL_READING	3
+#define SSL_X509_LOOKUP	4
+
+/* These will only be used when doing non-blocking IO */
+#define SSL_want_nothing(s)	(SSL_want(s) == SSL_NOTHING)
+#define SSL_want_read(s)	(SSL_want(s) == SSL_READING)
+#define SSL_want_write(s)	(SSL_want(s) == SSL_WRITING)
+#define SSL_want_x509_lookup(s)	(SSL_want(s) == SSL_X509_LOOKUP)
+
+struct ssl_st
+	{
+	/* protocol version
+	 * (one of SSL2_VERSION, SSL3_VERSION, TLS1_VERSION, DTLS1_VERSION)
+	 */
+	int version;
+	int type; /* SSL_ST_CONNECT or SSL_ST_ACCEPT */
+
+	SSL_METHOD *method; /* SSLv3 */
+
+	/* There are 2 BIO's even though they are normally both the
+	 * same.  This is so data can be read and written to different
+	 * handlers */
+
+#ifndef OPENSSL_NO_BIO
+	BIO *rbio; /* used by SSL_read */
+	BIO *wbio; /* used by SSL_write */
+	BIO *bbio; /* used during session-id reuse to concatenate
+		    * messages */
+#else
+	char *rbio; /* used by SSL_read */
+	char *wbio; /* used by SSL_write */
+	char *bbio;
+#endif
+	/* This holds a variable that indicates what we were doing
+	 * when a 0 or -1 is returned.  This is needed for
+	 * non-blocking IO so we know what request needs re-doing when
+	 * in SSL_accept or SSL_connect */
+	int rwstate;
+
+	/* true when we are actually in SSL_accept() or SSL_connect() */
+	int in_handshake;
+	int (*handshake_func)(SSL *);
+
+	/* Imagine that here's a boolean member "init" that is
+	 * switched as soon as SSL_set_{accept/connect}_state
+	 * is called for the first time, so that "state" and
+	 * "handshake_func" are properly initialized.  But as
+	 * handshake_func is == 0 until then, we use this
+	 * test instead of an "init" member.
+	 */
+
+	int server;	/* are we the server side? - mostly used by SSL_clear*/
+
+	int new_session;/* 1 if we are to use a new session.
+	                 * 2 if we are a server and are inside a handshake
+	                 *   (i.e. not just sending a HelloRequest)
+	                 * NB: For servers, the 'new' session may actually be a previously
+	                 * cached session or even the previous session unless
+	                 * SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION is set */
+	int quiet_shutdown;/* don't send shutdown packets */
+	int shutdown;	/* we have shut things down, 0x01 sent, 0x02
+			 * for received */
+	int state;	/* where we are */
+	int rstate;	/* where we are when reading */
+
+	BUF_MEM *init_buf;	/* buffer used during init */
+	void *init_msg;   	/* pointer to handshake message body, set by ssl3_get_message() */
+	int init_num;		/* amount read/written */
+	int init_off;		/* amount read/written */
+
+	/* used internally to point at a raw packet */
+	unsigned char *packet;
+	unsigned int packet_length;
+
+	struct ssl2_state_st *s2; /* SSLv2 variables */
+	struct ssl3_state_st *s3; /* SSLv3 variables */
+	struct dtls1_state_st *d1; /* DTLSv1 variables */
+
+	int read_ahead;		/* Read as many input bytes as possible
+	               	 	 * (for non-blocking reads) */
+
+	/* callback that allows applications to peek at protocol messages */
+	void (*msg_callback)(int write_p, int version, int content_type, const void *buf, size_t len, SSL *ssl, void *arg);
+	void *msg_callback_arg;
+
+	int hit;		/* reusing a previous session */
+
+	X509_VERIFY_PARAM *param;
+
+#if 0
+	int purpose;		/* Purpose setting */
+	int trust;		/* Trust setting */
+#endif
+
+	/* crypto */
+	STACK_OF(SSL_CIPHER) *cipher_list;
+	STACK_OF(SSL_CIPHER) *cipher_list_by_id;
+
+	/* These are the ones being used, the ones in SSL_SESSION are
+	 * the ones to be 'copied' into these ones */
+
+	EVP_CIPHER_CTX *enc_read_ctx;		/* cryptographic state */
+	const EVP_MD *read_hash;		/* used for mac generation */
+#ifndef OPENSSL_NO_COMP
+	COMP_CTX *expand;			/* uncompress */
+#else
+	char *expand;
+#endif
+
+	EVP_CIPHER_CTX *enc_write_ctx;		/* cryptographic state */
+	const EVP_MD *write_hash;		/* used for mac generation */
+#ifndef OPENSSL_NO_COMP
+	COMP_CTX *compress;			/* compression */
+#else
+	char *compress;	
+#endif
+
+	/* session info */
+
+	/* client cert? */
+	/* This is used to hold the server certificate used */
+	struct cert_st /* CERT */ *cert;
+
+	/* the session_id_context is used to ensure sessions are only reused
+	 * in the appropriate context */
+	unsigned int sid_ctx_length;
+	unsigned char sid_ctx[SSL_MAX_SID_CTX_LENGTH];
+
+	/* This can also be in the session once a session is established */
+	SSL_SESSION *session;
+
+	/* Default generate session ID callback. */
+	GEN_SESSION_CB generate_session_id;
+
+	/* Used in SSL2 and SSL3 */
+	int verify_mode;	/* 0 don't care about verify failure.
+				 * 1 fail if verify fails */
+	int (*verify_callback)(int ok,X509_STORE_CTX *ctx); /* fail if callback returns 0 */
+
+	void (*info_callback)(const SSL *ssl,int type,int val); /* optional informational callback */
+
+	int error;		/* error bytes to be written */
+	int error_code;		/* actual code */
+
+#ifndef OPENSSL_NO_KRB5
+	KSSL_CTX *kssl_ctx;     /* Kerberos 5 context */
+#endif	/* OPENSSL_NO_KRB5 */
+
+	SSL_CTX *ctx;
+	/* set this flag to 1 and a sleep(1) is put into all SSL_read()
+	 * and SSL_write() calls, good for nbio debuging :-) */
+	int debug;	
+
+	/* extra application data */
+	long verify_result;
+	CRYPTO_EX_DATA ex_data;
+
+	/* for server side, keep the list of CA_dn we can use */
+	STACK_OF(X509_NAME) *client_CA;
+
+	int references;
+	unsigned long options; /* protocol behaviour */
+	unsigned long mode; /* API behaviour */
+	long max_cert_list;
+	int first_packet;
+	int client_version;	/* what was passed, used for
+				 * SSLv3/TLS rollback check */
+	};
+
+#ifdef __cplusplus
+}
+#endif
+
+#include <openssl/ssl2.h>
+#include <openssl/ssl3.h>
+#include <openssl/tls1.h> /* This is mostly sslv3 with a few tweaks */
+#include <openssl/dtls1.h> /* Datagram TLS */
+#include <openssl/ssl23.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* compatibility */
+#define SSL_set_app_data(s,arg)		(SSL_set_ex_data(s,0,(char *)arg))
+#define SSL_get_app_data(s)		(SSL_get_ex_data(s,0))
+#define SSL_SESSION_set_app_data(s,a)	(SSL_SESSION_set_ex_data(s,0,(char *)a))
+#define SSL_SESSION_get_app_data(s)	(SSL_SESSION_get_ex_data(s,0))
+#define SSL_CTX_get_app_data(ctx)	(SSL_CTX_get_ex_data(ctx,0))
+#define SSL_CTX_set_app_data(ctx,arg)	(SSL_CTX_set_ex_data(ctx,0,(char *)arg))
+
+/* The following are the possible values for ssl->state are are
+ * used to indicate where we are up to in the SSL connection establishment.
+ * The macros that follow are about the only things you should need to use
+ * and even then, only when using non-blocking IO.
+ * It can also be useful to work out where you were when the connection
+ * failed */
+
+#define SSL_ST_CONNECT			0x1000
+#define SSL_ST_ACCEPT			0x2000
+#define SSL_ST_MASK			0x0FFF
+#define SSL_ST_INIT			(SSL_ST_CONNECT|SSL_ST_ACCEPT)
+#define SSL_ST_BEFORE			0x4000
+#define SSL_ST_OK			0x03
+#define SSL_ST_RENEGOTIATE		(0x04|SSL_ST_INIT)
+
+#define SSL_CB_LOOP			0x01
+#define SSL_CB_EXIT			0x02
+#define SSL_CB_READ			0x04
+#define SSL_CB_WRITE			0x08
+#define SSL_CB_ALERT			0x4000 /* used in callback */
+#define SSL_CB_READ_ALERT		(SSL_CB_ALERT|SSL_CB_READ)
+#define SSL_CB_WRITE_ALERT		(SSL_CB_ALERT|SSL_CB_WRITE)
+#define SSL_CB_ACCEPT_LOOP		(SSL_ST_ACCEPT|SSL_CB_LOOP)
+#define SSL_CB_ACCEPT_EXIT		(SSL_ST_ACCEPT|SSL_CB_EXIT)
+#define SSL_CB_CONNECT_LOOP		(SSL_ST_CONNECT|SSL_CB_LOOP)
+#define SSL_CB_CONNECT_EXIT		(SSL_ST_CONNECT|SSL_CB_EXIT)
+#define SSL_CB_HANDSHAKE_START		0x10
+#define SSL_CB_HANDSHAKE_DONE		0x20
+
+/* Is the SSL_connection established? */
+#define SSL_get_state(a)		SSL_state(a)
+#define SSL_is_init_finished(a)		(SSL_state(a) == SSL_ST_OK)
+#define SSL_in_init(a)			(SSL_state(a)&SSL_ST_INIT)
+#define SSL_in_before(a)		(SSL_state(a)&SSL_ST_BEFORE)
+#define SSL_in_connect_init(a)		(SSL_state(a)&SSL_ST_CONNECT)
+#define SSL_in_accept_init(a)		(SSL_state(a)&SSL_ST_ACCEPT)
+
+/* The following 2 states are kept in ssl->rstate when reads fail,
+ * you should not need these */
+#define SSL_ST_READ_HEADER			0xF0
+#define SSL_ST_READ_BODY			0xF1
+#define SSL_ST_READ_DONE			0xF2
+
+/* Obtain latest Finished message
+ *   -- that we sent (SSL_get_finished)
+ *   -- that we expected from peer (SSL_get_peer_finished).
+ * Returns length (0 == no Finished so far), copies up to 'count' bytes. */
+size_t SSL_get_finished(const SSL *s, void *buf, size_t count);
+size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count);
+
+/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options
+ * are 'ored' with SSL_VERIFY_PEER if they are desired */
+#define SSL_VERIFY_NONE			0x00
+#define SSL_VERIFY_PEER			0x01
+#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT	0x02
+#define SSL_VERIFY_CLIENT_ONCE		0x04
+
+#define OpenSSL_add_ssl_algorithms()	SSL_library_init()
+#define SSLeay_add_ssl_algorithms()	SSL_library_init()
+
+/* this is for backward compatibility */
+#if 0 /* NEW_SSLEAY */
+#define SSL_CTX_set_default_verify(a,b,c) SSL_CTX_set_verify(a,b,c)
+#define SSL_set_pref_cipher(c,n)	SSL_set_cipher_list(c,n)
+#define SSL_add_session(a,b)            SSL_CTX_add_session((a),(b))
+#define SSL_remove_session(a,b)		SSL_CTX_remove_session((a),(b))
+#define SSL_flush_sessions(a,b)		SSL_CTX_flush_sessions((a),(b))
+#endif
+/* More backward compatibility */
+#define SSL_get_cipher(s) \
+		SSL_CIPHER_get_name(SSL_get_current_cipher(s))
+#define SSL_get_cipher_bits(s,np) \
+		SSL_CIPHER_get_bits(SSL_get_current_cipher(s),np)
+#define SSL_get_cipher_version(s) \
+		SSL_CIPHER_get_version(SSL_get_current_cipher(s))
+#define SSL_get_cipher_name(s) \
+		SSL_CIPHER_get_name(SSL_get_current_cipher(s))
+#define SSL_get_time(a)		SSL_SESSION_get_time(a)
+#define SSL_set_time(a,b)	SSL_SESSION_set_time((a),(b))
+#define SSL_get_timeout(a)	SSL_SESSION_get_timeout(a)
+#define SSL_set_timeout(a,b)	SSL_SESSION_set_timeout((a),(b))
+
+#if 1 /*SSLEAY_MACROS*/
+#define d2i_SSL_SESSION_bio(bp,s_id) ASN1_d2i_bio_of(SSL_SESSION,SSL_SESSION_new,d2i_SSL_SESSION,bp,s_id)
+#define i2d_SSL_SESSION_bio(bp,s_id) ASN1_i2d_bio_of(SSL_SESSION,i2d_SSL_SESSION,bp,s_id)
+#define PEM_read_SSL_SESSION(fp,x,cb,u) (SSL_SESSION *)PEM_ASN1_read( \
+	(char *(*)())d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,fp,(char **)x,cb,u)
+#define PEM_read_bio_SSL_SESSION(bp,x,cb,u) PEM_ASN1_read_bio_of(SSL_SESSION,d2i_SSL_SESSION,PEM_STRING_SSL_SESSION,bp,x,cb,u)
+#define PEM_write_SSL_SESSION(fp,x) \
+	PEM_ASN1_write((int (*)())i2d_SSL_SESSION, \
+		PEM_STRING_SSL_SESSION,fp, (char *)x, NULL,NULL,0,NULL,NULL)
+#define PEM_write_bio_SSL_SESSION(bp,x) \
+	PEM_ASN1_write_bio_of(SSL_SESSION,i2d_SSL_SESSION,PEM_STRING_SSL_SESSION,bp,x,NULL,NULL,0,NULL,NULL)
+#endif
+
+#define SSL_AD_REASON_OFFSET		1000
+/* These alert types are for SSLv3 and TLSv1 */
+#define SSL_AD_CLOSE_NOTIFY		SSL3_AD_CLOSE_NOTIFY
+#define SSL_AD_UNEXPECTED_MESSAGE	SSL3_AD_UNEXPECTED_MESSAGE /* fatal */
+#define SSL_AD_BAD_RECORD_MAC		SSL3_AD_BAD_RECORD_MAC     /* fatal */
+#define SSL_AD_DECRYPTION_FAILED	TLS1_AD_DECRYPTION_FAILED
+#define SSL_AD_RECORD_OVERFLOW		TLS1_AD_RECORD_OVERFLOW
+#define SSL_AD_DECOMPRESSION_FAILURE	SSL3_AD_DECOMPRESSION_FAILURE/* fatal */
+#define SSL_AD_HANDSHAKE_FAILURE	SSL3_AD_HANDSHAKE_FAILURE/* fatal */
+#define SSL_AD_NO_CERTIFICATE		SSL3_AD_NO_CERTIFICATE /* Not for TLS */
+#define SSL_AD_BAD_CERTIFICATE		SSL3_AD_BAD_CERTIFICATE
+#define SSL_AD_UNSUPPORTED_CERTIFICATE	SSL3_AD_UNSUPPORTED_CERTIFICATE
+#define SSL_AD_CERTIFICATE_REVOKED	SSL3_AD_CERTIFICATE_REVOKED
+#define SSL_AD_CERTIFICATE_EXPIRED	SSL3_AD_CERTIFICATE_EXPIRED
+#define SSL_AD_CERTIFICATE_UNKNOWN	SSL3_AD_CERTIFICATE_UNKNOWN
+#define SSL_AD_ILLEGAL_PARAMETER	SSL3_AD_ILLEGAL_PARAMETER   /* fatal */
+#define SSL_AD_UNKNOWN_CA		TLS1_AD_UNKNOWN_CA	/* fatal */
+#define SSL_AD_ACCESS_DENIED		TLS1_AD_ACCESS_DENIED	/* fatal */
+#define SSL_AD_DECODE_ERROR		TLS1_AD_DECODE_ERROR	/* fatal */
+#define SSL_AD_DECRYPT_ERROR		TLS1_AD_DECRYPT_ERROR
+#define SSL_AD_EXPORT_RESTRICTION	TLS1_AD_EXPORT_RESTRICTION/* fatal */
+#define SSL_AD_PROTOCOL_VERSION		TLS1_AD_PROTOCOL_VERSION /* fatal */
+#define SSL_AD_INSUFFICIENT_SECURITY	TLS1_AD_INSUFFICIENT_SECURITY/* fatal */
+#define SSL_AD_INTERNAL_ERROR		TLS1_AD_INTERNAL_ERROR	/* fatal */
+#define SSL_AD_USER_CANCELLED		TLS1_AD_USER_CANCELLED
+#define SSL_AD_NO_RENEGOTIATION		TLS1_AD_NO_RENEGOTIATION
+
+#define SSL_ERROR_NONE			0
+#define SSL_ERROR_SSL			1
+#define SSL_ERROR_WANT_READ		2
+#define SSL_ERROR_WANT_WRITE		3
+#define SSL_ERROR_WANT_X509_LOOKUP	4
+#define SSL_ERROR_SYSCALL		5 /* look at error stack/return value/errno */
+#define SSL_ERROR_ZERO_RETURN		6
+#define SSL_ERROR_WANT_CONNECT		7
+#define SSL_ERROR_WANT_ACCEPT		8
+
+#define SSL_CTRL_NEED_TMP_RSA			1
+#define SSL_CTRL_SET_TMP_RSA			2
+#define SSL_CTRL_SET_TMP_DH			3
+#define SSL_CTRL_SET_TMP_ECDH			4
+#define SSL_CTRL_SET_TMP_RSA_CB			5
+#define SSL_CTRL_SET_TMP_DH_CB			6
+#define SSL_CTRL_SET_TMP_ECDH_CB		7
+
+#define SSL_CTRL_GET_SESSION_REUSED		8
+#define SSL_CTRL_GET_CLIENT_CERT_REQUEST	9
+#define SSL_CTRL_GET_NUM_RENEGOTIATIONS		10
+#define SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS	11
+#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS	12
+#define SSL_CTRL_GET_FLAGS			13
+#define SSL_CTRL_EXTRA_CHAIN_CERT		14
+
+#define SSL_CTRL_SET_MSG_CALLBACK               15
+#define SSL_CTRL_SET_MSG_CALLBACK_ARG           16
+
+/* only applies to datagram connections */
+#define SSL_CTRL_SET_MTU                17
+/* Stats */
+#define SSL_CTRL_SESS_NUMBER			20
+#define SSL_CTRL_SESS_CONNECT			21
+#define SSL_CTRL_SESS_CONNECT_GOOD		22
+#define SSL_CTRL_SESS_CONNECT_RENEGOTIATE	23
+#define SSL_CTRL_SESS_ACCEPT			24
+#define SSL_CTRL_SESS_ACCEPT_GOOD		25
+#define SSL_CTRL_SESS_ACCEPT_RENEGOTIATE	26
+#define SSL_CTRL_SESS_HIT			27
+#define SSL_CTRL_SESS_CB_HIT			28
+#define SSL_CTRL_SESS_MISSES			29
+#define SSL_CTRL_SESS_TIMEOUTS			30
+#define SSL_CTRL_SESS_CACHE_FULL		31
+#define SSL_CTRL_OPTIONS			32
+#define SSL_CTRL_MODE				33
+
+#define SSL_CTRL_GET_READ_AHEAD			40
+#define SSL_CTRL_SET_READ_AHEAD			41
+#define SSL_CTRL_SET_SESS_CACHE_SIZE		42
+#define SSL_CTRL_GET_SESS_CACHE_SIZE		43
+#define SSL_CTRL_SET_SESS_CACHE_MODE		44
+#define SSL_CTRL_GET_SESS_CACHE_MODE		45
+
+#define SSL_CTRL_GET_MAX_CERT_LIST		50
+#define SSL_CTRL_SET_MAX_CERT_LIST		51
+
+#define SSL_session_reused(ssl) \
+	SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
+#define SSL_num_renegotiations(ssl) \
+	SSL_ctrl((ssl),SSL_CTRL_GET_NUM_RENEGOTIATIONS,0,NULL)
+#define SSL_clear_num_renegotiations(ssl) \
+	SSL_ctrl((ssl),SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS,0,NULL)
+#define SSL_total_renegotiations(ssl) \
+	SSL_ctrl((ssl),SSL_CTRL_GET_TOTAL_RENEGOTIATIONS,0,NULL)
+
+#define SSL_CTX_need_tmp_RSA(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_NEED_TMP_RSA,0,NULL)
+#define SSL_CTX_set_tmp_rsa(ctx,rsa) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
+#define SSL_CTX_set_tmp_dh(ctx,dh) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
+#define SSL_CTX_set_tmp_ecdh(ctx,ecdh) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
+
+#define SSL_need_tmp_RSA(ssl) \
+	SSL_ctrl(ssl,SSL_CTRL_NEED_TMP_RSA,0,NULL)
+#define SSL_set_tmp_rsa(ssl,rsa) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_RSA,0,(char *)rsa)
+#define SSL_set_tmp_dh(ssl,dh) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_DH,0,(char *)dh)
+#define SSL_set_tmp_ecdh(ssl,ecdh) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_TMP_ECDH,0,(char *)ecdh)
+
+#define SSL_CTX_add_extra_chain_cert(ctx,x509) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
+
+#ifndef OPENSSL_NO_BIO
+BIO_METHOD *BIO_f_ssl(void);
+BIO *BIO_new_ssl(SSL_CTX *ctx,int client);
+BIO *BIO_new_ssl_connect(SSL_CTX *ctx);
+BIO *BIO_new_buffer_ssl_connect(SSL_CTX *ctx);
+int BIO_ssl_copy_session_id(BIO *to,BIO *from);
+void BIO_ssl_shutdown(BIO *ssl_bio);
+
+#endif
+
+int	SSL_CTX_set_cipher_list(SSL_CTX *,const char *str);
+SSL_CTX *SSL_CTX_new(SSL_METHOD *meth);
+void	SSL_CTX_free(SSL_CTX *);
+long SSL_CTX_set_timeout(SSL_CTX *ctx,long t);
+long SSL_CTX_get_timeout(const SSL_CTX *ctx);
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *);
+void SSL_CTX_set_cert_store(SSL_CTX *,X509_STORE *);
+int SSL_want(const SSL *s);
+int	SSL_clear(SSL *s);
+
+void	SSL_CTX_flush_sessions(SSL_CTX *ctx,long tm);
+
+SSL_CIPHER *SSL_get_current_cipher(const SSL *s);
+int	SSL_CIPHER_get_bits(const SSL_CIPHER *c,int *alg_bits);
+char *	SSL_CIPHER_get_version(const SSL_CIPHER *c);
+const char *	SSL_CIPHER_get_name(const SSL_CIPHER *c);
+
+int	SSL_get_fd(const SSL *s);
+int	SSL_get_rfd(const SSL *s);
+int	SSL_get_wfd(const SSL *s);
+const char  * SSL_get_cipher_list(const SSL *s,int n);
+char *	SSL_get_shared_ciphers(const SSL *s, char *buf, int len);
+int	SSL_get_read_ahead(const SSL * s);
+int	SSL_pending(const SSL *s);
+#ifndef OPENSSL_NO_SOCK
+int	SSL_set_fd(SSL *s, int fd);
+int	SSL_set_rfd(SSL *s, int fd);
+int	SSL_set_wfd(SSL *s, int fd);
+#endif
+#ifndef OPENSSL_NO_BIO
+void	SSL_set_bio(SSL *s, BIO *rbio,BIO *wbio);
+BIO *	SSL_get_rbio(const SSL *s);
+BIO *	SSL_get_wbio(const SSL *s);
+#endif
+int	SSL_set_cipher_list(SSL *s, const char *str);
+void	SSL_set_read_ahead(SSL *s, int yes);
+int	SSL_get_verify_mode(const SSL *s);
+int	SSL_get_verify_depth(const SSL *s);
+int	(*SSL_get_verify_callback(const SSL *s))(int,X509_STORE_CTX *);
+void	SSL_set_verify(SSL *s, int mode,
+		       int (*callback)(int ok,X509_STORE_CTX *ctx));
+void	SSL_set_verify_depth(SSL *s, int depth);
+#ifndef OPENSSL_NO_RSA
+int	SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa);
+#endif
+int	SSL_use_RSAPrivateKey_ASN1(SSL *ssl, unsigned char *d, long len);
+int	SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey);
+int	SSL_use_PrivateKey_ASN1(int pk,SSL *ssl, const unsigned char *d, long len);
+int	SSL_use_certificate(SSL *ssl, X509 *x);
+int	SSL_use_certificate_ASN1(SSL *ssl, const unsigned char *d, int len);
+
+#ifndef OPENSSL_NO_STDIO
+int	SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, int type);
+int	SSL_use_PrivateKey_file(SSL *ssl, const char *file, int type);
+int	SSL_use_certificate_file(SSL *ssl, const char *file, int type);
+int	SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type);
+int	SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);
+int	SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type);
+int	SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); /* PEM type */
+STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file);
+int	SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
+					    const char *file);
+#ifndef OPENSSL_SYS_VMS
+#ifndef OPENSSL_SYS_MACINTOSH_CLASSIC /* XXXXX: Better scheme needed! [was: #ifndef MAC_OS_pre_X] */
+int	SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stackCAs,
+					   const char *dir);
+#endif
+#endif
+
+#endif
+
+void	SSL_load_error_strings(void );
+const char *SSL_state_string(const SSL *s);
+const char *SSL_rstate_string(const SSL *s);
+const char *SSL_state_string_long(const SSL *s);
+const char *SSL_rstate_string_long(const SSL *s);
+long	SSL_SESSION_get_time(const SSL_SESSION *s);
+long	SSL_SESSION_set_time(SSL_SESSION *s, long t);
+long	SSL_SESSION_get_timeout(const SSL_SESSION *s);
+long	SSL_SESSION_set_timeout(SSL_SESSION *s, long t);
+void	SSL_copy_session_id(SSL *to,const SSL *from);
+
+SSL_SESSION *SSL_SESSION_new(void);
+unsigned long SSL_SESSION_hash(const SSL_SESSION *a);
+int	SSL_SESSION_cmp(const SSL_SESSION *a,const SSL_SESSION *b);
+const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *s, unsigned int *len);
+#ifndef OPENSSL_NO_FP_API
+int	SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses);
+#endif
+#ifndef OPENSSL_NO_BIO
+int	SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses);
+#endif
+void	SSL_SESSION_free(SSL_SESSION *ses);
+int	i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp);
+int	SSL_set_session(SSL *to, SSL_SESSION *session);
+int	SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c);
+int	SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c);
+int	SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB);
+int	SSL_set_generate_session_id(SSL *, GEN_SESSION_CB);
+int	SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id,
+					unsigned int id_len);
+SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp,
+			     long length);
+
+#ifdef HEADER_X509_H
+X509 *	SSL_get_peer_certificate(const SSL *s);
+#endif
+
+STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s);
+
+int SSL_CTX_get_verify_mode(const SSL_CTX *ctx);
+int SSL_CTX_get_verify_depth(const SSL_CTX *ctx);
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))(int,X509_STORE_CTX *);
+void SSL_CTX_set_verify(SSL_CTX *ctx,int mode,
+			int (*callback)(int, X509_STORE_CTX *));
+void SSL_CTX_set_verify_depth(SSL_CTX *ctx,int depth);
+void SSL_CTX_set_cert_verify_callback(SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *,void *), void *arg);
+#ifndef OPENSSL_NO_RSA
+int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa);
+#endif
+int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len);
+int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey);
+int SSL_CTX_use_PrivateKey_ASN1(int pk,SSL_CTX *ctx,
+	const unsigned char *d, long len);
+int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);
+int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d);
+
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb);
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *u);
+
+int SSL_CTX_check_private_key(const SSL_CTX *ctx);
+int SSL_check_private_key(const SSL *ctx);
+
+int	SSL_CTX_set_session_id_context(SSL_CTX *ctx,const unsigned char *sid_ctx,
+				       unsigned int sid_ctx_len);
+
+SSL *	SSL_new(SSL_CTX *ctx);
+int	SSL_set_session_id_context(SSL *ssl,const unsigned char *sid_ctx,
+				   unsigned int sid_ctx_len);
+
+int SSL_CTX_set_purpose(SSL_CTX *s, int purpose);
+int SSL_set_purpose(SSL *s, int purpose);
+int SSL_CTX_set_trust(SSL_CTX *s, int trust);
+int SSL_set_trust(SSL *s, int trust);
+
+void	SSL_free(SSL *ssl);
+int 	SSL_accept(SSL *ssl);
+int 	SSL_connect(SSL *ssl);
+int 	SSL_read(SSL *ssl,void *buf,int num);
+int 	SSL_peek(SSL *ssl,void *buf,int num);
+int 	SSL_write(SSL *ssl,const void *buf,int num);
+long	SSL_ctrl(SSL *ssl,int cmd, long larg, void *parg);
+long	SSL_callback_ctrl(SSL *, int, void (*)(void));
+long	SSL_CTX_ctrl(SSL_CTX *ctx,int cmd, long larg, void *parg);
+long	SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void));
+
+int	SSL_get_error(const SSL *s,int ret_code);
+const char *SSL_get_version(const SSL *s);
+
+/* This sets the 'default' SSL version that SSL_new() will create */
+int SSL_CTX_set_ssl_version(SSL_CTX *ctx,SSL_METHOD *meth);
+
+SSL_METHOD *SSLv2_method(void);		/* SSLv2 */
+SSL_METHOD *SSLv2_server_method(void);	/* SSLv2 */
+SSL_METHOD *SSLv2_client_method(void);	/* SSLv2 */
+
+SSL_METHOD *SSLv3_method(void);		/* SSLv3 */
+SSL_METHOD *SSLv3_server_method(void);	/* SSLv3 */
+SSL_METHOD *SSLv3_client_method(void);	/* SSLv3 */
+
+SSL_METHOD *SSLv23_method(void);	/* SSLv3 but can rollback to v2 */
+SSL_METHOD *SSLv23_server_method(void);	/* SSLv3 but can rollback to v2 */
+SSL_METHOD *SSLv23_client_method(void);	/* SSLv3 but can rollback to v2 */
+
+SSL_METHOD *TLSv1_method(void);		/* TLSv1.0 */
+SSL_METHOD *TLSv1_server_method(void);	/* TLSv1.0 */
+SSL_METHOD *TLSv1_client_method(void);	/* TLSv1.0 */
+
+SSL_METHOD *DTLSv1_method(void);		/* DTLSv1.0 */
+SSL_METHOD *DTLSv1_server_method(void);	/* DTLSv1.0 */
+SSL_METHOD *DTLSv1_client_method(void);	/* DTLSv1.0 */
+
+STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s);
+
+int SSL_do_handshake(SSL *s);
+int SSL_renegotiate(SSL *s);
+int SSL_renegotiate_pending(SSL *s);
+int SSL_shutdown(SSL *s);
+
+SSL_METHOD *SSL_get_ssl_method(SSL *s);
+int SSL_set_ssl_method(SSL *s,SSL_METHOD *method);
+const char *SSL_alert_type_string_long(int value);
+const char *SSL_alert_type_string(int value);
+const char *SSL_alert_desc_string_long(int value);
+const char *SSL_alert_desc_string(int value);
+
+void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list);
+void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list);
+STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s);
+STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *s);
+int SSL_add_client_CA(SSL *ssl,X509 *x);
+int SSL_CTX_add_client_CA(SSL_CTX *ctx,X509 *x);
+
+void SSL_set_connect_state(SSL *s);
+void SSL_set_accept_state(SSL *s);
+
+long SSL_get_default_timeout(const SSL *s);
+
+int SSL_library_init(void );
+
+char *SSL_CIPHER_description(SSL_CIPHER *,char *buf,int size);
+STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk);
+
+SSL *SSL_dup(SSL *ssl);
+
+X509 *SSL_get_certificate(const SSL *ssl);
+/* EVP_PKEY */ struct evp_pkey_st *SSL_get_privatekey(SSL *ssl);
+
+void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx,int mode);
+int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx);
+void SSL_set_quiet_shutdown(SSL *ssl,int mode);
+int SSL_get_quiet_shutdown(const SSL *ssl);
+void SSL_set_shutdown(SSL *ssl,int mode);
+int SSL_get_shutdown(const SSL *ssl);
+int SSL_version(const SSL *ssl);
+int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx);
+int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile,
+	const char *CApath);
+#define SSL_get0_session SSL_get_session /* just peek at pointer */
+SSL_SESSION *SSL_get_session(const SSL *ssl);
+SSL_SESSION *SSL_get1_session(SSL *ssl); /* obtain a reference count */
+SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl);
+void SSL_set_info_callback(SSL *ssl,
+			   void (*cb)(const SSL *ssl,int type,int val));
+void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl,int type,int val);
+int SSL_state(const SSL *ssl);
+
+void SSL_set_verify_result(SSL *ssl,long v);
+long SSL_get_verify_result(const SSL *ssl);
+
+int SSL_set_ex_data(SSL *ssl,int idx,void *data);
+void *SSL_get_ex_data(const SSL *ssl,int idx);
+int SSL_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_SESSION_set_ex_data(SSL_SESSION *ss,int idx,void *data);
+void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss,int idx);
+int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_CTX_set_ex_data(SSL_CTX *ssl,int idx,void *data);
+void *SSL_CTX_get_ex_data(const SSL_CTX *ssl,int idx);
+int SSL_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+
+int SSL_get_ex_data_X509_STORE_CTX_idx(void );
+
+#define SSL_CTX_sess_set_cache_size(ctx,t) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_SIZE,t,NULL)
+#define SSL_CTX_sess_get_cache_size(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_SIZE,0,NULL)
+#define SSL_CTX_set_session_cache_mode(ctx,m) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_SESS_CACHE_MODE,m,NULL)
+#define SSL_CTX_get_session_cache_mode(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_SESS_CACHE_MODE,0,NULL)
+
+#define SSL_CTX_get_default_read_ahead(ctx) SSL_CTX_get_read_ahead(ctx)
+#define SSL_CTX_set_default_read_ahead(ctx,m) SSL_CTX_set_read_ahead(ctx,m)
+#define SSL_CTX_get_read_ahead(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_READ_AHEAD,0,NULL)
+#define SSL_CTX_set_read_ahead(ctx,m) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_READ_AHEAD,m,NULL)
+#define SSL_CTX_get_max_cert_list(ctx) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
+#define SSL_CTX_set_max_cert_list(ctx,m) \
+	SSL_CTX_ctrl(ctx,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
+#define SSL_get_max_cert_list(ssl) \
+	SSL_ctrl(ssl,SSL_CTRL_GET_MAX_CERT_LIST,0,NULL)
+#define SSL_set_max_cert_list(ssl,m) \
+	SSL_ctrl(ssl,SSL_CTRL_SET_MAX_CERT_LIST,m,NULL)
+
+     /* NB: the keylength is only applicable when is_export is true */
+#ifndef OPENSSL_NO_RSA
+void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx,
+				  RSA *(*cb)(SSL *ssl,int is_export,
+					     int keylength));
+
+void SSL_set_tmp_rsa_callback(SSL *ssl,
+				  RSA *(*cb)(SSL *ssl,int is_export,
+					     int keylength));
+#endif
+#ifndef OPENSSL_NO_DH
+void SSL_CTX_set_tmp_dh_callback(SSL_CTX *ctx,
+				 DH *(*dh)(SSL *ssl,int is_export,
+					   int keylength));
+void SSL_set_tmp_dh_callback(SSL *ssl,
+				 DH *(*dh)(SSL *ssl,int is_export,
+					   int keylength));
+#endif
+#ifndef OPENSSL_NO_ECDH
+void SSL_CTX_set_tmp_ecdh_callback(SSL_CTX *ctx,
+				 EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+					   int keylength));
+void SSL_set_tmp_ecdh_callback(SSL *ssl,
+				 EC_KEY *(*ecdh)(SSL *ssl,int is_export,
+					   int keylength));
+#endif
+
+#ifndef OPENSSL_NO_COMP
+const COMP_METHOD *SSL_get_current_compression(SSL *s);
+const COMP_METHOD *SSL_get_current_expansion(SSL *s);
+const char *SSL_COMP_get_name(const COMP_METHOD *comp);
+STACK_OF(SSL_COMP) *SSL_COMP_get_compression_methods(void);
+int SSL_COMP_add_compression_method(int id,COMP_METHOD *cm);
+#else
+const void *SSL_get_current_compression(SSL *s);
+const void *SSL_get_current_expansion(SSL *s);
+const char *SSL_COMP_get_name(const void *comp);
+void *SSL_COMP_get_compression_methods(void);
+int SSL_COMP_add_compression_method(int id,void *cm);
+#endif
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_SSL_strings(void);
+
+/* Error codes for the SSL functions. */
+
+/* Function codes. */
+#define SSL_F_CLIENT_CERTIFICATE			 100
+#define SSL_F_CLIENT_FINISHED				 238
+#define SSL_F_CLIENT_HELLO				 101
+#define SSL_F_CLIENT_MASTER_KEY				 102
+#define SSL_F_D2I_SSL_SESSION				 103
+#define SSL_F_DO_DTLS1_WRITE				 1003
+#define SSL_F_DO_SSL3_WRITE				 104
+#define SSL_F_DTLS1_ACCEPT				 1004
+#define SSL_F_DTLS1_BUFFER_RECORD			 1005
+#define SSL_F_DTLS1_CLIENT_HELLO			 1006
+#define SSL_F_DTLS1_CONNECT				 1007
+#define SSL_F_DTLS1_ENC					 1008
+#define SSL_F_DTLS1_GET_HELLO_VERIFY			 1009
+#define SSL_F_DTLS1_GET_MESSAGE				 1010
+#define SSL_F_DTLS1_GET_MESSAGE_FRAGMENT		 1011
+#define SSL_F_DTLS1_GET_RECORD				 1012
+#define SSL_F_DTLS1_OUTPUT_CERT_CHAIN			 1013
+#define SSL_F_DTLS1_PROCESS_OUT_OF_SEQ_MESSAGE		 1014
+#define SSL_F_DTLS1_PROCESS_RECORD			 1015
+#define SSL_F_DTLS1_READ_BYTES				 1016
+#define SSL_F_DTLS1_READ_FAILED				 1001
+#define SSL_F_DTLS1_SEND_CERTIFICATE_REQUEST		 1017
+#define SSL_F_DTLS1_SEND_CLIENT_CERTIFICATE		 1018
+#define SSL_F_DTLS1_SEND_CLIENT_KEY_EXCHANGE		 1019
+#define SSL_F_DTLS1_SEND_CLIENT_VERIFY			 1020
+#define SSL_F_DTLS1_SEND_HELLO_VERIFY_REQUEST		 1002
+#define SSL_F_DTLS1_SEND_SERVER_CERTIFICATE		 1021
+#define SSL_F_DTLS1_SEND_SERVER_HELLO			 1022
+#define SSL_F_DTLS1_SEND_SERVER_KEY_EXCHANGE		 1023
+#define SSL_F_DTLS1_WRITE_APP_DATA_BYTES		 1024
+#define SSL_F_GET_CLIENT_FINISHED			 105
+#define SSL_F_GET_CLIENT_HELLO				 106
+#define SSL_F_GET_CLIENT_MASTER_KEY			 107
+#define SSL_F_GET_SERVER_FINISHED			 108
+#define SSL_F_GET_SERVER_HELLO				 109
+#define SSL_F_GET_SERVER_VERIFY				 110
+#define SSL_F_I2D_SSL_SESSION				 111
+#define SSL_F_READ_N					 112
+#define SSL_F_REQUEST_CERTIFICATE			 113
+#define SSL_F_SERVER_FINISH				 239
+#define SSL_F_SERVER_HELLO				 114
+#define SSL_F_SERVER_VERIFY				 240
+#define SSL_F_SSL23_ACCEPT				 115
+#define SSL_F_SSL23_CLIENT_HELLO			 116
+#define SSL_F_SSL23_CONNECT				 117
+#define SSL_F_SSL23_GET_CLIENT_HELLO			 118
+#define SSL_F_SSL23_GET_SERVER_HELLO			 119
+#define SSL_F_SSL23_PEEK				 237
+#define SSL_F_SSL23_READ				 120
+#define SSL_F_SSL23_WRITE				 121
+#define SSL_F_SSL2_ACCEPT				 122
+#define SSL_F_SSL2_CONNECT				 123
+#define SSL_F_SSL2_ENC_INIT				 124
+#define SSL_F_SSL2_GENERATE_KEY_MATERIAL		 241
+#define SSL_F_SSL2_PEEK					 234
+#define SSL_F_SSL2_READ					 125
+#define SSL_F_SSL2_READ_INTERNAL			 236
+#define SSL_F_SSL2_SET_CERTIFICATE			 126
+#define SSL_F_SSL2_WRITE				 127
+#define SSL_F_SSL3_ACCEPT				 128
+#define SSL_F_SSL3_CALLBACK_CTRL			 233
+#define SSL_F_SSL3_CHANGE_CIPHER_STATE			 129
+#define SSL_F_SSL3_CHECK_CERT_AND_ALGORITHM		 130
+#define SSL_F_SSL3_CLIENT_HELLO				 131
+#define SSL_F_SSL3_CONNECT				 132
+#define SSL_F_SSL3_CTRL					 213
+#define SSL_F_SSL3_CTX_CTRL				 133
+#define SSL_F_SSL3_ENC					 134
+#define SSL_F_SSL3_GENERATE_KEY_BLOCK			 238
+#define SSL_F_SSL3_GET_CERTIFICATE_REQUEST		 135
+#define SSL_F_SSL3_GET_CERT_VERIFY			 136
+#define SSL_F_SSL3_GET_CLIENT_CERTIFICATE		 137
+#define SSL_F_SSL3_GET_CLIENT_HELLO			 138
+#define SSL_F_SSL3_GET_CLIENT_KEY_EXCHANGE		 139
+#define SSL_F_SSL3_GET_FINISHED				 140
+#define SSL_F_SSL3_GET_KEY_EXCHANGE			 141
+#define SSL_F_SSL3_GET_MESSAGE				 142
+#define SSL_F_SSL3_GET_RECORD				 143
+#define SSL_F_SSL3_GET_SERVER_CERTIFICATE		 144
+#define SSL_F_SSL3_GET_SERVER_DONE			 145
+#define SSL_F_SSL3_GET_SERVER_HELLO			 146
+#define SSL_F_SSL3_OUTPUT_CERT_CHAIN			 147
+#define SSL_F_SSL3_PEEK					 235
+#define SSL_F_SSL3_READ_BYTES				 148
+#define SSL_F_SSL3_READ_N				 149
+#define SSL_F_SSL3_SEND_CERTIFICATE_REQUEST		 150
+#define SSL_F_SSL3_SEND_CLIENT_CERTIFICATE		 151
+#define SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE		 152
+#define SSL_F_SSL3_SEND_CLIENT_VERIFY			 153
+#define SSL_F_SSL3_SEND_SERVER_CERTIFICATE		 154
+#define SSL_F_SSL3_SEND_SERVER_HELLO			 242
+#define SSL_F_SSL3_SEND_SERVER_KEY_EXCHANGE		 155
+#define SSL_F_SSL3_SETUP_BUFFERS			 156
+#define SSL_F_SSL3_SETUP_KEY_BLOCK			 157
+#define SSL_F_SSL3_WRITE_BYTES				 158
+#define SSL_F_SSL3_WRITE_PENDING			 159
+#define SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK	 215
+#define SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK	 216
+#define SSL_F_SSL_BAD_METHOD				 160
+#define SSL_F_SSL_BYTES_TO_CIPHER_LIST			 161
+#define SSL_F_SSL_CERT_DUP				 221
+#define SSL_F_SSL_CERT_INST				 222
+#define SSL_F_SSL_CERT_INSTANTIATE			 214
+#define SSL_F_SSL_CERT_NEW				 162
+#define SSL_F_SSL_CHECK_PRIVATE_KEY			 163
+#define SSL_F_SSL_CIPHER_PROCESS_RULESTR		 230
+#define SSL_F_SSL_CIPHER_STRENGTH_SORT			 231
+#define SSL_F_SSL_CLEAR					 164
+#define SSL_F_SSL_COMP_ADD_COMPRESSION_METHOD		 165
+#define SSL_F_SSL_CREATE_CIPHER_LIST			 166
+#define SSL_F_SSL_CTRL					 232
+#define SSL_F_SSL_CTX_CHECK_PRIVATE_KEY			 168
+#define SSL_F_SSL_CTX_NEW				 169
+#define SSL_F_SSL_CTX_SET_CIPHER_LIST			 1026
+#define SSL_F_SSL_CTX_SET_PURPOSE			 226
+#define SSL_F_SSL_CTX_SET_SESSION_ID_CONTEXT		 219
+#define SSL_F_SSL_CTX_SET_SSL_VERSION			 170
+#define SSL_F_SSL_CTX_SET_TRUST				 229
+#define SSL_F_SSL_CTX_USE_CERTIFICATE			 171
+#define SSL_F_SSL_CTX_USE_CERTIFICATE_ASN1		 172
+#define SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE	 220
+#define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE		 173
+#define SSL_F_SSL_CTX_USE_PRIVATEKEY			 174
+#define SSL_F_SSL_CTX_USE_PRIVATEKEY_ASN1		 175
+#define SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE		 176
+#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY			 177
+#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_ASN1		 178
+#define SSL_F_SSL_CTX_USE_RSAPRIVATEKEY_FILE		 179
+#define SSL_F_SSL_DO_HANDSHAKE				 180
+#define SSL_F_SSL_GET_NEW_SESSION			 181
+#define SSL_F_SSL_GET_PREV_SESSION			 217
+#define SSL_F_SSL_GET_SERVER_SEND_CERT			 182
+#define SSL_F_SSL_GET_SIGN_PKEY				 183
+#define SSL_F_SSL_INIT_WBIO_BUFFER			 184
+#define SSL_F_SSL_LOAD_CLIENT_CA_FILE			 185
+#define SSL_F_SSL_NEW					 186
+#define SSL_F_SSL_PEEK					 1025
+#define SSL_F_SSL_READ					 223
+#define SSL_F_SSL_RSA_PRIVATE_DECRYPT			 187
+#define SSL_F_SSL_RSA_PUBLIC_ENCRYPT			 188
+#define SSL_F_SSL_SESSION_NEW				 189
+#define SSL_F_SSL_SESSION_PRINT_FP			 190
+#define SSL_F_SSL_SESS_CERT_NEW				 225
+#define SSL_F_SSL_SET_CERT				 191
+#define SSL_F_SSL_SET_CIPHER_LIST			 1027
+#define SSL_F_SSL_SET_FD				 192
+#define SSL_F_SSL_SET_PKEY				 193
+#define SSL_F_SSL_SET_PURPOSE				 227
+#define SSL_F_SSL_SET_RFD				 194
+#define SSL_F_SSL_SET_SESSION				 195
+#define SSL_F_SSL_SET_SESSION_ID_CONTEXT		 218
+#define SSL_F_SSL_SET_TRUST				 228
+#define SSL_F_SSL_SET_WFD				 196
+#define SSL_F_SSL_SHUTDOWN				 224
+#define SSL_F_SSL_UNDEFINED_CONST_FUNCTION		 243
+#define SSL_F_SSL_UNDEFINED_FUNCTION			 197
+#define SSL_F_SSL_UNDEFINED_VOID_FUNCTION		 244
+#define SSL_F_SSL_USE_CERTIFICATE			 198
+#define SSL_F_SSL_USE_CERTIFICATE_ASN1			 199
+#define SSL_F_SSL_USE_CERTIFICATE_FILE			 200
+#define SSL_F_SSL_USE_PRIVATEKEY			 201
+#define SSL_F_SSL_USE_PRIVATEKEY_ASN1			 202
+#define SSL_F_SSL_USE_PRIVATEKEY_FILE			 203
+#define SSL_F_SSL_USE_RSAPRIVATEKEY			 204
+#define SSL_F_SSL_USE_RSAPRIVATEKEY_ASN1		 205
+#define SSL_F_SSL_USE_RSAPRIVATEKEY_FILE		 206
+#define SSL_F_SSL_VERIFY_CERT_CHAIN			 207
+#define SSL_F_SSL_WRITE					 208
+#define SSL_F_TLS1_CHANGE_CIPHER_STATE			 209
+#define SSL_F_TLS1_ENC					 210
+#define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+#define SSL_F_WRITE_PENDING				 212
+
+/* Reason codes. */
+#define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 272
+#define SSL_R_BAD_ALERT_RECORD				 101
+#define SSL_R_BAD_AUTHENTICATION_TYPE			 102
+#define SSL_R_BAD_CHANGE_CIPHER_SPEC			 103
+#define SSL_R_BAD_CHECKSUM				 104
+#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK		 106
+#define SSL_R_BAD_DECOMPRESSION				 107
+#define SSL_R_BAD_DH_G_LENGTH				 108
+#define SSL_R_BAD_DH_PUB_KEY_LENGTH			 109
+#define SSL_R_BAD_DH_P_LENGTH				 110
+#define SSL_R_BAD_DIGEST_LENGTH				 111
+#define SSL_R_BAD_DSA_SIGNATURE				 112
+#define SSL_R_BAD_ECC_CERT				 1117
+#define SSL_R_BAD_ECDSA_SIGNATURE			 1112
+#define SSL_R_BAD_ECPOINT				 1113
+#define SSL_R_BAD_HELLO_REQUEST				 105
+#define SSL_R_BAD_LENGTH				 271
+#define SSL_R_BAD_MAC_DECODE				 113
+#define SSL_R_BAD_MESSAGE_TYPE				 114
+#define SSL_R_BAD_PACKET_LENGTH				 115
+#define SSL_R_BAD_PROTOCOL_VERSION_NUMBER		 116
+#define SSL_R_BAD_RESPONSE_ARGUMENT			 117
+#define SSL_R_BAD_RSA_DECRYPT				 118
+#define SSL_R_BAD_RSA_ENCRYPT				 119
+#define SSL_R_BAD_RSA_E_LENGTH				 120
+#define SSL_R_BAD_RSA_MODULUS_LENGTH			 121
+#define SSL_R_BAD_RSA_SIGNATURE				 122
+#define SSL_R_BAD_SIGNATURE				 123
+#define SSL_R_BAD_SSL_FILETYPE				 124
+#define SSL_R_BAD_SSL_SESSION_ID_LENGTH			 125
+#define SSL_R_BAD_STATE					 126
+#define SSL_R_BAD_WRITE_RETRY				 127
+#define SSL_R_BIO_NOT_SET				 128
+#define SSL_R_BLOCK_CIPHER_PAD_IS_WRONG			 129
+#define SSL_R_BN_LIB					 130
+#define SSL_R_CA_DN_LENGTH_MISMATCH			 131
+#define SSL_R_CA_DN_TOO_LONG				 132
+#define SSL_R_CCS_RECEIVED_EARLY			 133
+#define SSL_R_CERTIFICATE_VERIFY_FAILED			 134
+#define SSL_R_CERT_LENGTH_MISMATCH			 135
+#define SSL_R_CHALLENGE_IS_DIFFERENT			 136
+#define SSL_R_CIPHER_CODE_WRONG_LENGTH			 137
+#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE		 138
+#define SSL_R_CIPHER_TABLE_SRC_ERROR			 139
+#define SSL_R_COMPRESSED_LENGTH_TOO_LONG		 140
+#define SSL_R_COMPRESSION_FAILURE			 141
+#define SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE	 1120
+#define SSL_R_COMPRESSION_LIBRARY_ERROR			 142
+#define SSL_R_CONNECTION_ID_IS_DIFFERENT		 143
+#define SSL_R_CONNECTION_TYPE_NOT_SET			 144
+#define SSL_R_COOKIE_MISMATCH				 2002
+#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED		 145
+#define SSL_R_DATA_LENGTH_TOO_LONG			 146
+#define SSL_R_DECRYPTION_FAILED				 147
+#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC	 1109
+#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG		 148
+#define SSL_R_DIGEST_CHECK_FAILED			 149
+#define SSL_R_DUPLICATE_COMPRESSION_ID			 1121
+#define SSL_R_ECGROUP_TOO_LARGE_FOR_CIPHER		 1119
+#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG			 150
+#define SSL_R_ERROR_GENERATING_TMP_RSA_KEY		 1092
+#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST		 151
+#define SSL_R_EXCESSIVE_MESSAGE_SIZE			 152
+#define SSL_R_EXTRA_DATA_IN_MESSAGE			 153
+#define SSL_R_GOT_A_FIN_BEFORE_A_CCS			 154
+#define SSL_R_HTTPS_PROXY_REQUEST			 155
+#define SSL_R_HTTP_REQUEST				 156
+#define SSL_R_ILLEGAL_PADDING				 1110
+#define SSL_R_INVALID_CHALLENGE_LENGTH			 158
+#define SSL_R_INVALID_COMMAND				 280
+#define SSL_R_INVALID_PURPOSE				 278
+#define SSL_R_INVALID_TRUST				 279
+#define SSL_R_KEY_ARG_TOO_LONG				 1112
+#define SSL_R_KRB5					 1104
+#define SSL_R_KRB5_C_CC_PRINC				 1094
+#define SSL_R_KRB5_C_GET_CRED				 1095
+#define SSL_R_KRB5_C_INIT				 1096
+#define SSL_R_KRB5_C_MK_REQ				 1097
+#define SSL_R_KRB5_S_BAD_TICKET				 1098
+#define SSL_R_KRB5_S_INIT				 1099
+#define SSL_R_KRB5_S_RD_REQ				 1108
+#define SSL_R_KRB5_S_TKT_EXPIRED			 1105
+#define SSL_R_KRB5_S_TKT_NYV				 1106
+#define SSL_R_KRB5_S_TKT_SKEW				 1107
+#define SSL_R_LENGTH_MISMATCH				 159
+#define SSL_R_LENGTH_TOO_SHORT				 160
+#define SSL_R_LIBRARY_BUG				 274
+#define SSL_R_LIBRARY_HAS_NO_CIPHERS			 161
+#define SSL_R_MASTER_KEY_TOO_LONG			 1112
+#define SSL_R_MESSAGE_TOO_LONG				 1111
+#define SSL_R_MISSING_DH_DSA_CERT			 162
+#define SSL_R_MISSING_DH_KEY				 163
+#define SSL_R_MISSING_DH_RSA_CERT			 164
+#define SSL_R_MISSING_DSA_SIGNING_CERT			 165
+#define SSL_R_MISSING_EXPORT_TMP_DH_KEY			 166
+#define SSL_R_MISSING_EXPORT_TMP_RSA_KEY		 167
+#define SSL_R_MISSING_RSA_CERTIFICATE			 168
+#define SSL_R_MISSING_RSA_ENCRYPTING_CERT		 169
+#define SSL_R_MISSING_RSA_SIGNING_CERT			 170
+#define SSL_R_MISSING_TMP_DH_KEY			 171
+#define SSL_R_MISSING_TMP_ECDH_KEY			 1114
+#define SSL_R_MISSING_TMP_RSA_KEY			 172
+#define SSL_R_MISSING_TMP_RSA_PKEY			 173
+#define SSL_R_MISSING_VERIFY_MESSAGE			 174
+#define SSL_R_NON_SSLV2_INITIAL_PACKET			 175
+#define SSL_R_NO_CERTIFICATES_RETURNED			 176
+#define SSL_R_NO_CERTIFICATE_ASSIGNED			 177
+#define SSL_R_NO_CERTIFICATE_RETURNED			 178
+#define SSL_R_NO_CERTIFICATE_SET			 179
+#define SSL_R_NO_CERTIFICATE_SPECIFIED			 180
+#define SSL_R_NO_CIPHERS_AVAILABLE			 181
+#define SSL_R_NO_CIPHERS_PASSED				 182
+#define SSL_R_NO_CIPHERS_SPECIFIED			 183
+#define SSL_R_NO_CIPHER_LIST				 184
+#define SSL_R_NO_CIPHER_MATCH				 185
+#define SSL_R_NO_CLIENT_CERT_RECEIVED			 186
+#define SSL_R_NO_COMPRESSION_SPECIFIED			 187
+#define SSL_R_NO_METHOD_SPECIFIED			 188
+#define SSL_R_NO_PRIVATEKEY				 189
+#define SSL_R_NO_PRIVATE_KEY_ASSIGNED			 190
+#define SSL_R_NO_PROTOCOLS_AVAILABLE			 191
+#define SSL_R_NO_PUBLICKEY				 192
+#define SSL_R_NO_SHARED_CIPHER				 193
+#define SSL_R_NO_VERIFY_CALLBACK			 194
+#define SSL_R_NULL_SSL_CTX				 195
+#define SSL_R_NULL_SSL_METHOD_PASSED			 196
+#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED		 197
+#define SSL_R_PACKET_LENGTH_TOO_LONG			 198
+#define SSL_R_PATH_TOO_LONG				 270
+#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE		 199
+#define SSL_R_PEER_ERROR				 200
+#define SSL_R_PEER_ERROR_CERTIFICATE			 201
+#define SSL_R_PEER_ERROR_NO_CERTIFICATE			 202
+#define SSL_R_PEER_ERROR_NO_CIPHER			 203
+#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE	 204
+#define SSL_R_PRE_MAC_LENGTH_TOO_LONG			 205
+#define SSL_R_PROBLEMS_MAPPING_CIPHER_FUNCTIONS		 206
+#define SSL_R_PROTOCOL_IS_SHUTDOWN			 207
+#define SSL_R_PUBLIC_KEY_ENCRYPT_ERROR			 208
+#define SSL_R_PUBLIC_KEY_IS_NOT_RSA			 209
+#define SSL_R_PUBLIC_KEY_NOT_RSA			 210
+#define SSL_R_READ_BIO_NOT_SET				 211
+#define SSL_R_READ_TIMEOUT_EXPIRED			 2001
+#define SSL_R_READ_WRONG_PACKET_TYPE			 212
+#define SSL_R_RECORD_LENGTH_MISMATCH			 213
+#define SSL_R_RECORD_TOO_LARGE				 214
+#define SSL_R_RECORD_TOO_SMALL				 1093
+#define SSL_R_REQUIRED_CIPHER_MISSING			 215
+#define SSL_R_REUSE_CERT_LENGTH_NOT_ZERO		 216
+#define SSL_R_REUSE_CERT_TYPE_NOT_ZERO			 217
+#define SSL_R_REUSE_CIPHER_LIST_NOT_ZERO		 218
+#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED		 277
+#define SSL_R_SHORT_READ				 219
+#define SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE	 220
+#define SSL_R_SSL23_DOING_SESSION_ID_REUSE		 221
+#define SSL_R_SSL2_CONNECTION_ID_TOO_LONG		 1114
+#define SSL_R_SSL3_SESSION_ID_TOO_LONG			 1113
+#define SSL_R_SSL3_SESSION_ID_TOO_SHORT			 222
+#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE		 1042
+#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC		 1020
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED		 1045
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED		 1044
+#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN		 1046
+#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE		 1030
+#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE		 1040
+#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER		 1047
+#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE		 1041
+#define SSL_R_SSLV3_ALERT_PEER_ERROR_CERTIFICATE	 223
+#define SSL_R_SSLV3_ALERT_PEER_ERROR_NO_CERTIFICATE	 224
+#define SSL_R_SSLV3_ALERT_PEER_ERROR_NO_CIPHER		 225
+#define SSL_R_SSLV3_ALERT_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 226
+#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE		 1010
+#define SSL_R_SSLV3_ALERT_UNKNOWN_REMOTE_ERROR_TYPE	 227
+#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE	 1043
+#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION	 228
+#define SSL_R_SSL_HANDSHAKE_FAILURE			 229
+#define SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS		 230
+#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED		 1102
+#define SSL_R_SSL_SESSION_ID_CONFLICT			 1103
+#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG		 273
+#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH		 1101
+#define SSL_R_SSL_SESSION_ID_IS_DIFFERENT		 231
+#define SSL_R_TLSV1_ALERT_ACCESS_DENIED			 1049
+#define SSL_R_TLSV1_ALERT_DECODE_ERROR			 1050
+#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED		 1021
+#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR			 1051
+#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION		 1060
+#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY		 1071
+#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR		 1080
+#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION		 1100
+#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION		 1070
+#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW		 1022
+#define SSL_R_TLSV1_ALERT_UNKNOWN_CA			 1048
+#define SSL_R_TLSV1_ALERT_USER_CANCELLED		 1090
+#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER	 232
+#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 233
+#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG	 234
+#define SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER		 235
+#define SSL_R_UNABLE_TO_DECODE_DH_CERTS			 236
+#define SSL_R_UNABLE_TO_DECODE_ECDH_CERTS		 1115
+#define SSL_R_UNABLE_TO_EXTRACT_PUBLIC_KEY		 237
+#define SSL_R_UNABLE_TO_FIND_DH_PARAMETERS		 238
+#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS		 1116
+#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS	 239
+#define SSL_R_UNABLE_TO_FIND_SSL_METHOD			 240
+#define SSL_R_UNABLE_TO_LOAD_SSL2_MD5_ROUTINES		 241
+#define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES		 242
+#define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES		 243
+#define SSL_R_UNEXPECTED_MESSAGE			 244
+#define SSL_R_UNEXPECTED_RECORD				 245
+#define SSL_R_UNINITIALIZED				 276
+#define SSL_R_UNKNOWN_ALERT_TYPE			 246
+#define SSL_R_UNKNOWN_CERTIFICATE_TYPE			 247
+#define SSL_R_UNKNOWN_CIPHER_RETURNED			 248
+#define SSL_R_UNKNOWN_CIPHER_TYPE			 249
+#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE			 250
+#define SSL_R_UNKNOWN_PKEY_TYPE				 251
+#define SSL_R_UNKNOWN_PROTOCOL				 252
+#define SSL_R_UNKNOWN_REMOTE_ERROR_TYPE			 253
+#define SSL_R_UNKNOWN_SSL_VERSION			 254
+#define SSL_R_UNKNOWN_STATE				 255
+#define SSL_R_UNSUPPORTED_CIPHER			 256
+#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM		 257
+#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE		 1118
+#define SSL_R_UNSUPPORTED_OPTION			 1091
+#define SSL_R_UNSUPPORTED_PROTOCOL			 258
+#define SSL_R_UNSUPPORTED_SSL_VERSION			 259
+#define SSL_R_WRITE_BIO_NOT_SET				 260
+#define SSL_R_WRONG_CIPHER_RETURNED			 261
+#define SSL_R_WRONG_MESSAGE_TYPE			 262
+#define SSL_R_WRONG_NUMBER_OF_KEY_BITS			 263
+#define SSL_R_WRONG_SIGNATURE_LENGTH			 264
+#define SSL_R_WRONG_SIGNATURE_SIZE			 265
+#define SSL_R_WRONG_SSL_VERSION				 266
+#define SSL_R_WRONG_VERSION_NUMBER			 267
+#define SSL_R_X509_LIB					 268
+#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS		 269
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl2.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl2.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,268 @@
+/* ssl/ssl2.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_SSL2_H 
+#define HEADER_SSL2_H 
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Protocol Version Codes */
+#define SSL2_VERSION		0x0002
+#define SSL2_VERSION_MAJOR	0x00
+#define SSL2_VERSION_MINOR	0x02
+/* #define SSL2_CLIENT_VERSION	0x0002 */
+/* #define SSL2_SERVER_VERSION	0x0002 */
+
+/* Protocol Message Codes */
+#define SSL2_MT_ERROR			0
+#define SSL2_MT_CLIENT_HELLO		1
+#define SSL2_MT_CLIENT_MASTER_KEY	2
+#define SSL2_MT_CLIENT_FINISHED		3
+#define SSL2_MT_SERVER_HELLO		4
+#define SSL2_MT_SERVER_VERIFY		5
+#define SSL2_MT_SERVER_FINISHED		6
+#define SSL2_MT_REQUEST_CERTIFICATE	7
+#define SSL2_MT_CLIENT_CERTIFICATE	8
+
+/* Error Message Codes */
+#define SSL2_PE_UNDEFINED_ERROR		0x0000
+#define SSL2_PE_NO_CIPHER		0x0001
+#define SSL2_PE_NO_CERTIFICATE		0x0002
+#define SSL2_PE_BAD_CERTIFICATE		0x0004
+#define SSL2_PE_UNSUPPORTED_CERTIFICATE_TYPE 0x0006
+
+/* Cipher Kind Values */
+#define SSL2_CK_NULL_WITH_MD5			0x02000000 /* v3 */
+#define SSL2_CK_RC4_128_WITH_MD5		0x02010080
+#define SSL2_CK_RC4_128_EXPORT40_WITH_MD5	0x02020080
+#define SSL2_CK_RC2_128_CBC_WITH_MD5		0x02030080
+#define SSL2_CK_RC2_128_CBC_EXPORT40_WITH_MD5	0x02040080
+#define SSL2_CK_IDEA_128_CBC_WITH_MD5		0x02050080
+#define SSL2_CK_DES_64_CBC_WITH_MD5		0x02060040
+#define SSL2_CK_DES_64_CBC_WITH_SHA		0x02060140 /* v3 */
+#define SSL2_CK_DES_192_EDE3_CBC_WITH_MD5	0x020700c0
+#define SSL2_CK_DES_192_EDE3_CBC_WITH_SHA	0x020701c0 /* v3 */
+#define SSL2_CK_RC4_64_WITH_MD5			0x02080080 /* MS hack */
+ 
+#define SSL2_CK_DES_64_CFB64_WITH_MD5_1		0x02ff0800 /* SSLeay */
+#define SSL2_CK_NULL				0x02ff0810 /* SSLeay */
+
+#define SSL2_TXT_DES_64_CFB64_WITH_MD5_1	"DES-CFB-M1"
+#define SSL2_TXT_NULL_WITH_MD5			"NULL-MD5"
+#define SSL2_TXT_RC4_128_WITH_MD5		"RC4-MD5"
+#define SSL2_TXT_RC4_128_EXPORT40_WITH_MD5	"EXP-RC4-MD5"
+#define SSL2_TXT_RC2_128_CBC_WITH_MD5		"RC2-CBC-MD5"
+#define SSL2_TXT_RC2_128_CBC_EXPORT40_WITH_MD5	"EXP-RC2-CBC-MD5"
+#define SSL2_TXT_IDEA_128_CBC_WITH_MD5		"IDEA-CBC-MD5"
+#define SSL2_TXT_DES_64_CBC_WITH_MD5		"DES-CBC-MD5"
+#define SSL2_TXT_DES_64_CBC_WITH_SHA		"DES-CBC-SHA"
+#define SSL2_TXT_DES_192_EDE3_CBC_WITH_MD5	"DES-CBC3-MD5"
+#define SSL2_TXT_DES_192_EDE3_CBC_WITH_SHA	"DES-CBC3-SHA"
+#define SSL2_TXT_RC4_64_WITH_MD5		"RC4-64-MD5"
+
+#define SSL2_TXT_NULL				"NULL"
+
+/* Flags for the SSL_CIPHER.algorithm2 field */
+#define SSL2_CF_5_BYTE_ENC			0x01
+#define SSL2_CF_8_BYTE_ENC			0x02
+
+/* Certificate Type Codes */
+#define SSL2_CT_X509_CERTIFICATE		0x01
+
+/* Authentication Type Code */
+#define SSL2_AT_MD5_WITH_RSA_ENCRYPTION		0x01
+
+#define SSL2_MAX_SSL_SESSION_ID_LENGTH		32
+
+/* Upper/Lower Bounds */
+#define SSL2_MAX_MASTER_KEY_LENGTH_IN_BITS	256
+#ifdef OPENSSL_SYS_MPE
+#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER	29998u
+#else
+#define SSL2_MAX_RECORD_LENGTH_2_BYTE_HEADER	32767u  /* 2^15-1 */
+#endif
+#define SSL2_MAX_RECORD_LENGTH_3_BYTE_HEADER	16383 /* 2^14-1 */
+
+#define SSL2_CHALLENGE_LENGTH	16
+/*#define SSL2_CHALLENGE_LENGTH	32 */
+#define SSL2_MIN_CHALLENGE_LENGTH	16
+#define SSL2_MAX_CHALLENGE_LENGTH	32
+#define SSL2_CONNECTION_ID_LENGTH	16
+#define SSL2_MAX_CONNECTION_ID_LENGTH	16
+#define SSL2_SSL_SESSION_ID_LENGTH	16
+#define SSL2_MAX_CERT_CHALLENGE_LENGTH	32
+#define SSL2_MIN_CERT_CHALLENGE_LENGTH	16
+#define SSL2_MAX_KEY_MATERIAL_LENGTH	24
+
+#ifndef HEADER_SSL_LOCL_H
+#define  CERT		char
+#endif
+
+typedef struct ssl2_state_st
+	{
+	int three_byte_header;
+	int clear_text;		/* clear text */
+	int escape;		/* not used in SSLv2 */
+	int ssl2_rollback;	/* used if SSLv23 rolled back to SSLv2 */
+
+	/* non-blocking io info, used to make sure the same
+	 * args were passwd */
+	unsigned int wnum;	/* number of bytes sent so far */
+	int wpend_tot;
+	const unsigned char *wpend_buf;
+
+	int wpend_off;	/* offset to data to write */
+	int wpend_len; 	/* number of bytes passwd to write */
+	int wpend_ret; 	/* number of bytes to return to caller */
+
+	/* buffer raw data */
+	int rbuf_left;
+	int rbuf_offs;
+	unsigned char *rbuf;
+	unsigned char *wbuf;
+
+	unsigned char *write_ptr;/* used to point to the start due to
+				  * 2/3 byte header. */
+
+	unsigned int padding;
+	unsigned int rlength; /* passed to ssl2_enc */
+	int ract_data_length; /* Set when things are encrypted. */
+	unsigned int wlength; /* passed to ssl2_enc */
+	int wact_data_length; /* Set when things are decrypted. */
+	unsigned char *ract_data;
+	unsigned char *wact_data;
+	unsigned char *mac_data;
+
+	unsigned char *read_key;
+	unsigned char *write_key;
+
+		/* Stuff specifically to do with this SSL session */
+	unsigned int challenge_length;
+	unsigned char challenge[SSL2_MAX_CHALLENGE_LENGTH];
+	unsigned int conn_id_length;
+	unsigned char conn_id[SSL2_MAX_CONNECTION_ID_LENGTH];
+	unsigned int key_material_length;
+	unsigned char key_material[SSL2_MAX_KEY_MATERIAL_LENGTH*2];
+
+	unsigned long read_sequence;
+	unsigned long write_sequence;
+
+	struct	{
+		unsigned int conn_id_length;
+		unsigned int cert_type;	
+		unsigned int cert_length;
+		unsigned int csl; 
+		unsigned int clear;
+		unsigned int enc; 
+		unsigned char ccl[SSL2_MAX_CERT_CHALLENGE_LENGTH];
+		unsigned int cipher_spec_length;
+		unsigned int session_id_length;
+		unsigned int clen;
+		unsigned int rlen;
+		} tmp;
+	} SSL2_STATE;
+
+/* SSLv2 */
+/* client */
+#define SSL2_ST_SEND_CLIENT_HELLO_A		(0x10|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_HELLO_B		(0x11|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_HELLO_A		(0x20|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_HELLO_B		(0x21|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_MASTER_KEY_A	(0x30|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_MASTER_KEY_B	(0x31|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_FINISHED_A		(0x40|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_FINISHED_B		(0x41|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_CERTIFICATE_A	(0x50|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_CERTIFICATE_B	(0x51|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_CERTIFICATE_C	(0x52|SSL_ST_CONNECT)
+#define SSL2_ST_SEND_CLIENT_CERTIFICATE_D	(0x53|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_VERIFY_A		(0x60|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_VERIFY_B		(0x61|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_FINISHED_A		(0x70|SSL_ST_CONNECT)
+#define SSL2_ST_GET_SERVER_FINISHED_B		(0x71|SSL_ST_CONNECT)
+#define SSL2_ST_CLIENT_START_ENCRYPTION		(0x80|SSL_ST_CONNECT)
+#define SSL2_ST_X509_GET_CLIENT_CERTIFICATE	(0x90|SSL_ST_CONNECT)
+/* server */
+#define SSL2_ST_GET_CLIENT_HELLO_A		(0x10|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_HELLO_B		(0x11|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_HELLO_C		(0x12|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_HELLO_A		(0x20|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_HELLO_B		(0x21|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_MASTER_KEY_A		(0x30|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_MASTER_KEY_B		(0x31|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_VERIFY_A		(0x40|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_VERIFY_B		(0x41|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_VERIFY_C		(0x42|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_FINISHED_A		(0x50|SSL_ST_ACCEPT)
+#define SSL2_ST_GET_CLIENT_FINISHED_B		(0x51|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_FINISHED_A		(0x60|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_SERVER_FINISHED_B		(0x61|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_REQUEST_CERTIFICATE_A	(0x70|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_REQUEST_CERTIFICATE_B	(0x71|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_REQUEST_CERTIFICATE_C	(0x72|SSL_ST_ACCEPT)
+#define SSL2_ST_SEND_REQUEST_CERTIFICATE_D	(0x73|SSL_ST_ACCEPT)
+#define SSL2_ST_SERVER_START_ENCRYPTION		(0x80|SSL_ST_ACCEPT)
+#define SSL2_ST_X509_GET_SERVER_CERTIFICATE	(0x90|SSL_ST_ACCEPT)
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl23.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl23.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl23.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,83 @@
+/* ssl/ssl23.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_SSL23_H 
+#define HEADER_SSL23_H 
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*client */
+/* write to server */
+#define SSL23_ST_CW_CLNT_HELLO_A	(0x210|SSL_ST_CONNECT)
+#define SSL23_ST_CW_CLNT_HELLO_B	(0x211|SSL_ST_CONNECT)
+/* read from server */
+#define SSL23_ST_CR_SRVR_HELLO_A	(0x220|SSL_ST_CONNECT)
+#define SSL23_ST_CR_SRVR_HELLO_B	(0x221|SSL_ST_CONNECT)
+
+/* server */
+/* read from client */
+#define SSL23_ST_SR_CLNT_HELLO_A	(0x210|SSL_ST_ACCEPT)
+#define SSL23_ST_SR_CLNT_HELLO_B	(0x211|SSL_ST_ACCEPT)
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl3.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl3.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ssl3.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,551 @@
+/* ssl/ssl3.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright (c) 1998-2002 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECC cipher suite support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#ifndef HEADER_SSL3_H 
+#define HEADER_SSL3_H 
+
+#ifndef OPENSSL_NO_COMP
+#include <openssl/comp.h>
+#endif
+#include <openssl/buffer.h>
+#include <openssl/evp.h>
+#include <openssl/ssl.h>
+#include <openssl/pq_compat.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define SSL3_CK_RSA_NULL_MD5			0x03000001
+#define SSL3_CK_RSA_NULL_SHA			0x03000002
+#define SSL3_CK_RSA_RC4_40_MD5 			0x03000003
+#define SSL3_CK_RSA_RC4_128_MD5			0x03000004
+#define SSL3_CK_RSA_RC4_128_SHA			0x03000005
+#define SSL3_CK_RSA_RC2_40_MD5			0x03000006
+#define SSL3_CK_RSA_IDEA_128_SHA		0x03000007
+#define SSL3_CK_RSA_DES_40_CBC_SHA		0x03000008
+#define SSL3_CK_RSA_DES_64_CBC_SHA		0x03000009
+#define SSL3_CK_RSA_DES_192_CBC3_SHA		0x0300000A
+
+#define SSL3_CK_DH_DSS_DES_40_CBC_SHA		0x0300000B
+#define SSL3_CK_DH_DSS_DES_64_CBC_SHA		0x0300000C
+#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 	0x0300000D
+#define SSL3_CK_DH_RSA_DES_40_CBC_SHA		0x0300000E
+#define SSL3_CK_DH_RSA_DES_64_CBC_SHA		0x0300000F
+#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 	0x03000010
+
+#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA		0x03000011
+#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA		0x03000012
+#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA	0x03000013
+#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA		0x03000014
+#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA		0x03000015
+#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA	0x03000016
+
+#define SSL3_CK_ADH_RC4_40_MD5			0x03000017
+#define SSL3_CK_ADH_RC4_128_MD5			0x03000018
+#define SSL3_CK_ADH_DES_40_CBC_SHA		0x03000019
+#define SSL3_CK_ADH_DES_64_CBC_SHA		0x0300001A
+#define SSL3_CK_ADH_DES_192_CBC_SHA		0x0300001B
+
+#define SSL3_CK_FZA_DMS_NULL_SHA		0x0300001C
+#define SSL3_CK_FZA_DMS_FZA_SHA			0x0300001D
+#if 0 /* Because it clashes with KRB5, is never used any more, and is safe
+	 to remove according to David Hopwood <david.hopwood@zetnet.co.uk>
+	 of the ietf-tls list */
+#define SSL3_CK_FZA_DMS_RC4_SHA			0x0300001E
+#endif
+
+/*    VRS Additional Kerberos5 entries
+ */
+#define SSL3_CK_KRB5_DES_64_CBC_SHA		0x0300001E
+#define SSL3_CK_KRB5_DES_192_CBC3_SHA		0x0300001F
+#define SSL3_CK_KRB5_RC4_128_SHA		0x03000020
+#define SSL3_CK_KRB5_IDEA_128_CBC_SHA	       	0x03000021
+#define SSL3_CK_KRB5_DES_64_CBC_MD5       	0x03000022
+#define SSL3_CK_KRB5_DES_192_CBC3_MD5       	0x03000023
+#define SSL3_CK_KRB5_RC4_128_MD5	       	0x03000024
+#define SSL3_CK_KRB5_IDEA_128_CBC_MD5 		0x03000025
+
+#define SSL3_CK_KRB5_DES_40_CBC_SHA 		0x03000026
+#define SSL3_CK_KRB5_RC2_40_CBC_SHA 		0x03000027
+#define SSL3_CK_KRB5_RC4_40_SHA	 		0x03000028
+#define SSL3_CK_KRB5_DES_40_CBC_MD5 		0x03000029
+#define SSL3_CK_KRB5_RC2_40_CBC_MD5 		0x0300002A
+#define SSL3_CK_KRB5_RC4_40_MD5	 		0x0300002B
+
+#define SSL3_TXT_RSA_NULL_MD5			"NULL-MD5"
+#define SSL3_TXT_RSA_NULL_SHA			"NULL-SHA"
+#define SSL3_TXT_RSA_RC4_40_MD5 		"EXP-RC4-MD5"
+#define SSL3_TXT_RSA_RC4_128_MD5		"RC4-MD5"
+#define SSL3_TXT_RSA_RC4_128_SHA		"RC4-SHA"
+#define SSL3_TXT_RSA_RC2_40_MD5			"EXP-RC2-CBC-MD5"
+#define SSL3_TXT_RSA_IDEA_128_SHA		"IDEA-CBC-SHA"
+#define SSL3_TXT_RSA_DES_40_CBC_SHA		"EXP-DES-CBC-SHA"
+#define SSL3_TXT_RSA_DES_64_CBC_SHA		"DES-CBC-SHA"
+#define SSL3_TXT_RSA_DES_192_CBC3_SHA		"DES-CBC3-SHA"
+
+#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA		"EXP-DH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA		"DH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA 	"DH-DSS-DES-CBC3-SHA"
+#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA		"EXP-DH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA		"DH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA 	"DH-RSA-DES-CBC3-SHA"
+
+#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA		"EXP-EDH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA		"EDH-DSS-DES-CBC-SHA"
+#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA	"EDH-DSS-DES-CBC3-SHA"
+#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA		"EXP-EDH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA		"EDH-RSA-DES-CBC-SHA"
+#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA	"EDH-RSA-DES-CBC3-SHA"
+
+#define SSL3_TXT_ADH_RC4_40_MD5			"EXP-ADH-RC4-MD5"
+#define SSL3_TXT_ADH_RC4_128_MD5		"ADH-RC4-MD5"
+#define SSL3_TXT_ADH_DES_40_CBC_SHA		"EXP-ADH-DES-CBC-SHA"
+#define SSL3_TXT_ADH_DES_64_CBC_SHA		"ADH-DES-CBC-SHA"
+#define SSL3_TXT_ADH_DES_192_CBC_SHA		"ADH-DES-CBC3-SHA"
+
+#define SSL3_TXT_FZA_DMS_NULL_SHA		"FZA-NULL-SHA"
+#define SSL3_TXT_FZA_DMS_FZA_SHA		"FZA-FZA-CBC-SHA"
+#define SSL3_TXT_FZA_DMS_RC4_SHA		"FZA-RC4-SHA"
+
+#define SSL3_TXT_KRB5_DES_64_CBC_SHA		"KRB5-DES-CBC-SHA"
+#define SSL3_TXT_KRB5_DES_192_CBC3_SHA		"KRB5-DES-CBC3-SHA"
+#define SSL3_TXT_KRB5_RC4_128_SHA		"KRB5-RC4-SHA"
+#define SSL3_TXT_KRB5_IDEA_128_CBC_SHA	       	"KRB5-IDEA-CBC-SHA"
+#define SSL3_TXT_KRB5_DES_64_CBC_MD5       	"KRB5-DES-CBC-MD5"
+#define SSL3_TXT_KRB5_DES_192_CBC3_MD5       	"KRB5-DES-CBC3-MD5"
+#define SSL3_TXT_KRB5_RC4_128_MD5		"KRB5-RC4-MD5"
+#define SSL3_TXT_KRB5_IDEA_128_CBC_MD5 		"KRB5-IDEA-CBC-MD5"
+
+#define SSL3_TXT_KRB5_DES_40_CBC_SHA 		"EXP-KRB5-DES-CBC-SHA"
+#define SSL3_TXT_KRB5_RC2_40_CBC_SHA 		"EXP-KRB5-RC2-CBC-SHA"
+#define SSL3_TXT_KRB5_RC4_40_SHA	 	"EXP-KRB5-RC4-SHA"
+#define SSL3_TXT_KRB5_DES_40_CBC_MD5 		"EXP-KRB5-DES-CBC-MD5"
+#define SSL3_TXT_KRB5_RC2_40_CBC_MD5 		"EXP-KRB5-RC2-CBC-MD5"
+#define SSL3_TXT_KRB5_RC4_40_MD5	 	"EXP-KRB5-RC4-MD5"
+
+#define SSL3_SSL_SESSION_ID_LENGTH		32
+#define SSL3_MAX_SSL_SESSION_ID_LENGTH		32
+
+#define SSL3_MASTER_SECRET_SIZE			48
+#define SSL3_RANDOM_SIZE			32
+#define SSL3_SESSION_ID_SIZE			32
+#define SSL3_RT_HEADER_LENGTH			5
+
+/* Due to MS stuffing up, this can change.... */
+#if defined(OPENSSL_SYS_WIN16) || \
+	(defined(OPENSSL_SYS_MSDOS) && !defined(OPENSSL_SYS_WIN32))
+#define SSL3_RT_MAX_EXTRA			(14000)
+#else
+#define SSL3_RT_MAX_EXTRA			(16384)
+#endif
+
+#define SSL3_RT_MAX_PLAIN_LENGTH		16384
+#define SSL3_RT_MAX_COMPRESSED_LENGTH	(1024+SSL3_RT_MAX_PLAIN_LENGTH)
+#define SSL3_RT_MAX_ENCRYPTED_LENGTH	(1024+SSL3_RT_MAX_COMPRESSED_LENGTH)
+#define SSL3_RT_MAX_PACKET_SIZE		(SSL3_RT_MAX_ENCRYPTED_LENGTH+SSL3_RT_HEADER_LENGTH)
+#define SSL3_RT_MAX_DATA_SIZE			(1024*1024)
+
+#define SSL3_MD_CLIENT_FINISHED_CONST	"\x43\x4C\x4E\x54"
+#define SSL3_MD_SERVER_FINISHED_CONST	"\x53\x52\x56\x52"
+
+#define SSL3_VERSION			0x0300
+#define SSL3_VERSION_MAJOR		0x03
+#define SSL3_VERSION_MINOR		0x00
+
+#define SSL3_RT_CHANGE_CIPHER_SPEC	20
+#define SSL3_RT_ALERT			21
+#define SSL3_RT_HANDSHAKE		22
+#define SSL3_RT_APPLICATION_DATA	23
+
+#define SSL3_AL_WARNING			1
+#define SSL3_AL_FATAL			2
+
+#define SSL3_AD_CLOSE_NOTIFY		 0
+#define SSL3_AD_UNEXPECTED_MESSAGE	10	/* fatal */
+#define SSL3_AD_BAD_RECORD_MAC		20	/* fatal */
+#define SSL3_AD_DECOMPRESSION_FAILURE	30	/* fatal */
+#define SSL3_AD_HANDSHAKE_FAILURE	40	/* fatal */
+#define SSL3_AD_NO_CERTIFICATE		41
+#define SSL3_AD_BAD_CERTIFICATE		42
+#define SSL3_AD_UNSUPPORTED_CERTIFICATE	43
+#define SSL3_AD_CERTIFICATE_REVOKED	44
+#define SSL3_AD_CERTIFICATE_EXPIRED	45
+#define SSL3_AD_CERTIFICATE_UNKNOWN	46
+#define SSL3_AD_ILLEGAL_PARAMETER	47	/* fatal */
+
+typedef struct ssl3_record_st
+	{
+/*r */	int type;               /* type of record */
+/*rw*/	unsigned int length;    /* How many bytes available */
+/*r */	unsigned int off;       /* read/write offset into 'buf' */
+/*rw*/	unsigned char *data;    /* pointer to the record data */
+/*rw*/	unsigned char *input;   /* where the decode bytes are */
+/*r */	unsigned char *comp;    /* only used with decompression - malloc()ed */
+/*r */  unsigned long epoch;    /* epoch number, needed by DTLS1 */
+/*r */  PQ_64BIT seq_num;       /* sequence number, needed by DTLS1 */
+	} SSL3_RECORD;
+
+typedef struct ssl3_buffer_st
+	{
+	unsigned char *buf;     /* at least SSL3_RT_MAX_PACKET_SIZE bytes,
+	                         * see ssl3_setup_buffers() */
+	size_t len;             /* buffer size */
+	int offset;             /* where to 'copy from' */
+	int left;               /* how many bytes left */
+	} SSL3_BUFFER;
+
+#define SSL3_CT_RSA_SIGN			1
+#define SSL3_CT_DSS_SIGN			2
+#define SSL3_CT_RSA_FIXED_DH			3
+#define SSL3_CT_DSS_FIXED_DH			4
+#define SSL3_CT_RSA_EPHEMERAL_DH		5
+#define SSL3_CT_DSS_EPHEMERAL_DH		6
+#define SSL3_CT_FORTEZZA_DMS			20
+/* SSL3_CT_NUMBER is used to size arrays and it must be large
+ * enough to contain all of the cert types defined either for
+ * SSLv3 and TLSv1.
+ */
+#define SSL3_CT_NUMBER			7
+
+
+#define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS	0x0001
+#define SSL3_FLAGS_DELAY_CLIENT_FINISHED	0x0002
+#define SSL3_FLAGS_POP_BUFFER			0x0004
+#define TLS1_FLAGS_TLS_PADDING_BUG		0x0008
+
+typedef struct ssl3_state_st
+	{
+	long flags;
+	int delay_buf_pop_ret;
+
+	unsigned char read_sequence[8];
+	unsigned char read_mac_secret[EVP_MAX_MD_SIZE];
+	unsigned char write_sequence[8];
+	unsigned char write_mac_secret[EVP_MAX_MD_SIZE];
+
+	unsigned char server_random[SSL3_RANDOM_SIZE];
+	unsigned char client_random[SSL3_RANDOM_SIZE];
+
+	/* flags for countermeasure against known-IV weakness */
+	int need_empty_fragments;
+	int empty_fragment_done;
+
+	SSL3_BUFFER rbuf;	/* read IO goes into here */
+	SSL3_BUFFER wbuf;	/* write IO goes into here */
+
+	SSL3_RECORD rrec;	/* each decoded record goes in here */
+	SSL3_RECORD wrec;	/* goes out from here */
+
+	/* storage for Alert/Handshake protocol data received but not
+	 * yet processed by ssl3_read_bytes: */
+	unsigned char alert_fragment[2];
+	unsigned int alert_fragment_len;
+	unsigned char handshake_fragment[4];
+	unsigned int handshake_fragment_len;
+
+	/* partial write - check the numbers match */
+	unsigned int wnum;	/* number of bytes sent so far */
+	int wpend_tot;		/* number bytes written */
+	int wpend_type;
+	int wpend_ret;		/* number of bytes submitted */
+	const unsigned char *wpend_buf;
+
+	/* used during startup, digest all incoming/outgoing packets */
+	EVP_MD_CTX finish_dgst1;
+	EVP_MD_CTX finish_dgst2;
+
+	/* this is set whenerver we see a change_cipher_spec message
+	 * come in when we are not looking for one */
+	int change_cipher_spec;
+
+	int warn_alert;
+	int fatal_alert;
+	/* we allow one fatal and one warning alert to be outstanding,
+	 * send close alert via the warning alert */
+	int alert_dispatch;
+	unsigned char send_alert[2];
+
+	/* This flag is set when we should renegotiate ASAP, basically when
+	 * there is no more data in the read or write buffers */
+	int renegotiate;
+	int total_renegotiations;
+	int num_renegotiations;
+
+	int in_read_app_data;
+
+	struct	{
+		/* actually only needs to be 16+20 */
+		unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
+
+		/* actually only need to be 16+20 for SSLv3 and 12 for TLS */
+		unsigned char finish_md[EVP_MAX_MD_SIZE*2];
+		int finish_md_len;
+		unsigned char peer_finish_md[EVP_MAX_MD_SIZE*2];
+		int peer_finish_md_len;
+		
+		unsigned long message_size;
+		int message_type;
+
+		/* used to hold the new cipher we are going to use */
+		SSL_CIPHER *new_cipher;
+#ifndef OPENSSL_NO_DH
+		DH *dh;
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+		EC_KEY *ecdh; /* holds short lived ECDH key */
+#endif
+
+		/* used when SSL_ST_FLUSH_DATA is entered */
+		int next_state;			
+
+		int reuse_message;
+
+		/* used for certificate requests */
+		int cert_req;
+		int ctype_num;
+		char ctype[SSL3_CT_NUMBER];
+		STACK_OF(X509_NAME) *ca_names;
+
+		int use_rsa_tmp;
+
+		int key_block_length;
+		unsigned char *key_block;
+
+		const EVP_CIPHER *new_sym_enc;
+		const EVP_MD *new_hash;
+#ifndef OPENSSL_NO_COMP
+		const SSL_COMP *new_compression;
+#else
+		char *new_compression;
+#endif
+		int cert_request;
+		} tmp;
+
+	} SSL3_STATE;
+
+
+/* SSLv3 */
+/*client */
+/* extra state */
+#define SSL3_ST_CW_FLUSH		(0x100|SSL_ST_CONNECT)
+/* write to server */
+#define SSL3_ST_CW_CLNT_HELLO_A		(0x110|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CLNT_HELLO_B		(0x111|SSL_ST_CONNECT)
+/* read from server */
+#define SSL3_ST_CR_SRVR_HELLO_A		(0x120|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SRVR_HELLO_B		(0x121|SSL_ST_CONNECT)
+#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126|SSL_ST_CONNECT)
+#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_A		(0x130|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_B		(0x131|SSL_ST_CONNECT)
+#define SSL3_ST_CR_KEY_EXCH_A		(0x140|SSL_ST_CONNECT)
+#define SSL3_ST_CR_KEY_EXCH_B		(0x141|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_REQ_A		(0x150|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CERT_REQ_B		(0x151|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SRVR_DONE_A		(0x160|SSL_ST_CONNECT)
+#define SSL3_ST_CR_SRVR_DONE_B		(0x161|SSL_ST_CONNECT)
+/* write to server */
+#define SSL3_ST_CW_CERT_A		(0x170|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_B		(0x171|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_C		(0x172|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_D		(0x173|SSL_ST_CONNECT)
+#define SSL3_ST_CW_KEY_EXCH_A		(0x180|SSL_ST_CONNECT)
+#define SSL3_ST_CW_KEY_EXCH_B		(0x181|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_VRFY_A		(0x190|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CERT_VRFY_B		(0x191|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CHANGE_A		(0x1A0|SSL_ST_CONNECT)
+#define SSL3_ST_CW_CHANGE_B		(0x1A1|SSL_ST_CONNECT)
+#define SSL3_ST_CW_FINISHED_A		(0x1B0|SSL_ST_CONNECT)
+#define SSL3_ST_CW_FINISHED_B		(0x1B1|SSL_ST_CONNECT)
+/* read from server */
+#define SSL3_ST_CR_CHANGE_A		(0x1C0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_CHANGE_B		(0x1C1|SSL_ST_CONNECT)
+#define SSL3_ST_CR_FINISHED_A		(0x1D0|SSL_ST_CONNECT)
+#define SSL3_ST_CR_FINISHED_B		(0x1D1|SSL_ST_CONNECT)
+
+/* server */
+/* extra state */
+#define SSL3_ST_SW_FLUSH		(0x100|SSL_ST_ACCEPT)
+/* read from client */
+/* Do not change the number values, they do matter */
+#define SSL3_ST_SR_CLNT_HELLO_A		(0x110|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CLNT_HELLO_B		(0x111|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CLNT_HELLO_C		(0x112|SSL_ST_ACCEPT)
+/* write to client */
+#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_A (0x113|SSL_ST_ACCEPT)
+#define DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B (0x114|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_HELLO_REQ_A		(0x120|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_HELLO_REQ_B		(0x121|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_HELLO_REQ_C		(0x122|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SRVR_HELLO_A		(0x130|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SRVR_HELLO_B		(0x131|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_A		(0x140|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_B		(0x141|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_KEY_EXCH_A		(0x150|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_KEY_EXCH_B		(0x151|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_REQ_A		(0x160|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CERT_REQ_B		(0x161|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SRVR_DONE_A		(0x170|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_SRVR_DONE_B		(0x171|SSL_ST_ACCEPT)
+/* read from client */
+#define SSL3_ST_SR_CERT_A		(0x180|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CERT_B		(0x181|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_KEY_EXCH_A		(0x190|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_KEY_EXCH_B		(0x191|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CERT_VRFY_A		(0x1A0|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CERT_VRFY_B		(0x1A1|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CHANGE_A		(0x1B0|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CHANGE_B		(0x1B1|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_FINISHED_A		(0x1C0|SSL_ST_ACCEPT)
+#define SSL3_ST_SR_FINISHED_B		(0x1C1|SSL_ST_ACCEPT)
+/* write to client */
+#define SSL3_ST_SW_CHANGE_A		(0x1D0|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_CHANGE_B		(0x1D1|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_FINISHED_A		(0x1E0|SSL_ST_ACCEPT)
+#define SSL3_ST_SW_FINISHED_B		(0x1E1|SSL_ST_ACCEPT)
+
+#define SSL3_MT_HELLO_REQUEST			0
+#define SSL3_MT_CLIENT_HELLO			1
+#define SSL3_MT_SERVER_HELLO			2
+#define SSL3_MT_CERTIFICATE			11
+#define SSL3_MT_SERVER_KEY_EXCHANGE		12
+#define SSL3_MT_CERTIFICATE_REQUEST		13
+#define SSL3_MT_SERVER_DONE			14
+#define SSL3_MT_CERTIFICATE_VERIFY		15
+#define SSL3_MT_CLIENT_KEY_EXCHANGE		16
+#define SSL3_MT_FINISHED			20
+#define DTLS1_MT_HELLO_VERIFY_REQUEST    3
+
+
+#define SSL3_MT_CCS				1
+
+/* These are used when changing over to a new cipher */
+#define SSL3_CC_READ		0x01
+#define SSL3_CC_WRITE		0x02
+#define SSL3_CC_CLIENT		0x10
+#define SSL3_CC_SERVER		0x20
+#define SSL3_CHANGE_CIPHER_CLIENT_WRITE	(SSL3_CC_CLIENT|SSL3_CC_WRITE)	
+#define SSL3_CHANGE_CIPHER_SERVER_READ	(SSL3_CC_SERVER|SSL3_CC_READ)
+#define SSL3_CHANGE_CIPHER_CLIENT_READ	(SSL3_CC_CLIENT|SSL3_CC_READ)
+#define SSL3_CHANGE_CIPHER_SERVER_WRITE	(SSL3_CC_SERVER|SSL3_CC_WRITE)
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/stack.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/stack.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/stack.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,109 @@
+/* crypto/stack/stack.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_STACK_H
+#define HEADER_STACK_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct stack_st
+	{
+	int num;
+	char **data;
+	int sorted;
+
+	int num_alloc;
+	int (*comp)(const char * const *, const char * const *);
+	} STACK;
+
+#define M_sk_num(sk)		((sk) ? (sk)->num:-1)
+#define M_sk_value(sk,n)	((sk) ? (sk)->data[n] : NULL)
+
+int sk_num(const STACK *);
+char *sk_value(const STACK *, int);
+
+char *sk_set(STACK *, int, char *);
+
+STACK *sk_new(int (*cmp)(const char * const *, const char * const *));
+STACK *sk_new_null(void);
+void sk_free(STACK *);
+void sk_pop_free(STACK *st, void (*func)(void *));
+int sk_insert(STACK *sk,char *data,int where);
+char *sk_delete(STACK *st,int loc);
+char *sk_delete_ptr(STACK *st, char *p);
+int sk_find(STACK *st,char *data);
+int sk_find_ex(STACK *st,char *data);
+int sk_push(STACK *st,char *data);
+int sk_unshift(STACK *st,char *data);
+char *sk_shift(STACK *st);
+char *sk_pop(STACK *st);
+void sk_zero(STACK *st);
+int (*sk_set_cmp_func(STACK *sk, int (*c)(const char * const *,
+			const char * const *)))
+			(const char * const *, const char * const *);
+STACK *sk_dup(STACK *st);
+void sk_sort(STACK *st);
+int sk_is_sorted(const STACK *st);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/store.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/store.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/store.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,554 @@
+/* crypto/store/store.h -*- mode:C; c-file-style: "eay" -*- */
+/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
+ * project 2003.
+ */
+/* ====================================================================
+ * Copyright (c) 2003 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_STORE_H
+#define HEADER_STORE_H
+
+#include <openssl/ossl_typ.h>
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/evp.h>
+#include <openssl/bn.h>
+#include <openssl/x509.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Already defined in ossl_typ.h */
+/* typedef struct store_st STORE; */
+/* typedef struct store_method_st STORE_METHOD; */
+
+
+/* All the following functions return 0, a negative number or NULL on error.
+   When everything is fine, they return a positive value or a non-NULL
+   pointer, all depending on their purpose. */
+
+/* Creators and destructor.   */
+STORE *STORE_new_method(const STORE_METHOD *method);
+STORE *STORE_new_engine(ENGINE *engine);
+void STORE_free(STORE *ui);
+
+
+/* Give a user interface parametrised control commands.  This can be used to
+   send down an integer, a data pointer or a function pointer, as well as
+   be used to get information from a STORE. */
+int STORE_ctrl(STORE *store, int cmd, long i, void *p, void (*f)(void));
+
+/* A control to set the directory with keys and certificates.  Used by the
+   built-in directory level method. */
+#define STORE_CTRL_SET_DIRECTORY	0x0001
+/* A control to set a file to load.  Used by the built-in file level method. */
+#define STORE_CTRL_SET_FILE		0x0002
+/* A control to set a configuration file to load.  Can be used by any method
+   that wishes to load a configuration file. */
+#define STORE_CTRL_SET_CONF_FILE	0x0003
+/* A control to set a the section of the loaded configuration file.  Can be
+   used by any method that wishes to load a configuration file. */
+#define STORE_CTRL_SET_CONF_SECTION	0x0004
+
+
+/* Some methods may use extra data */
+#define STORE_set_app_data(s,arg)	STORE_set_ex_data(s,0,arg)
+#define STORE_get_app_data(s)		STORE_get_ex_data(s,0)
+int STORE_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int STORE_set_ex_data(STORE *r,int idx,void *arg);
+void *STORE_get_ex_data(STORE *r, int idx);
+
+/* Use specific methods instead of the built-in one */
+const STORE_METHOD *STORE_get_method(STORE *store);
+const STORE_METHOD *STORE_set_method(STORE *store, const STORE_METHOD *meth);
+
+/* The standard OpenSSL methods. */
+/* This is the in-memory method.  It does everything except revoking and updating,
+   and is of course volatile.  It's used by other methods that have an in-memory
+   cache. */
+const STORE_METHOD *STORE_Memory(void);
+#if 0 /* Not yet implemented */
+/* This is the directory store.  It does everything except revoking and updating,
+   and uses STORE_Memory() to cache things in memory. */
+const STORE_METHOD *STORE_Directory(void);
+/* This is the file store.  It does everything except revoking and updating,
+   and uses STORE_Memory() to cache things in memory.  Certificates are added
+   to it with the store operation, and it will only get cached certificates. */
+const STORE_METHOD *STORE_File(void);
+#endif
+
+/* Store functions take a type code for the type of data they should store
+   or fetch */
+typedef enum STORE_object_types
+	{
+	STORE_OBJECT_TYPE_X509_CERTIFICATE=	0x01, /* X509 * */
+	STORE_OBJECT_TYPE_X509_CRL=		0x02, /* X509_CRL * */
+	STORE_OBJECT_TYPE_PRIVATE_KEY=		0x03, /* EVP_PKEY * */
+	STORE_OBJECT_TYPE_PUBLIC_KEY=		0x04, /* EVP_PKEY * */
+	STORE_OBJECT_TYPE_NUMBER=		0x05, /* BIGNUM * */
+	STORE_OBJECT_TYPE_ARBITRARY=		0x06, /* BUF_MEM * */
+	STORE_OBJECT_TYPE_NUM=			0x06  /* The amount of known
+							 object types */
+	} STORE_OBJECT_TYPES;
+/* List of text strings corresponding to the object types. */
+extern const char * const STORE_object_type_string[STORE_OBJECT_TYPE_NUM+1];
+
+/* Some store functions take a parameter list.  Those parameters come with
+   one of the following codes. The comments following the codes below indicate
+   what type the value should be a pointer to. */
+typedef enum STORE_params
+	{
+	STORE_PARAM_EVP_TYPE=			0x01, /* int */
+	STORE_PARAM_BITS=			0x02, /* size_t */
+	STORE_PARAM_KEY_PARAMETERS=		0x03, /* ??? */
+	STORE_PARAM_KEY_NO_PARAMETERS=		0x04, /* N/A */
+	STORE_PARAM_AUTH_PASSPHRASE=		0x05, /* char * */
+	STORE_PARAM_AUTH_KRB5_TICKET=		0x06, /* void * */
+	STORE_PARAM_TYPE_NUM=			0x06  /* The amount of known
+							 parameter types */
+	} STORE_PARAM_TYPES;
+/* Parameter value sizes.  -1 means unknown, anything else is the required size. */
+extern const int STORE_param_sizes[STORE_PARAM_TYPE_NUM+1];
+
+/* Store functions take attribute lists.  Those attributes come with codes.
+   The comments following the codes below indicate what type the value should
+   be a pointer to. */
+typedef enum STORE_attribs
+	{
+	STORE_ATTR_END=				0x00,
+	STORE_ATTR_FRIENDLYNAME=		0x01, /* C string */
+	STORE_ATTR_KEYID=			0x02, /* 160 bit string (SHA1) */
+	STORE_ATTR_ISSUERKEYID=			0x03, /* 160 bit string (SHA1) */
+	STORE_ATTR_SUBJECTKEYID=		0x04, /* 160 bit string (SHA1) */
+	STORE_ATTR_ISSUERSERIALHASH=		0x05, /* 160 bit string (SHA1) */
+	STORE_ATTR_ISSUER=			0x06, /* X509_NAME * */
+	STORE_ATTR_SERIAL=			0x07, /* BIGNUM * */
+	STORE_ATTR_SUBJECT=			0x08, /* X509_NAME * */
+	STORE_ATTR_CERTHASH=			0x09, /* 160 bit string (SHA1) */
+	STORE_ATTR_EMAIL=			0x0a, /* C string */
+	STORE_ATTR_FILENAME=			0x0b, /* C string */
+	STORE_ATTR_TYPE_NUM=			0x0b, /* The amount of known
+							 attribute types */
+	STORE_ATTR_OR=				0xff  /* This is a special
+							 separator, which
+							 expresses the OR
+							 operation.  */
+	} STORE_ATTR_TYPES;
+/* Attribute value sizes.  -1 means unknown, anything else is the required size. */
+extern const int STORE_attr_sizes[STORE_ATTR_TYPE_NUM+1];
+
+typedef enum STORE_certificate_status
+	{
+	STORE_X509_VALID=			0x00,
+	STORE_X509_EXPIRED=			0x01,
+	STORE_X509_SUSPENDED=			0x02,
+	STORE_X509_REVOKED=			0x03
+	} STORE_CERTIFICATE_STATUS;
+
+/* Engine store functions will return a structure that contains all the necessary
+ * information, including revokation status for certificates.  This is really not
+ * needed for application authors, as the ENGINE framework functions will extract
+ * the OpenSSL-specific information when at all possible.  However, for engine
+ * authors, it's crucial to know this structure.  */
+typedef struct STORE_OBJECT_st
+	{
+	STORE_OBJECT_TYPES type;
+	union
+		{
+		struct
+			{
+			STORE_CERTIFICATE_STATUS status;
+			X509 *certificate;
+			} x509;
+		X509_CRL *crl;
+		EVP_PKEY *key;
+		BIGNUM *number;
+		BUF_MEM *arbitrary;
+		} data;
+	} STORE_OBJECT;
+DECLARE_STACK_OF(STORE_OBJECT)
+STORE_OBJECT *STORE_OBJECT_new(void);
+void STORE_OBJECT_free(STORE_OBJECT *data);
+
+
+
+/* The following functions handle the storage. They return 0, a negative number
+   or NULL on error, anything else on success. */
+X509 *STORE_get_certificate(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_store_certificate(STORE *e, X509 *data, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_modify_certificate(STORE *e, OPENSSL_ITEM search_attributes[],
+	OPENSSL_ITEM add_attributes[], OPENSSL_ITEM modify_attributes[],
+	OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]);
+int STORE_revoke_certificate(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_delete_certificate(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+void *STORE_list_certificate_start(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+X509 *STORE_list_certificate_next(STORE *e, void *handle);
+int STORE_list_certificate_end(STORE *e, void *handle);
+int STORE_list_certificate_endp(STORE *e, void *handle);
+EVP_PKEY *STORE_generate_key(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+EVP_PKEY *STORE_get_private_key(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_store_private_key(STORE *e, EVP_PKEY *data,
+	OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]);
+int STORE_modify_private_key(STORE *e, OPENSSL_ITEM search_attributes[],
+	OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[],
+	OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]);
+int STORE_revoke_private_key(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_delete_private_key(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+void *STORE_list_private_key_start(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+EVP_PKEY *STORE_list_private_key_next(STORE *e, void *handle);
+int STORE_list_private_key_end(STORE *e, void *handle);
+int STORE_list_private_key_endp(STORE *e, void *handle);
+EVP_PKEY *STORE_get_public_key(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_store_public_key(STORE *e, EVP_PKEY *data, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_modify_public_key(STORE *e, OPENSSL_ITEM search_attributes[],
+	OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[],
+	OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]);
+int STORE_revoke_public_key(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_delete_public_key(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+void *STORE_list_public_key_start(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+EVP_PKEY *STORE_list_public_key_next(STORE *e, void *handle);
+int STORE_list_public_key_end(STORE *e, void *handle);
+int STORE_list_public_key_endp(STORE *e, void *handle);
+X509_CRL *STORE_generate_crl(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+X509_CRL *STORE_get_crl(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_store_crl(STORE *e, X509_CRL *data, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_modify_crl(STORE *e, OPENSSL_ITEM search_attributes[],
+	OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[],
+	OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]);
+int STORE_delete_crl(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+void *STORE_list_crl_start(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+X509_CRL *STORE_list_crl_next(STORE *e, void *handle);
+int STORE_list_crl_end(STORE *e, void *handle);
+int STORE_list_crl_endp(STORE *e, void *handle);
+int STORE_store_number(STORE *e, BIGNUM *data, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_modify_number(STORE *e, OPENSSL_ITEM search_attributes[],
+	OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[],
+	OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]);
+BIGNUM *STORE_get_number(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_delete_number(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_store_arbitrary(STORE *e, BUF_MEM *data, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_modify_arbitrary(STORE *e, OPENSSL_ITEM search_attributes[],
+	OPENSSL_ITEM add_sttributes[], OPENSSL_ITEM modify_attributes[],
+	OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]);
+BUF_MEM *STORE_get_arbitrary(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+int STORE_delete_arbitrary(STORE *e, OPENSSL_ITEM attributes[],
+	OPENSSL_ITEM parameters[]);
+
+
+/* Create and manipulate methods */
+STORE_METHOD *STORE_create_method(char *name);
+void STORE_destroy_method(STORE_METHOD *store_method);
+
+/* These callback types are use for store handlers */
+typedef int (*STORE_INITIALISE_FUNC_PTR)(STORE *);
+typedef void (*STORE_CLEANUP_FUNC_PTR)(STORE *);
+typedef STORE_OBJECT *(*STORE_GENERATE_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]);
+typedef STORE_OBJECT *(*STORE_GET_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]);
+typedef void *(*STORE_START_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]);
+typedef STORE_OBJECT *(*STORE_NEXT_OBJECT_FUNC_PTR)(STORE *, void *handle);
+typedef int (*STORE_END_OBJECT_FUNC_PTR)(STORE *, void *handle);
+typedef int (*STORE_HANDLE_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]);
+typedef int (*STORE_STORE_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, STORE_OBJECT *data, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]);
+typedef int (*STORE_MODIFY_OBJECT_FUNC_PTR)(STORE *, STORE_OBJECT_TYPES type, OPENSSL_ITEM search_attributes[], OPENSSL_ITEM add_attributes[], OPENSSL_ITEM modify_attributes[], OPENSSL_ITEM delete_attributes[], OPENSSL_ITEM parameters[]);
+typedef int (*STORE_GENERIC_FUNC_PTR)(STORE *, OPENSSL_ITEM attributes[], OPENSSL_ITEM parameters[]);
+typedef int (*STORE_CTRL_FUNC_PTR)(STORE *, int cmd, long l, void *p, void (*f)(void));
+
+int STORE_method_set_initialise_function(STORE_METHOD *sm, STORE_INITIALISE_FUNC_PTR init_f);
+int STORE_method_set_cleanup_function(STORE_METHOD *sm, STORE_CLEANUP_FUNC_PTR clean_f);
+int STORE_method_set_generate_function(STORE_METHOD *sm, STORE_GENERATE_OBJECT_FUNC_PTR generate_f);
+int STORE_method_set_get_function(STORE_METHOD *sm, STORE_GET_OBJECT_FUNC_PTR get_f);
+int STORE_method_set_store_function(STORE_METHOD *sm, STORE_STORE_OBJECT_FUNC_PTR store_f);
+int STORE_method_set_modify_function(STORE_METHOD *sm, STORE_MODIFY_OBJECT_FUNC_PTR store_f);
+int STORE_method_set_revoke_function(STORE_METHOD *sm, STORE_HANDLE_OBJECT_FUNC_PTR revoke_f);
+int STORE_method_set_delete_function(STORE_METHOD *sm, STORE_HANDLE_OBJECT_FUNC_PTR delete_f);
+int STORE_method_set_list_start_function(STORE_METHOD *sm, STORE_START_OBJECT_FUNC_PTR list_start_f);
+int STORE_method_set_list_next_function(STORE_METHOD *sm, STORE_NEXT_OBJECT_FUNC_PTR list_next_f);
+int STORE_method_set_list_end_function(STORE_METHOD *sm, STORE_END_OBJECT_FUNC_PTR list_end_f);
+int STORE_method_set_update_store_function(STORE_METHOD *sm, STORE_GENERIC_FUNC_PTR);
+int STORE_method_set_lock_store_function(STORE_METHOD *sm, STORE_GENERIC_FUNC_PTR);
+int STORE_method_set_unlock_store_function(STORE_METHOD *sm, STORE_GENERIC_FUNC_PTR);
+int STORE_method_set_ctrl_function(STORE_METHOD *sm, STORE_CTRL_FUNC_PTR ctrl_f);
+
+STORE_INITIALISE_FUNC_PTR STORE_method_get_initialise_function(STORE_METHOD *sm);
+STORE_CLEANUP_FUNC_PTR STORE_method_get_cleanup_function(STORE_METHOD *sm);
+STORE_GENERATE_OBJECT_FUNC_PTR STORE_method_get_generate_function(STORE_METHOD *sm);
+STORE_GET_OBJECT_FUNC_PTR STORE_method_get_get_function(STORE_METHOD *sm);
+STORE_STORE_OBJECT_FUNC_PTR STORE_method_get_store_function(STORE_METHOD *sm);
+STORE_MODIFY_OBJECT_FUNC_PTR STORE_method_get_modify_function(STORE_METHOD *sm);
+STORE_HANDLE_OBJECT_FUNC_PTR STORE_method_get_revoke_function(STORE_METHOD *sm);
+STORE_HANDLE_OBJECT_FUNC_PTR STORE_method_get_delete_function(STORE_METHOD *sm);
+STORE_START_OBJECT_FUNC_PTR STORE_method_get_list_start_function(STORE_METHOD *sm);
+STORE_NEXT_OBJECT_FUNC_PTR STORE_method_get_list_next_function(STORE_METHOD *sm);
+STORE_END_OBJECT_FUNC_PTR STORE_method_get_list_end_function(STORE_METHOD *sm);
+STORE_GENERIC_FUNC_PTR STORE_method_get_update_store_function(STORE_METHOD *sm);
+STORE_GENERIC_FUNC_PTR STORE_method_get_lock_store_function(STORE_METHOD *sm);
+STORE_GENERIC_FUNC_PTR STORE_method_get_unlock_store_function(STORE_METHOD *sm);
+STORE_CTRL_FUNC_PTR STORE_method_get_ctrl_function(STORE_METHOD *sm);
+
+/* Method helper structures and functions. */
+
+/* This structure is the result of parsing through the information in a list
+   of OPENSSL_ITEMs.  It stores all the necessary information in a structured
+   way.*/
+typedef struct STORE_attr_info_st STORE_ATTR_INFO;
+
+/* Parse a list of OPENSSL_ITEMs and return a pointer to a STORE_ATTR_INFO.
+   Note that we do this in the list form, since the list of OPENSSL_ITEMs can
+   come in blocks separated with STORE_ATTR_OR.  Note that the value returned
+   by STORE_parse_attrs_next() must be freed with STORE_ATTR_INFO_free(). */
+void *STORE_parse_attrs_start(OPENSSL_ITEM *attributes);
+STORE_ATTR_INFO *STORE_parse_attrs_next(void *handle);
+int STORE_parse_attrs_end(void *handle);
+int STORE_parse_attrs_endp(void *handle);
+
+/* Creator and destructor */
+STORE_ATTR_INFO *STORE_ATTR_INFO_new(void);
+int STORE_ATTR_INFO_free(STORE_ATTR_INFO *attrs);
+
+/* Manipulators */
+char *STORE_ATTR_INFO_get0_cstr(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code);
+unsigned char *STORE_ATTR_INFO_get0_sha1str(STORE_ATTR_INFO *attrs,
+	STORE_ATTR_TYPES code);
+X509_NAME *STORE_ATTR_INFO_get0_dn(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code);
+BIGNUM *STORE_ATTR_INFO_get0_number(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code);
+int STORE_ATTR_INFO_set_cstr(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code,
+	char *cstr, size_t cstr_size);
+int STORE_ATTR_INFO_set_sha1str(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code,
+	unsigned char *sha1str, size_t sha1str_size);
+int STORE_ATTR_INFO_set_dn(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code,
+	X509_NAME *dn);
+int STORE_ATTR_INFO_set_number(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code,
+	BIGNUM *number);
+int STORE_ATTR_INFO_modify_cstr(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code,
+	char *cstr, size_t cstr_size);
+int STORE_ATTR_INFO_modify_sha1str(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code,
+	unsigned char *sha1str, size_t sha1str_size);
+int STORE_ATTR_INFO_modify_dn(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code,
+	X509_NAME *dn);
+int STORE_ATTR_INFO_modify_number(STORE_ATTR_INFO *attrs, STORE_ATTR_TYPES code,
+	BIGNUM *number);
+
+/* Compare on basis of a bit pattern formed by the STORE_ATTR_TYPES values
+   in each contained attribute. */
+int STORE_ATTR_INFO_compare(STORE_ATTR_INFO *a, STORE_ATTR_INFO *b);
+/* Check if the set of attributes in a is within the range of attributes
+   set in b. */
+int STORE_ATTR_INFO_in_range(STORE_ATTR_INFO *a, STORE_ATTR_INFO *b);
+/* Check if the set of attributes in a are also set in b. */
+int STORE_ATTR_INFO_in(STORE_ATTR_INFO *a, STORE_ATTR_INFO *b);
+/* Same as STORE_ATTR_INFO_in(), but also checks the attribute values. */
+int STORE_ATTR_INFO_in_ex(STORE_ATTR_INFO *a, STORE_ATTR_INFO *b);
+
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_STORE_strings(void);
+
+/* Error codes for the STORE functions. */
+
+/* Function codes. */
+#define STORE_F_MEM_DELETE				 134
+#define STORE_F_MEM_GENERATE				 135
+#define STORE_F_MEM_LIST_END				 168
+#define STORE_F_MEM_LIST_NEXT				 136
+#define STORE_F_MEM_LIST_START				 137
+#define STORE_F_MEM_MODIFY				 169
+#define STORE_F_MEM_STORE				 138
+#define STORE_F_STORE_ATTR_INFO_GET0_CSTR		 139
+#define STORE_F_STORE_ATTR_INFO_GET0_DN			 140
+#define STORE_F_STORE_ATTR_INFO_GET0_NUMBER		 141
+#define STORE_F_STORE_ATTR_INFO_GET0_SHA1STR		 142
+#define STORE_F_STORE_ATTR_INFO_MODIFY_CSTR		 143
+#define STORE_F_STORE_ATTR_INFO_MODIFY_DN		 144
+#define STORE_F_STORE_ATTR_INFO_MODIFY_NUMBER		 145
+#define STORE_F_STORE_ATTR_INFO_MODIFY_SHA1STR		 146
+#define STORE_F_STORE_ATTR_INFO_SET_CSTR		 147
+#define STORE_F_STORE_ATTR_INFO_SET_DN			 148
+#define STORE_F_STORE_ATTR_INFO_SET_NUMBER		 149
+#define STORE_F_STORE_ATTR_INFO_SET_SHA1STR		 150
+#define STORE_F_STORE_CERTIFICATE			 170
+#define STORE_F_STORE_CTRL				 161
+#define STORE_F_STORE_DELETE_ARBITRARY			 158
+#define STORE_F_STORE_DELETE_CERTIFICATE		 102
+#define STORE_F_STORE_DELETE_CRL			 103
+#define STORE_F_STORE_DELETE_NUMBER			 104
+#define STORE_F_STORE_DELETE_PRIVATE_KEY		 105
+#define STORE_F_STORE_DELETE_PUBLIC_KEY			 106
+#define STORE_F_STORE_GENERATE_CRL			 107
+#define STORE_F_STORE_GENERATE_KEY			 108
+#define STORE_F_STORE_GET_ARBITRARY			 159
+#define STORE_F_STORE_GET_CERTIFICATE			 109
+#define STORE_F_STORE_GET_CRL				 110
+#define STORE_F_STORE_GET_NUMBER			 111
+#define STORE_F_STORE_GET_PRIVATE_KEY			 112
+#define STORE_F_STORE_GET_PUBLIC_KEY			 113
+#define STORE_F_STORE_LIST_CERTIFICATE_END		 114
+#define STORE_F_STORE_LIST_CERTIFICATE_ENDP		 153
+#define STORE_F_STORE_LIST_CERTIFICATE_NEXT		 115
+#define STORE_F_STORE_LIST_CERTIFICATE_START		 116
+#define STORE_F_STORE_LIST_CRL_END			 117
+#define STORE_F_STORE_LIST_CRL_ENDP			 154
+#define STORE_F_STORE_LIST_CRL_NEXT			 118
+#define STORE_F_STORE_LIST_CRL_START			 119
+#define STORE_F_STORE_LIST_PRIVATE_KEY_END		 120
+#define STORE_F_STORE_LIST_PRIVATE_KEY_ENDP		 155
+#define STORE_F_STORE_LIST_PRIVATE_KEY_NEXT		 121
+#define STORE_F_STORE_LIST_PRIVATE_KEY_START		 122
+#define STORE_F_STORE_LIST_PUBLIC_KEY_END		 123
+#define STORE_F_STORE_LIST_PUBLIC_KEY_ENDP		 156
+#define STORE_F_STORE_LIST_PUBLIC_KEY_NEXT		 124
+#define STORE_F_STORE_LIST_PUBLIC_KEY_START		 125
+#define STORE_F_STORE_MODIFY_ARBITRARY			 162
+#define STORE_F_STORE_MODIFY_CERTIFICATE		 163
+#define STORE_F_STORE_MODIFY_CRL			 164
+#define STORE_F_STORE_MODIFY_NUMBER			 165
+#define STORE_F_STORE_MODIFY_PRIVATE_KEY		 166
+#define STORE_F_STORE_MODIFY_PUBLIC_KEY			 167
+#define STORE_F_STORE_NEW_ENGINE			 133
+#define STORE_F_STORE_NEW_METHOD			 132
+#define STORE_F_STORE_PARSE_ATTRS_END			 151
+#define STORE_F_STORE_PARSE_ATTRS_ENDP			 172
+#define STORE_F_STORE_PARSE_ATTRS_NEXT			 152
+#define STORE_F_STORE_PARSE_ATTRS_START			 171
+#define STORE_F_STORE_REVOKE_CERTIFICATE		 129
+#define STORE_F_STORE_REVOKE_PRIVATE_KEY		 130
+#define STORE_F_STORE_REVOKE_PUBLIC_KEY			 131
+#define STORE_F_STORE_STORE_ARBITRARY			 157
+#define STORE_F_STORE_STORE_CERTIFICATE			 100
+#define STORE_F_STORE_STORE_CRL				 101
+#define STORE_F_STORE_STORE_NUMBER			 126
+#define STORE_F_STORE_STORE_PRIVATE_KEY			 127
+#define STORE_F_STORE_STORE_PUBLIC_KEY			 128
+
+/* Reason codes. */
+#define STORE_R_ALREADY_HAS_A_VALUE			 127
+#define STORE_R_FAILED_DELETING_ARBITRARY		 132
+#define STORE_R_FAILED_DELETING_CERTIFICATE		 100
+#define STORE_R_FAILED_DELETING_KEY			 101
+#define STORE_R_FAILED_DELETING_NUMBER			 102
+#define STORE_R_FAILED_GENERATING_CRL			 103
+#define STORE_R_FAILED_GENERATING_KEY			 104
+#define STORE_R_FAILED_GETTING_ARBITRARY		 133
+#define STORE_R_FAILED_GETTING_CERTIFICATE		 105
+#define STORE_R_FAILED_GETTING_KEY			 106
+#define STORE_R_FAILED_GETTING_NUMBER			 107
+#define STORE_R_FAILED_LISTING_CERTIFICATES		 108
+#define STORE_R_FAILED_LISTING_KEYS			 109
+#define STORE_R_FAILED_MODIFYING_ARBITRARY		 138
+#define STORE_R_FAILED_MODIFYING_CERTIFICATE		 139
+#define STORE_R_FAILED_MODIFYING_CRL			 140
+#define STORE_R_FAILED_MODIFYING_NUMBER			 141
+#define STORE_R_FAILED_MODIFYING_PRIVATE_KEY		 142
+#define STORE_R_FAILED_MODIFYING_PUBLIC_KEY		 143
+#define STORE_R_FAILED_REVOKING_CERTIFICATE		 110
+#define STORE_R_FAILED_REVOKING_KEY			 111
+#define STORE_R_FAILED_STORING_ARBITRARY		 134
+#define STORE_R_FAILED_STORING_CERTIFICATE		 112
+#define STORE_R_FAILED_STORING_KEY			 113
+#define STORE_R_FAILED_STORING_NUMBER			 114
+#define STORE_R_NOT_IMPLEMENTED				 128
+#define STORE_R_NO_CONTROL_FUNCTION			 144
+#define STORE_R_NO_DELETE_ARBITRARY_FUNCTION		 135
+#define STORE_R_NO_DELETE_NUMBER_FUNCTION		 115
+#define STORE_R_NO_DELETE_OBJECT_FUNCTION		 116
+#define STORE_R_NO_GENERATE_CRL_FUNCTION		 117
+#define STORE_R_NO_GENERATE_OBJECT_FUNCTION		 118
+#define STORE_R_NO_GET_OBJECT_ARBITRARY_FUNCTION	 136
+#define STORE_R_NO_GET_OBJECT_FUNCTION			 119
+#define STORE_R_NO_GET_OBJECT_NUMBER_FUNCTION		 120
+#define STORE_R_NO_LIST_OBJECT_ENDP_FUNCTION		 131
+#define STORE_R_NO_LIST_OBJECT_END_FUNCTION		 121
+#define STORE_R_NO_LIST_OBJECT_NEXT_FUNCTION		 122
+#define STORE_R_NO_LIST_OBJECT_START_FUNCTION		 123
+#define STORE_R_NO_MODIFY_OBJECT_FUNCTION		 145
+#define STORE_R_NO_REVOKE_OBJECT_FUNCTION		 124
+#define STORE_R_NO_STORE				 129
+#define STORE_R_NO_STORE_OBJECT_ARBITRARY_FUNCTION	 137
+#define STORE_R_NO_STORE_OBJECT_FUNCTION		 125
+#define STORE_R_NO_STORE_OBJECT_NUMBER_FUNCTION		 126
+#define STORE_R_NO_VALUE				 130
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/symhacks.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/symhacks.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/symhacks.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,383 @@
+/* ====================================================================
+ * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_SYMHACKS_H
+#define HEADER_SYMHACKS_H
+
+#include <openssl/e_os2.h>
+
+/* Hacks to solve the problem with linkers incapable of handling very long
+   symbol names.  In the case of VMS, the limit is 31 characters on VMS for
+   VAX. */
+#ifdef OPENSSL_SYS_VMS
+
+/* Hack a long name in crypto/ex_data.c */
+#undef CRYPTO_get_ex_data_implementation
+#define CRYPTO_get_ex_data_implementation	CRYPTO_get_ex_data_impl
+#undef CRYPTO_set_ex_data_implementation
+#define CRYPTO_set_ex_data_implementation	CRYPTO_set_ex_data_impl
+
+/* Hack a long name in crypto/asn1/a_mbstr.c */
+#undef ASN1_STRING_set_default_mask_asc
+#define ASN1_STRING_set_default_mask_asc	ASN1_STRING_set_def_mask_asc
+
+#if 0 /* No longer needed, since safestack macro magic does the job */
+/* Hack the names created with DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO) */
+#undef i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO
+#define i2d_ASN1_SET_OF_PKCS7_SIGNER_INFO	i2d_ASN1_SET_OF_PKCS7_SIGINF
+#undef d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO
+#define d2i_ASN1_SET_OF_PKCS7_SIGNER_INFO	d2i_ASN1_SET_OF_PKCS7_SIGINF
+#endif
+
+#if 0 /* No longer needed, since safestack macro magic does the job */
+/* Hack the names created with DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO) */
+#undef i2d_ASN1_SET_OF_PKCS7_RECIP_INFO
+#define i2d_ASN1_SET_OF_PKCS7_RECIP_INFO	i2d_ASN1_SET_OF_PKCS7_RECINF
+#undef d2i_ASN1_SET_OF_PKCS7_RECIP_INFO
+#define d2i_ASN1_SET_OF_PKCS7_RECIP_INFO	d2i_ASN1_SET_OF_PKCS7_RECINF
+#endif
+
+#if 0 /* No longer needed, since safestack macro magic does the job */
+/* Hack the names created with DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION) */
+#undef i2d_ASN1_SET_OF_ACCESS_DESCRIPTION
+#define i2d_ASN1_SET_OF_ACCESS_DESCRIPTION	i2d_ASN1_SET_OF_ACC_DESC
+#undef d2i_ASN1_SET_OF_ACCESS_DESCRIPTION
+#define d2i_ASN1_SET_OF_ACCESS_DESCRIPTION	d2i_ASN1_SET_OF_ACC_DESC
+#endif
+
+/* Hack the names created with DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE) */
+#undef PEM_read_NETSCAPE_CERT_SEQUENCE
+#define PEM_read_NETSCAPE_CERT_SEQUENCE		PEM_read_NS_CERT_SEQ
+#undef PEM_write_NETSCAPE_CERT_SEQUENCE
+#define PEM_write_NETSCAPE_CERT_SEQUENCE	PEM_write_NS_CERT_SEQ
+#undef PEM_read_bio_NETSCAPE_CERT_SEQUENCE
+#define PEM_read_bio_NETSCAPE_CERT_SEQUENCE	PEM_read_bio_NS_CERT_SEQ
+#undef PEM_write_bio_NETSCAPE_CERT_SEQUENCE
+#define PEM_write_bio_NETSCAPE_CERT_SEQUENCE	PEM_write_bio_NS_CERT_SEQ
+#undef PEM_write_cb_bio_NETSCAPE_CERT_SEQUENCE
+#define PEM_write_cb_bio_NETSCAPE_CERT_SEQUENCE	PEM_write_cb_bio_NS_CERT_SEQ
+
+/* Hack the names created with DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO) */
+#undef PEM_read_PKCS8_PRIV_KEY_INFO
+#define PEM_read_PKCS8_PRIV_KEY_INFO		PEM_read_P8_PRIV_KEY_INFO
+#undef PEM_write_PKCS8_PRIV_KEY_INFO
+#define PEM_write_PKCS8_PRIV_KEY_INFO		PEM_write_P8_PRIV_KEY_INFO
+#undef PEM_read_bio_PKCS8_PRIV_KEY_INFO
+#define PEM_read_bio_PKCS8_PRIV_KEY_INFO	PEM_read_bio_P8_PRIV_KEY_INFO
+#undef PEM_write_bio_PKCS8_PRIV_KEY_INFO
+#define PEM_write_bio_PKCS8_PRIV_KEY_INFO	PEM_write_bio_P8_PRIV_KEY_INFO
+#undef PEM_write_cb_bio_PKCS8_PRIV_KEY_INFO
+#define PEM_write_cb_bio_PKCS8_PRIV_KEY_INFO	PEM_wrt_cb_bio_P8_PRIV_KEY_INFO
+
+/* Hack other PEM names */
+#undef PEM_write_bio_PKCS8PrivateKey_nid
+#define PEM_write_bio_PKCS8PrivateKey_nid	PEM_write_bio_PKCS8PrivKey_nid
+
+/* Hack some long X509 names */
+#undef X509_REVOKED_get_ext_by_critical
+#define X509_REVOKED_get_ext_by_critical	X509_REVOKED_get_ext_by_critic
+#undef X509_policy_tree_get0_user_policies
+#define X509_policy_tree_get0_user_policies	X509_pcy_tree_get0_usr_policies
+#undef X509_policy_node_get0_qualifiers
+#define X509_policy_node_get0_qualifiers	X509_pcy_node_get0_qualifiers
+#undef X509_STORE_CTX_get_explicit_policy
+#define X509_STORE_CTX_get_explicit_policy	X509_STORE_CTX_get_expl_policy
+
+/* Hack some long CRYPTO names */
+#undef CRYPTO_set_dynlock_destroy_callback
+#define CRYPTO_set_dynlock_destroy_callback     CRYPTO_set_dynlock_destroy_cb
+#undef CRYPTO_set_dynlock_create_callback
+#define CRYPTO_set_dynlock_create_callback      CRYPTO_set_dynlock_create_cb
+#undef CRYPTO_set_dynlock_lock_callback
+#define CRYPTO_set_dynlock_lock_callback        CRYPTO_set_dynlock_lock_cb
+#undef CRYPTO_get_dynlock_lock_callback
+#define CRYPTO_get_dynlock_lock_callback        CRYPTO_get_dynlock_lock_cb
+#undef CRYPTO_get_dynlock_destroy_callback
+#define CRYPTO_get_dynlock_destroy_callback     CRYPTO_get_dynlock_destroy_cb
+#undef CRYPTO_get_dynlock_create_callback
+#define CRYPTO_get_dynlock_create_callback      CRYPTO_get_dynlock_create_cb
+#undef CRYPTO_set_locked_mem_ex_functions
+#define CRYPTO_set_locked_mem_ex_functions      CRYPTO_set_locked_mem_ex_funcs
+#undef CRYPTO_get_locked_mem_ex_functions
+#define CRYPTO_get_locked_mem_ex_functions      CRYPTO_get_locked_mem_ex_funcs
+
+/* Hack some long SSL names */
+#undef SSL_CTX_set_default_verify_paths
+#define SSL_CTX_set_default_verify_paths        SSL_CTX_set_def_verify_paths
+#undef SSL_get_ex_data_X509_STORE_CTX_idx
+#define SSL_get_ex_data_X509_STORE_CTX_idx      SSL_get_ex_d_X509_STORE_CTX_idx
+#undef SSL_add_file_cert_subjects_to_stack
+#define SSL_add_file_cert_subjects_to_stack     SSL_add_file_cert_subjs_to_stk
+#undef SSL_add_dir_cert_subjects_to_stack
+#define SSL_add_dir_cert_subjects_to_stack      SSL_add_dir_cert_subjs_to_stk
+#undef SSL_CTX_use_certificate_chain_file
+#define SSL_CTX_use_certificate_chain_file      SSL_CTX_use_cert_chain_file
+#undef SSL_CTX_set_cert_verify_callback
+#define SSL_CTX_set_cert_verify_callback        SSL_CTX_set_cert_verify_cb
+#undef SSL_CTX_set_default_passwd_cb_userdata
+#define SSL_CTX_set_default_passwd_cb_userdata  SSL_CTX_set_def_passwd_cb_ud
+#undef SSL_COMP_get_compression_methods
+#define SSL_COMP_get_compression_methods	SSL_COMP_get_compress_methods
+
+/* Hack some long ENGINE names */
+#undef ENGINE_get_default_BN_mod_exp_crt
+#define ENGINE_get_default_BN_mod_exp_crt	ENGINE_get_def_BN_mod_exp_crt
+#undef ENGINE_set_default_BN_mod_exp_crt
+#define ENGINE_set_default_BN_mod_exp_crt	ENGINE_set_def_BN_mod_exp_crt
+#undef ENGINE_set_load_privkey_function
+#define ENGINE_set_load_privkey_function        ENGINE_set_load_privkey_fn
+#undef ENGINE_get_load_privkey_function
+#define ENGINE_get_load_privkey_function        ENGINE_get_load_privkey_fn
+
+/* Hack some long OCSP names */
+#undef OCSP_REQUEST_get_ext_by_critical
+#define OCSP_REQUEST_get_ext_by_critical        OCSP_REQUEST_get_ext_by_crit
+#undef OCSP_BASICRESP_get_ext_by_critical
+#define OCSP_BASICRESP_get_ext_by_critical      OCSP_BASICRESP_get_ext_by_crit
+#undef OCSP_SINGLERESP_get_ext_by_critical
+#define OCSP_SINGLERESP_get_ext_by_critical     OCSP_SINGLERESP_get_ext_by_crit
+
+/* Hack some long DES names */
+#undef _ossl_old_des_ede3_cfb64_encrypt
+#define _ossl_old_des_ede3_cfb64_encrypt	_ossl_odes_ede3_cfb64_encrypt
+#undef _ossl_old_des_ede3_ofb64_encrypt
+#define _ossl_old_des_ede3_ofb64_encrypt	_ossl_odes_ede3_ofb64_encrypt
+
+/* Hack some long EVP names */
+#undef OPENSSL_add_all_algorithms_noconf
+#define OPENSSL_add_all_algorithms_noconf	OPENSSL_add_all_algo_noconf
+#undef OPENSSL_add_all_algorithms_conf
+#define OPENSSL_add_all_algorithms_conf		OPENSSL_add_all_algo_conf
+
+/* Hack some long EC names */
+#undef EC_GROUP_set_point_conversion_form
+#define EC_GROUP_set_point_conversion_form	EC_GROUP_set_point_conv_form
+#undef EC_GROUP_get_point_conversion_form
+#define EC_GROUP_get_point_conversion_form	EC_GROUP_get_point_conv_form
+#undef EC_GROUP_clear_free_all_extra_data
+#define EC_GROUP_clear_free_all_extra_data	EC_GROUP_clr_free_all_xtra_data
+#undef EC_POINT_set_Jprojective_coordinates_GFp
+#define EC_POINT_set_Jprojective_coordinates_GFp \
+                                                EC_POINT_set_Jproj_coords_GFp
+#undef EC_POINT_get_Jprojective_coordinates_GFp
+#define EC_POINT_get_Jprojective_coordinates_GFp \
+                                                EC_POINT_get_Jproj_coords_GFp
+#undef EC_POINT_set_affine_coordinates_GFp
+#define EC_POINT_set_affine_coordinates_GFp     EC_POINT_set_affine_coords_GFp
+#undef EC_POINT_get_affine_coordinates_GFp
+#define EC_POINT_get_affine_coordinates_GFp     EC_POINT_get_affine_coords_GFp
+#undef EC_POINT_set_compressed_coordinates_GFp
+#define EC_POINT_set_compressed_coordinates_GFp EC_POINT_set_compr_coords_GFp
+#undef EC_POINT_set_affine_coordinates_GF2m
+#define EC_POINT_set_affine_coordinates_GF2m    EC_POINT_set_affine_coords_GF2m
+#undef EC_POINT_get_affine_coordinates_GF2m
+#define EC_POINT_get_affine_coordinates_GF2m    EC_POINT_get_affine_coords_GF2m
+#undef EC_POINT_set_compressed_coordinates_GF2m
+#define EC_POINT_set_compressed_coordinates_GF2m \
+                                                EC_POINT_set_compr_coords_GF2m
+#undef ec_GF2m_simple_group_clear_finish
+#define ec_GF2m_simple_group_clear_finish        ec_GF2m_simple_grp_clr_finish
+#undef ec_GF2m_simple_group_check_discriminant
+#define ec_GF2m_simple_group_check_discriminant	ec_GF2m_simple_grp_chk_discrim
+#undef ec_GF2m_simple_point_clear_finish
+#define ec_GF2m_simple_point_clear_finish        ec_GF2m_simple_pt_clr_finish
+#undef ec_GF2m_simple_point_set_to_infinity
+#define ec_GF2m_simple_point_set_to_infinity     ec_GF2m_simple_pt_set_to_inf
+#undef ec_GF2m_simple_points_make_affine
+#define ec_GF2m_simple_points_make_affine        ec_GF2m_simple_pts_make_affine
+#undef ec_GF2m_simple_point_set_affine_coordinates
+#define ec_GF2m_simple_point_set_affine_coordinates \
+                                                ec_GF2m_smp_pt_set_af_coords
+#undef ec_GF2m_simple_point_get_affine_coordinates
+#define ec_GF2m_simple_point_get_affine_coordinates \
+                                                ec_GF2m_smp_pt_get_af_coords
+#undef ec_GF2m_simple_set_compressed_coordinates
+#define ec_GF2m_simple_set_compressed_coordinates \
+                                                ec_GF2m_smp_set_compr_coords
+#undef ec_GFp_simple_group_set_curve_GFp
+#define ec_GFp_simple_group_set_curve_GFp       ec_GFp_simple_grp_set_curve_GFp
+#undef ec_GFp_simple_group_get_curve_GFp
+#define ec_GFp_simple_group_get_curve_GFp       ec_GFp_simple_grp_get_curve_GFp
+#undef ec_GFp_simple_group_clear_finish
+#define ec_GFp_simple_group_clear_finish        ec_GFp_simple_grp_clear_finish
+#undef ec_GFp_simple_group_set_generator
+#define ec_GFp_simple_group_set_generator       ec_GFp_simple_grp_set_generator
+#undef ec_GFp_simple_group_get0_generator
+#define ec_GFp_simple_group_get0_generator      ec_GFp_simple_grp_gt0_generator
+#undef ec_GFp_simple_group_get_cofactor
+#define ec_GFp_simple_group_get_cofactor        ec_GFp_simple_grp_get_cofactor
+#undef ec_GFp_simple_point_clear_finish
+#define ec_GFp_simple_point_clear_finish        ec_GFp_simple_pt_clear_finish
+#undef ec_GFp_simple_point_set_to_infinity
+#define ec_GFp_simple_point_set_to_infinity     ec_GFp_simple_pt_set_to_inf
+#undef ec_GFp_simple_points_make_affine
+#define ec_GFp_simple_points_make_affine        ec_GFp_simple_pts_make_affine
+#undef ec_GFp_simple_group_get_curve_GFp
+#define ec_GFp_simple_group_get_curve_GFp       ec_GFp_simple_grp_get_curve_GFp
+#undef ec_GFp_simple_set_Jprojective_coordinates_GFp
+#define ec_GFp_simple_set_Jprojective_coordinates_GFp \
+                                                ec_GFp_smp_set_Jproj_coords_GFp
+#undef ec_GFp_simple_get_Jprojective_coordinates_GFp
+#define ec_GFp_simple_get_Jprojective_coordinates_GFp \
+                                                ec_GFp_smp_get_Jproj_coords_GFp
+#undef ec_GFp_simple_point_set_affine_coordinates_GFp
+#define ec_GFp_simple_point_set_affine_coordinates_GFp \
+                                                ec_GFp_smp_pt_set_af_coords_GFp
+#undef ec_GFp_simple_point_get_affine_coordinates_GFp
+#define ec_GFp_simple_point_get_affine_coordinates_GFp \
+                                                ec_GFp_smp_pt_get_af_coords_GFp
+#undef ec_GFp_simple_set_compressed_coordinates_GFp
+#define ec_GFp_simple_set_compressed_coordinates_GFp \
+                                                ec_GFp_smp_set_compr_coords_GFp
+#undef ec_GFp_simple_point_set_affine_coordinates
+#define ec_GFp_simple_point_set_affine_coordinates \
+                                                ec_GFp_smp_pt_set_af_coords
+#undef ec_GFp_simple_point_get_affine_coordinates
+#define ec_GFp_simple_point_get_affine_coordinates \
+                                                ec_GFp_smp_pt_get_af_coords
+#undef ec_GFp_simple_set_compressed_coordinates
+#define ec_GFp_simple_set_compressed_coordinates \
+                                                ec_GFp_smp_set_compr_coords
+#undef ec_GFp_simple_group_check_discriminant
+#define ec_GFp_simple_group_check_discriminant	ec_GFp_simple_grp_chk_discrim
+
+/* Hack som long STORE names */
+#undef STORE_method_set_initialise_function
+#define STORE_method_set_initialise_function	STORE_meth_set_initialise_fn
+#undef STORE_method_set_cleanup_function
+#define STORE_method_set_cleanup_function	STORE_meth_set_cleanup_fn
+#undef STORE_method_set_generate_function
+#define STORE_method_set_generate_function	STORE_meth_set_generate_fn
+#undef STORE_method_set_modify_function
+#define STORE_method_set_modify_function	STORE_meth_set_modify_fn
+#undef STORE_method_set_revoke_function
+#define STORE_method_set_revoke_function	STORE_meth_set_revoke_fn
+#undef STORE_method_set_delete_function
+#define STORE_method_set_delete_function	STORE_meth_set_delete_fn
+#undef STORE_method_set_list_start_function
+#define STORE_method_set_list_start_function	STORE_meth_set_list_start_fn
+#undef STORE_method_set_list_next_function
+#define STORE_method_set_list_next_function	STORE_meth_set_list_next_fn
+#undef STORE_method_set_list_end_function
+#define STORE_method_set_list_end_function	STORE_meth_set_list_end_fn
+#undef STORE_method_set_update_store_function
+#define STORE_method_set_update_store_function	STORE_meth_set_update_store_fn
+#undef STORE_method_set_lock_store_function
+#define STORE_method_set_lock_store_function	STORE_meth_set_lock_store_fn
+#undef STORE_method_set_unlock_store_function
+#define STORE_method_set_unlock_store_function	STORE_meth_set_unlock_store_fn
+#undef STORE_method_get_initialise_function
+#define STORE_method_get_initialise_function	STORE_meth_get_initialise_fn
+#undef STORE_method_get_cleanup_function
+#define STORE_method_get_cleanup_function	STORE_meth_get_cleanup_fn
+#undef STORE_method_get_generate_function
+#define STORE_method_get_generate_function	STORE_meth_get_generate_fn
+#undef STORE_method_get_modify_function
+#define STORE_method_get_modify_function	STORE_meth_get_modify_fn
+#undef STORE_method_get_revoke_function
+#define STORE_method_get_revoke_function	STORE_meth_get_revoke_fn
+#undef STORE_method_get_delete_function
+#define STORE_method_get_delete_function	STORE_meth_get_delete_fn
+#undef STORE_method_get_list_start_function
+#define STORE_method_get_list_start_function	STORE_meth_get_list_start_fn
+#undef STORE_method_get_list_next_function
+#define STORE_method_get_list_next_function	STORE_meth_get_list_next_fn
+#undef STORE_method_get_list_end_function
+#define STORE_method_get_list_end_function	STORE_meth_get_list_end_fn
+#undef STORE_method_get_update_store_function
+#define STORE_method_get_update_store_function	STORE_meth_get_update_store_fn
+#undef STORE_method_get_lock_store_function
+#define STORE_method_get_lock_store_function	STORE_meth_get_lock_store_fn
+#undef STORE_method_get_unlock_store_function
+#define STORE_method_get_unlock_store_function	STORE_meth_get_unlock_store_fn
+
+#endif /* defined OPENSSL_SYS_VMS */
+
+
+/* Case insensiteve linking causes problems.... */
+#if defined(OPENSSL_SYS_WIN16) || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_OS2)
+#undef ERR_load_CRYPTO_strings
+#define ERR_load_CRYPTO_strings			ERR_load_CRYPTOlib_strings
+#undef OCSP_crlID_new
+#define OCSP_crlID_new                          OCSP_crlID2_new
+
+#undef d2i_ECPARAMETERS
+#define d2i_ECPARAMETERS                        d2i_UC_ECPARAMETERS
+#undef i2d_ECPARAMETERS
+#define i2d_ECPARAMETERS                        i2d_UC_ECPARAMETERS
+#undef d2i_ECPKPARAMETERS
+#define d2i_ECPKPARAMETERS                      d2i_UC_ECPKPARAMETERS
+#undef i2d_ECPKPARAMETERS
+#define i2d_ECPKPARAMETERS                      i2d_UC_ECPKPARAMETERS
+
+/* These functions do not seem to exist!  However, I'm paranoid...
+   Original command in x509v3.h:
+   These functions are being redefined in another directory,
+   and clash when the linker is case-insensitive, so let's
+   hide them a little, by giving them an extra 'o' at the
+   beginning of the name... */
+#undef X509v3_cleanup_extensions
+#define X509v3_cleanup_extensions               oX509v3_cleanup_extensions
+#undef X509v3_add_extension
+#define X509v3_add_extension                    oX509v3_add_extension
+#undef X509v3_add_netscape_extensions
+#define X509v3_add_netscape_extensions          oX509v3_add_netscape_extensions
+#undef X509v3_add_standard_extensions
+#define X509v3_add_standard_extensions          oX509v3_add_standard_extensions
+
+
+#endif
+
+
+#endif /* ! defined HEADER_VMS_IDHACKS_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/tls1.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/tls1.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/tls1.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,291 @@
+/* ssl/tls1.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ *
+ * Portions of the attached software ("Contribution") are developed by 
+ * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
+ *
+ * The Contribution is licensed pursuant to the OpenSSL open source
+ * license provided above.
+ *
+ * ECC cipher suite support in OpenSSL originally written by
+ * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories.
+ *
+ */
+
+#ifndef HEADER_TLS1_H 
+#define HEADER_TLS1_H 
+
+#include <openssl/buffer.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES	1
+
+#define TLS1_VERSION			0x0301
+#define TLS1_VERSION_MAJOR		0x03
+#define TLS1_VERSION_MINOR		0x01
+
+#define TLS1_AD_DECRYPTION_FAILED	21
+#define TLS1_AD_RECORD_OVERFLOW		22
+#define TLS1_AD_UNKNOWN_CA		48	/* fatal */
+#define TLS1_AD_ACCESS_DENIED		49	/* fatal */
+#define TLS1_AD_DECODE_ERROR		50	/* fatal */
+#define TLS1_AD_DECRYPT_ERROR		51
+#define TLS1_AD_EXPORT_RESTRICTION	60	/* fatal */
+#define TLS1_AD_PROTOCOL_VERSION	70	/* fatal */
+#define TLS1_AD_INSUFFICIENT_SECURITY	71	/* fatal */
+#define TLS1_AD_INTERNAL_ERROR		80	/* fatal */
+#define TLS1_AD_USER_CANCELLED		90
+#define TLS1_AD_NO_RENEGOTIATION	100
+
+/* Additional TLS ciphersuites from draft-ietf-tls-56-bit-ciphersuites-00.txt
+ * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see
+ * s3_lib.c).  We actually treat them like SSL 3.0 ciphers, which we probably
+ * shouldn't. */
+#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5		0x03000060
+#define TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5	0x03000061
+#define TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA		0x03000062
+#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA	0x03000063
+#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA		0x03000064
+#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA	0x03000065
+#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA		0x03000066
+
+/* AES ciphersuites from RFC3268 */
+
+#define TLS1_CK_RSA_WITH_AES_128_SHA			0x0300002F
+#define TLS1_CK_DH_DSS_WITH_AES_128_SHA			0x03000030
+#define TLS1_CK_DH_RSA_WITH_AES_128_SHA			0x03000031
+#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA		0x03000032
+#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA		0x03000033
+#define TLS1_CK_ADH_WITH_AES_128_SHA			0x03000034
+
+#define TLS1_CK_RSA_WITH_AES_256_SHA			0x03000035
+#define TLS1_CK_DH_DSS_WITH_AES_256_SHA			0x03000036
+#define TLS1_CK_DH_RSA_WITH_AES_256_SHA			0x03000037
+#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA		0x03000038
+#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA		0x03000039
+#define TLS1_CK_ADH_WITH_AES_256_SHA			0x0300003A
+
+/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001).
+ * XXX NOTE: There is a bug in the draft, cipher numbers 4B, and 4C
+ * are defined twice so we define ECDH_ECDSA_EXPORT cipher
+ * suites to use 5B and 5C instead (this may change with future
+ * updates to the IETF draft).
+ */
+/* draft-ietf-tls-ecc-03.txt (June 2003) gives a changed list of
+ * ciphersuites, but does not define numbers for all of them
+ * because of possible conflicts with other Internet Drafts;
+ * most numbers are still subject to change. */
+#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA                0x03000047
+#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA             0x03000048
+#define TLS1_CK_ECDH_ECDSA_WITH_DES_CBC_SHA             0x03000049
+#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA        0x0300004A
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA         0x0300004B
+#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA         0x0300004C
+#define TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA       0x0300005B
+#define TLS1_CK_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA       0x0300005C
+
+#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA                  0x0300004D
+#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA               0x0300004E
+#define TLS1_CK_ECDH_RSA_WITH_DES_CBC_SHA               0x0300004F
+#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA          0x03000050
+#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA           0x03000051
+#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA           0x03000052
+#define TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_40_SHA         0x03000053
+#define TLS1_CK_ECDH_RSA_EXPORT_WITH_RC4_56_SHA         0x03000054
+
+#define TLS1_CK_ECDH_anon_WITH_NULL_SHA                 0x03000055
+#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA              0x03000056
+#define TLS1_CK_ECDH_anon_WITH_DES_CBC_SHA              0x03000057
+#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA         0x03000058
+#define TLS1_CK_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA    0x03000059
+#define TLS1_CK_ECDH_anon_EXPORT_WITH_RC4_40_SHA        0x0300005A
+
+/* XXX: ECC ciphersuites offering forward secrecy are not yet specified
+ * in the ECC/TLS draft but our code allows them to be implemented
+ * very easily. To add such a cipher suite, one needs to add two constant
+ * definitions to this file and a new structure in s3_lib.c. We illustrate
+ * the process for the made-up ciphers ECDHE-ECDSA-AES128-SHA and
+ * ECDHE-RSA-AES128-SHA.
+ */
+#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA        0x03000077
+#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA          0x03000078
+
+
+/* XXX
+ * Inconsistency alert:
+ * The OpenSSL names of ciphers with ephemeral DH here include the string
+ * "DHE", while elsewhere it has always been "EDH".
+ * (The alias for the list of all such ciphers also is "EDH".)
+ * The specifications speak of "EDH"; maybe we should allow both forms
+ * for everything. */
+#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5		"EXP1024-RC4-MD5"
+#define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5	"EXP1024-RC2-CBC-MD5"
+#define TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA	"EXP1024-DES-CBC-SHA"
+#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA	"EXP1024-DHE-DSS-DES-CBC-SHA"
+#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA		"EXP1024-RC4-SHA"
+#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA	"EXP1024-DHE-DSS-RC4-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA		"DHE-DSS-RC4-SHA"
+
+/* AES ciphersuites from RFC3268 */
+#define TLS1_TXT_RSA_WITH_AES_128_SHA			"AES128-SHA"
+#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA		"DH-DSS-AES128-SHA"
+#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA		"DH-RSA-AES128-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA		"DHE-DSS-AES128-SHA"
+#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA		"DHE-RSA-AES128-SHA"
+#define TLS1_TXT_ADH_WITH_AES_128_SHA			"ADH-AES128-SHA"
+
+#define TLS1_TXT_RSA_WITH_AES_256_SHA			"AES256-SHA"
+#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA		"DH-DSS-AES256-SHA"
+#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA		"DH-RSA-AES256-SHA"
+#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA		"DHE-DSS-AES256-SHA"
+#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA		"DHE-RSA-AES256-SHA"
+#define TLS1_TXT_ADH_WITH_AES_256_SHA			"ADH-AES256-SHA"
+
+/* ECC ciphersuites from draft-ietf-tls-ecc-01.txt (Mar 15, 2001) */
+#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA               "ECDH-ECDSA-NULL-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA            "ECDH-ECDSA-RC4-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_DES_CBC_SHA            "ECDH-ECDSA-DES-CBC-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA       "ECDH-ECDSA-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA        "ECDH-ECDSA-AES128-SHA"
+#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA        "ECDH-ECDSA-AES256-SHA"
+#define TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_40_SHA      "EXP-ECDH-ECDSA-RC4-40-SHA"
+#define TLS1_TXT_ECDH_ECDSA_EXPORT_WITH_RC4_56_SHA      "EXP-ECDH-ECDSA-RC4-56-SHA"
+
+#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA                 "ECDH-RSA-NULL-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA              "ECDH-RSA-RC4-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_DES_CBC_SHA              "ECDH-RSA-DES-CBC-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA         "ECDH-RSA-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA          "ECDH-RSA-AES128-SHA"
+#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA          "ECDH-RSA-AES256-SHA"
+#define TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_40_SHA        "EXP-ECDH-RSA-RC4-40-SHA"
+#define TLS1_TXT_ECDH_RSA_EXPORT_WITH_RC4_56_SHA        "EXP-ECDH-RSA-RC4-56-SHA"
+
+#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA                "AECDH-NULL-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA             "AECDH-RC4-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_DES_CBC_SHA             "AECDH-DES-CBC-SHA"
+#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA        "AECDH-DES-CBC3-SHA"
+#define TLS1_TXT_ECDH_anon_EXPORT_WITH_DES_40_CBC_SHA   "EXP-AECDH-DES-40-CBC-SHA"
+#define TLS1_TXT_ECDH_anon_EXPORT_WITH_RC4_40_SHA       "EXP-AECDH-RC4-40-SHA"
+
+/* XXX: Made-up ECC cipher suites offering forward secrecy. This is for 
+ * illustration only. 
+ */
+#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA       "ECDHE-ECDSA-AES128-SHA"
+#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA         "ECDHE-RSA-AES128-SHA"
+
+
+#define TLS_CT_RSA_SIGN			1
+#define TLS_CT_DSS_SIGN			2
+#define TLS_CT_RSA_FIXED_DH		3
+#define TLS_CT_DSS_FIXED_DH		4
+#define TLS_CT_ECDSA_SIGN		5
+#define TLS_CT_RSA_FIXED_ECDH		6
+#define TLS_CT_ECDSA_FIXED_ECDH 	7
+#define TLS_CT_NUMBER			7
+
+#define TLS1_FINISH_MAC_LENGTH		12
+
+#define TLS_MD_MAX_CONST_SIZE			20
+#define TLS_MD_CLIENT_FINISH_CONST		"client finished"
+#define TLS_MD_CLIENT_FINISH_CONST_SIZE		15
+#define TLS_MD_SERVER_FINISH_CONST		"server finished"
+#define TLS_MD_SERVER_FINISH_CONST_SIZE		15
+#define TLS_MD_SERVER_WRITE_KEY_CONST		"server write key"
+#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE	16
+#define TLS_MD_KEY_EXPANSION_CONST		"key expansion"
+#define TLS_MD_KEY_EXPANSION_CONST_SIZE		13
+#define TLS_MD_CLIENT_WRITE_KEY_CONST		"client write key"
+#define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE	16
+#define TLS_MD_SERVER_WRITE_KEY_CONST		"server write key"
+#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE	16
+#define TLS_MD_IV_BLOCK_CONST			"IV block"
+#define TLS_MD_IV_BLOCK_CONST_SIZE		8
+#define TLS_MD_MASTER_SECRET_CONST		"master secret"
+#define TLS_MD_MASTER_SECRET_CONST_SIZE		13
+
+#ifdef CHARSET_EBCDIC
+#undef TLS_MD_CLIENT_FINISH_CONST
+#define TLS_MD_CLIENT_FINISH_CONST    "\x63\x6c\x69\x65\x6e\x74\x20\x66\x69\x6e\x69\x73\x68\x65\x64"  /*client finished*/
+#undef TLS_MD_SERVER_FINISH_CONST
+#define TLS_MD_SERVER_FINISH_CONST    "\x73\x65\x72\x76\x65\x72\x20\x66\x69\x6e\x69\x73\x68\x65\x64"  /*server finished*/
+#undef TLS_MD_SERVER_WRITE_KEY_CONST
+#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79"  /*server write key*/
+#undef TLS_MD_KEY_EXPANSION_CONST
+#define TLS_MD_KEY_EXPANSION_CONST    "\x6b\x65\x79\x20\x65\x78\x70\x61\x6e\x73\x69\x6f\x6e"  /*key expansion*/
+#undef TLS_MD_CLIENT_WRITE_KEY_CONST
+#define TLS_MD_CLIENT_WRITE_KEY_CONST "\x63\x6c\x69\x65\x6e\x74\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79"  /*client write key*/
+#undef TLS_MD_SERVER_WRITE_KEY_CONST
+#define TLS_MD_SERVER_WRITE_KEY_CONST "\x73\x65\x72\x76\x65\x72\x20\x77\x72\x69\x74\x65\x20\x6b\x65\x79"  /*server write key*/
+#undef TLS_MD_IV_BLOCK_CONST
+#define TLS_MD_IV_BLOCK_CONST         "\x49\x56\x20\x62\x6c\x6f\x63\x6b"  /*IV block*/
+#undef TLS_MD_MASTER_SECRET_CONST
+#define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/tmdiff.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/tmdiff.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/tmdiff.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,94 @@
+/* crypto/tmdiff.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+/* Header for dynamic hash table routines
+ * Author - Eric Young
+ */
+/* ... erm yeah, "dynamic hash tables" you say?
+ * 
+ * And what would dynamic hash tables have to do with any of this code *now*?
+ * AFAICS, this code is only referenced by crypto/bn/exp.c which is an unused
+ * file that I doubt compiles any more. speed.c is the only thing that could
+ * use this (and it has nothing to do with hash tables), yet it instead has its
+ * own duplication of all this stuff and looks, if anything, more complete. See
+ * the corresponding note in apps/speed.c.
+ * The Bemused - Geoff
+ */
+
+#ifndef HEADER_TMDIFF_H
+#define HEADER_TMDIFF_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct ms_tm MS_TM;
+
+MS_TM *ms_time_new(void );
+void ms_time_free(MS_TM *a);
+void ms_time_get(MS_TM *a);
+double ms_time_diff(MS_TM *start, MS_TM *end);
+int ms_time_cmp(const MS_TM *ap, const MS_TM *bp);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/txt_db.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/txt_db.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/txt_db.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,109 @@
+/* crypto/txt_db/txt_db.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_TXT_DB_H
+#define HEADER_TXT_DB_H
+
+#include <openssl/opensslconf.h>
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/stack.h>
+#include <openssl/lhash.h>
+
+#define DB_ERROR_OK			0
+#define DB_ERROR_MALLOC			1
+#define DB_ERROR_INDEX_CLASH    	2
+#define DB_ERROR_INDEX_OUT_OF_RANGE	3
+#define DB_ERROR_NO_INDEX		4
+#define DB_ERROR_INSERT_INDEX_CLASH    	5
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef struct txt_db_st
+	{
+	int num_fields;
+	STACK /* char ** */ *data;
+	LHASH **index;
+	int (**qual)(char **);
+	long error;
+	long arg1;
+	long arg2;
+	char **arg_row;
+	} TXT_DB;
+
+#ifndef OPENSSL_NO_BIO
+TXT_DB *TXT_DB_read(BIO *in, int num);
+long TXT_DB_write(BIO *out, TXT_DB *db);
+#else
+TXT_DB *TXT_DB_read(char *in, int num);
+long TXT_DB_write(char *out, TXT_DB *db);
+#endif
+int TXT_DB_create_index(TXT_DB *db,int field,int (*qual)(char **),
+		LHASH_HASH_FN_TYPE hash, LHASH_COMP_FN_TYPE cmp);
+void TXT_DB_free(TXT_DB *db);
+char **TXT_DB_get_by_index(TXT_DB *db, int idx, char **value);
+int TXT_DB_insert(TXT_DB *db,char **value);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ui.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ui.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ui.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,381 @@
+/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */
+/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
+ * project 2001.
+ */
+/* ====================================================================
+ * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_UI_H
+#define HEADER_UI_H
+
+#ifndef OPENSSL_NO_DEPRECATED
+#include <openssl/crypto.h>
+#endif
+#include <openssl/safestack.h>
+#include <openssl/ossl_typ.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Declared already in ossl_typ.h */
+/* typedef struct ui_st UI; */
+/* typedef struct ui_method_st UI_METHOD; */
+
+
+/* All the following functions return -1 or NULL on error and in some cases
+   (UI_process()) -2 if interrupted or in some other way cancelled.
+   When everything is fine, they return 0, a positive value or a non-NULL
+   pointer, all depending on their purpose. */
+
+/* Creators and destructor.   */
+UI *UI_new(void);
+UI *UI_new_method(const UI_METHOD *method);
+void UI_free(UI *ui);
+
+/* The following functions are used to add strings to be printed and prompt
+   strings to prompt for data.  The names are UI_{add,dup}_<function>_string
+   and UI_{add,dup}_input_boolean.
+
+   UI_{add,dup}_<function>_string have the following meanings:
+	add	add a text or prompt string.  The pointers given to these
+		functions are used verbatim, no copying is done.
+	dup	make a copy of the text or prompt string, then add the copy
+		to the collection of strings in the user interface.
+	<function>
+		The function is a name for the functionality that the given
+		string shall be used for.  It can be one of:
+			input	use the string as data prompt.
+			verify	use the string as verification prompt.  This
+				is used to verify a previous input.
+			info	use the string for informational output.
+			error	use the string for error output.
+   Honestly, there's currently no difference between info and error for the
+   moment.
+
+   UI_{add,dup}_input_boolean have the same semantics for "add" and "dup",
+   and are typically used when one wants to prompt for a yes/no response.
+
+
+   All of the functions in this group take a UI and a prompt string.
+   The string input and verify addition functions also take a flag argument,
+   a buffer for the result to end up with, a minimum input size and a maximum
+   input size (the result buffer MUST be large enough to be able to contain
+   the maximum number of characters).  Additionally, the verify addition
+   functions takes another buffer to compare the result against.
+   The boolean input functions take an action description string (which should
+   be safe to ignore if the expected user action is obvious, for example with
+   a dialog box with an OK button and a Cancel button), a string of acceptable
+   characters to mean OK and to mean Cancel.  The two last strings are checked
+   to make sure they don't have common characters.  Additionally, the same
+   flag argument as for the string input is taken, as well as a result buffer.
+   The result buffer is required to be at least one byte long.  Depending on
+   the answer, the first character from the OK or the Cancel character strings
+   will be stored in the first byte of the result buffer.  No NUL will be
+   added, so the result is *not* a string.
+
+   On success, the all return an index of the added information.  That index
+   is usefull when retrieving results with UI_get0_result(). */
+int UI_add_input_string(UI *ui, const char *prompt, int flags,
+	char *result_buf, int minsize, int maxsize);
+int UI_dup_input_string(UI *ui, const char *prompt, int flags,
+	char *result_buf, int minsize, int maxsize);
+int UI_add_verify_string(UI *ui, const char *prompt, int flags,
+	char *result_buf, int minsize, int maxsize, const char *test_buf);
+int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
+	char *result_buf, int minsize, int maxsize, const char *test_buf);
+int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
+	const char *ok_chars, const char *cancel_chars,
+	int flags, char *result_buf);
+int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
+	const char *ok_chars, const char *cancel_chars,
+	int flags, char *result_buf);
+int UI_add_info_string(UI *ui, const char *text);
+int UI_dup_info_string(UI *ui, const char *text);
+int UI_add_error_string(UI *ui, const char *text);
+int UI_dup_error_string(UI *ui, const char *text);
+
+/* These are the possible flags.  They can be or'ed together. */
+/* Use to have echoing of input */
+#define UI_INPUT_FLAG_ECHO		0x01
+/* Use a default password.  Where that password is found is completely
+   up to the application, it might for example be in the user data set
+   with UI_add_user_data().  It is not recommended to have more than
+   one input in each UI being marked with this flag, or the application
+   might get confused. */
+#define UI_INPUT_FLAG_DEFAULT_PWD	0x02
+
+/* The user of these routines may want to define flags of their own.  The core
+   UI won't look at those, but will pass them on to the method routines.  They
+   must use higher bits so they don't get confused with the UI bits above.
+   UI_INPUT_FLAG_USER_BASE tells which is the lowest bit to use.  A good
+   example of use is this:
+
+	#define MY_UI_FLAG1	(0x01 << UI_INPUT_FLAG_USER_BASE)
+
+*/
+#define UI_INPUT_FLAG_USER_BASE	16
+
+
+/* The following function helps construct a prompt.  object_desc is a
+   textual short description of the object, for example "pass phrase",
+   and object_name is the name of the object (might be a card name or
+   a file name.
+   The returned string shall always be allocated on the heap with
+   OPENSSL_malloc(), and need to be free'd with OPENSSL_free().
+
+   If the ui_method doesn't contain a pointer to a user-defined prompt
+   constructor, a default string is built, looking like this:
+
+	"Enter {object_desc} for {object_name}:"
+
+   So, if object_desc has the value "pass phrase" and object_name has
+   the value "foo.key", the resulting string is:
+
+	"Enter pass phrase for foo.key:"
+*/
+char *UI_construct_prompt(UI *ui_method,
+	const char *object_desc, const char *object_name);
+
+
+/* The following function is used to store a pointer to user-specific data.
+   Any previous such pointer will be returned and replaced.
+
+   For callback purposes, this function makes a lot more sense than using
+   ex_data, since the latter requires that different parts of OpenSSL or
+   applications share the same ex_data index.
+
+   Note that the UI_OpenSSL() method completely ignores the user data.
+   Other methods may not, however.  */
+void *UI_add_user_data(UI *ui, void *user_data);
+/* We need a user data retrieving function as well.  */
+void *UI_get0_user_data(UI *ui);
+
+/* Return the result associated with a prompt given with the index i. */
+const char *UI_get0_result(UI *ui, int i);
+
+/* When all strings have been added, process the whole thing. */
+int UI_process(UI *ui);
+
+/* Give a user interface parametrised control commands.  This can be used to
+   send down an integer, a data pointer or a function pointer, as well as
+   be used to get information from a UI. */
+int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f)(void));
+
+/* The commands */
+/* Use UI_CONTROL_PRINT_ERRORS with the value 1 to have UI_process print the
+   OpenSSL error stack before printing any info or added error messages and
+   before any prompting. */
+#define UI_CTRL_PRINT_ERRORS		1
+/* Check if a UI_process() is possible to do again with the same instance of
+   a user interface.  This makes UI_ctrl() return 1 if it is redoable, and 0
+   if not. */
+#define UI_CTRL_IS_REDOABLE		2
+
+
+/* Some methods may use extra data */
+#define UI_set_app_data(s,arg)         UI_set_ex_data(s,0,arg)
+#define UI_get_app_data(s)             UI_get_ex_data(s,0)
+int UI_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int UI_set_ex_data(UI *r,int idx,void *arg);
+void *UI_get_ex_data(UI *r, int idx);
+
+/* Use specific methods instead of the built-in one */
+void UI_set_default_method(const UI_METHOD *meth);
+const UI_METHOD *UI_get_default_method(void);
+const UI_METHOD *UI_get_method(UI *ui);
+const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth);
+
+/* The method with all the built-in thingies */
+UI_METHOD *UI_OpenSSL(void);
+
+
+/* ---------- For method writers ---------- */
+/* A method contains a number of functions that implement the low level
+   of the User Interface.  The functions are:
+
+	an opener	This function starts a session, maybe by opening
+			a channel to a tty, or by opening a window.
+	a writer	This function is called to write a given string,
+			maybe to the tty, maybe as a field label in a
+			window.
+	a flusher	This function is called to flush everything that
+			has been output so far.  It can be used to actually
+			display a dialog box after it has been built.
+	a reader	This function is called to read a given prompt,
+			maybe from the tty, maybe from a field in a
+			window.  Note that it's called wth all string
+			structures, not only the prompt ones, so it must
+			check such things itself.
+	a closer	This function closes the session, maybe by closing
+			the channel to the tty, or closing the window.
+
+   All these functions are expected to return:
+
+	0	on error.
+	1	on success.
+	-1	on out-of-band events, for example if some prompting has
+		been canceled (by pressing Ctrl-C, for example).  This is
+		only checked when returned by the flusher or the reader.
+
+   The way this is used, the opener is first called, then the writer for all
+   strings, then the flusher, then the reader for all strings and finally the
+   closer.  Note that if you want to prompt from a terminal or other command
+   line interface, the best is to have the reader also write the prompts
+   instead of having the writer do it.  If you want to prompt from a dialog
+   box, the writer can be used to build up the contents of the box, and the
+   flusher to actually display the box and run the event loop until all data
+   has been given, after which the reader only grabs the given data and puts
+   them back into the UI strings.
+
+   All method functions take a UI as argument.  Additionally, the writer and
+   the reader take a UI_STRING.
+*/
+
+/* The UI_STRING type is the data structure that contains all the needed info
+   about a string or a prompt, including test data for a verification prompt.
+*/
+DECLARE_STACK_OF(UI_STRING)
+typedef struct ui_string_st UI_STRING;
+
+/* The different types of strings that are currently supported.
+   This is only needed by method authors. */
+enum UI_string_types
+	{
+	UIT_NONE=0,
+	UIT_PROMPT,		/* Prompt for a string */
+	UIT_VERIFY,		/* Prompt for a string and verify */
+	UIT_BOOLEAN,		/* Prompt for a yes/no response */
+	UIT_INFO,		/* Send info to the user */
+	UIT_ERROR		/* Send an error message to the user */
+	};
+
+/* Create and manipulate methods */
+UI_METHOD *UI_create_method(char *name);
+void UI_destroy_method(UI_METHOD *ui_method);
+int UI_method_set_opener(UI_METHOD *method, int (*opener)(UI *ui));
+int UI_method_set_writer(UI_METHOD *method, int (*writer)(UI *ui, UI_STRING *uis));
+int UI_method_set_flusher(UI_METHOD *method, int (*flusher)(UI *ui));
+int UI_method_set_reader(UI_METHOD *method, int (*reader)(UI *ui, UI_STRING *uis));
+int UI_method_set_closer(UI_METHOD *method, int (*closer)(UI *ui));
+int (*UI_method_get_opener(UI_METHOD *method))(UI*);
+int (*UI_method_get_writer(UI_METHOD *method))(UI*,UI_STRING*);
+int (*UI_method_get_flusher(UI_METHOD *method))(UI*);
+int (*UI_method_get_reader(UI_METHOD *method))(UI*,UI_STRING*);
+int (*UI_method_get_closer(UI_METHOD *method))(UI*);
+
+/* The following functions are helpers for method writers to access relevant
+   data from a UI_STRING. */
+
+/* Return type of the UI_STRING */
+enum UI_string_types UI_get_string_type(UI_STRING *uis);
+/* Return input flags of the UI_STRING */
+int UI_get_input_flags(UI_STRING *uis);
+/* Return the actual string to output (the prompt, info or error) */
+const char *UI_get0_output_string(UI_STRING *uis);
+/* Return the optional action string to output (the boolean promtp instruction) */
+const char *UI_get0_action_string(UI_STRING *uis);
+/* Return the result of a prompt */
+const char *UI_get0_result_string(UI_STRING *uis);
+/* Return the string to test the result against.  Only useful with verifies. */
+const char *UI_get0_test_string(UI_STRING *uis);
+/* Return the required minimum size of the result */
+int UI_get_result_minsize(UI_STRING *uis);
+/* Return the required maximum size of the result */
+int UI_get_result_maxsize(UI_STRING *uis);
+/* Set the result of a UI_STRING. */
+int UI_set_result(UI *ui, UI_STRING *uis, const char *result);
+
+
+/* A couple of popular utility functions */
+int UI_UTIL_read_pw_string(char *buf,int length,const char *prompt,int verify);
+int UI_UTIL_read_pw(char *buf,char *buff,int size,const char *prompt,int verify);
+
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_UI_strings(void);
+
+/* Error codes for the UI functions. */
+
+/* Function codes. */
+#define UI_F_GENERAL_ALLOCATE_BOOLEAN			 108
+#define UI_F_GENERAL_ALLOCATE_PROMPT			 109
+#define UI_F_GENERAL_ALLOCATE_STRING			 100
+#define UI_F_UI_CTRL					 111
+#define UI_F_UI_DUP_ERROR_STRING			 101
+#define UI_F_UI_DUP_INFO_STRING				 102
+#define UI_F_UI_DUP_INPUT_BOOLEAN			 110
+#define UI_F_UI_DUP_INPUT_STRING			 103
+#define UI_F_UI_DUP_VERIFY_STRING			 106
+#define UI_F_UI_GET0_RESULT				 107
+#define UI_F_UI_NEW_METHOD				 104
+#define UI_F_UI_SET_RESULT				 105
+
+/* Reason codes. */
+#define UI_R_COMMON_OK_AND_CANCEL_CHARACTERS		 104
+#define UI_R_INDEX_TOO_LARGE				 102
+#define UI_R_INDEX_TOO_SMALL				 103
+#define UI_R_NO_RESULT_BUFFER				 105
+#define UI_R_RESULT_TOO_LARGE				 100
+#define UI_R_RESULT_TOO_SMALL				 101
+#define UI_R_UNKNOWN_CONTROL_COMMAND			 106
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ui_compat.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ui_compat.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/ui_compat.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,83 @@
+/* crypto/ui/ui.h -*- mode:C; c-file-style: "eay" -*- */
+/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
+ * project 2001.
+ */
+/* ====================================================================
+ * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+#ifndef HEADER_UI_COMPAT_H
+#define HEADER_UI_COMPAT_H
+
+#include <openssl/opensslconf.h>
+#include <openssl/ui.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* The following functions were previously part of the DES section,
+   and are provided here for backward compatibility reasons. */
+
+#define des_read_pw_string(b,l,p,v) \
+	_ossl_old_des_read_pw_string((b),(l),(p),(v))
+#define des_read_pw(b,bf,s,p,v) \
+	_ossl_old_des_read_pw((b),(bf),(s),(p),(v))
+
+int _ossl_old_des_read_pw_string(char *buf,int length,const char *prompt,int verify);
+int _ossl_old_des_read_pw(char *buf,char *buff,int size,const char *prompt,int verify);
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1340 @@
+/* crypto/x509/x509.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+/* ====================================================================
+ * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
+ * ECDH support in OpenSSL originally developed by 
+ * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project.
+ */
+
+#ifndef HEADER_X509_H
+#define HEADER_X509_H
+
+#include <openssl/e_os2.h>
+#include <openssl/symhacks.h>
+#ifndef OPENSSL_NO_BUFFER
+#include <openssl/buffer.h>
+#endif
+#ifndef OPENSSL_NO_EVP
+#include <openssl/evp.h>
+#endif
+#ifndef OPENSSL_NO_BIO
+#include <openssl/bio.h>
+#endif
+#include <openssl/stack.h>
+#include <openssl/asn1.h>
+#include <openssl/safestack.h>
+
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#endif
+
+#ifndef OPENSSL_NO_ECDSA
+#include <openssl/ecdsa.h>
+#endif
+
+#ifndef OPENSSL_NO_ECDH
+#include <openssl/ecdh.h>
+#endif
+
+#ifndef OPENSSL_NO_DEPRECATED
+#ifndef OPENSSL_NO_RSA
+#include <openssl/rsa.h>
+#endif
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#ifndef OPENSSL_NO_DH
+#include <openssl/dh.h>
+#endif
+#endif
+
+#ifndef OPENSSL_NO_SHA
+#include <openssl/sha.h>
+#endif
+#include <openssl/ossl_typ.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef OPENSSL_SYS_WIN32
+/* Under Win32 these are defined in wincrypt.h */
+#undef X509_NAME
+#undef X509_CERT_PAIR
+#endif
+
+#define X509_FILETYPE_PEM	1
+#define X509_FILETYPE_ASN1	2
+#define X509_FILETYPE_DEFAULT	3
+
+#define X509v3_KU_DIGITAL_SIGNATURE	0x0080
+#define X509v3_KU_NON_REPUDIATION	0x0040
+#define X509v3_KU_KEY_ENCIPHERMENT	0x0020
+#define X509v3_KU_DATA_ENCIPHERMENT	0x0010
+#define X509v3_KU_KEY_AGREEMENT		0x0008
+#define X509v3_KU_KEY_CERT_SIGN		0x0004
+#define X509v3_KU_CRL_SIGN		0x0002
+#define X509v3_KU_ENCIPHER_ONLY		0x0001
+#define X509v3_KU_DECIPHER_ONLY		0x8000
+#define X509v3_KU_UNDEF			0xffff
+
+typedef struct X509_objects_st
+	{
+	int nid;
+	int (*a2i)(void);
+	int (*i2a)(void);
+	} X509_OBJECTS;
+
+struct X509_algor_st
+	{
+	ASN1_OBJECT *algorithm;
+	ASN1_TYPE *parameter;
+	} /* X509_ALGOR */;
+
+DECLARE_STACK_OF(X509_ALGOR)
+DECLARE_ASN1_SET_OF(X509_ALGOR)
+
+typedef struct X509_val_st
+	{
+	ASN1_TIME *notBefore;
+	ASN1_TIME *notAfter;
+	} X509_VAL;
+
+typedef struct X509_pubkey_st
+	{
+	X509_ALGOR *algor;
+	ASN1_BIT_STRING *public_key;
+	EVP_PKEY *pkey;
+	} X509_PUBKEY;
+
+typedef struct X509_sig_st
+	{
+	X509_ALGOR *algor;
+	ASN1_OCTET_STRING *digest;
+	} X509_SIG;
+
+typedef struct X509_name_entry_st
+	{
+	ASN1_OBJECT *object;
+	ASN1_STRING *value;
+	int set;
+	int size; 	/* temp variable */
+	} X509_NAME_ENTRY;
+
+DECLARE_STACK_OF(X509_NAME_ENTRY)
+DECLARE_ASN1_SET_OF(X509_NAME_ENTRY)
+
+/* we always keep X509_NAMEs in 2 forms. */
+struct X509_name_st
+	{
+	STACK_OF(X509_NAME_ENTRY) *entries;
+	int modified;	/* true if 'bytes' needs to be built */
+#ifndef OPENSSL_NO_BUFFER
+	BUF_MEM *bytes;
+#else
+	char *bytes;
+#endif
+	unsigned long hash; /* Keep the hash around for lookups */
+	} /* X509_NAME */;
+
+DECLARE_STACK_OF(X509_NAME)
+
+#define X509_EX_V_NETSCAPE_HACK		0x8000
+#define X509_EX_V_INIT			0x0001
+typedef struct X509_extension_st
+	{
+	ASN1_OBJECT *object;
+	ASN1_BOOLEAN critical;
+	ASN1_OCTET_STRING *value;
+	} X509_EXTENSION;
+
+DECLARE_STACK_OF(X509_EXTENSION)
+DECLARE_ASN1_SET_OF(X509_EXTENSION)
+
+/* a sequence of these are used */
+typedef struct x509_attributes_st
+	{
+	ASN1_OBJECT *object;
+	int single; /* 0 for a set, 1 for a single item (which is wrong) */
+	union	{
+		char		*ptr;
+/* 0 */		STACK_OF(ASN1_TYPE) *set;
+/* 1 */		ASN1_TYPE	*single;
+		} value;
+	} X509_ATTRIBUTE;
+
+DECLARE_STACK_OF(X509_ATTRIBUTE)
+DECLARE_ASN1_SET_OF(X509_ATTRIBUTE)
+
+
+typedef struct X509_req_info_st
+	{
+	ASN1_ENCODING enc;
+	ASN1_INTEGER *version;
+	X509_NAME *subject;
+	X509_PUBKEY *pubkey;
+	/*  d=2 hl=2 l=  0 cons: cont: 00 */
+	STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
+	} X509_REQ_INFO;
+
+typedef struct X509_req_st
+	{
+	X509_REQ_INFO *req_info;
+	X509_ALGOR *sig_alg;
+	ASN1_BIT_STRING *signature;
+	int references;
+	} X509_REQ;
+
+typedef struct x509_cinf_st
+	{
+	ASN1_INTEGER *version;		/* [ 0 ] default of v1 */
+	ASN1_INTEGER *serialNumber;
+	X509_ALGOR *signature;
+	X509_NAME *issuer;
+	X509_VAL *validity;
+	X509_NAME *subject;
+	X509_PUBKEY *key;
+	ASN1_BIT_STRING *issuerUID;		/* [ 1 ] optional in v2 */
+	ASN1_BIT_STRING *subjectUID;		/* [ 2 ] optional in v2 */
+	STACK_OF(X509_EXTENSION) *extensions;	/* [ 3 ] optional in v3 */
+	} X509_CINF;
+
+/* This stuff is certificate "auxiliary info"
+ * it contains details which are useful in certificate
+ * stores and databases. When used this is tagged onto
+ * the end of the certificate itself
+ */
+
+typedef struct x509_cert_aux_st
+	{
+	STACK_OF(ASN1_OBJECT) *trust;		/* trusted uses */
+	STACK_OF(ASN1_OBJECT) *reject;		/* rejected uses */
+	ASN1_UTF8STRING *alias;			/* "friendly name" */
+	ASN1_OCTET_STRING *keyid;		/* key id of private key */
+	STACK_OF(X509_ALGOR) *other;		/* other unspecified info */
+	} X509_CERT_AUX;
+
+struct x509_st
+	{
+	X509_CINF *cert_info;
+	X509_ALGOR *sig_alg;
+	ASN1_BIT_STRING *signature;
+	int valid;
+	int references;
+	char *name;
+	CRYPTO_EX_DATA ex_data;
+	/* These contain copies of various extension values */
+	long ex_pathlen;
+	long ex_pcpathlen;
+	unsigned long ex_flags;
+	unsigned long ex_kusage;
+	unsigned long ex_xkusage;
+	unsigned long ex_nscert;
+	ASN1_OCTET_STRING *skid;
+	struct AUTHORITY_KEYID_st *akid;
+	X509_POLICY_CACHE *policy_cache;
+#ifndef OPENSSL_NO_SHA
+	unsigned char sha1_hash[SHA_DIGEST_LENGTH];
+#endif
+	X509_CERT_AUX *aux;
+	} /* X509 */;
+
+DECLARE_STACK_OF(X509)
+DECLARE_ASN1_SET_OF(X509)
+
+/* This is used for a table of trust checking functions */
+
+typedef struct x509_trust_st {
+	int trust;
+	int flags;
+	int (*check_trust)(struct x509_trust_st *, X509 *, int);
+	char *name;
+	int arg1;
+	void *arg2;
+} X509_TRUST;
+
+DECLARE_STACK_OF(X509_TRUST)
+
+typedef struct x509_cert_pair_st {
+	X509 *forward;
+	X509 *reverse;
+} X509_CERT_PAIR;
+
+/* standard trust ids */
+
+#define X509_TRUST_DEFAULT	-1	/* Only valid in purpose settings */
+
+#define X509_TRUST_COMPAT	1
+#define X509_TRUST_SSL_CLIENT	2
+#define X509_TRUST_SSL_SERVER	3
+#define X509_TRUST_EMAIL	4
+#define X509_TRUST_OBJECT_SIGN	5
+#define X509_TRUST_OCSP_SIGN	6
+#define X509_TRUST_OCSP_REQUEST	7
+
+/* Keep these up to date! */
+#define X509_TRUST_MIN		1
+#define X509_TRUST_MAX		7
+
+
+/* trust_flags values */
+#define	X509_TRUST_DYNAMIC 	1
+#define	X509_TRUST_DYNAMIC_NAME	2
+
+/* check_trust return codes */
+
+#define X509_TRUST_TRUSTED	1
+#define X509_TRUST_REJECTED	2
+#define X509_TRUST_UNTRUSTED	3
+
+/* Flags for X509_print_ex() */
+
+#define	X509_FLAG_COMPAT		0
+#define	X509_FLAG_NO_HEADER		1L
+#define	X509_FLAG_NO_VERSION		(1L << 1)
+#define	X509_FLAG_NO_SERIAL		(1L << 2)
+#define	X509_FLAG_NO_SIGNAME		(1L << 3)
+#define	X509_FLAG_NO_ISSUER		(1L << 4)
+#define	X509_FLAG_NO_VALIDITY		(1L << 5)
+#define	X509_FLAG_NO_SUBJECT		(1L << 6)
+#define	X509_FLAG_NO_PUBKEY		(1L << 7)
+#define	X509_FLAG_NO_EXTENSIONS		(1L << 8)
+#define	X509_FLAG_NO_SIGDUMP		(1L << 9)
+#define	X509_FLAG_NO_AUX		(1L << 10)
+#define	X509_FLAG_NO_ATTRIBUTES		(1L << 11)
+
+/* Flags specific to X509_NAME_print_ex() */	
+
+/* The field separator information */
+
+#define XN_FLAG_SEP_MASK	(0xf << 16)
+
+#define XN_FLAG_COMPAT		0		/* Traditional SSLeay: use old X509_NAME_print */
+#define XN_FLAG_SEP_COMMA_PLUS	(1 << 16)	/* RFC2253 ,+ */
+#define XN_FLAG_SEP_CPLUS_SPC	(2 << 16)	/* ,+ spaced: more readable */
+#define XN_FLAG_SEP_SPLUS_SPC	(3 << 16)	/* ;+ spaced */
+#define XN_FLAG_SEP_MULTILINE	(4 << 16)	/* One line per field */
+
+#define XN_FLAG_DN_REV		(1 << 20)	/* Reverse DN order */
+
+/* How the field name is shown */
+
+#define XN_FLAG_FN_MASK		(0x3 << 21)
+
+#define XN_FLAG_FN_SN		0		/* Object short name */
+#define XN_FLAG_FN_LN		(1 << 21)	/* Object long name */
+#define XN_FLAG_FN_OID		(2 << 21)	/* Always use OIDs */
+#define XN_FLAG_FN_NONE		(3 << 21)	/* No field names */
+
+#define XN_FLAG_SPC_EQ		(1 << 23)	/* Put spaces round '=' */
+
+/* This determines if we dump fields we don't recognise:
+ * RFC2253 requires this.
+ */
+
+#define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24)
+
+#define XN_FLAG_FN_ALIGN	(1 << 25)	/* Align field names to 20 characters */
+
+/* Complete set of RFC2253 flags */
+
+#define XN_FLAG_RFC2253 (ASN1_STRFLGS_RFC2253 | \
+			XN_FLAG_SEP_COMMA_PLUS | \
+			XN_FLAG_DN_REV | \
+			XN_FLAG_FN_SN | \
+			XN_FLAG_DUMP_UNKNOWN_FIELDS)
+
+/* readable oneline form */
+
+#define XN_FLAG_ONELINE (ASN1_STRFLGS_RFC2253 | \
+			ASN1_STRFLGS_ESC_QUOTE | \
+			XN_FLAG_SEP_CPLUS_SPC | \
+			XN_FLAG_SPC_EQ | \
+			XN_FLAG_FN_SN)
+
+/* readable multiline form */
+
+#define XN_FLAG_MULTILINE (ASN1_STRFLGS_ESC_CTRL | \
+			ASN1_STRFLGS_ESC_MSB | \
+			XN_FLAG_SEP_MULTILINE | \
+			XN_FLAG_SPC_EQ | \
+			XN_FLAG_FN_LN | \
+			XN_FLAG_FN_ALIGN)
+
+typedef struct X509_revoked_st
+	{
+	ASN1_INTEGER *serialNumber;
+	ASN1_TIME *revocationDate;
+	STACK_OF(X509_EXTENSION) /* optional */ *extensions;
+	int sequence; /* load sequence */
+	} X509_REVOKED;
+
+DECLARE_STACK_OF(X509_REVOKED)
+DECLARE_ASN1_SET_OF(X509_REVOKED)
+
+typedef struct X509_crl_info_st
+	{
+	ASN1_INTEGER *version;
+	X509_ALGOR *sig_alg;
+	X509_NAME *issuer;
+	ASN1_TIME *lastUpdate;
+	ASN1_TIME *nextUpdate;
+	STACK_OF(X509_REVOKED) *revoked;
+	STACK_OF(X509_EXTENSION) /* [0] */ *extensions;
+	ASN1_ENCODING enc;
+	} X509_CRL_INFO;
+
+struct X509_crl_st
+	{
+	/* actual signature */
+	X509_CRL_INFO *crl;
+	X509_ALGOR *sig_alg;
+	ASN1_BIT_STRING *signature;
+	int references;
+	} /* X509_CRL */;
+
+DECLARE_STACK_OF(X509_CRL)
+DECLARE_ASN1_SET_OF(X509_CRL)
+
+typedef struct private_key_st
+	{
+	int version;
+	/* The PKCS#8 data types */
+	X509_ALGOR *enc_algor;
+	ASN1_OCTET_STRING *enc_pkey;	/* encrypted pub key */
+
+	/* When decrypted, the following will not be NULL */
+	EVP_PKEY *dec_pkey;
+
+	/* used to encrypt and decrypt */
+	int key_length;
+	char *key_data;
+	int key_free;	/* true if we should auto free key_data */
+
+	/* expanded version of 'enc_algor' */
+	EVP_CIPHER_INFO cipher;
+
+	int references;
+	} X509_PKEY;
+
+#ifndef OPENSSL_NO_EVP
+typedef struct X509_info_st
+	{
+	X509 *x509;
+	X509_CRL *crl;
+	X509_PKEY *x_pkey;
+
+	EVP_CIPHER_INFO enc_cipher;
+	int enc_len;
+	char *enc_data;
+
+	int references;
+	} X509_INFO;
+
+DECLARE_STACK_OF(X509_INFO)
+#endif
+
+/* The next 2 structures and their 8 routines were sent to me by
+ * Pat Richard <patr@x509.com> and are used to manipulate
+ * Netscapes spki structures - useful if you are writing a CA web page
+ */
+typedef struct Netscape_spkac_st
+	{
+	X509_PUBKEY *pubkey;
+	ASN1_IA5STRING *challenge;	/* challenge sent in atlas >= PR2 */
+	} NETSCAPE_SPKAC;
+
+typedef struct Netscape_spki_st
+	{
+	NETSCAPE_SPKAC *spkac;	/* signed public key and challenge */
+	X509_ALGOR *sig_algor;
+	ASN1_BIT_STRING *signature;
+	} NETSCAPE_SPKI;
+
+/* Netscape certificate sequence structure */
+typedef struct Netscape_certificate_sequence
+	{
+	ASN1_OBJECT *type;
+	STACK_OF(X509) *certs;
+	} NETSCAPE_CERT_SEQUENCE;
+
+/* Unused (and iv length is wrong)
+typedef struct CBCParameter_st
+	{
+	unsigned char iv[8];
+	} CBC_PARAM;
+*/
+
+/* Password based encryption structure */
+
+typedef struct PBEPARAM_st {
+ASN1_OCTET_STRING *salt;
+ASN1_INTEGER *iter;
+} PBEPARAM;
+
+/* Password based encryption V2 structures */
+
+typedef struct PBE2PARAM_st {
+X509_ALGOR *keyfunc;
+X509_ALGOR *encryption;
+} PBE2PARAM;
+
+typedef struct PBKDF2PARAM_st {
+ASN1_TYPE *salt;	/* Usually OCTET STRING but could be anything */
+ASN1_INTEGER *iter;
+ASN1_INTEGER *keylength;
+X509_ALGOR *prf;
+} PBKDF2PARAM;
+
+
+/* PKCS#8 private key info structure */
+
+typedef struct pkcs8_priv_key_info_st
+        {
+        int broken;     /* Flag for various broken formats */
+#define PKCS8_OK		0
+#define PKCS8_NO_OCTET		1
+#define PKCS8_EMBEDDED_PARAM	2
+#define PKCS8_NS_DB		3
+        ASN1_INTEGER *version;
+        X509_ALGOR *pkeyalg;
+        ASN1_TYPE *pkey; /* Should be OCTET STRING but some are broken */
+        STACK_OF(X509_ATTRIBUTE) *attributes;
+        } PKCS8_PRIV_KEY_INFO;
+
+#ifdef  __cplusplus
+}
+#endif
+
+#include <openssl/x509_vfy.h>
+#include <openssl/pkcs7.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifdef SSLEAY_MACROS
+#define X509_verify(a,r) ASN1_verify((int (*)())i2d_X509_CINF,a->sig_alg,\
+	a->signature,(char *)a->cert_info,r)
+#define X509_REQ_verify(a,r) ASN1_verify((int (*)())i2d_X509_REQ_INFO, \
+	a->sig_alg,a->signature,(char *)a->req_info,r)
+#define X509_CRL_verify(a,r) ASN1_verify((int (*)())i2d_X509_CRL_INFO, \
+	a->sig_alg, a->signature,(char *)a->crl,r)
+
+#define X509_sign(x,pkey,md) \
+	ASN1_sign((int (*)())i2d_X509_CINF, x->cert_info->signature, \
+		x->sig_alg, x->signature, (char *)x->cert_info,pkey,md)
+#define X509_REQ_sign(x,pkey,md) \
+	ASN1_sign((int (*)())i2d_X509_REQ_INFO,x->sig_alg, NULL, \
+		x->signature, (char *)x->req_info,pkey,md)
+#define X509_CRL_sign(x,pkey,md) \
+	ASN1_sign((int (*)())i2d_X509_CRL_INFO,x->crl->sig_alg,x->sig_alg, \
+		x->signature, (char *)x->crl,pkey,md)
+#define NETSCAPE_SPKI_sign(x,pkey,md) \
+	ASN1_sign((int (*)())i2d_NETSCAPE_SPKAC, x->sig_algor,NULL, \
+		x->signature, (char *)x->spkac,pkey,md)
+
+#define X509_dup(x509) (X509 *)ASN1_dup((int (*)())i2d_X509, \
+		(char *(*)())d2i_X509,(char *)x509)
+#define X509_ATTRIBUTE_dup(xa) (X509_ATTRIBUTE *)ASN1_dup(\
+		(int (*)())i2d_X509_ATTRIBUTE, \
+		(char *(*)())d2i_X509_ATTRIBUTE,(char *)xa)
+#define X509_EXTENSION_dup(ex) (X509_EXTENSION *)ASN1_dup( \
+		(int (*)())i2d_X509_EXTENSION, \
+		(char *(*)())d2i_X509_EXTENSION,(char *)ex)
+#define d2i_X509_fp(fp,x509) (X509 *)ASN1_d2i_fp((char *(*)())X509_new, \
+		(char *(*)())d2i_X509, (fp),(unsigned char **)(x509))
+#define i2d_X509_fp(fp,x509) ASN1_i2d_fp(i2d_X509,fp,(unsigned char *)x509)
+#define d2i_X509_bio(bp,x509) (X509 *)ASN1_d2i_bio((char *(*)())X509_new, \
+		(char *(*)())d2i_X509, (bp),(unsigned char **)(x509))
+#define i2d_X509_bio(bp,x509) ASN1_i2d_bio(i2d_X509,bp,(unsigned char *)x509)
+
+#define X509_CRL_dup(crl) (X509_CRL *)ASN1_dup((int (*)())i2d_X509_CRL, \
+		(char *(*)())d2i_X509_CRL,(char *)crl)
+#define d2i_X509_CRL_fp(fp,crl) (X509_CRL *)ASN1_d2i_fp((char *(*)()) \
+		X509_CRL_new,(char *(*)())d2i_X509_CRL, (fp),\
+		(unsigned char **)(crl))
+#define i2d_X509_CRL_fp(fp,crl) ASN1_i2d_fp(i2d_X509_CRL,fp,\
+		(unsigned char *)crl)
+#define d2i_X509_CRL_bio(bp,crl) (X509_CRL *)ASN1_d2i_bio((char *(*)()) \
+		X509_CRL_new,(char *(*)())d2i_X509_CRL, (bp),\
+		(unsigned char **)(crl))
+#define i2d_X509_CRL_bio(bp,crl) ASN1_i2d_bio(i2d_X509_CRL,bp,\
+		(unsigned char *)crl)
+
+#define PKCS7_dup(p7) (PKCS7 *)ASN1_dup((int (*)())i2d_PKCS7, \
+		(char *(*)())d2i_PKCS7,(char *)p7)
+#define d2i_PKCS7_fp(fp,p7) (PKCS7 *)ASN1_d2i_fp((char *(*)()) \
+		PKCS7_new,(char *(*)())d2i_PKCS7, (fp),\
+		(unsigned char **)(p7))
+#define i2d_PKCS7_fp(fp,p7) ASN1_i2d_fp(i2d_PKCS7,fp,\
+		(unsigned char *)p7)
+#define d2i_PKCS7_bio(bp,p7) (PKCS7 *)ASN1_d2i_bio((char *(*)()) \
+		PKCS7_new,(char *(*)())d2i_PKCS7, (bp),\
+		(unsigned char **)(p7))
+#define i2d_PKCS7_bio(bp,p7) ASN1_i2d_bio(i2d_PKCS7,bp,\
+		(unsigned char *)p7)
+
+#define X509_REQ_dup(req) (X509_REQ *)ASN1_dup((int (*)())i2d_X509_REQ, \
+		(char *(*)())d2i_X509_REQ,(char *)req)
+#define d2i_X509_REQ_fp(fp,req) (X509_REQ *)ASN1_d2i_fp((char *(*)())\
+		X509_REQ_new, (char *(*)())d2i_X509_REQ, (fp),\
+		(unsigned char **)(req))
+#define i2d_X509_REQ_fp(fp,req) ASN1_i2d_fp(i2d_X509_REQ,fp,\
+		(unsigned char *)req)
+#define d2i_X509_REQ_bio(bp,req) (X509_REQ *)ASN1_d2i_bio((char *(*)())\
+		X509_REQ_new, (char *(*)())d2i_X509_REQ, (bp),\
+		(unsigned char **)(req))
+#define i2d_X509_REQ_bio(bp,req) ASN1_i2d_bio(i2d_X509_REQ,bp,\
+		(unsigned char *)req)
+
+#define RSAPublicKey_dup(rsa) (RSA *)ASN1_dup((int (*)())i2d_RSAPublicKey, \
+		(char *(*)())d2i_RSAPublicKey,(char *)rsa)
+#define RSAPrivateKey_dup(rsa) (RSA *)ASN1_dup((int (*)())i2d_RSAPrivateKey, \
+		(char *(*)())d2i_RSAPrivateKey,(char *)rsa)
+
+#define d2i_RSAPrivateKey_fp(fp,rsa) (RSA *)ASN1_d2i_fp((char *(*)())\
+		RSA_new,(char *(*)())d2i_RSAPrivateKey, (fp), \
+		(unsigned char **)(rsa))
+#define i2d_RSAPrivateKey_fp(fp,rsa) ASN1_i2d_fp(i2d_RSAPrivateKey,fp, \
+		(unsigned char *)rsa)
+#define d2i_RSAPrivateKey_bio(bp,rsa) (RSA *)ASN1_d2i_bio((char *(*)())\
+		RSA_new,(char *(*)())d2i_RSAPrivateKey, (bp), \
+		(unsigned char **)(rsa))
+#define i2d_RSAPrivateKey_bio(bp,rsa) ASN1_i2d_bio(i2d_RSAPrivateKey,bp, \
+		(unsigned char *)rsa)
+
+#define d2i_RSAPublicKey_fp(fp,rsa) (RSA *)ASN1_d2i_fp((char *(*)())\
+		RSA_new,(char *(*)())d2i_RSAPublicKey, (fp), \
+		(unsigned char **)(rsa))
+#define i2d_RSAPublicKey_fp(fp,rsa) ASN1_i2d_fp(i2d_RSAPublicKey,fp, \
+		(unsigned char *)rsa)
+#define d2i_RSAPublicKey_bio(bp,rsa) (RSA *)ASN1_d2i_bio((char *(*)())\
+		RSA_new,(char *(*)())d2i_RSAPublicKey, (bp), \
+		(unsigned char **)(rsa))
+#define i2d_RSAPublicKey_bio(bp,rsa) ASN1_i2d_bio(i2d_RSAPublicKey,bp, \
+		(unsigned char *)rsa)
+
+#define d2i_DSAPrivateKey_fp(fp,dsa) (DSA *)ASN1_d2i_fp((char *(*)())\
+		DSA_new,(char *(*)())d2i_DSAPrivateKey, (fp), \
+		(unsigned char **)(dsa))
+#define i2d_DSAPrivateKey_fp(fp,dsa) ASN1_i2d_fp(i2d_DSAPrivateKey,fp, \
+		(unsigned char *)dsa)
+#define d2i_DSAPrivateKey_bio(bp,dsa) (DSA *)ASN1_d2i_bio((char *(*)())\
+		DSA_new,(char *(*)())d2i_DSAPrivateKey, (bp), \
+		(unsigned char **)(dsa))
+#define i2d_DSAPrivateKey_bio(bp,dsa) ASN1_i2d_bio(i2d_DSAPrivateKey,bp, \
+		(unsigned char *)dsa)
+
+#define d2i_ECPrivateKey_fp(fp,ecdsa) (EC_KEY *)ASN1_d2i_fp((char *(*)())\
+		EC_KEY_new,(char *(*)())d2i_ECPrivateKey, (fp), \
+		(unsigned char **)(ecdsa))
+#define i2d_ECPrivateKey_fp(fp,ecdsa) ASN1_i2d_fp(i2d_ECPrivateKey,fp, \
+		(unsigned char *)ecdsa)
+#define d2i_ECPrivateKey_bio(bp,ecdsa) (EC_KEY *)ASN1_d2i_bio((char *(*)())\
+		EC_KEY_new,(char *(*)())d2i_ECPrivateKey, (bp), \
+		(unsigned char **)(ecdsa))
+#define i2d_ECPrivateKey_bio(bp,ecdsa) ASN1_i2d_bio(i2d_ECPrivateKey,bp, \
+		(unsigned char *)ecdsa)
+
+#define X509_ALGOR_dup(xn) (X509_ALGOR *)ASN1_dup((int (*)())i2d_X509_ALGOR,\
+		(char *(*)())d2i_X509_ALGOR,(char *)xn)
+
+#define X509_NAME_dup(xn) (X509_NAME *)ASN1_dup((int (*)())i2d_X509_NAME, \
+		(char *(*)())d2i_X509_NAME,(char *)xn)
+#define X509_NAME_ENTRY_dup(ne) (X509_NAME_ENTRY *)ASN1_dup( \
+		(int (*)())i2d_X509_NAME_ENTRY, \
+		(char *(*)())d2i_X509_NAME_ENTRY,\
+		(char *)ne)
+
+#define X509_digest(data,type,md,len) \
+	ASN1_digest((int (*)())i2d_X509,type,(char *)data,md,len)
+#define X509_NAME_digest(data,type,md,len) \
+	ASN1_digest((int (*)())i2d_X509_NAME,type,(char *)data,md,len)
+#ifndef PKCS7_ISSUER_AND_SERIAL_digest
+#define PKCS7_ISSUER_AND_SERIAL_digest(data,type,md,len) \
+	ASN1_digest((int (*)())i2d_PKCS7_ISSUER_AND_SERIAL,type,\
+		(char *)data,md,len)
+#endif
+#endif
+
+#define X509_EXT_PACK_UNKNOWN	1
+#define X509_EXT_PACK_STRING	2
+
+#define		X509_get_version(x) ASN1_INTEGER_get((x)->cert_info->version)
+/* #define	X509_get_serialNumber(x) ((x)->cert_info->serialNumber) */
+#define		X509_get_notBefore(x) ((x)->cert_info->validity->notBefore)
+#define		X509_get_notAfter(x) ((x)->cert_info->validity->notAfter)
+#define		X509_extract_key(x)	X509_get_pubkey(x) /*****/
+#define		X509_REQ_get_version(x) ASN1_INTEGER_get((x)->req_info->version)
+#define		X509_REQ_get_subject_name(x) ((x)->req_info->subject)
+#define		X509_REQ_extract_key(a)	X509_REQ_get_pubkey(a)
+#define		X509_name_cmp(a,b)	X509_NAME_cmp((a),(b))
+#define		X509_get_signature_type(x) EVP_PKEY_type(OBJ_obj2nid((x)->sig_alg->algorithm))
+
+#define		X509_CRL_get_version(x) ASN1_INTEGER_get((x)->crl->version)
+#define 	X509_CRL_get_lastUpdate(x) ((x)->crl->lastUpdate)
+#define 	X509_CRL_get_nextUpdate(x) ((x)->crl->nextUpdate)
+#define		X509_CRL_get_issuer(x) ((x)->crl->issuer)
+#define		X509_CRL_get_REVOKED(x) ((x)->crl->revoked)
+
+/* This one is only used so that a binary form can output, as in
+ * i2d_X509_NAME(X509_get_X509_PUBKEY(x),&buf) */
+#define 	X509_get_X509_PUBKEY(x) ((x)->cert_info->key)
+
+
+const char *X509_verify_cert_error_string(long n);
+
+#ifndef SSLEAY_MACROS
+#ifndef OPENSSL_NO_EVP
+int X509_verify(X509 *a, EVP_PKEY *r);
+
+int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r);
+int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r);
+int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r);
+
+NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len);
+char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *x);
+EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x);
+int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey);
+
+int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki);
+
+int X509_signature_print(BIO *bp,X509_ALGOR *alg, ASN1_STRING *sig);
+
+int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
+int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md);
+int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md);
+int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md);
+
+int X509_pubkey_digest(const X509 *data,const EVP_MD *type,
+		unsigned char *md, unsigned int *len);
+int X509_digest(const X509 *data,const EVP_MD *type,
+		unsigned char *md, unsigned int *len);
+int X509_CRL_digest(const X509_CRL *data,const EVP_MD *type,
+		unsigned char *md, unsigned int *len);
+int X509_REQ_digest(const X509_REQ *data,const EVP_MD *type,
+		unsigned char *md, unsigned int *len);
+int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type,
+		unsigned char *md, unsigned int *len);
+#endif
+
+#ifndef OPENSSL_NO_FP_API
+X509 *d2i_X509_fp(FILE *fp, X509 **x509);
+int i2d_X509_fp(FILE *fp,X509 *x509);
+X509_CRL *d2i_X509_CRL_fp(FILE *fp,X509_CRL **crl);
+int i2d_X509_CRL_fp(FILE *fp,X509_CRL *crl);
+X509_REQ *d2i_X509_REQ_fp(FILE *fp,X509_REQ **req);
+int i2d_X509_REQ_fp(FILE *fp,X509_REQ *req);
+#ifndef OPENSSL_NO_RSA
+RSA *d2i_RSAPrivateKey_fp(FILE *fp,RSA **rsa);
+int i2d_RSAPrivateKey_fp(FILE *fp,RSA *rsa);
+RSA *d2i_RSAPublicKey_fp(FILE *fp,RSA **rsa);
+int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa);
+RSA *d2i_RSA_PUBKEY_fp(FILE *fp,RSA **rsa);
+int i2d_RSA_PUBKEY_fp(FILE *fp,RSA *rsa);
+#endif
+#ifndef OPENSSL_NO_DSA
+DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa);
+int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa);
+DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa);
+int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa);
+#endif
+#ifndef OPENSSL_NO_EC
+EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey);
+int   i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey);
+EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey);
+int   i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey);
+#endif
+X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8);
+int i2d_PKCS8_fp(FILE *fp,X509_SIG *p8);
+PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,
+						PKCS8_PRIV_KEY_INFO **p8inf);
+int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf);
+int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key);
+int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey);
+EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a);
+int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey);
+EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a);
+#endif
+
+#ifndef OPENSSL_NO_BIO
+X509 *d2i_X509_bio(BIO *bp,X509 **x509);
+int i2d_X509_bio(BIO *bp,X509 *x509);
+X509_CRL *d2i_X509_CRL_bio(BIO *bp,X509_CRL **crl);
+int i2d_X509_CRL_bio(BIO *bp,X509_CRL *crl);
+X509_REQ *d2i_X509_REQ_bio(BIO *bp,X509_REQ **req);
+int i2d_X509_REQ_bio(BIO *bp,X509_REQ *req);
+#ifndef OPENSSL_NO_RSA
+RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **rsa);
+int i2d_RSAPrivateKey_bio(BIO *bp,RSA *rsa);
+RSA *d2i_RSAPublicKey_bio(BIO *bp,RSA **rsa);
+int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa);
+RSA *d2i_RSA_PUBKEY_bio(BIO *bp,RSA **rsa);
+int i2d_RSA_PUBKEY_bio(BIO *bp,RSA *rsa);
+#endif
+#ifndef OPENSSL_NO_DSA
+DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa);
+int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa);
+DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa);
+int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa);
+#endif
+#ifndef OPENSSL_NO_EC
+EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey);
+int   i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey);
+EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey);
+int   i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey);
+#endif
+X509_SIG *d2i_PKCS8_bio(BIO *bp,X509_SIG **p8);
+int i2d_PKCS8_bio(BIO *bp,X509_SIG *p8);
+PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,
+						PKCS8_PRIV_KEY_INFO **p8inf);
+int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf);
+int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key);
+int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey);
+EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a);
+int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey);
+EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a);
+#endif
+
+X509 *X509_dup(X509 *x509);
+X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa);
+X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex);
+X509_CRL *X509_CRL_dup(X509_CRL *crl);
+X509_REQ *X509_REQ_dup(X509_REQ *req);
+X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn);
+X509_NAME *X509_NAME_dup(X509_NAME *xn);
+X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne);
+
+#endif /* !SSLEAY_MACROS */
+
+int		X509_cmp_time(ASN1_TIME *s, time_t *t);
+int		X509_cmp_current_time(ASN1_TIME *s);
+ASN1_TIME *	X509_time_adj(ASN1_TIME *s, long adj, time_t *t);
+ASN1_TIME *	X509_gmtime_adj(ASN1_TIME *s, long adj);
+
+const char *	X509_get_default_cert_area(void );
+const char *	X509_get_default_cert_dir(void );
+const char *	X509_get_default_cert_file(void );
+const char *	X509_get_default_cert_dir_env(void );
+const char *	X509_get_default_cert_file_env(void );
+const char *	X509_get_default_private_dir(void );
+
+X509_REQ *	X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
+X509 *		X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY *pkey);
+
+DECLARE_ASN1_FUNCTIONS(X509_ALGOR)
+DECLARE_ASN1_FUNCTIONS(X509_VAL)
+
+DECLARE_ASN1_FUNCTIONS(X509_PUBKEY)
+
+int		X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey);
+EVP_PKEY *	X509_PUBKEY_get(X509_PUBKEY *key);
+int		X509_get_pubkey_parameters(EVP_PKEY *pkey,
+					   STACK_OF(X509) *chain);
+int		i2d_PUBKEY(EVP_PKEY *a,unsigned char **pp);
+EVP_PKEY *	d2i_PUBKEY(EVP_PKEY **a,const unsigned char **pp,
+			long length);
+#ifndef OPENSSL_NO_RSA
+int		i2d_RSA_PUBKEY(RSA *a,unsigned char **pp);
+RSA *		d2i_RSA_PUBKEY(RSA **a,const unsigned char **pp,
+			long length);
+#endif
+#ifndef OPENSSL_NO_DSA
+int		i2d_DSA_PUBKEY(DSA *a,unsigned char **pp);
+DSA *		d2i_DSA_PUBKEY(DSA **a,const unsigned char **pp,
+			long length);
+#endif
+#ifndef OPENSSL_NO_EC
+int		i2d_EC_PUBKEY(EC_KEY *a, unsigned char **pp);
+EC_KEY 		*d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp,
+			long length);
+#endif
+
+DECLARE_ASN1_FUNCTIONS(X509_SIG)
+DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO)
+DECLARE_ASN1_FUNCTIONS(X509_REQ)
+
+DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE)
+X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value);
+
+DECLARE_ASN1_FUNCTIONS(X509_EXTENSION)
+
+DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY)
+
+DECLARE_ASN1_FUNCTIONS(X509_NAME)
+
+int		X509_NAME_set(X509_NAME **xn, X509_NAME *name);
+
+DECLARE_ASN1_FUNCTIONS(X509_CINF)
+
+DECLARE_ASN1_FUNCTIONS(X509)
+DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX)
+
+DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR)
+
+int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int X509_set_ex_data(X509 *r, int idx, void *arg);
+void *X509_get_ex_data(X509 *r, int idx);
+int		i2d_X509_AUX(X509 *a,unsigned char **pp);
+X509 *		d2i_X509_AUX(X509 **a,const unsigned char **pp,long length);
+
+int X509_alias_set1(X509 *x, unsigned char *name, int len);
+int X509_keyid_set1(X509 *x, unsigned char *id, int len);
+unsigned char * X509_alias_get0(X509 *x, int *len);
+unsigned char * X509_keyid_get0(X509 *x, int *len);
+int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int);
+int X509_TRUST_set(int *t, int trust);
+int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj);
+int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj);
+void X509_trust_clear(X509 *x);
+void X509_reject_clear(X509 *x);
+
+DECLARE_ASN1_FUNCTIONS(X509_REVOKED)
+DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO)
+DECLARE_ASN1_FUNCTIONS(X509_CRL)
+
+int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev);
+
+X509_PKEY *	X509_PKEY_new(void );
+void		X509_PKEY_free(X509_PKEY *a);
+int		i2d_X509_PKEY(X509_PKEY *a,unsigned char **pp);
+X509_PKEY *	d2i_X509_PKEY(X509_PKEY **a,const unsigned char **pp,long length);
+
+DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI)
+DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC)
+DECLARE_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE)
+
+#ifndef OPENSSL_NO_EVP
+X509_INFO *	X509_INFO_new(void);
+void		X509_INFO_free(X509_INFO *a);
+char *		X509_NAME_oneline(X509_NAME *a,char *buf,int size);
+
+int ASN1_verify(i2d_of_void *i2d, X509_ALGOR *algor1,
+		ASN1_BIT_STRING *signature,char *data,EVP_PKEY *pkey);
+
+int ASN1_digest(i2d_of_void *i2d,const EVP_MD *type,char *data,
+		unsigned char *md,unsigned int *len);
+
+int ASN1_sign(i2d_of_void *i2d, X509_ALGOR *algor1,
+	      X509_ALGOR *algor2, ASN1_BIT_STRING *signature,
+	      char *data,EVP_PKEY *pkey, const EVP_MD *type);
+
+int ASN1_item_digest(const ASN1_ITEM *it,const EVP_MD *type,void *data,
+	unsigned char *md,unsigned int *len);
+
+int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1,
+	ASN1_BIT_STRING *signature,void *data,EVP_PKEY *pkey);
+
+int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2,
+	ASN1_BIT_STRING *signature,
+	void *data, EVP_PKEY *pkey, const EVP_MD *type);
+#endif
+
+int 		X509_set_version(X509 *x,long version);
+int 		X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial);
+ASN1_INTEGER *	X509_get_serialNumber(X509 *x);
+int 		X509_set_issuer_name(X509 *x, X509_NAME *name);
+X509_NAME *	X509_get_issuer_name(X509 *a);
+int 		X509_set_subject_name(X509 *x, X509_NAME *name);
+X509_NAME *	X509_get_subject_name(X509 *a);
+int 		X509_set_notBefore(X509 *x, ASN1_TIME *tm);
+int 		X509_set_notAfter(X509 *x, ASN1_TIME *tm);
+int 		X509_set_pubkey(X509 *x, EVP_PKEY *pkey);
+EVP_PKEY *	X509_get_pubkey(X509 *x);
+ASN1_BIT_STRING * X509_get0_pubkey_bitstr(const X509 *x);
+int		X509_certificate_type(X509 *x,EVP_PKEY *pubkey /* optional */);
+
+int		X509_REQ_set_version(X509_REQ *x,long version);
+int		X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name);
+int		X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
+EVP_PKEY *	X509_REQ_get_pubkey(X509_REQ *req);
+int		X509_REQ_extension_nid(int nid);
+int *		X509_REQ_get_extension_nids(void);
+void		X509_REQ_set_extension_nids(int *nids);
+STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req);
+int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts,
+				int nid);
+int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts);
+int X509_REQ_get_attr_count(const X509_REQ *req);
+int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid,
+			  int lastpos);
+int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj,
+			  int lastpos);
+X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc);
+X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc);
+int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr);
+int X509_REQ_add1_attr_by_OBJ(X509_REQ *req,
+			const ASN1_OBJECT *obj, int type,
+			const unsigned char *bytes, int len);
+int X509_REQ_add1_attr_by_NID(X509_REQ *req,
+			int nid, int type,
+			const unsigned char *bytes, int len);
+int X509_REQ_add1_attr_by_txt(X509_REQ *req,
+			const char *attrname, int type,
+			const unsigned char *bytes, int len);
+
+int X509_CRL_set_version(X509_CRL *x, long version);
+int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name);
+int X509_CRL_set_lastUpdate(X509_CRL *x, ASN1_TIME *tm);
+int X509_CRL_set_nextUpdate(X509_CRL *x, ASN1_TIME *tm);
+int X509_CRL_sort(X509_CRL *crl);
+
+int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial);
+int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm);
+
+int		X509_REQ_check_private_key(X509_REQ *x509,EVP_PKEY *pkey);
+
+int		X509_check_private_key(X509 *x509,EVP_PKEY *pkey);
+
+int		X509_issuer_and_serial_cmp(const X509 *a, const X509 *b);
+unsigned long	X509_issuer_and_serial_hash(X509 *a);
+
+int		X509_issuer_name_cmp(const X509 *a, const X509 *b);
+unsigned long	X509_issuer_name_hash(X509 *a);
+
+int		X509_subject_name_cmp(const X509 *a, const X509 *b);
+unsigned long	X509_subject_name_hash(X509 *x);
+
+int		X509_cmp(const X509 *a, const X509 *b);
+int		X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b);
+unsigned long	X509_NAME_hash(X509_NAME *x);
+
+int		X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b);
+#ifndef OPENSSL_NO_FP_API
+int		X509_print_ex_fp(FILE *bp,X509 *x, unsigned long nmflag, unsigned long cflag);
+int		X509_print_fp(FILE *bp,X509 *x);
+int		X509_CRL_print_fp(FILE *bp,X509_CRL *x);
+int		X509_REQ_print_fp(FILE *bp,X509_REQ *req);
+int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags);
+#endif
+
+#ifndef OPENSSL_NO_BIO
+int		X509_NAME_print(BIO *bp, X509_NAME *name, int obase);
+int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags);
+int		X509_print_ex(BIO *bp,X509 *x, unsigned long nmflag, unsigned long cflag);
+int		X509_print(BIO *bp,X509 *x);
+int		X509_ocspid_print(BIO *bp,X509 *x);
+int		X509_CERT_AUX_print(BIO *bp,X509_CERT_AUX *x, int indent);
+int		X509_CRL_print(BIO *bp,X509_CRL *x);
+int		X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag);
+int		X509_REQ_print(BIO *bp,X509_REQ *req);
+#endif
+
+int 		X509_NAME_entry_count(X509_NAME *name);
+int 		X509_NAME_get_text_by_NID(X509_NAME *name, int nid,
+			char *buf,int len);
+int		X509_NAME_get_text_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj,
+			char *buf,int len);
+
+/* NOTE: you should be passsing -1, not 0 as lastpos.  The functions that use
+ * lastpos, search after that position on. */
+int 		X509_NAME_get_index_by_NID(X509_NAME *name,int nid,int lastpos);
+int 		X509_NAME_get_index_by_OBJ(X509_NAME *name,ASN1_OBJECT *obj,
+			int lastpos);
+X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc);
+X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc);
+int 		X509_NAME_add_entry(X509_NAME *name,X509_NAME_ENTRY *ne,
+			int loc, int set);
+int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type,
+			unsigned char *bytes, int len, int loc, int set);
+int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type,
+			unsigned char *bytes, int len, int loc, int set);
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne,
+		const char *field, int type, const unsigned char *bytes, int len);
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid,
+			int type,unsigned char *bytes, int len);
+int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type,
+			const unsigned char *bytes, int len, int loc, int set);
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne,
+			ASN1_OBJECT *obj, int type,const unsigned char *bytes,
+			int len);
+int 		X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne,
+			ASN1_OBJECT *obj);
+int 		X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type,
+			const unsigned char *bytes, int len);
+ASN1_OBJECT *	X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne);
+ASN1_STRING *	X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne);
+
+int		X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x);
+int		X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x,
+				      int nid, int lastpos);
+int		X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x,
+				      ASN1_OBJECT *obj,int lastpos);
+int		X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x,
+					   int crit, int lastpos);
+X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc);
+X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc);
+STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x,
+					 X509_EXTENSION *ex, int loc);
+
+int		X509_get_ext_count(X509 *x);
+int		X509_get_ext_by_NID(X509 *x, int nid, int lastpos);
+int		X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos);
+int		X509_get_ext_by_critical(X509 *x, int crit, int lastpos);
+X509_EXTENSION *X509_get_ext(X509 *x, int loc);
+X509_EXTENSION *X509_delete_ext(X509 *x, int loc);
+int		X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc);
+void	*	X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx);
+int		X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit,
+							unsigned long flags);
+
+int		X509_CRL_get_ext_count(X509_CRL *x);
+int		X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos);
+int		X509_CRL_get_ext_by_OBJ(X509_CRL *x,ASN1_OBJECT *obj,int lastpos);
+int		X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos);
+X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc);
+X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc);
+int		X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc);
+void	*	X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx);
+int		X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit,
+							unsigned long flags);
+
+int		X509_REVOKED_get_ext_count(X509_REVOKED *x);
+int		X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos);
+int		X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x,ASN1_OBJECT *obj,int lastpos);
+int		X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos);
+X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc);
+X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc);
+int		X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc);
+void	*	X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx);
+int		X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit,
+							unsigned long flags);
+
+X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex,
+			int nid, int crit, ASN1_OCTET_STRING *data);
+X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex,
+			ASN1_OBJECT *obj,int crit,ASN1_OCTET_STRING *data);
+int		X509_EXTENSION_set_object(X509_EXTENSION *ex,ASN1_OBJECT *obj);
+int		X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit);
+int		X509_EXTENSION_set_data(X509_EXTENSION *ex,
+			ASN1_OCTET_STRING *data);
+ASN1_OBJECT *	X509_EXTENSION_get_object(X509_EXTENSION *ex);
+ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne);
+int		X509_EXTENSION_get_critical(X509_EXTENSION *ex);
+
+int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x);
+int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid,
+			  int lastpos);
+int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, ASN1_OBJECT *obj,
+			  int lastpos);
+X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc);
+X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc);
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x,
+					 X509_ATTRIBUTE *attr);
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x,
+			const ASN1_OBJECT *obj, int type,
+			const unsigned char *bytes, int len);
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x,
+			int nid, int type,
+			const unsigned char *bytes, int len);
+STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x,
+			const char *attrname, int type,
+			const unsigned char *bytes, int len);
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid,
+	     int atrtype, const void *data, int len);
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr,
+	     const ASN1_OBJECT *obj, int atrtype, const void *data, int len);
+X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr,
+		const char *atrname, int type, const unsigned char *bytes, int len);
+int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj);
+int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len);
+void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx,
+					int atrtype, void *data);
+int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr);
+ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr);
+ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx);
+
+int EVP_PKEY_get_attr_count(const EVP_PKEY *key);
+int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid,
+			  int lastpos);
+int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj,
+			  int lastpos);
+X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc);
+X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc);
+int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr);
+int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key,
+			const ASN1_OBJECT *obj, int type,
+			const unsigned char *bytes, int len);
+int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key,
+			int nid, int type,
+			const unsigned char *bytes, int len);
+int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key,
+			const char *attrname, int type,
+			const unsigned char *bytes, int len);
+
+int		X509_verify_cert(X509_STORE_CTX *ctx);
+
+/* lookup a cert from a X509 STACK */
+X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk,X509_NAME *name,
+				     ASN1_INTEGER *serial);
+X509 *X509_find_by_subject(STACK_OF(X509) *sk,X509_NAME *name);
+
+DECLARE_ASN1_FUNCTIONS(PBEPARAM)
+DECLARE_ASN1_FUNCTIONS(PBE2PARAM)
+DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM)
+
+X509_ALGOR *PKCS5_pbe_set(int alg, int iter, unsigned char *salt, int saltlen);
+X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
+					 unsigned char *salt, int saltlen);
+
+/* PKCS#8 utilities */
+
+DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO)
+
+EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8);
+PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey);
+PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken);
+PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken);
+
+int X509_check_trust(X509 *x, int id, int flags);
+int X509_TRUST_get_count(void);
+X509_TRUST * X509_TRUST_get0(int idx);
+int X509_TRUST_get_by_id(int id);
+int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int),
+					char *name, int arg1, void *arg2);
+void X509_TRUST_cleanup(void);
+int X509_TRUST_get_flags(X509_TRUST *xp);
+char *X509_TRUST_get0_name(X509_TRUST *xp);
+int X509_TRUST_get_trust(X509_TRUST *xp);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_X509_strings(void);
+
+/* Error codes for the X509 functions. */
+
+/* Function codes. */
+#define X509_F_ADD_CERT_DIR				 100
+#define X509_F_BY_FILE_CTRL				 101
+#define X509_F_CHECK_POLICY				 145
+#define X509_F_DIR_CTRL					 102
+#define X509_F_GET_CERT_BY_SUBJECT			 103
+#define X509_F_NETSCAPE_SPKI_B64_DECODE			 129
+#define X509_F_NETSCAPE_SPKI_B64_ENCODE			 130
+#define X509_F_X509AT_ADD1_ATTR				 135
+#define X509_F_X509V3_ADD_EXT				 104
+#define X509_F_X509_ATTRIBUTE_CREATE_BY_NID		 136
+#define X509_F_X509_ATTRIBUTE_CREATE_BY_OBJ		 137
+#define X509_F_X509_ATTRIBUTE_CREATE_BY_TXT		 140
+#define X509_F_X509_ATTRIBUTE_GET0_DATA			 139
+#define X509_F_X509_ATTRIBUTE_SET1_DATA			 138
+#define X509_F_X509_CHECK_PRIVATE_KEY			 128
+#define X509_F_X509_CRL_PRINT_FP			 147
+#define X509_F_X509_EXTENSION_CREATE_BY_NID		 108
+#define X509_F_X509_EXTENSION_CREATE_BY_OBJ		 109
+#define X509_F_X509_GET_PUBKEY_PARAMETERS		 110
+#define X509_F_X509_LOAD_CERT_CRL_FILE			 132
+#define X509_F_X509_LOAD_CERT_FILE			 111
+#define X509_F_X509_LOAD_CRL_FILE			 112
+#define X509_F_X509_NAME_ADD_ENTRY			 113
+#define X509_F_X509_NAME_ENTRY_CREATE_BY_NID		 114
+#define X509_F_X509_NAME_ENTRY_CREATE_BY_TXT		 131
+#define X509_F_X509_NAME_ENTRY_SET_OBJECT		 115
+#define X509_F_X509_NAME_ONELINE			 116
+#define X509_F_X509_NAME_PRINT				 117
+#define X509_F_X509_PRINT_EX_FP				 118
+#define X509_F_X509_PUBKEY_GET				 119
+#define X509_F_X509_PUBKEY_SET				 120
+#define X509_F_X509_REQ_CHECK_PRIVATE_KEY		 144
+#define X509_F_X509_REQ_PRINT_EX			 121
+#define X509_F_X509_REQ_PRINT_FP			 122
+#define X509_F_X509_REQ_TO_X509				 123
+#define X509_F_X509_STORE_ADD_CERT			 124
+#define X509_F_X509_STORE_ADD_CRL			 125
+#define X509_F_X509_STORE_CTX_GET1_ISSUER		 146
+#define X509_F_X509_STORE_CTX_INIT			 143
+#define X509_F_X509_STORE_CTX_NEW			 142
+#define X509_F_X509_STORE_CTX_PURPOSE_INHERIT		 134
+#define X509_F_X509_TO_X509_REQ				 126
+#define X509_F_X509_TRUST_ADD				 133
+#define X509_F_X509_TRUST_SET				 141
+#define X509_F_X509_VERIFY_CERT				 127
+
+/* Reason codes. */
+#define X509_R_BAD_X509_FILETYPE			 100
+#define X509_R_BASE64_DECODE_ERROR			 118
+#define X509_R_CANT_CHECK_DH_KEY			 114
+#define X509_R_CERT_ALREADY_IN_HASH_TABLE		 101
+#define X509_R_ERR_ASN1_LIB				 102
+#define X509_R_INVALID_DIRECTORY			 113
+#define X509_R_INVALID_FIELD_NAME			 119
+#define X509_R_INVALID_TRUST				 123
+#define X509_R_KEY_TYPE_MISMATCH			 115
+#define X509_R_KEY_VALUES_MISMATCH			 116
+#define X509_R_LOADING_CERT_DIR				 103
+#define X509_R_LOADING_DEFAULTS				 104
+#define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY		 105
+#define X509_R_SHOULD_RETRY				 106
+#define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN	 107
+#define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY		 108
+#define X509_R_UNKNOWN_KEY_TYPE				 117
+#define X509_R_UNKNOWN_NID				 109
+#define X509_R_UNKNOWN_PURPOSE_ID			 121
+#define X509_R_UNKNOWN_TRUST_ID				 120
+#define X509_R_UNSUPPORTED_ALGORITHM			 111
+#define X509_R_WRONG_LOOKUP_TYPE			 112
+#define X509_R_WRONG_TYPE				 122
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509_vfy.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509_vfy.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509_vfy.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,527 @@
+/* crypto/x509/x509_vfy.h */
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ * 
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to.  The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ * 
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *    "This product includes cryptographic software written by
+ *     Eric Young (eay@cryptsoft.com)"
+ *    The word 'cryptographic' can be left out if the rouines from the library
+ *    being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from 
+ *    the apps directory (application code) you must include an acknowledgement:
+ *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ * 
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * 
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed.  i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_X509_H
+#include <openssl/x509.h>
+/* openssl/x509.h ends up #include-ing this file at about the only
+ * appropriate moment. */
+#endif
+
+#ifndef HEADER_X509_VFY_H
+#define HEADER_X509_VFY_H
+
+#include <openssl/opensslconf.h>
+#ifndef OPENSSL_NO_LHASH
+#include <openssl/lhash.h>
+#endif
+#include <openssl/bio.h>
+#include <openssl/crypto.h>
+#include <openssl/symhacks.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* Outer object */
+typedef struct x509_hash_dir_st
+	{
+	int num_dirs;
+	char **dirs;
+	int *dirs_type;
+	int num_dirs_alloced;
+	} X509_HASH_DIR_CTX;
+
+typedef struct x509_file_st
+	{
+	int num_paths;	/* number of paths to files or directories */
+	int num_alloced;
+	char **paths;	/* the list of paths or directories */
+	int *path_type;
+	} X509_CERT_FILE_CTX;
+
+/*******************************/
+/*
+SSL_CTX -> X509_STORE    
+		-> X509_LOOKUP
+			->X509_LOOKUP_METHOD
+		-> X509_LOOKUP
+			->X509_LOOKUP_METHOD
+ 
+SSL	-> X509_STORE_CTX
+		->X509_STORE    
+
+The X509_STORE holds the tables etc for verification stuff.
+A X509_STORE_CTX is used while validating a single certificate.
+The X509_STORE has X509_LOOKUPs for looking up certs.
+The X509_STORE then calls a function to actually verify the
+certificate chain.
+*/
+
+#define X509_LU_RETRY		-1
+#define X509_LU_FAIL		0
+#define X509_LU_X509		1
+#define X509_LU_CRL		2
+#define X509_LU_PKEY		3
+
+typedef struct x509_object_st
+	{
+	/* one of the above types */
+	int type;
+	union	{
+		char *ptr;
+		X509 *x509;
+		X509_CRL *crl;
+		EVP_PKEY *pkey;
+		} data;
+	} X509_OBJECT;
+
+typedef struct x509_lookup_st X509_LOOKUP;
+
+DECLARE_STACK_OF(X509_LOOKUP)
+DECLARE_STACK_OF(X509_OBJECT)
+
+/* This is a static that defines the function interface */
+typedef struct x509_lookup_method_st
+	{
+	const char *name;
+	int (*new_item)(X509_LOOKUP *ctx);
+	void (*free)(X509_LOOKUP *ctx);
+	int (*init)(X509_LOOKUP *ctx);
+	int (*shutdown)(X509_LOOKUP *ctx);
+	int (*ctrl)(X509_LOOKUP *ctx,int cmd,const char *argc,long argl,
+			char **ret);
+	int (*get_by_subject)(X509_LOOKUP *ctx,int type,X509_NAME *name,
+			      X509_OBJECT *ret);
+	int (*get_by_issuer_serial)(X509_LOOKUP *ctx,int type,X509_NAME *name,
+				    ASN1_INTEGER *serial,X509_OBJECT *ret);
+	int (*get_by_fingerprint)(X509_LOOKUP *ctx,int type,
+				  unsigned char *bytes,int len,
+				  X509_OBJECT *ret);
+	int (*get_by_alias)(X509_LOOKUP *ctx,int type,char *str,int len,
+			    X509_OBJECT *ret);
+	} X509_LOOKUP_METHOD;
+
+/* This structure hold all parameters associated with a verify operation
+ * by including an X509_VERIFY_PARAM structure in related structures the
+ * parameters used can be customized
+ */
+
+typedef struct X509_VERIFY_PARAM_st
+	{
+	char *name;
+	time_t check_time;	/* Time to use */
+	unsigned long inh_flags; /* Inheritance flags */
+	unsigned long flags;	/* Various verify flags */
+	int purpose;		/* purpose to check untrusted certificates */
+	int trust;		/* trust setting to check */
+	int depth;		/* Verify depth */
+	STACK_OF(ASN1_OBJECT) *policies;	/* Permissible policies */
+	} X509_VERIFY_PARAM;
+
+DECLARE_STACK_OF(X509_VERIFY_PARAM)
+
+/* This is used to hold everything.  It is used for all certificate
+ * validation.  Once we have a certificate chain, the 'verify'
+ * function is then called to actually check the cert chain. */
+struct x509_store_st
+	{
+	/* The following is a cache of trusted certs */
+	int cache; 	/* if true, stash any hits */
+	STACK_OF(X509_OBJECT) *objs;	/* Cache of all objects */
+
+	/* These are external lookup methods */
+	STACK_OF(X509_LOOKUP) *get_cert_methods;
+
+	X509_VERIFY_PARAM *param;
+
+	/* Callbacks for various operations */
+	int (*verify)(X509_STORE_CTX *ctx);	/* called to verify a certificate */
+	int (*verify_cb)(int ok,X509_STORE_CTX *ctx);	/* error callback */
+	int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);	/* get issuers cert from ctx */
+	int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */
+	int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */
+	int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */
+	int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
+	int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
+	int (*cleanup)(X509_STORE_CTX *ctx);
+
+	CRYPTO_EX_DATA ex_data;
+	int references;
+	} /* X509_STORE */;
+
+int X509_STORE_set_depth(X509_STORE *store, int depth);
+
+#define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func))
+#define X509_STORE_set_verify_func(ctx,func)	((ctx)->verify=(func))
+
+/* This is the functions plus an instance of the local variables. */
+struct x509_lookup_st
+	{
+	int init;			/* have we been started */
+	int skip;			/* don't use us. */
+	X509_LOOKUP_METHOD *method;	/* the functions */
+	char *method_data;		/* method data */
+
+	X509_STORE *store_ctx;	/* who owns us */
+	} /* X509_LOOKUP */;
+
+/* This is a used when verifying cert chains.  Since the
+ * gathering of the cert chain can take some time (and have to be
+ * 'retried', this needs to be kept and passed around. */
+struct x509_store_ctx_st      /* X509_STORE_CTX */
+	{
+	X509_STORE *ctx;
+	int current_method;	/* used when looking up certs */
+
+	/* The following are set by the caller */
+	X509 *cert;		/* The cert to check */
+	STACK_OF(X509) *untrusted;	/* chain of X509s - untrusted - passed in */
+	STACK_OF(X509_CRL) *crls;	/* set of CRLs passed in */
+
+	X509_VERIFY_PARAM *param;
+	void *other_ctx;	/* Other info for use with get_issuer() */
+
+	/* Callbacks for various operations */
+	int (*verify)(X509_STORE_CTX *ctx);	/* called to verify a certificate */
+	int (*verify_cb)(int ok,X509_STORE_CTX *ctx);		/* error callback */
+	int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);	/* get issuers cert from ctx */
+	int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */
+	int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */
+	int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */
+	int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
+	int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
+	int (*check_policy)(X509_STORE_CTX *ctx);
+	int (*cleanup)(X509_STORE_CTX *ctx);
+
+	/* The following is built up */
+	int valid;		/* if 0, rebuild chain */
+	int last_untrusted;	/* index of last untrusted cert */
+	STACK_OF(X509) *chain; 		/* chain of X509s - built up and trusted */
+	X509_POLICY_TREE *tree;	/* Valid policy tree */
+
+	int explicit_policy;	/* Require explicit policy value */
+
+	/* When something goes wrong, this is why */
+	int error_depth;
+	int error;
+	X509 *current_cert;
+	X509 *current_issuer;	/* cert currently being tested as valid issuer */
+	X509_CRL *current_crl;	/* current CRL */
+
+	CRYPTO_EX_DATA ex_data;
+	} /* X509_STORE_CTX */;
+
+void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
+
+#define X509_STORE_CTX_set_app_data(ctx,data) \
+	X509_STORE_CTX_set_ex_data(ctx,0,data)
+#define X509_STORE_CTX_get_app_data(ctx) \
+	X509_STORE_CTX_get_ex_data(ctx,0)
+
+#define X509_L_FILE_LOAD	1
+#define X509_L_ADD_DIR		2
+
+#define X509_LOOKUP_load_file(x,name,type) \
+		X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL)
+
+#define X509_LOOKUP_add_dir(x,name,type) \
+		X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL)
+
+#define		X509_V_OK					0
+/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */
+
+#define		X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT		2
+#define		X509_V_ERR_UNABLE_TO_GET_CRL			3
+#define		X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE	4
+#define		X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE	5
+#define		X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY	6
+#define		X509_V_ERR_CERT_SIGNATURE_FAILURE		7
+#define		X509_V_ERR_CRL_SIGNATURE_FAILURE		8
+#define		X509_V_ERR_CERT_NOT_YET_VALID			9
+#define		X509_V_ERR_CERT_HAS_EXPIRED			10
+#define		X509_V_ERR_CRL_NOT_YET_VALID			11
+#define		X509_V_ERR_CRL_HAS_EXPIRED			12
+#define		X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD	13
+#define		X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD	14
+#define		X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD	15
+#define		X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD	16
+#define		X509_V_ERR_OUT_OF_MEM				17
+#define		X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT		18
+#define		X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN		19
+#define		X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY	20
+#define		X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE	21
+#define		X509_V_ERR_CERT_CHAIN_TOO_LONG			22
+#define		X509_V_ERR_CERT_REVOKED				23
+#define		X509_V_ERR_INVALID_CA				24
+#define		X509_V_ERR_PATH_LENGTH_EXCEEDED			25
+#define		X509_V_ERR_INVALID_PURPOSE			26
+#define		X509_V_ERR_CERT_UNTRUSTED			27
+#define		X509_V_ERR_CERT_REJECTED			28
+/* These are 'informational' when looking for issuer cert */
+#define		X509_V_ERR_SUBJECT_ISSUER_MISMATCH		29
+#define		X509_V_ERR_AKID_SKID_MISMATCH			30
+#define		X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH		31
+#define		X509_V_ERR_KEYUSAGE_NO_CERTSIGN			32
+
+#define		X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER		33
+#define		X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION		34
+#define		X509_V_ERR_KEYUSAGE_NO_CRL_SIGN			35
+#define		X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION	36
+#define		X509_V_ERR_INVALID_NON_CA			37
+#define		X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED		38
+#define		X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE	39
+#define		X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED	40
+
+#define		X509_V_ERR_INVALID_EXTENSION			41
+#define		X509_V_ERR_INVALID_POLICY_EXTENSION		42
+#define		X509_V_ERR_NO_EXPLICIT_POLICY			43
+
+
+/* The application is not happy */
+#define		X509_V_ERR_APPLICATION_VERIFICATION		50
+
+/* Certificate verify flags */
+
+/* Send issuer+subject checks to verify_cb */
+#define	X509_V_FLAG_CB_ISSUER_CHECK		0x1
+/* Use check time instead of current time */
+#define	X509_V_FLAG_USE_CHECK_TIME		0x2
+/* Lookup CRLs */
+#define	X509_V_FLAG_CRL_CHECK			0x4
+/* Lookup CRLs for whole chain */
+#define	X509_V_FLAG_CRL_CHECK_ALL		0x8
+/* Ignore unhandled critical extensions */
+#define	X509_V_FLAG_IGNORE_CRITICAL		0x10
+/* Disable workarounds for broken certificates */
+#define	X509_V_FLAG_X509_STRICT			0x20
+/* Enable proxy certificate validation */
+#define	X509_V_FLAG_ALLOW_PROXY_CERTS		0x40
+/* Enable policy checking */
+#define X509_V_FLAG_POLICY_CHECK		0x80
+/* Policy variable require-explicit-policy */
+#define X509_V_FLAG_EXPLICIT_POLICY		0x100
+/* Policy variable inhibit-any-policy */
+#define	X509_V_FLAG_INHIBIT_ANY			0x200
+/* Policy variable inhibit-policy-mapping */
+#define X509_V_FLAG_INHIBIT_MAP			0x400
+/* Notify callback that policy is OK */
+#define X509_V_FLAG_NOTIFY_POLICY		0x800
+
+#define X509_VP_FLAG_DEFAULT			0x1
+#define X509_VP_FLAG_OVERWRITE			0x2
+#define X509_VP_FLAG_RESET_FLAGS		0x4
+#define X509_VP_FLAG_LOCKED			0x8
+#define X509_VP_FLAG_ONCE			0x10
+
+/* Internal use: mask of policy related options */
+#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \
+				| X509_V_FLAG_EXPLICIT_POLICY \
+				| X509_V_FLAG_INHIBIT_ANY \
+				| X509_V_FLAG_INHIBIT_MAP)
+
+int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
+	     X509_NAME *name);
+X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name);
+X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x);
+void X509_OBJECT_up_ref_count(X509_OBJECT *a);
+void X509_OBJECT_free_contents(X509_OBJECT *a);
+X509_STORE *X509_STORE_new(void );
+void X509_STORE_free(X509_STORE *v);
+
+int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags);
+int X509_STORE_set_purpose(X509_STORE *ctx, int purpose);
+int X509_STORE_set_trust(X509_STORE *ctx, int trust);
+int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm);
+
+X509_STORE_CTX *X509_STORE_CTX_new(void);
+
+int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x);
+
+void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
+int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
+			 X509 *x509, STACK_OF(X509) *chain);
+void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk);
+void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
+
+X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m);
+
+X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void);
+X509_LOOKUP_METHOD *X509_LOOKUP_file(void);
+
+int X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
+int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x);
+
+int X509_STORE_get_by_subject(X509_STORE_CTX *vs,int type,X509_NAME *name,
+	X509_OBJECT *ret);
+
+int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc,
+	long argl, char **ret);
+
+#ifndef OPENSSL_NO_STDIO
+int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type);
+int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type);
+int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type);
+#endif
+
+
+X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method);
+void X509_LOOKUP_free(X509_LOOKUP *ctx);
+int X509_LOOKUP_init(X509_LOOKUP *ctx);
+int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name,
+	X509_OBJECT *ret);
+int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name,
+	ASN1_INTEGER *serial, X509_OBJECT *ret);
+int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type,
+	unsigned char *bytes, int len, X509_OBJECT *ret);
+int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str,
+	int len, X509_OBJECT *ret);
+int X509_LOOKUP_shutdown(X509_LOOKUP *ctx);
+
+#ifndef OPENSSL_NO_STDIO
+int	X509_STORE_load_locations (X509_STORE *ctx,
+		const char *file, const char *dir);
+int	X509_STORE_set_default_paths(X509_STORE *ctx);
+#endif
+
+int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
+	CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func);
+int	X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data);
+void *	X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx);
+int	X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
+void	X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s);
+int	X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
+X509 *	X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
+STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx);
+STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx);
+void	X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x);
+void	X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk);
+void	X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,STACK_OF(X509_CRL) *sk);
+int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
+int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust);
+int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose,
+				int purpose, int trust);
+void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags);
+void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags,
+								time_t t);
+void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx,
+				  int (*verify_cb)(int, X509_STORE_CTX *));
+  
+X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx);
+int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx);
+
+X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx);
+void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param);
+int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name);
+
+/* X509_VERIFY_PARAM functions */
+
+X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
+void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param);
+int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to,
+						const X509_VERIFY_PARAM *from);
+int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, 
+						const X509_VERIFY_PARAM *from);
+int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name);
+int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags);
+int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose);
+int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust);
+void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth);
+void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t);
+int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param,
+						ASN1_OBJECT *policy);
+int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, 
+					STACK_OF(ASN1_OBJECT) *policies);
+int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param);
+
+int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param);
+const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name);
+void X509_VERIFY_PARAM_table_cleanup(void);
+
+int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
+			STACK_OF(X509) *certs,
+			STACK_OF(ASN1_OBJECT) *policy_oids,
+			unsigned int flags);
+
+void X509_policy_tree_free(X509_POLICY_TREE *tree);
+
+int X509_policy_tree_level_count(const X509_POLICY_TREE *tree);
+X509_POLICY_LEVEL *
+	X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i);
+
+STACK_OF(X509_POLICY_NODE) *
+	X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree);
+
+STACK_OF(X509_POLICY_NODE) *
+	X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree);
+
+int X509_policy_level_node_count(X509_POLICY_LEVEL *level);
+
+X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i);
+
+const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node);
+
+STACK_OF(POLICYQUALINFO) *
+	X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node);
+const X509_POLICY_NODE *
+	X509_policy_node_get0_parent(const X509_POLICY_NODE *node);
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509v3.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509v3.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/openssl/x509v3.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,759 @@
+/* x509v3.h */
+/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
+ * project 1999.
+ */
+/* ====================================================================
+ * Copyright (c) 1999-2004 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer. 
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    licensing@OpenSSL.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com).  This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+#ifndef HEADER_X509V3_H
+#define HEADER_X509V3_H
+
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+#include <openssl/conf.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward reference */
+struct v3_ext_method;
+struct v3_ext_ctx;
+
+/* Useful typedefs */
+
+typedef void * (*X509V3_EXT_NEW)(void);
+typedef void (*X509V3_EXT_FREE)(void *);
+typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char ** , long);
+typedef int (*X509V3_EXT_I2D)(void *, unsigned char **);
+typedef STACK_OF(CONF_VALUE) * (*X509V3_EXT_I2V)(struct v3_ext_method *method, void *ext, STACK_OF(CONF_VALUE) *extlist);
+typedef void * (*X509V3_EXT_V2I)(struct v3_ext_method *method, struct v3_ext_ctx *ctx, STACK_OF(CONF_VALUE) *values);
+typedef char * (*X509V3_EXT_I2S)(struct v3_ext_method *method, void *ext);
+typedef void * (*X509V3_EXT_S2I)(struct v3_ext_method *method, struct v3_ext_ctx *ctx, const char *str);
+typedef int (*X509V3_EXT_I2R)(struct v3_ext_method *method, void *ext, BIO *out, int indent);
+typedef void * (*X509V3_EXT_R2I)(struct v3_ext_method *method, struct v3_ext_ctx *ctx, const char *str);
+
+/* V3 extension structure */
+
+struct v3_ext_method {
+int ext_nid;
+int ext_flags;
+/* If this is set the following four fields are ignored */
+ASN1_ITEM_EXP *it;
+/* Old style ASN1 calls */
+X509V3_EXT_NEW ext_new;
+X509V3_EXT_FREE ext_free;
+X509V3_EXT_D2I d2i;
+X509V3_EXT_I2D i2d;
+
+/* The following pair is used for string extensions */
+X509V3_EXT_I2S i2s;
+X509V3_EXT_S2I s2i;
+
+/* The following pair is used for multi-valued extensions */
+X509V3_EXT_I2V i2v;
+X509V3_EXT_V2I v2i;
+
+/* The following are used for raw extensions */
+X509V3_EXT_I2R i2r;
+X509V3_EXT_R2I r2i;
+
+void *usr_data;	/* Any extension specific data */
+};
+
+typedef struct X509V3_CONF_METHOD_st {
+char * (*get_string)(void *db, char *section, char *value);
+STACK_OF(CONF_VALUE) * (*get_section)(void *db, char *section);
+void (*free_string)(void *db, char * string);
+void (*free_section)(void *db, STACK_OF(CONF_VALUE) *section);
+} X509V3_CONF_METHOD;
+
+/* Context specific info */
+struct v3_ext_ctx {
+#define CTX_TEST 0x1
+int flags;
+X509 *issuer_cert;
+X509 *subject_cert;
+X509_REQ *subject_req;
+X509_CRL *crl;
+X509V3_CONF_METHOD *db_meth;
+void *db;
+/* Maybe more here */
+};
+
+typedef struct v3_ext_method X509V3_EXT_METHOD;
+
+DECLARE_STACK_OF(X509V3_EXT_METHOD)
+
+/* ext_flags values */
+#define X509V3_EXT_DYNAMIC	0x1
+#define X509V3_EXT_CTX_DEP	0x2
+#define X509V3_EXT_MULTILINE	0x4
+
+typedef BIT_STRING_BITNAME ENUMERATED_NAMES;
+
+typedef struct BASIC_CONSTRAINTS_st {
+int ca;
+ASN1_INTEGER *pathlen;
+} BASIC_CONSTRAINTS;
+
+
+typedef struct PKEY_USAGE_PERIOD_st {
+ASN1_GENERALIZEDTIME *notBefore;
+ASN1_GENERALIZEDTIME *notAfter;
+} PKEY_USAGE_PERIOD;
+
+typedef struct otherName_st {
+ASN1_OBJECT *type_id;
+ASN1_TYPE *value;
+} OTHERNAME;
+
+typedef struct EDIPartyName_st {
+	ASN1_STRING *nameAssigner;
+	ASN1_STRING *partyName;
+} EDIPARTYNAME;
+
+typedef struct GENERAL_NAME_st {
+
+#define GEN_OTHERNAME	0
+#define GEN_EMAIL	1
+#define GEN_DNS		2
+#define GEN_X400	3
+#define GEN_DIRNAME	4
+#define GEN_EDIPARTY	5
+#define GEN_URI		6
+#define GEN_IPADD	7
+#define GEN_RID		8
+
+int type;
+union {
+	char *ptr;
+	OTHERNAME *otherName; /* otherName */
+	ASN1_IA5STRING *rfc822Name;
+	ASN1_IA5STRING *dNSName;
+	ASN1_TYPE *x400Address;
+	X509_NAME *directoryName;
+	EDIPARTYNAME *ediPartyName;
+	ASN1_IA5STRING *uniformResourceIdentifier;
+	ASN1_OCTET_STRING *iPAddress;
+	ASN1_OBJECT *registeredID;
+
+	/* Old names */
+	ASN1_OCTET_STRING *ip; /* iPAddress */
+	X509_NAME *dirn;		/* dirn */
+	ASN1_IA5STRING *ia5;/* rfc822Name, dNSName, uniformResourceIdentifier */
+	ASN1_OBJECT *rid; /* registeredID */
+	ASN1_TYPE *other; /* x400Address */
+} d;
+} GENERAL_NAME;
+
+typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES;
+
+typedef struct ACCESS_DESCRIPTION_st {
+	ASN1_OBJECT *method;
+	GENERAL_NAME *location;
+} ACCESS_DESCRIPTION;
+
+typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS;
+
+typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE;
+
+DECLARE_STACK_OF(GENERAL_NAME)
+DECLARE_ASN1_SET_OF(GENERAL_NAME)
+
+DECLARE_STACK_OF(ACCESS_DESCRIPTION)
+DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION)
+
+typedef struct DIST_POINT_NAME_st {
+int type;
+union {
+	GENERAL_NAMES *fullname;
+	STACK_OF(X509_NAME_ENTRY) *relativename;
+} name;
+} DIST_POINT_NAME;
+
+typedef struct DIST_POINT_st {
+DIST_POINT_NAME	*distpoint;
+ASN1_BIT_STRING *reasons;
+GENERAL_NAMES *CRLissuer;
+} DIST_POINT;
+
+typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS;
+
+DECLARE_STACK_OF(DIST_POINT)
+DECLARE_ASN1_SET_OF(DIST_POINT)
+
+typedef struct AUTHORITY_KEYID_st {
+ASN1_OCTET_STRING *keyid;
+GENERAL_NAMES *issuer;
+ASN1_INTEGER *serial;
+} AUTHORITY_KEYID;
+
+/* Strong extranet structures */
+
+typedef struct SXNET_ID_st {
+	ASN1_INTEGER *zone;
+	ASN1_OCTET_STRING *user;
+} SXNETID;
+
+DECLARE_STACK_OF(SXNETID)
+DECLARE_ASN1_SET_OF(SXNETID)
+
+typedef struct SXNET_st {
+	ASN1_INTEGER *version;
+	STACK_OF(SXNETID) *ids;
+} SXNET;
+
+typedef struct NOTICEREF_st {
+	ASN1_STRING *organization;
+	STACK_OF(ASN1_INTEGER) *noticenos;
+} NOTICEREF;
+
+typedef struct USERNOTICE_st {
+	NOTICEREF *noticeref;
+	ASN1_STRING *exptext;
+} USERNOTICE;
+
+typedef struct POLICYQUALINFO_st {
+	ASN1_OBJECT *pqualid;
+	union {
+		ASN1_IA5STRING *cpsuri;
+		USERNOTICE *usernotice;
+		ASN1_TYPE *other;
+	} d;
+} POLICYQUALINFO;
+
+DECLARE_STACK_OF(POLICYQUALINFO)
+DECLARE_ASN1_SET_OF(POLICYQUALINFO)
+
+typedef struct POLICYINFO_st {
+	ASN1_OBJECT *policyid;
+	STACK_OF(POLICYQUALINFO) *qualifiers;
+} POLICYINFO;
+
+typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES;
+
+DECLARE_STACK_OF(POLICYINFO)
+DECLARE_ASN1_SET_OF(POLICYINFO)
+
+typedef struct POLICY_MAPPING_st {
+	ASN1_OBJECT *issuerDomainPolicy;
+	ASN1_OBJECT *subjectDomainPolicy;
+} POLICY_MAPPING;
+
+DECLARE_STACK_OF(POLICY_MAPPING)
+
+typedef STACK_OF(POLICY_MAPPING) POLICY_MAPPINGS;
+
+typedef struct GENERAL_SUBTREE_st {
+	GENERAL_NAME *base;
+	ASN1_INTEGER *minimum;
+	ASN1_INTEGER *maximum;
+} GENERAL_SUBTREE;
+
+DECLARE_STACK_OF(GENERAL_SUBTREE)
+
+typedef struct NAME_CONSTRAINTS_st {
+	STACK_OF(GENERAL_SUBTREE) *permittedSubtrees;
+	STACK_OF(GENERAL_SUBTREE) *excludedSubtrees;
+} NAME_CONSTRAINTS;
+
+typedef struct POLICY_CONSTRAINTS_st {
+	ASN1_INTEGER *requireExplicitPolicy;
+	ASN1_INTEGER *inhibitPolicyMapping;
+} POLICY_CONSTRAINTS;
+
+/* Proxy certificate structures, see RFC 3820 */
+typedef struct PROXY_POLICY_st
+	{
+	ASN1_OBJECT *policyLanguage;
+	ASN1_OCTET_STRING *policy;
+	} PROXY_POLICY;
+
+typedef struct PROXY_CERT_INFO_EXTENSION_st
+	{
+	ASN1_INTEGER *pcPathLengthConstraint;
+	PROXY_POLICY *proxyPolicy;
+	} PROXY_CERT_INFO_EXTENSION;
+
+DECLARE_ASN1_FUNCTIONS(PROXY_POLICY)
+DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION)
+
+
+#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \
+",name:", val->name, ",value:", val->value);
+
+#define X509V3_set_ctx_test(ctx) \
+			X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST)
+#define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL;
+
+#define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \
+			0,0,0,0, \
+			0,0, \
+			(X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \
+			(X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \
+			NULL, NULL, \
+			table}
+
+#define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \
+			0,0,0,0, \
+			(X509V3_EXT_I2S)i2s_ASN1_IA5STRING, \
+			(X509V3_EXT_S2I)s2i_ASN1_IA5STRING, \
+			0,0,0,0, \
+			NULL}
+
+#define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+
+/* X509_PURPOSE stuff */
+
+#define EXFLAG_BCONS		0x1
+#define EXFLAG_KUSAGE		0x2
+#define EXFLAG_XKUSAGE		0x4
+#define EXFLAG_NSCERT		0x8
+
+#define EXFLAG_CA		0x10
+#define EXFLAG_SS		0x20
+#define EXFLAG_V1		0x40
+#define EXFLAG_INVALID		0x80
+#define EXFLAG_SET		0x100
+#define EXFLAG_CRITICAL		0x200
+#define EXFLAG_PROXY		0x400
+
+#define EXFLAG_INVALID_POLICY	0x400
+
+#define KU_DIGITAL_SIGNATURE	0x0080
+#define KU_NON_REPUDIATION	0x0040
+#define KU_KEY_ENCIPHERMENT	0x0020
+#define KU_DATA_ENCIPHERMENT	0x0010
+#define KU_KEY_AGREEMENT	0x0008
+#define KU_KEY_CERT_SIGN	0x0004
+#define KU_CRL_SIGN		0x0002
+#define KU_ENCIPHER_ONLY	0x0001
+#define KU_DECIPHER_ONLY	0x8000
+
+#define NS_SSL_CLIENT		0x80
+#define NS_SSL_SERVER		0x40
+#define NS_SMIME		0x20
+#define NS_OBJSIGN		0x10
+#define NS_SSL_CA		0x04
+#define NS_SMIME_CA		0x02
+#define NS_OBJSIGN_CA		0x01
+#define NS_ANY_CA		(NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA)
+
+#define XKU_SSL_SERVER		0x1	
+#define XKU_SSL_CLIENT		0x2
+#define XKU_SMIME		0x4
+#define XKU_CODE_SIGN		0x8
+#define XKU_SGC			0x10
+#define XKU_OCSP_SIGN		0x20
+#define XKU_TIMESTAMP		0x40
+#define XKU_DVCS		0x80
+
+#define X509_PURPOSE_DYNAMIC	0x1
+#define X509_PURPOSE_DYNAMIC_NAME	0x2
+
+typedef struct x509_purpose_st {
+	int purpose;
+	int trust;		/* Default trust ID */
+	int flags;
+	int (*check_purpose)(const struct x509_purpose_st *,
+				const X509 *, int);
+	char *name;
+	char *sname;
+	void *usr_data;
+} X509_PURPOSE;
+
+#define X509_PURPOSE_SSL_CLIENT		1
+#define X509_PURPOSE_SSL_SERVER		2
+#define X509_PURPOSE_NS_SSL_SERVER	3
+#define X509_PURPOSE_SMIME_SIGN		4
+#define X509_PURPOSE_SMIME_ENCRYPT	5
+#define X509_PURPOSE_CRL_SIGN		6
+#define X509_PURPOSE_ANY		7
+#define X509_PURPOSE_OCSP_HELPER	8
+
+#define X509_PURPOSE_MIN		1
+#define X509_PURPOSE_MAX		8
+
+/* Flags for X509V3_EXT_print() */
+
+#define X509V3_EXT_UNKNOWN_MASK		(0xfL << 16)
+/* Return error for unknown extensions */
+#define X509V3_EXT_DEFAULT		0
+/* Print error for unknown extensions */
+#define X509V3_EXT_ERROR_UNKNOWN	(1L << 16)
+/* ASN1 parse unknown extensions */
+#define X509V3_EXT_PARSE_UNKNOWN	(2L << 16)
+/* BIO_dump unknown extensions */
+#define X509V3_EXT_DUMP_UNKNOWN		(3L << 16)
+
+/* Flags for X509V3_add1_i2d */
+
+#define X509V3_ADD_OP_MASK		0xfL
+#define X509V3_ADD_DEFAULT		0L
+#define X509V3_ADD_APPEND		1L
+#define X509V3_ADD_REPLACE		2L
+#define X509V3_ADD_REPLACE_EXISTING	3L
+#define X509V3_ADD_KEEP_EXISTING	4L
+#define X509V3_ADD_DELETE		5L
+#define X509V3_ADD_SILENT		0x10
+
+DECLARE_STACK_OF(X509_PURPOSE)
+
+DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS)
+
+DECLARE_ASN1_FUNCTIONS(SXNET)
+DECLARE_ASN1_FUNCTIONS(SXNETID)
+
+int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, int userlen); 
+int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, int userlen); 
+int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *izone, char *user, int userlen); 
+
+ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone);
+ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone);
+ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone);
+
+DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID)
+
+DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD)
+
+DECLARE_ASN1_FUNCTIONS(GENERAL_NAME)
+
+
+ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
+				X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method,
+				ASN1_BIT_STRING *bits,
+				STACK_OF(CONF_VALUE) *extlist);
+
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret);
+int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen);
+
+DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES)
+
+STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method,
+		GENERAL_NAMES *gen, STACK_OF(CONF_VALUE) *extlist);
+GENERAL_NAMES *v2i_GENERAL_NAMES(X509V3_EXT_METHOD *method,
+				X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval);
+
+DECLARE_ASN1_FUNCTIONS(OTHERNAME)
+DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME)
+
+char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5);
+ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str);
+
+DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE)
+int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a);
+
+DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES)
+DECLARE_ASN1_FUNCTIONS(POLICYINFO)
+DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO)
+DECLARE_ASN1_FUNCTIONS(USERNOTICE)
+DECLARE_ASN1_FUNCTIONS(NOTICEREF)
+
+DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS)
+DECLARE_ASN1_FUNCTIONS(DIST_POINT)
+DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME)
+
+DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION)
+DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS)
+
+DECLARE_ASN1_ITEM(POLICY_MAPPING)
+DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING)
+DECLARE_ASN1_ITEM(POLICY_MAPPINGS)
+
+DECLARE_ASN1_ITEM(GENERAL_SUBTREE)
+DECLARE_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE)
+
+DECLARE_ASN1_ITEM(NAME_CONSTRAINTS)
+DECLARE_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS)
+
+DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS)
+DECLARE_ASN1_ITEM(POLICY_CONSTRAINTS)
+
+#ifdef HEADER_CONF_H
+GENERAL_NAME *v2i_GENERAL_NAME(X509V3_EXT_METHOD *method, X509V3_CTX *ctx,
+							CONF_VALUE *cnf);
+GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, X509V3_EXT_METHOD *method,
+				X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc);
+void X509V3_conf_free(CONF_VALUE *val);
+
+X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value);
+X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value);
+int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk);
+int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509 *cert);
+int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_REQ *req);
+int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl);
+
+X509_EXTENSION *X509V3_EXT_conf_nid(LHASH *conf, X509V3_CTX *ctx, int ext_nid, char *value);
+X509_EXTENSION *X509V3_EXT_conf(LHASH *conf, X509V3_CTX *ctx, char *name, char *value);
+int X509V3_EXT_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section, X509 *cert);
+int X509V3_EXT_REQ_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section, X509_REQ *req);
+int X509V3_EXT_CRL_add_conf(LHASH *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl);
+
+int X509V3_add_value_bool_nf(char *name, int asn1_bool,
+						STACK_OF(CONF_VALUE) **extlist);
+int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool);
+int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint);
+void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf);
+void X509V3_set_conf_lhash(X509V3_CTX *ctx, LHASH *lhash);
+#endif
+
+char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section);
+STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section);
+void X509V3_string_free(X509V3_CTX *ctx, char *str);
+void X509V3_section_free( X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section);
+void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
+				 X509_REQ *req, X509_CRL *crl, int flags);
+
+int X509V3_add_value(const char *name, const char *value,
+						STACK_OF(CONF_VALUE) **extlist);
+int X509V3_add_value_uchar(const char *name, const unsigned char *value,
+						STACK_OF(CONF_VALUE) **extlist);
+int X509V3_add_value_bool(const char *name, int asn1_bool,
+						STACK_OF(CONF_VALUE) **extlist);
+int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint,
+						STACK_OF(CONF_VALUE) **extlist);
+char * i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint);
+ASN1_INTEGER * s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, char *value);
+char * i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint);
+char * i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint);
+int X509V3_EXT_add(X509V3_EXT_METHOD *ext);
+int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist);
+int X509V3_EXT_add_alias(int nid_to, int nid_from);
+void X509V3_EXT_cleanup(void);
+
+X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext);
+X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid);
+int X509V3_add_standard_extensions(void);
+STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line);
+void *X509V3_EXT_d2i(X509_EXTENSION *ext);
+void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx);
+
+
+X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc);
+int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, int crit, unsigned long flags);
+
+char *hex_to_string(unsigned char *buffer, long len);
+unsigned char *string_to_hex(char *str, long *len);
+int name_cmp(const char *name, const char *cmp);
+
+void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent,
+								 int ml);
+int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent);
+int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);
+
+int X509V3_extensions_print(BIO *out, char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent);
+
+int X509_check_ca(X509 *x);
+int X509_check_purpose(X509 *x, int id, int ca);
+int X509_supported_extension(X509_EXTENSION *ex);
+int X509_PURPOSE_set(int *p, int purpose);
+int X509_check_issued(X509 *issuer, X509 *subject);
+int X509_PURPOSE_get_count(void);
+X509_PURPOSE * X509_PURPOSE_get0(int idx);
+int X509_PURPOSE_get_by_sname(char *sname);
+int X509_PURPOSE_get_by_id(int id);
+int X509_PURPOSE_add(int id, int trust, int flags,
+			int (*ck)(const X509_PURPOSE *, const X509 *, int),
+				char *name, char *sname, void *arg);
+char *X509_PURPOSE_get0_name(X509_PURPOSE *xp);
+char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp);
+int X509_PURPOSE_get_trust(X509_PURPOSE *xp);
+void X509_PURPOSE_cleanup(void);
+int X509_PURPOSE_get_id(X509_PURPOSE *);
+
+STACK *X509_get1_email(X509 *x);
+STACK *X509_REQ_get1_email(X509_REQ *x);
+void X509_email_free(STACK *sk);
+
+ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc);
+ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc);
+int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk,
+						unsigned long chtype);
+
+void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent);
+
+/* BEGIN ERROR CODES */
+/* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+ */
+void ERR_load_X509V3_strings(void);
+
+/* Error codes for the X509V3 functions. */
+
+/* Function codes. */
+#define X509V3_F_COPY_EMAIL				 122
+#define X509V3_F_COPY_ISSUER				 123
+#define X509V3_F_DO_DIRNAME				 144
+#define X509V3_F_DO_EXT_CONF				 124
+#define X509V3_F_DO_EXT_I2D				 135
+#define X509V3_F_DO_EXT_NCONF				 151
+#define X509V3_F_DO_I2V_NAME_CONSTRAINTS		 148
+#define X509V3_F_HEX_TO_STRING				 111
+#define X509V3_F_I2S_ASN1_ENUMERATED			 121
+#define X509V3_F_I2S_ASN1_IA5STRING			 149
+#define X509V3_F_I2S_ASN1_INTEGER			 120
+#define X509V3_F_I2V_AUTHORITY_INFO_ACCESS		 138
+#define X509V3_F_NOTICE_SECTION				 132
+#define X509V3_F_NREF_NOS				 133
+#define X509V3_F_POLICY_SECTION				 131
+#define X509V3_F_PROCESS_PCI_VALUE			 150
+#define X509V3_F_R2I_CERTPOL				 130
+#define X509V3_F_R2I_PCI				 149
+#define X509V3_F_S2I_ASN1_IA5STRING			 100
+#define X509V3_F_S2I_ASN1_INTEGER			 108
+#define X509V3_F_S2I_ASN1_OCTET_STRING			 112
+#define X509V3_F_S2I_ASN1_SKEY_ID			 114
+#define X509V3_F_S2I_SKEY_ID				 115
+#define X509V3_F_STRING_TO_HEX				 113
+#define X509V3_F_SXNET_ADD_ID_ASC			 125
+#define X509V3_F_SXNET_ADD_ID_INTEGER			 126
+#define X509V3_F_SXNET_ADD_ID_ULONG			 127
+#define X509V3_F_SXNET_GET_ID_ASC			 128
+#define X509V3_F_SXNET_GET_ID_ULONG			 129
+#define X509V3_F_V2I_ASN1_BIT_STRING			 101
+#define X509V3_F_V2I_AUTHORITY_INFO_ACCESS		 139
+#define X509V3_F_V2I_AUTHORITY_KEYID			 119
+#define X509V3_F_V2I_BASIC_CONSTRAINTS			 102
+#define X509V3_F_V2I_CRLD				 134
+#define X509V3_F_V2I_EXTENDED_KEY_USAGE			 103
+#define X509V3_F_V2I_GENERAL_NAMES			 118
+#define X509V3_F_V2I_GENERAL_NAME_EX			 117
+#define X509V3_F_V2I_ISSUER_ALT				 153
+#define X509V3_F_V2I_NAME_CONSTRAINTS			 147
+#define X509V3_F_V2I_POLICY_CONSTRAINTS			 146
+#define X509V3_F_V2I_POLICY_MAPPINGS			 145
+#define X509V3_F_V2I_SUBJECT_ALT			 154
+#define X509V3_F_V3_GENERIC_EXTENSION			 116
+#define X509V3_F_X509V3_ADD1_I2D			 140
+#define X509V3_F_X509V3_ADD_VALUE			 105
+#define X509V3_F_X509V3_EXT_ADD				 104
+#define X509V3_F_X509V3_EXT_ADD_ALIAS			 106
+#define X509V3_F_X509V3_EXT_CONF			 107
+#define X509V3_F_X509V3_EXT_I2D				 136
+#define X509V3_F_X509V3_EXT_NCONF			 152
+#define X509V3_F_X509V3_GET_SECTION			 142
+#define X509V3_F_X509V3_GET_STRING			 143
+#define X509V3_F_X509V3_GET_VALUE_BOOL			 110
+#define X509V3_F_X509V3_PARSE_LIST			 109
+#define X509V3_F_X509_PURPOSE_ADD			 137
+#define X509V3_F_X509_PURPOSE_SET			 141
+
+/* Reason codes. */
+#define X509V3_R_BAD_IP_ADDRESS				 118
+#define X509V3_R_BAD_OBJECT				 119
+#define X509V3_R_BN_DEC2BN_ERROR			 100
+#define X509V3_R_BN_TO_ASN1_INTEGER_ERROR		 101
+#define X509V3_R_DIRNAME_ERROR				 149
+#define X509V3_R_DUPLICATE_ZONE_ID			 133
+#define X509V3_R_ERROR_CONVERTING_ZONE			 131
+#define X509V3_R_ERROR_CREATING_EXTENSION		 144
+#define X509V3_R_ERROR_IN_EXTENSION			 128
+#define X509V3_R_EXPECTED_A_SECTION_NAME		 137
+#define X509V3_R_EXTENSION_EXISTS			 145
+#define X509V3_R_EXTENSION_NAME_ERROR			 115
+#define X509V3_R_EXTENSION_NOT_FOUND			 102
+#define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED	 103
+#define X509V3_R_EXTENSION_VALUE_ERROR			 116
+#define X509V3_R_ILLEGAL_EMPTY_EXTENSION		 151
+#define X509V3_R_ILLEGAL_HEX_DIGIT			 113
+#define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG		 152
+#define X509V3_R_INVALID_BOOLEAN_STRING			 104
+#define X509V3_R_INVALID_EXTENSION_STRING		 105
+#define X509V3_R_INVALID_NAME				 106
+#define X509V3_R_INVALID_NULL_ARGUMENT			 107
+#define X509V3_R_INVALID_NULL_NAME			 108
+#define X509V3_R_INVALID_NULL_VALUE			 109
+#define X509V3_R_INVALID_NUMBER				 140
+#define X509V3_R_INVALID_NUMBERS			 141
+#define X509V3_R_INVALID_OBJECT_IDENTIFIER		 110
+#define X509V3_R_INVALID_OPTION				 138
+#define X509V3_R_INVALID_POLICY_IDENTIFIER		 134
+#define X509V3_R_INVALID_PROXY_POLICY_SETTING		 153
+#define X509V3_R_INVALID_PURPOSE			 146
+#define X509V3_R_INVALID_SECTION			 135
+#define X509V3_R_INVALID_SYNTAX				 143
+#define X509V3_R_ISSUER_DECODE_ERROR			 126
+#define X509V3_R_MISSING_VALUE				 124
+#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS		 142
+#define X509V3_R_NO_CONFIG_DATABASE			 136
+#define X509V3_R_NO_ISSUER_CERTIFICATE			 121
+#define X509V3_R_NO_ISSUER_DETAILS			 127
+#define X509V3_R_NO_POLICY_IDENTIFIER			 139
+#define X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED	 154
+#define X509V3_R_NO_PUBLIC_KEY				 114
+#define X509V3_R_NO_SUBJECT_DETAILS			 125
+#define X509V3_R_ODD_NUMBER_OF_DIGITS			 112
+#define X509V3_R_OPERATION_NOT_DEFINED			 148
+#define X509V3_R_OTHERNAME_ERROR			 147
+#define X509V3_R_POLICY_LANGUAGE_ALREADTY_DEFINED	 155
+#define X509V3_R_POLICY_PATH_LENGTH			 156
+#define X509V3_R_POLICY_PATH_LENGTH_ALREADTY_DEFINED	 157
+#define X509V3_R_POLICY_SYNTAX_NOT_CURRENTLY_SUPPORTED	 158
+#define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 159
+#define X509V3_R_SECTION_NOT_FOUND			 150
+#define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS		 122
+#define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID		 123
+#define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT		 111
+#define X509V3_R_UNKNOWN_EXTENSION			 129
+#define X509V3_R_UNKNOWN_EXTENSION_NAME			 130
+#define X509V3_R_UNKNOWN_OPTION				 120
+#define X509V3_R_UNSUPPORTED_OPTION			 117
+#define X509V3_R_USER_TOO_LONG				 132
+
+#ifdef  __cplusplus
+}
+#endif
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,299 @@
+/* pkcs11.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the 
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+#ifndef _PKCS11_H_
+#define _PKCS11_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Before including this file (pkcs11.h) (or pkcs11t.h by
+ * itself), 6 platform-specific macros must be defined.  These
+ * macros are described below, and typical definitions for them
+ * are also given.  Be advised that these definitions can depend
+ * on both the platform and the compiler used (and possibly also
+ * on whether a Cryptoki library is linked statically or
+ * dynamically).
+ *
+ * In addition to defining these 6 macros, the packing convention
+ * for Cryptoki structures should be set.  The Cryptoki
+ * convention on packing is that structures should be 1-byte
+ * aligned.
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, this might be done by using the following
+ * preprocessor directive before including pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(push, cryptoki, 1)
+ *
+ * and using the following preprocessor directive after including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(pop, cryptoki)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, this might be done by using
+ * the following preprocessor directive before including
+ * pkcs11.h or pkcs11t.h:
+ *
+ * #pragma pack(1)
+ *
+ * In a UNIX environment, you're on your own for this.  You might
+ * not need to do (or be able to do!) anything.
+ *
+ *
+ * Now for the macros:
+ *
+ *
+ * 1. CK_PTR: The indirection string for making a pointer to an
+ * object.  It can be used like this:
+ *
+ * typedef CK_BYTE CK_PTR CK_BYTE_PTR;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to produce
+ * Win32 stuff, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to produce Win16 stuff, it might be defined by:
+ *
+ * #define CK_PTR far *
+ *
+ * In a typical UNIX environment, it might be defined by:
+ *
+ * #define CK_PTR *
+ *
+ *
+ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes
+ * an exportable Cryptoki library function definition out of a
+ * return type and a function name.  It should be used in the
+ * following fashion to define the exposed Cryptoki functions in
+ * a Cryptoki library:
+ *
+ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)(
+ *   CK_VOID_PTR pReserved
+ * )
+ * {
+ *   ...
+ * }
+ *
+ * If you're using Microsoft Developer Studio 5.0 to define a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ *   returnType __declspec(dllexport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to define a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ *   returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DEFINE_FUNCTION(returnType, name) \
+ *   returnType name
+ *
+ *
+ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes
+ * an importable Cryptoki library function declaration out of a
+ * return type and a function name.  It should be used in the
+ * following fashion:
+ *
+ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)(
+ *   CK_VOID_PTR pReserved
+ * );
+ *
+ * If you're using Microsoft Developer Studio 5.0 to declare a
+ * function in a Win32 Cryptoki .dll, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType __declspec(dllimport) name
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to declare a function in a Win16 Cryptoki .dll, it
+ * might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType __export _far _pascal name
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION(returnType, name) \
+ *   returnType name
+ *
+ *
+ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro
+ * which makes a Cryptoki API function pointer declaration or
+ * function pointer type declaration out of a return type and a
+ * function name.  It should be used in the following fashion:
+ *
+ * // Define funcPtr to be a pointer to a Cryptoki API function
+ * // taking arguments args and returning CK_RV.
+ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args);
+ *
+ * or
+ *
+ * // Define funcPtrType to be the type of a pointer to a
+ * // Cryptoki API function taking arguments args and returning
+ * // CK_RV, and then define funcPtr to be a variable of type
+ * // funcPtrType.
+ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args);
+ * funcPtrType funcPtr;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to access
+ * functions in a Win32 Cryptoki .dll, in might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType __declspec(dllimport) (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to access functions in a Win16 Cryptoki .dll, it might
+ * be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType __export _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \
+ *   returnType (* name)
+ *
+ *
+ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes
+ * a function pointer type for an application callback out of
+ * a return type for the callback and a name for the callback.
+ * It should be used in the following fashion:
+ *
+ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args);
+ *
+ * to declare a function pointer, myCallback, to a callback
+ * which takes arguments args and returns a CK_RV.  It can also
+ * be used like this:
+ *
+ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args);
+ * myCallbackType myCallback;
+ *
+ * If you're using Microsoft Developer Studio 5.0 to do Win32
+ * Cryptoki development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType (* name)
+ *
+ * If you're using an earlier version of Microsoft Developer
+ * Studio to do Win16 development, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType _far _pascal (* name)
+ *
+ * In a UNIX environment, it might be defined by:
+ *
+ * #define CK_CALLBACK_FUNCTION(returnType, name) \
+ *   returnType (* name)
+ *
+ *
+ * 6. NULL_PTR: This macro is the value of a NULL pointer.
+ *
+ * In any ANSI/ISO C environment (and in many others as well),
+ * this should best be defined by
+ *
+ * #ifndef NULL_PTR
+ * #define NULL_PTR 0
+ * #endif
+ */
+
+
+/* All the various Cryptoki types and #define'd values are in the
+ * file pkcs11t.h. */
+#include "pkcs11t.h"
+
+#define __PASTE(x,y)      x##y
+
+
+/* ==============================================================
+ * Define the "extern" form of all the entry points.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST  1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  extern CK_DECLARE_FUNCTION(CK_RV, name)
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define the typedef form of all the entry points.  That is, for
+ * each Cryptoki function C_XXX, define a type CK_C_XXX which is
+ * a pointer to that kind of function.
+ * ==============================================================
+ */
+
+#define CK_NEED_ARG_LIST  1
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name))
+
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+#undef CK_NEED_ARG_LIST
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+/* ==============================================================
+ * Define structed vector of entry points.  A CK_FUNCTION_LIST
+ * contains a CK_VERSION indicating a library's Cryptoki version
+ * and then a whole slew of function pointers to the routines in
+ * the library.  This type was declared, but not defined, in
+ * pkcs11t.h.
+ * ==============================================================
+ */
+
+#define CK_PKCS11_FUNCTION_INFO(name) \
+  __PASTE(CK_,name) name;
+  
+struct CK_FUNCTION_LIST {
+
+  CK_VERSION    version;  /* Cryptoki version */
+
+/* Pile all the function pointers into the CK_FUNCTION_LIST. */
+/* pkcs11f.h has all the information about the Cryptoki
+ * function prototypes. */
+#include "pkcs11f.h"
+
+};
+
+#undef CK_PKCS11_FUNCTION_INFO
+
+
+#undef __PASTE
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11f.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11f.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11f.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,912 @@
+/* pkcs11f.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the 
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* This header file contains pretty much everything about all the */
+/* Cryptoki function prototypes.  Because this information is */
+/* used for more than just declaring function prototypes, the */
+/* order of the functions appearing herein is important, and */
+/* should not be altered. */
+
+/* General-purpose */
+
+/* C_Initialize initializes the Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Initialize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_VOID_PTR   pInitArgs  /* if this is not NULL_PTR, it gets
+                            * cast to CK_C_INITIALIZE_ARGS_PTR
+                            * and dereferenced */
+);
+#endif
+
+
+/* C_Finalize indicates that an application is done with the
+ * Cryptoki library. */
+CK_PKCS11_FUNCTION_INFO(C_Finalize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_VOID_PTR   pReserved  /* reserved.  Should be NULL_PTR */
+);
+#endif
+
+
+/* C_GetInfo returns general information about Cryptoki. */
+CK_PKCS11_FUNCTION_INFO(C_GetInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_INFO_PTR   pInfo  /* location that receives information */
+);
+#endif
+
+
+/* C_GetFunctionList returns the function list. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_FUNCTION_LIST_PTR_PTR ppFunctionList  /* receives pointer to
+                                            * function list */
+);
+#endif
+
+
+
+/* Slot and token management */
+
+/* C_GetSlotList obtains a list of slots in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_BBOOL       tokenPresent,  /* only slots with tokens? */
+  CK_SLOT_ID_PTR pSlotList,     /* receives array of slot IDs */
+  CK_ULONG_PTR   pulCount       /* receives number of slots */
+);
+#endif
+
+
+/* C_GetSlotInfo obtains information about a particular slot in
+ * the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID       slotID,  /* the ID of the slot */
+  CK_SLOT_INFO_PTR pInfo    /* receives the slot information */
+);
+#endif
+
+
+/* C_GetTokenInfo obtains information about a particular token
+ * in the system. */
+CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID        slotID,  /* ID of the token's slot */
+  CK_TOKEN_INFO_PTR pInfo    /* receives the token information */
+);
+#endif
+
+
+/* C_GetMechanismList obtains a list of mechanism types
+ * supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismList)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,          /* ID of token's slot */
+  CK_MECHANISM_TYPE_PTR pMechanismList,  /* gets mech. array */
+  CK_ULONG_PTR          pulCount         /* gets # of mechs. */
+);
+#endif
+
+
+/* C_GetMechanismInfo obtains information about a particular
+ * mechanism possibly supported by a token. */
+CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,  /* ID of the token's slot */
+  CK_MECHANISM_TYPE     type,    /* type of mechanism */
+  CK_MECHANISM_INFO_PTR pInfo    /* receives mechanism info */
+);
+#endif
+
+
+/* C_InitToken initializes a token. */
+CK_PKCS11_FUNCTION_INFO(C_InitToken)
+#ifdef CK_NEED_ARG_LIST
+/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */
+(
+  CK_SLOT_ID      slotID,    /* ID of the token's slot */
+  CK_UTF8CHAR_PTR pPin,      /* the SO's initial PIN */
+  CK_ULONG        ulPinLen,  /* length in bytes of the PIN */
+  CK_UTF8CHAR_PTR pLabel     /* 32-byte token label (blank padded) */
+);
+#endif
+
+
+/* C_InitPIN initializes the normal user's PIN. */
+CK_PKCS11_FUNCTION_INFO(C_InitPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pPin,      /* the normal user's PIN */
+  CK_ULONG          ulPinLen   /* length in bytes of the PIN */
+);
+#endif
+
+
+/* C_SetPIN modifies the PIN of the user who is logged in. */
+CK_PKCS11_FUNCTION_INFO(C_SetPIN)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_UTF8CHAR_PTR   pOldPin,   /* the old PIN */
+  CK_ULONG          ulOldLen,  /* length of the old PIN */
+  CK_UTF8CHAR_PTR   pNewPin,   /* the new PIN */
+  CK_ULONG          ulNewLen   /* length of the new PIN */
+);
+#endif
+
+
+
+/* Session management */
+
+/* C_OpenSession opens a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_OpenSession)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID            slotID,        /* the slot's ID */
+  CK_FLAGS              flags,         /* from CK_SESSION_INFO */
+  CK_VOID_PTR           pApplication,  /* passed to callback */
+  CK_NOTIFY             Notify,        /* callback function */
+  CK_SESSION_HANDLE_PTR phSession      /* gets session handle */
+);
+#endif
+
+
+/* C_CloseSession closes a session between an application and a
+ * token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseSession)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_CloseAllSessions closes all sessions with a token. */
+CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SLOT_ID     slotID  /* the token's slot */
+);
+#endif
+
+
+/* C_GetSessionInfo obtains information about the session. */
+CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE   hSession,  /* the session's handle */
+  CK_SESSION_INFO_PTR pInfo      /* receives session info */
+);
+#endif
+
+
+/* C_GetOperationState obtains the state of the cryptographic operation
+ * in a session. */
+CK_PKCS11_FUNCTION_INFO(C_GetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,             /* session's handle */
+  CK_BYTE_PTR       pOperationState,      /* gets state */
+  CK_ULONG_PTR      pulOperationStateLen  /* gets state length */
+);
+#endif
+
+
+/* C_SetOperationState restores the state of the cryptographic
+ * operation in a session. */
+CK_PKCS11_FUNCTION_INFO(C_SetOperationState)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR      pOperationState,      /* holds state */
+  CK_ULONG         ulOperationStateLen,  /* holds state length */
+  CK_OBJECT_HANDLE hEncryptionKey,       /* en/decryption key */
+  CK_OBJECT_HANDLE hAuthenticationKey    /* sign/verify key */
+);
+#endif
+
+
+/* C_Login logs a user into a token. */
+CK_PKCS11_FUNCTION_INFO(C_Login)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_USER_TYPE      userType,  /* the user type */
+  CK_UTF8CHAR_PTR   pPin,      /* the user's PIN */
+  CK_ULONG          ulPinLen   /* the length of the PIN */
+);
+#endif
+
+
+/* C_Logout logs a user out from a token. */
+CK_PKCS11_FUNCTION_INFO(C_Logout)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Object management */
+
+/* C_CreateObject creates a new object. */
+CK_PKCS11_FUNCTION_INFO(C_CreateObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,   /* the object's template */
+  CK_ULONG          ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phObject  /* gets new object's handle. */
+);
+#endif
+
+
+/* C_CopyObject copies an object, creating a new object for the
+ * copy. */
+CK_PKCS11_FUNCTION_INFO(C_CopyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_OBJECT_HANDLE     hObject,     /* the object's handle */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new object */
+  CK_ULONG             ulCount,     /* attributes in template */
+  CK_OBJECT_HANDLE_PTR phNewObject  /* receives handle of copy */
+);
+#endif
+
+
+/* C_DestroyObject destroys an object. */
+CK_PKCS11_FUNCTION_INFO(C_DestroyObject)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject    /* the object's handle */
+);
+#endif
+
+
+/* C_GetObjectSize gets the size of an object in bytes. */
+CK_PKCS11_FUNCTION_INFO(C_GetObjectSize)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,   /* the object's handle */
+  CK_ULONG_PTR      pulSize    /* receives size of object */
+);
+#endif
+
+
+/* C_GetAttributeValue obtains the value of one or more object
+ * attributes. */
+CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs; gets vals */
+  CK_ULONG          ulCount     /* attributes in template */
+);
+#endif
+
+
+/* C_SetAttributeValue modifies the value of one or more object
+ * attributes */
+CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_OBJECT_HANDLE  hObject,    /* the object's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* specifies attrs and values */
+  CK_ULONG          ulCount     /* attributes in template */
+);
+#endif
+
+
+/* C_FindObjectsInit initializes a search for token and session
+ * objects that match a template. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_ATTRIBUTE_PTR  pTemplate,  /* attribute values to match */
+  CK_ULONG          ulCount     /* attrs in search template */
+);
+#endif
+
+
+/* C_FindObjects continues a search for token and session
+ * objects that match a template, obtaining additional object
+ * handles. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjects)
+#ifdef CK_NEED_ARG_LIST
+(
+ CK_SESSION_HANDLE    hSession,          /* session's handle */
+ CK_OBJECT_HANDLE_PTR phObject,          /* gets obj. handles */
+ CK_ULONG             ulMaxObjectCount,  /* max handles to get */
+ CK_ULONG_PTR         pulObjectCount     /* actual # returned */
+);
+#endif
+
+
+/* C_FindObjectsFinal finishes a search for token and session
+ * objects. */
+CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Encryption and decryption */
+
+/* C_EncryptInit initializes an encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the encryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of encryption key */
+);
+#endif
+
+
+/* C_Encrypt encrypts single-part data. */
+CK_PKCS11_FUNCTION_INFO(C_Encrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pData,               /* the plaintext data */
+  CK_ULONG          ulDataLen,           /* bytes of plaintext */
+  CK_BYTE_PTR       pEncryptedData,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedDataLen  /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptUpdate continues a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pPart,              /* the plaintext data */
+  CK_ULONG          ulPartLen,          /* plaintext data len */
+  CK_BYTE_PTR       pEncryptedPart,     /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen /* gets c-text size */
+);
+#endif
+
+
+/* C_EncryptFinal finishes a multiple-part encryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_EncryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,                /* session handle */
+  CK_BYTE_PTR       pLastEncryptedPart,      /* last c-text */
+  CK_ULONG_PTR      pulLastEncryptedPartLen  /* gets last size */
+);
+#endif
+
+
+/* C_DecryptInit initializes a decryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the decryption mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of decryption key */
+);
+#endif
+
+
+/* C_Decrypt decrypts encrypted data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Decrypt)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,           /* session's handle */
+  CK_BYTE_PTR       pEncryptedData,     /* ciphertext */
+  CK_ULONG          ulEncryptedDataLen, /* ciphertext length */
+  CK_BYTE_PTR       pData,              /* gets plaintext */
+  CK_ULONG_PTR      pulDataLen          /* gets p-text size */
+);
+#endif
+
+
+/* C_DecryptUpdate continues a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* encrypted data */
+  CK_ULONG          ulEncryptedPartLen,  /* input length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* p-text size */
+);
+#endif
+
+
+/* C_DecryptFinal finishes a multiple-part decryption
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pLastPart,      /* gets plaintext */
+  CK_ULONG_PTR      pulLastPartLen  /* p-text size */
+);
+#endif
+
+
+
+/* Message digesting */
+
+/* C_DigestInit initializes a message-digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism  /* the digesting mechanism */
+);
+#endif
+
+
+/* C_Digest digests data in a single part. */
+CK_PKCS11_FUNCTION_INFO(C_Digest)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pData,        /* data to be digested */
+  CK_ULONG          ulDataLen,    /* bytes of data to digest */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets digest length */
+);
+#endif
+
+
+/* C_DigestUpdate continues a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* data to be digested */
+  CK_ULONG          ulPartLen  /* bytes of data to be digested */
+);
+#endif
+
+
+/* C_DigestKey continues a multi-part message-digesting
+ * operation, by digesting the value of a secret key as part of
+ * the data already digested. */
+CK_PKCS11_FUNCTION_INFO(C_DigestKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_OBJECT_HANDLE  hKey       /* secret key to digest */
+);
+#endif
+
+
+/* C_DigestFinal finishes a multiple-part message-digesting
+ * operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_BYTE_PTR       pDigest,      /* gets the message digest */
+  CK_ULONG_PTR      pulDigestLen  /* gets byte count of digest */
+);
+#endif
+
+
+
+/* Signing and MACing */
+
+/* C_SignInit initializes a signature (private key encryption)
+ * operation, where the signature is (will be) an appendix to
+ * the data, and plaintext cannot be recovered from the
+ *signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey         /* handle of signature key */
+);
+#endif
+
+
+/* C_Sign signs (encrypts with private key) data in a single
+ * part, where the signature is (will be) an appendix to the
+ * data, and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Sign)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+/* C_SignUpdate continues a multiple-part signature operation,
+ * where the signature is (will be) an appendix to the data, 
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* the data to sign */
+  CK_ULONG          ulPartLen  /* count of bytes to sign */
+);
+#endif
+
+
+/* C_SignFinal finishes a multiple-part signature operation, 
+ * returning the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+/* C_SignRecoverInit initializes a signature operation, where
+ * the data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,   /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism, /* the signature mechanism */
+  CK_OBJECT_HANDLE  hKey        /* handle of the signature key */
+);
+#endif
+
+
+/* C_SignRecover signs data in a single operation, where the
+ * data can be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_SignRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pData,           /* the data to sign */
+  CK_ULONG          ulDataLen,       /* count of bytes to sign */
+  CK_BYTE_PTR       pSignature,      /* gets the signature */
+  CK_ULONG_PTR      pulSignatureLen  /* gets signature length */
+);
+#endif
+
+
+
+/* Verifying signatures and MACs */
+
+/* C_VerifyInit initializes a verification operation, where the
+ * signature is an appendix to the data, and plaintext cannot
+ *  cannot be recovered from the signature (e.g. DSA). */
+CK_PKCS11_FUNCTION_INFO(C_VerifyInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */ 
+);
+#endif
+
+
+/* C_Verify verifies a signature in a single-part operation, 
+ * where the signature is an appendix to the data, and plaintext
+ * cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_Verify)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pData,          /* signed data */
+  CK_ULONG          ulDataLen,      /* length of signed data */
+  CK_BYTE_PTR       pSignature,     /* signature */
+  CK_ULONG          ulSignatureLen  /* signature length*/
+);
+#endif
+
+
+/* C_VerifyUpdate continues a multiple-part verification
+ * operation, where the signature is an appendix to the data, 
+ * and plaintext cannot be recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pPart,     /* signed data */
+  CK_ULONG          ulPartLen  /* length of signed data */
+);
+#endif
+
+
+/* C_VerifyFinal finishes a multiple-part verification
+ * operation, checking the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyFinal)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,       /* the session's handle */
+  CK_BYTE_PTR       pSignature,     /* signature to verify */
+  CK_ULONG          ulSignatureLen  /* signature length */
+);
+#endif
+
+
+/* C_VerifyRecoverInit initializes a signature verification
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,  /* the verification mechanism */
+  CK_OBJECT_HANDLE  hKey         /* verification key */
+);
+#endif
+
+
+/* C_VerifyRecover verifies a signature in a single-part
+ * operation, where the data is recovered from the signature. */
+CK_PKCS11_FUNCTION_INFO(C_VerifyRecover)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_BYTE_PTR       pSignature,      /* signature to verify */
+  CK_ULONG          ulSignatureLen,  /* signature length */
+  CK_BYTE_PTR       pData,           /* gets signed data */
+  CK_ULONG_PTR      pulDataLen       /* gets signed data len */
+);
+#endif
+
+
+
+/* Dual-function cryptographic operations */
+
+/* C_DigestEncryptUpdate continues a multiple-part digesting
+ * and encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptDigestUpdate continues a multiple-part decryption and
+ * digesting operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets plaintext len */
+);
+#endif
+
+
+/* C_SignEncryptUpdate continues a multiple-part signing and
+ * encryption operation. */
+CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pPart,               /* the plaintext data */
+  CK_ULONG          ulPartLen,           /* plaintext length */
+  CK_BYTE_PTR       pEncryptedPart,      /* gets ciphertext */
+  CK_ULONG_PTR      pulEncryptedPartLen  /* gets c-text length */
+);
+#endif
+
+
+/* C_DecryptVerifyUpdate continues a multiple-part decryption and
+ * verify operation. */
+CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,            /* session's handle */
+  CK_BYTE_PTR       pEncryptedPart,      /* ciphertext */
+  CK_ULONG          ulEncryptedPartLen,  /* ciphertext length */
+  CK_BYTE_PTR       pPart,               /* gets plaintext */
+  CK_ULONG_PTR      pulPartLen           /* gets p-text length */
+);
+#endif
+
+
+
+/* Key management */
+
+/* C_GenerateKey generates a secret key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,    /* the session's handle */
+  CK_MECHANISM_PTR     pMechanism,  /* key generation mech. */
+  CK_ATTRIBUTE_PTR     pTemplate,   /* template for new key */
+  CK_ULONG             ulCount,     /* # of attrs in template */
+  CK_OBJECT_HANDLE_PTR phKey        /* gets handle of new key */
+);
+#endif
+
+
+/* C_GenerateKeyPair generates a public-key/private-key pair, 
+ * creating new key objects. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,                    /* session
+                                                     * handle */
+  CK_MECHANISM_PTR     pMechanism,                  /* key-gen
+                                                     * mech. */
+  CK_ATTRIBUTE_PTR     pPublicKeyTemplate,          /* template
+                                                     * for pub.
+                                                     * key */
+  CK_ULONG             ulPublicKeyAttributeCount,   /* # pub.
+                                                     * attrs. */
+  CK_ATTRIBUTE_PTR     pPrivateKeyTemplate,         /* template
+                                                     * for priv.
+                                                     * key */
+  CK_ULONG             ulPrivateKeyAttributeCount,  /* # priv.
+                                                     * attrs. */
+  CK_OBJECT_HANDLE_PTR phPublicKey,                 /* gets pub.
+                                                     * key
+                                                     * handle */
+  CK_OBJECT_HANDLE_PTR phPrivateKey                 /* gets
+                                                     * priv. key
+                                                     * handle */
+);
+#endif
+
+
+/* C_WrapKey wraps (i.e., encrypts) a key. */
+CK_PKCS11_FUNCTION_INFO(C_WrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,        /* the session's handle */
+  CK_MECHANISM_PTR  pMechanism,      /* the wrapping mechanism */
+  CK_OBJECT_HANDLE  hWrappingKey,    /* wrapping key */
+  CK_OBJECT_HANDLE  hKey,            /* key to be wrapped */
+  CK_BYTE_PTR       pWrappedKey,     /* gets wrapped key */
+  CK_ULONG_PTR      pulWrappedKeyLen /* gets wrapped key size */
+);
+#endif
+
+
+/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new
+ * key object. */
+CK_PKCS11_FUNCTION_INFO(C_UnwrapKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* unwrapping mech. */
+  CK_OBJECT_HANDLE     hUnwrappingKey,    /* unwrapping key */
+  CK_BYTE_PTR          pWrappedKey,       /* the wrapped key */
+  CK_ULONG             ulWrappedKeyLen,   /* wrapped key len */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+);
+#endif
+
+
+/* C_DeriveKey derives a key from a base key, creating a new key
+ * object. */
+CK_PKCS11_FUNCTION_INFO(C_DeriveKey)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE    hSession,          /* session's handle */
+  CK_MECHANISM_PTR     pMechanism,        /* key deriv. mech. */
+  CK_OBJECT_HANDLE     hBaseKey,          /* base key */
+  CK_ATTRIBUTE_PTR     pTemplate,         /* new key template */
+  CK_ULONG             ulAttributeCount,  /* template length */
+  CK_OBJECT_HANDLE_PTR phKey              /* gets new handle */
+);
+#endif
+
+
+
+/* Random number generation */
+
+/* C_SeedRandom mixes additional seed material into the token's
+ * random number generator. */
+CK_PKCS11_FUNCTION_INFO(C_SeedRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,  /* the session's handle */
+  CK_BYTE_PTR       pSeed,     /* the seed material */
+  CK_ULONG          ulSeedLen  /* length of seed material */
+);
+#endif
+
+
+/* C_GenerateRandom generates random data. */
+CK_PKCS11_FUNCTION_INFO(C_GenerateRandom)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession,    /* the session's handle */
+  CK_BYTE_PTR       RandomData,  /* receives the random data */
+  CK_ULONG          ulRandomLen  /* # of bytes to generate */
+);
+#endif
+
+
+
+/* Parallel function management */
+
+/* C_GetFunctionStatus is a legacy function; it obtains an
+ * updated status of a function running in parallel with an
+ * application. */
+CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+/* C_CancelFunction is a legacy function; it cancels a function
+ * running in parallel. */
+CK_PKCS11_FUNCTION_INFO(C_CancelFunction)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_SESSION_HANDLE hSession  /* the session's handle */
+);
+#endif
+
+
+
+/* Functions added in for Cryptoki Version 2.01 or later */
+
+/* C_WaitForSlotEvent waits for a slot event (token insertion,
+ * removal, etc.) to occur. */
+CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent)
+#ifdef CK_NEED_ARG_LIST
+(
+  CK_FLAGS flags,        /* blocking/nonblocking flag */
+  CK_SLOT_ID_PTR pSlot,  /* location that receives the slot ID */
+  CK_VOID_PTR pRserved   /* reserved.  Should be NULL_PTR */
+);
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11t.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11t.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/pkcs11t.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1440 @@
+/* pkcs11t.h include file for PKCS #11. */
+/* $Revision: 1.4 $ */
+
+/* License to copy and use this software is granted provided that it is
+ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface
+ * (Cryptoki)" in all material mentioning or referencing this software.
+
+ * License is also granted to make and use derivative works provided that
+ * such works are identified as "derived from the RSA Security Inc. PKCS #11
+ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or 
+ * referencing the derived work.
+
+ * RSA Security Inc. makes no representations concerning either the 
+ * merchantability of this software or the suitability of this software for
+ * any particular purpose. It is provided "as is" without express or implied
+ * warranty of any kind.
+ */
+
+/* See top of pkcs11.h for information about the macros that
+ * must be defined and the structure-packing conventions that
+ * must be set before including this file. */
+
+#ifndef _PKCS11T_H_
+#define _PKCS11T_H_ 1
+
+#ifndef CK_DISABLE_TRUE_FALSE
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE !(FALSE)
+#endif
+#endif
+
+#define CK_TRUE 1
+#define CK_FALSE 0
+
+/* an unsigned 8-bit value */
+typedef unsigned char     CK_BYTE;
+
+/* an unsigned 8-bit character */
+typedef CK_BYTE           CK_CHAR;
+
+/* an 8-bit UTF-8 character */
+typedef CK_BYTE           CK_UTF8CHAR;
+
+/* a BYTE-sized Boolean flag */
+typedef CK_BYTE           CK_BBOOL;
+
+/* an unsigned value, at least 32 bits long */
+typedef unsigned long int CK_ULONG;
+
+/* a signed value, the same size as a CK_ULONG */
+/* CK_LONG is new for v2.0 */
+typedef long int          CK_LONG;
+
+/* at least 32 bits; each bit is a Boolean flag */
+typedef CK_ULONG          CK_FLAGS;
+
+
+/* some special values for certain CK_ULONG variables */
+#define CK_UNAVAILABLE_INFORMATION (~0UL)
+#define CK_EFFECTIVELY_INFINITE    0
+
+
+typedef CK_BYTE     CK_PTR   CK_BYTE_PTR;
+typedef CK_CHAR     CK_PTR   CK_CHAR_PTR;
+typedef CK_UTF8CHAR CK_PTR   CK_UTF8CHAR_PTR;
+typedef CK_ULONG    CK_PTR   CK_ULONG_PTR;
+typedef void        CK_PTR   CK_VOID_PTR;
+
+/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */
+typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR;
+
+
+/* The following value is always invalid if used as a session */
+/* handle or object handle */
+#define CK_INVALID_HANDLE 0
+
+
+typedef struct CK_VERSION {
+  CK_BYTE       major;  /* integer portion of version number */
+  CK_BYTE       minor;  /* 1/100ths portion of version number */
+} CK_VERSION;
+
+typedef CK_VERSION CK_PTR CK_VERSION_PTR;
+
+
+typedef struct CK_INFO {
+  /* manufacturerID and libraryDecription have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_VERSION    cryptokiVersion;     /* Cryptoki interface ver */
+  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
+  CK_FLAGS      flags;               /* must be zero */
+
+  /* libraryDescription and libraryVersion are new for v2.0 */
+  CK_UTF8CHAR   libraryDescription[32];  /* blank padded */
+  CK_VERSION    libraryVersion;          /* version of library */
+} CK_INFO;
+
+typedef CK_INFO CK_PTR    CK_INFO_PTR;
+
+
+/* CK_NOTIFICATION enumerates the types of notifications that
+ * Cryptoki provides to an application */
+/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG CK_NOTIFICATION;
+#define CKN_SURRENDER       0
+
+
+typedef CK_ULONG          CK_SLOT_ID;
+
+typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR;
+
+
+/* CK_SLOT_INFO provides information about a slot */
+typedef struct CK_SLOT_INFO {
+  /* slotDescription and manufacturerID have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_UTF8CHAR   slotDescription[64];  /* blank padded */
+  CK_UTF8CHAR   manufacturerID[32];   /* blank padded */
+  CK_FLAGS      flags;
+
+  /* hardwareVersion and firmwareVersion are new for v2.0 */
+  CK_VERSION    hardwareVersion;  /* version of hardware */
+  CK_VERSION    firmwareVersion;  /* version of firmware */
+} CK_SLOT_INFO;
+
+/* flags: bit flags that provide capabilities of the slot
+ *      Bit Flag              Mask        Meaning
+ */
+#define CKF_TOKEN_PRESENT     0x00000001  /* a token is there */
+#define CKF_REMOVABLE_DEVICE  0x00000002  /* removable devices*/
+#define CKF_HW_SLOT           0x00000004  /* hardware slot */
+
+typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR;
+
+
+/* CK_TOKEN_INFO provides information about a token */
+typedef struct CK_TOKEN_INFO {
+  /* label, manufacturerID, and model have been changed from
+   * CK_CHAR to CK_UTF8CHAR for v2.10 */
+  CK_UTF8CHAR   label[32];           /* blank padded */
+  CK_UTF8CHAR   manufacturerID[32];  /* blank padded */
+  CK_UTF8CHAR   model[16];           /* blank padded */
+  CK_CHAR       serialNumber[16];    /* blank padded */
+  CK_FLAGS      flags;               /* see below */
+
+  /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount,
+   * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been
+   * changed from CK_USHORT to CK_ULONG for v2.0 */
+  CK_ULONG      ulMaxSessionCount;     /* max open sessions */
+  CK_ULONG      ulSessionCount;        /* sess. now open */
+  CK_ULONG      ulMaxRwSessionCount;   /* max R/W sessions */
+  CK_ULONG      ulRwSessionCount;      /* R/W sess. now open */
+  CK_ULONG      ulMaxPinLen;           /* in bytes */
+  CK_ULONG      ulMinPinLen;           /* in bytes */
+  CK_ULONG      ulTotalPublicMemory;   /* in bytes */
+  CK_ULONG      ulFreePublicMemory;    /* in bytes */
+  CK_ULONG      ulTotalPrivateMemory;  /* in bytes */
+  CK_ULONG      ulFreePrivateMemory;   /* in bytes */
+
+  /* hardwareVersion, firmwareVersion, and time are new for
+   * v2.0 */
+  CK_VERSION    hardwareVersion;       /* version of hardware */
+  CK_VERSION    firmwareVersion;       /* version of firmware */
+  CK_CHAR       utcTime[16];           /* time */
+} CK_TOKEN_INFO;
+
+/* The flags parameter is defined as follows:
+ *      Bit Flag                    Mask        Meaning 
+ */
+#define CKF_RNG                     0x00000001  /* has random #
+                                                 * generator */
+#define CKF_WRITE_PROTECTED         0x00000002  /* token is
+                                                 * write-
+                                                 * protected */
+#define CKF_LOGIN_REQUIRED          0x00000004  /* user must
+                                                 * login */
+#define CKF_USER_PIN_INITIALIZED    0x00000008  /* normal user's
+                                                 * PIN is set */
+
+/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0.  If it is set,
+ * that means that *every* time the state of cryptographic
+ * operations of a session is successfully saved, all keys
+ * needed to continue those operations are stored in the state */
+#define CKF_RESTORE_KEY_NOT_NEEDED  0x00000020
+
+/* CKF_CLOCK_ON_TOKEN is new for v2.0.  If it is set, that means
+ * that the token has some sort of clock.  The time on that
+ * clock is returned in the token info structure */
+#define CKF_CLOCK_ON_TOKEN          0x00000040
+
+/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0.  If it is
+ * set, that means that there is some way for the user to login
+ * without sending a PIN through the Cryptoki library itself */
+#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100
+
+/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0.  If it is true,
+ * that means that a single session with the token can perform
+ * dual simultaneous cryptographic operations (digest and
+ * encrypt; decrypt and digest; sign and encrypt; and decrypt
+ * and sign) */
+#define CKF_DUAL_CRYPTO_OPERATIONS  0x00000200
+
+/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the
+ * token has been initialized using C_InitializeToken or an 
+ * equivalent mechanism outside the scope of PKCS #11.
+ * Calling C_InitializeToken when this flag is set will cause 
+ * the token to be reinitialized. */
+#define CKF_TOKEN_INITIALIZED       0x00000400
+
+/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is 
+ * true, the token supports secondary authentication for 
+ * private key objects. */
+#define CKF_SECONDARY_AUTHENTICATION  0x00000800
+
+/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an 
+ * incorrect user login PIN has been entered at least once 
+ * since the last successful authentication. */
+#define CKF_USER_PIN_COUNT_LOW       0x00010000
+
+/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect user PIN will it to become locked. */
+#define CKF_USER_PIN_FINAL_TRY       0x00020000
+
+/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the 
+ * user PIN has been locked. User login to the token is not 
+ * possible. */
+#define CKF_USER_PIN_LOCKED          0x00040000
+
+/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true, 
+ * the user PIN value is the default value set by token 
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_USER_PIN_TO_BE_CHANGED   0x00080000
+
+/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an 
+ * incorrect SO login PIN has been entered at least once since 
+ * the last successful authentication. */
+#define CKF_SO_PIN_COUNT_LOW         0x00100000
+
+/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true,
+ * supplying an incorrect SO PIN will it to become locked. */
+#define CKF_SO_PIN_FINAL_TRY         0x00200000
+
+/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO 
+ * PIN has been locked. SO login to the token is not possible.
+ */
+#define CKF_SO_PIN_LOCKED            0x00400000
+
+/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true, 
+ * the SO PIN value is the default value set by token 
+ * initialization or manufacturing, or the PIN has been
+ * expired by the card. */
+#define CKF_SO_PIN_TO_BE_CHANGED     0x00800000
+
+typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR;
+
+
+/* CK_SESSION_HANDLE is a Cryptoki-assigned value that
+ * identifies a session */
+typedef CK_ULONG          CK_SESSION_HANDLE;
+
+typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR; 
+
+
+/* CK_USER_TYPE enumerates the types of Cryptoki users */
+/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_USER_TYPE;
+/* Security Officer */
+#define CKU_SO    0
+/* Normal user */
+#define CKU_USER  1
+
+
+/* CK_STATE enumerates the session states */
+/* CK_STATE has been changed from an enum to a CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_STATE;
+#define CKS_RO_PUBLIC_SESSION  0
+#define CKS_RO_USER_FUNCTIONS  1
+#define CKS_RW_PUBLIC_SESSION  2
+#define CKS_RW_USER_FUNCTIONS  3
+#define CKS_RW_SO_FUNCTIONS    4
+
+
+/* CK_SESSION_INFO provides information about a session */
+typedef struct CK_SESSION_INFO {
+  CK_SLOT_ID    slotID;
+  CK_STATE      state;
+  CK_FLAGS      flags;          /* see below */
+
+  /* ulDeviceError was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG      ulDeviceError;  /* device-dependent error code */
+} CK_SESSION_INFO;
+
+/* The flags are defined in the following table:
+ *      Bit Flag                Mask        Meaning
+ */
+#define CKF_RW_SESSION          0x00000002  /* session is r/w */
+#define CKF_SERIAL_SESSION      0x00000004  /* no parallel */
+
+typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR;
+
+
+/* CK_OBJECT_HANDLE is a token-specific identifier for an
+ * object  */
+typedef CK_ULONG          CK_OBJECT_HANDLE;
+
+typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR;
+
+
+/* CK_OBJECT_CLASS is a value that identifies the classes (or
+ * types) of objects that Cryptoki recognizes.  It is defined
+ * as follows: */
+/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_OBJECT_CLASS;
+
+/* The following classes of objects are defined: */
+/* CKO_HW_FEATURE is new for v2.10 */
+/* CKO_DOMAIN_PARAMETERS is new for v2.11 */
+#define CKO_DATA              0x00000000
+#define CKO_CERTIFICATE       0x00000001
+#define CKO_PUBLIC_KEY        0x00000002
+#define CKO_PRIVATE_KEY       0x00000003
+#define CKO_SECRET_KEY        0x00000004
+#define CKO_HW_FEATURE        0x00000005
+#define CKO_DOMAIN_PARAMETERS 0x00000006
+#define CKO_VENDOR_DEFINED    0x80000000
+
+typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR;
+
+/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a
+ * value that identifies the hardware feature type of an object
+ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */
+typedef CK_ULONG          CK_HW_FEATURE_TYPE;
+ 
+/* The following hardware feature types are defined */
+#define CKH_MONOTONIC_COUNTER  0x00000001
+#define CKH_CLOCK           0x00000002
+#define CKH_VENDOR_DEFINED  0x80000000
+
+/* CK_KEY_TYPE is a value that identifies a key type */
+/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG          CK_KEY_TYPE;
+
+/* the following key types are defined: */
+#define CKK_RSA             0x00000000
+#define CKK_DSA             0x00000001
+#define CKK_DH              0x00000002
+
+/* CKK_ECDSA and CKK_KEA are new for v2.0 */
+/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */
+#define CKK_ECDSA           0x00000003
+#define CKK_EC              0x00000003
+#define CKK_X9_42_DH        0x00000004
+#define CKK_KEA             0x00000005
+
+#define CKK_GENERIC_SECRET  0x00000010
+#define CKK_RC2             0x00000011
+#define CKK_RC4             0x00000012
+#define CKK_DES             0x00000013
+#define CKK_DES2            0x00000014
+#define CKK_DES3            0x00000015
+
+/* all these key types are new for v2.0 */
+#define CKK_CAST            0x00000016
+#define CKK_CAST3           0x00000017
+/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */
+#define CKK_CAST5           0x00000018
+#define CKK_CAST128         0x00000018
+#define CKK_RC5             0x00000019
+#define CKK_IDEA            0x0000001A
+#define CKK_SKIPJACK        0x0000001B
+#define CKK_BATON           0x0000001C
+#define CKK_JUNIPER         0x0000001D
+#define CKK_CDMF            0x0000001E
+#define CKK_AES             0x0000001F
+
+#define CKK_VENDOR_DEFINED  0x80000000
+
+
+/* CK_CERTIFICATE_TYPE is a value that identifies a certificate
+ * type */
+/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG
+ * for v2.0 */
+typedef CK_ULONG          CK_CERTIFICATE_TYPE;
+
+/* The following certificate types are defined: */
+/* CKC_X_509_ATTR_CERT is new for v2.10 */
+#define CKC_X_509           0x00000000
+#define CKC_X_509_ATTR_CERT 0x00000001
+#define CKC_VENDOR_DEFINED  0x80000000
+
+
+/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute
+ * type */
+/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_ATTRIBUTE_TYPE;
+
+/* The following attribute types are defined: */
+#define CKA_CLASS              0x00000000
+#define CKA_TOKEN              0x00000001
+#define CKA_PRIVATE            0x00000002
+#define CKA_LABEL              0x00000003
+#define CKA_APPLICATION        0x00000010
+#define CKA_VALUE              0x00000011
+
+/* CKA_OBJECT_ID is new for v2.10 */
+#define CKA_OBJECT_ID          0x00000012
+
+#define CKA_CERTIFICATE_TYPE   0x00000080
+#define CKA_ISSUER             0x00000081
+#define CKA_SERIAL_NUMBER      0x00000082
+
+/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new 
+ * for v2.10 */
+#define CKA_AC_ISSUER          0x00000083
+#define CKA_OWNER              0x00000084
+#define CKA_ATTR_TYPES         0x00000085
+
+/* CKA_TRUSTED is new for v2.11 */
+#define CKA_TRUSTED            0x00000086
+
+#define CKA_KEY_TYPE           0x00000100
+#define CKA_SUBJECT            0x00000101
+#define CKA_ID                 0x00000102
+#define CKA_SENSITIVE          0x00000103
+#define CKA_ENCRYPT            0x00000104
+#define CKA_DECRYPT            0x00000105
+#define CKA_WRAP               0x00000106
+#define CKA_UNWRAP             0x00000107
+#define CKA_SIGN               0x00000108
+#define CKA_SIGN_RECOVER       0x00000109
+#define CKA_VERIFY             0x0000010A
+#define CKA_VERIFY_RECOVER     0x0000010B
+#define CKA_DERIVE             0x0000010C
+#define CKA_START_DATE         0x00000110
+#define CKA_END_DATE           0x00000111
+#define CKA_MODULUS            0x00000120
+#define CKA_MODULUS_BITS       0x00000121
+#define CKA_PUBLIC_EXPONENT    0x00000122
+#define CKA_PRIVATE_EXPONENT   0x00000123
+#define CKA_PRIME_1            0x00000124
+#define CKA_PRIME_2            0x00000125
+#define CKA_EXPONENT_1         0x00000126
+#define CKA_EXPONENT_2         0x00000127
+#define CKA_COEFFICIENT        0x00000128
+#define CKA_PRIME              0x00000130
+#define CKA_SUBPRIME           0x00000131
+#define CKA_BASE               0x00000132
+
+/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */
+#define CKA_PRIME_BITS         0x00000133
+#define CKA_SUBPRIME_BITS      0x00000134 
+#define CKA_SUB_PRIME_BITS     CKA_SUBPRIME_BITS 
+/* (To retain backwards-compatibility) */
+
+#define CKA_VALUE_BITS         0x00000160
+#define CKA_VALUE_LEN          0x00000161
+
+/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE,
+ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS,
+ * and CKA_EC_POINT are new for v2.0 */
+#define CKA_EXTRACTABLE        0x00000162
+#define CKA_LOCAL              0x00000163
+#define CKA_NEVER_EXTRACTABLE  0x00000164
+#define CKA_ALWAYS_SENSITIVE   0x00000165
+
+/* CKA_KEY_GEN_MECHANISM is new for v2.11 */
+#define CKA_KEY_GEN_MECHANISM  0x00000166
+
+#define CKA_MODIFIABLE         0x00000170
+
+/* CKA_ECDSA_PARAMS is deprecated in v2.11,
+ * CKA_EC_PARAMS is preferred. */
+#define CKA_ECDSA_PARAMS       0x00000180
+#define CKA_EC_PARAMS          0x00000180
+
+#define CKA_EC_POINT           0x00000181
+
+/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, 
+ * CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET
+ * are new for v2.10 */
+#define CKA_SECONDARY_AUTH     0x00000200
+#define CKA_AUTH_PIN_FLAGS     0x00000201
+#define CKA_HW_FEATURE_TYPE    0x00000300
+#define CKA_RESET_ON_INIT      0x00000301
+#define CKA_HAS_RESET          0x00000302
+
+#define CKA_VENDOR_DEFINED     0x80000000
+
+
+/* CK_ATTRIBUTE is a structure that includes the type, length
+ * and value of an attribute */
+typedef struct CK_ATTRIBUTE {
+  CK_ATTRIBUTE_TYPE type;
+  CK_VOID_PTR       pValue;
+
+  /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */
+  CK_ULONG          ulValueLen;  /* in bytes */
+} CK_ATTRIBUTE;
+
+typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR;
+
+
+/* CK_DATE is a structure that defines a date */
+typedef struct CK_DATE{
+  CK_CHAR       year[4];   /* the year ("1900" - "9999") */
+  CK_CHAR       month[2];  /* the month ("01" - "12") */
+  CK_CHAR       day[2];    /* the day   ("01" - "31") */
+} CK_DATE;
+
+
+/* CK_MECHANISM_TYPE is a value that identifies a mechanism
+ * type */
+/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for
+ * v2.0 */
+typedef CK_ULONG          CK_MECHANISM_TYPE;
+
+/* the following mechanism types are defined: */
+#define CKM_RSA_PKCS_KEY_PAIR_GEN      0x00000000
+#define CKM_RSA_PKCS                   0x00000001
+#define CKM_RSA_9796                   0x00000002
+#define CKM_RSA_X_509                  0x00000003
+
+/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS
+ * are new for v2.0.  They are mechanisms which hash and sign */
+#define CKM_MD2_RSA_PKCS               0x00000004
+#define CKM_MD5_RSA_PKCS               0x00000005
+#define CKM_SHA1_RSA_PKCS              0x00000006
+
+/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and
+ * CKM_RSA_PKCS_OAEP are new for v2.10 */
+#define CKM_RIPEMD128_RSA_PKCS         0x00000007
+#define CKM_RIPEMD160_RSA_PKCS         0x00000008
+#define CKM_RSA_PKCS_OAEP              0x00000009
+
+/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31,
+ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */
+#define CKM_RSA_X9_31_KEY_PAIR_GEN     0x0000000A
+#define CKM_RSA_X9_31                  0x0000000B
+#define CKM_SHA1_RSA_X9_31             0x0000000C
+#define CKM_RSA_PKCS_PSS               0x0000000D
+#define CKM_SHA1_RSA_PKCS_PSS          0x0000000E
+
+#define CKM_DSA_KEY_PAIR_GEN           0x00000010
+#define CKM_DSA                        0x00000011
+#define CKM_DSA_SHA1                   0x00000012
+#define CKM_DH_PKCS_KEY_PAIR_GEN       0x00000020
+#define CKM_DH_PKCS_DERIVE             0x00000021
+
+/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE,
+ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for
+ * v2.11 */
+#define CKM_X9_42_DH_KEY_PAIR_GEN      0x00000030
+#define CKM_X9_42_DH_DERIVE            0x00000031
+#define CKM_X9_42_DH_HYBRID_DERIVE     0x00000032
+#define CKM_X9_42_MQV_DERIVE           0x00000033
+
+#define CKM_RC2_KEY_GEN                0x00000100
+#define CKM_RC2_ECB                    0x00000101
+#define CKM_RC2_CBC                    0x00000102
+#define CKM_RC2_MAC                    0x00000103
+
+/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */
+#define CKM_RC2_MAC_GENERAL            0x00000104
+#define CKM_RC2_CBC_PAD                0x00000105
+
+#define CKM_RC4_KEY_GEN                0x00000110
+#define CKM_RC4                        0x00000111
+#define CKM_DES_KEY_GEN                0x00000120
+#define CKM_DES_ECB                    0x00000121
+#define CKM_DES_CBC                    0x00000122
+#define CKM_DES_MAC                    0x00000123
+
+/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */
+#define CKM_DES_MAC_GENERAL            0x00000124
+#define CKM_DES_CBC_PAD                0x00000125
+
+#define CKM_DES2_KEY_GEN               0x00000130
+#define CKM_DES3_KEY_GEN               0x00000131
+#define CKM_DES3_ECB                   0x00000132
+#define CKM_DES3_CBC                   0x00000133
+#define CKM_DES3_MAC                   0x00000134
+
+/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN,
+ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC,
+ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0 */
+#define CKM_DES3_MAC_GENERAL           0x00000135
+#define CKM_DES3_CBC_PAD               0x00000136
+#define CKM_CDMF_KEY_GEN               0x00000140
+#define CKM_CDMF_ECB                   0x00000141
+#define CKM_CDMF_CBC                   0x00000142
+#define CKM_CDMF_MAC                   0x00000143
+#define CKM_CDMF_MAC_GENERAL           0x00000144
+#define CKM_CDMF_CBC_PAD               0x00000145
+
+#define CKM_MD2                        0x00000200
+
+/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD2_HMAC                   0x00000201
+#define CKM_MD2_HMAC_GENERAL           0x00000202
+
+#define CKM_MD5                        0x00000210
+
+/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */
+#define CKM_MD5_HMAC                   0x00000211
+#define CKM_MD5_HMAC_GENERAL           0x00000212
+
+#define CKM_SHA_1                      0x00000220
+
+/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */
+#define CKM_SHA_1_HMAC                 0x00000221
+#define CKM_SHA_1_HMAC_GENERAL         0x00000222
+
+/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC, 
+ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC,
+ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */
+#define CKM_RIPEMD128                  0x00000230
+#define CKM_RIPEMD128_HMAC             0x00000231
+#define CKM_RIPEMD128_HMAC_GENERAL     0x00000232
+#define CKM_RIPEMD160                  0x00000240
+#define CKM_RIPEMD160_HMAC             0x00000241
+#define CKM_RIPEMD160_HMAC_GENERAL     0x00000242
+
+/* All of the following mechanisms are new for v2.0 */
+/* Note that CAST128 and CAST5 are the same algorithm */
+#define CKM_CAST_KEY_GEN               0x00000300
+#define CKM_CAST_ECB                   0x00000301
+#define CKM_CAST_CBC                   0x00000302
+#define CKM_CAST_MAC                   0x00000303
+#define CKM_CAST_MAC_GENERAL           0x00000304
+#define CKM_CAST_CBC_PAD               0x00000305
+#define CKM_CAST3_KEY_GEN              0x00000310
+#define CKM_CAST3_ECB                  0x00000311
+#define CKM_CAST3_CBC                  0x00000312
+#define CKM_CAST3_MAC                  0x00000313
+#define CKM_CAST3_MAC_GENERAL          0x00000314
+#define CKM_CAST3_CBC_PAD              0x00000315
+#define CKM_CAST5_KEY_GEN              0x00000320
+#define CKM_CAST128_KEY_GEN            0x00000320
+#define CKM_CAST5_ECB                  0x00000321
+#define CKM_CAST128_ECB                0x00000321
+#define CKM_CAST5_CBC                  0x00000322
+#define CKM_CAST128_CBC                0x00000322
+#define CKM_CAST5_MAC                  0x00000323
+#define CKM_CAST128_MAC                0x00000323
+#define CKM_CAST5_MAC_GENERAL          0x00000324
+#define CKM_CAST128_MAC_GENERAL        0x00000324
+#define CKM_CAST5_CBC_PAD              0x00000325
+#define CKM_CAST128_CBC_PAD            0x00000325
+#define CKM_RC5_KEY_GEN                0x00000330
+#define CKM_RC5_ECB                    0x00000331
+#define CKM_RC5_CBC                    0x00000332
+#define CKM_RC5_MAC                    0x00000333
+#define CKM_RC5_MAC_GENERAL            0x00000334
+#define CKM_RC5_CBC_PAD                0x00000335
+#define CKM_IDEA_KEY_GEN               0x00000340
+#define CKM_IDEA_ECB                   0x00000341
+#define CKM_IDEA_CBC                   0x00000342
+#define CKM_IDEA_MAC                   0x00000343
+#define CKM_IDEA_MAC_GENERAL           0x00000344
+#define CKM_IDEA_CBC_PAD               0x00000345
+#define CKM_GENERIC_SECRET_KEY_GEN     0x00000350
+#define CKM_CONCATENATE_BASE_AND_KEY   0x00000360
+#define CKM_CONCATENATE_BASE_AND_DATA  0x00000362
+#define CKM_CONCATENATE_DATA_AND_BASE  0x00000363
+#define CKM_XOR_BASE_AND_DATA          0x00000364
+#define CKM_EXTRACT_KEY_FROM_KEY       0x00000365
+#define CKM_SSL3_PRE_MASTER_KEY_GEN    0x00000370
+#define CKM_SSL3_MASTER_KEY_DERIVE     0x00000371
+#define CKM_SSL3_KEY_AND_MAC_DERIVE    0x00000372
+
+/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN,
+ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and
+ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */
+#define CKM_SSL3_MASTER_KEY_DERIVE_DH  0x00000373
+#define CKM_TLS_PRE_MASTER_KEY_GEN     0x00000374
+#define CKM_TLS_MASTER_KEY_DERIVE      0x00000375
+#define CKM_TLS_KEY_AND_MAC_DERIVE     0x00000376
+#define CKM_TLS_MASTER_KEY_DERIVE_DH   0x00000377
+
+#define CKM_SSL3_MD5_MAC               0x00000380
+#define CKM_SSL3_SHA1_MAC              0x00000381
+#define CKM_MD5_KEY_DERIVATION         0x00000390
+#define CKM_MD2_KEY_DERIVATION         0x00000391
+#define CKM_SHA1_KEY_DERIVATION        0x00000392
+#define CKM_PBE_MD2_DES_CBC            0x000003A0
+#define CKM_PBE_MD5_DES_CBC            0x000003A1
+#define CKM_PBE_MD5_CAST_CBC           0x000003A2
+#define CKM_PBE_MD5_CAST3_CBC          0x000003A3
+#define CKM_PBE_MD5_CAST5_CBC          0x000003A4
+#define CKM_PBE_MD5_CAST128_CBC        0x000003A4
+#define CKM_PBE_SHA1_CAST5_CBC         0x000003A5
+#define CKM_PBE_SHA1_CAST128_CBC       0x000003A5
+#define CKM_PBE_SHA1_RC4_128           0x000003A6
+#define CKM_PBE_SHA1_RC4_40            0x000003A7
+#define CKM_PBE_SHA1_DES3_EDE_CBC      0x000003A8
+#define CKM_PBE_SHA1_DES2_EDE_CBC      0x000003A9
+#define CKM_PBE_SHA1_RC2_128_CBC       0x000003AA
+#define CKM_PBE_SHA1_RC2_40_CBC        0x000003AB
+
+/* CKM_PKCS5_PBKD2 is new for v2.10 */
+#define CKM_PKCS5_PBKD2                0x000003B0
+
+#define CKM_PBA_SHA1_WITH_SHA1_HMAC    0x000003C0
+#define CKM_KEY_WRAP_LYNKS             0x00000400
+#define CKM_KEY_WRAP_SET_OAEP          0x00000401
+
+/* Fortezza mechanisms */
+#define CKM_SKIPJACK_KEY_GEN           0x00001000
+#define CKM_SKIPJACK_ECB64             0x00001001
+#define CKM_SKIPJACK_CBC64             0x00001002
+#define CKM_SKIPJACK_OFB64             0x00001003
+#define CKM_SKIPJACK_CFB64             0x00001004
+#define CKM_SKIPJACK_CFB32             0x00001005
+#define CKM_SKIPJACK_CFB16             0x00001006
+#define CKM_SKIPJACK_CFB8              0x00001007
+#define CKM_SKIPJACK_WRAP              0x00001008
+#define CKM_SKIPJACK_PRIVATE_WRAP      0x00001009
+#define CKM_SKIPJACK_RELAYX            0x0000100a
+#define CKM_KEA_KEY_PAIR_GEN           0x00001010
+#define CKM_KEA_KEY_DERIVE             0x00001011
+#define CKM_FORTEZZA_TIMESTAMP         0x00001020
+#define CKM_BATON_KEY_GEN              0x00001030
+#define CKM_BATON_ECB128               0x00001031
+#define CKM_BATON_ECB96                0x00001032
+#define CKM_BATON_CBC128               0x00001033
+#define CKM_BATON_COUNTER              0x00001034
+#define CKM_BATON_SHUFFLE              0x00001035
+#define CKM_BATON_WRAP                 0x00001036
+
+/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11,
+ * CKM_EC_KEY_PAIR_GEN is preferred */
+#define CKM_ECDSA_KEY_PAIR_GEN         0x00001040
+#define CKM_EC_KEY_PAIR_GEN            0x00001040
+
+#define CKM_ECDSA                      0x00001041
+#define CKM_ECDSA_SHA1                 0x00001042
+
+/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE
+ * are new for v2.11 */
+#define CKM_ECDH1_DERIVE               0x00001050
+#define CKM_ECDH1_COFACTOR_DERIVE      0x00001051
+#define CKM_ECMQV_DERIVE               0x00001052
+
+#define CKM_JUNIPER_KEY_GEN            0x00001060
+#define CKM_JUNIPER_ECB128             0x00001061
+#define CKM_JUNIPER_CBC128             0x00001062
+#define CKM_JUNIPER_COUNTER            0x00001063
+#define CKM_JUNIPER_SHUFFLE            0x00001064
+#define CKM_JUNIPER_WRAP               0x00001065
+#define CKM_FASTHASH                   0x00001070
+
+/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC,
+ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN,
+ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are
+ * new for v2.11 */
+#define CKM_AES_KEY_GEN                0x00001080
+#define CKM_AES_ECB                    0x00001081
+#define CKM_AES_CBC                    0x00001082
+#define CKM_AES_MAC                    0x00001083
+#define CKM_AES_MAC_GENERAL            0x00001084
+#define CKM_AES_CBC_PAD                0x00001085
+#define CKM_DSA_PARAMETER_GEN          0x00002000
+#define CKM_DH_PKCS_PARAMETER_GEN      0x00002001
+#define CKM_X9_42_DH_PARAMETER_GEN     0x00002002
+
+#define CKM_VENDOR_DEFINED             0x80000000
+
+typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR;
+
+
+/* CK_MECHANISM is a structure that specifies a particular
+ * mechanism  */
+typedef struct CK_MECHANISM {
+  CK_MECHANISM_TYPE mechanism;
+  CK_VOID_PTR       pParameter;
+
+  /* ulParameterLen was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG          ulParameterLen;  /* in bytes */
+} CK_MECHANISM;
+
+typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR;
+
+
+/* CK_MECHANISM_INFO provides information about a particular
+ * mechanism */
+typedef struct CK_MECHANISM_INFO {
+    CK_ULONG    ulMinKeySize;
+    CK_ULONG    ulMaxKeySize;
+    CK_FLAGS    flags;
+} CK_MECHANISM_INFO;
+
+/* The flags are defined as follows:
+ *      Bit Flag               Mask        Meaning */
+#define CKF_HW                 0x00000001  /* performed by HW */
+
+/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN,
+ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER,
+ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP,
+ * and CKF_DERIVE are new for v2.0.  They specify whether or not
+ * a mechanism can be used for a particular task */
+#define CKF_ENCRYPT            0x00000100
+#define CKF_DECRYPT            0x00000200
+#define CKF_DIGEST             0x00000400
+#define CKF_SIGN               0x00000800
+#define CKF_SIGN_RECOVER       0x00001000
+#define CKF_VERIFY             0x00002000
+#define CKF_VERIFY_RECOVER     0x00004000
+#define CKF_GENERATE           0x00008000
+#define CKF_GENERATE_KEY_PAIR  0x00010000
+#define CKF_WRAP               0x00020000
+#define CKF_UNWRAP             0x00040000
+#define CKF_DERIVE             0x00080000
+
+/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE,
+ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They
+ * describe a token's EC capabilities not available in mechanism
+ * information. */
+#define CKF_EC_F_P	           0x00100000
+#define CKF_EC_F_2M	           0x00200000
+#define CKF_EC_ECPARAMETERS	   0x00400000
+#define CKF_EC_NAMEDCURVE	   0x00800000
+#define CKF_EC_UNCOMPRESS	   0x01000000
+#define CKF_EC_COMPRESS	       0x02000000
+
+#define CKF_EXTENSION          0x80000000  /* FALSE for 2.01 */
+
+typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR;
+
+
+/* CK_RV is a value that identifies the return value of a
+ * Cryptoki function */
+/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */
+typedef CK_ULONG          CK_RV;
+
+#define CKR_OK                                0x00000000
+#define CKR_CANCEL                            0x00000001
+#define CKR_HOST_MEMORY                       0x00000002
+#define CKR_SLOT_ID_INVALID                   0x00000003
+
+/* CKR_FLAGS_INVALID was removed for v2.0 */
+
+/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */
+#define CKR_GENERAL_ERROR                     0x00000005
+#define CKR_FUNCTION_FAILED                   0x00000006
+
+/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS,
+ * and CKR_CANT_LOCK are new for v2.01 */
+#define CKR_ARGUMENTS_BAD                     0x00000007
+#define CKR_NO_EVENT                          0x00000008
+#define CKR_NEED_TO_CREATE_THREADS            0x00000009
+#define CKR_CANT_LOCK                         0x0000000A
+
+#define CKR_ATTRIBUTE_READ_ONLY               0x00000010
+#define CKR_ATTRIBUTE_SENSITIVE               0x00000011
+#define CKR_ATTRIBUTE_TYPE_INVALID            0x00000012
+#define CKR_ATTRIBUTE_VALUE_INVALID           0x00000013
+#define CKR_DATA_INVALID                      0x00000020
+#define CKR_DATA_LEN_RANGE                    0x00000021
+#define CKR_DEVICE_ERROR                      0x00000030
+#define CKR_DEVICE_MEMORY                     0x00000031
+#define CKR_DEVICE_REMOVED                    0x00000032
+#define CKR_ENCRYPTED_DATA_INVALID            0x00000040
+#define CKR_ENCRYPTED_DATA_LEN_RANGE          0x00000041
+#define CKR_FUNCTION_CANCELED                 0x00000050
+#define CKR_FUNCTION_NOT_PARALLEL             0x00000051
+
+/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */
+#define CKR_FUNCTION_NOT_SUPPORTED            0x00000054
+
+#define CKR_KEY_HANDLE_INVALID                0x00000060
+
+/* CKR_KEY_SENSITIVE was removed for v2.0 */
+
+#define CKR_KEY_SIZE_RANGE                    0x00000062
+#define CKR_KEY_TYPE_INCONSISTENT             0x00000063
+
+/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED,
+ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED,
+ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for
+ * v2.0 */
+#define CKR_KEY_NOT_NEEDED                    0x00000064
+#define CKR_KEY_CHANGED                       0x00000065
+#define CKR_KEY_NEEDED                        0x00000066
+#define CKR_KEY_INDIGESTIBLE                  0x00000067
+#define CKR_KEY_FUNCTION_NOT_PERMITTED        0x00000068
+#define CKR_KEY_NOT_WRAPPABLE                 0x00000069
+#define CKR_KEY_UNEXTRACTABLE                 0x0000006A
+
+#define CKR_MECHANISM_INVALID                 0x00000070
+#define CKR_MECHANISM_PARAM_INVALID           0x00000071
+
+/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID
+ * were removed for v2.0 */
+#define CKR_OBJECT_HANDLE_INVALID             0x00000082
+#define CKR_OPERATION_ACTIVE                  0x00000090
+#define CKR_OPERATION_NOT_INITIALIZED         0x00000091
+#define CKR_PIN_INCORRECT                     0x000000A0
+#define CKR_PIN_INVALID                       0x000000A1
+#define CKR_PIN_LEN_RANGE                     0x000000A2
+
+/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */
+#define CKR_PIN_EXPIRED                       0x000000A3
+#define CKR_PIN_LOCKED                        0x000000A4
+
+#define CKR_SESSION_CLOSED                    0x000000B0
+#define CKR_SESSION_COUNT                     0x000000B1
+#define CKR_SESSION_HANDLE_INVALID            0x000000B3
+#define CKR_SESSION_PARALLEL_NOT_SUPPORTED    0x000000B4
+#define CKR_SESSION_READ_ONLY                 0x000000B5
+#define CKR_SESSION_EXISTS                    0x000000B6
+
+/* CKR_SESSION_READ_ONLY_EXISTS and
+ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */
+#define CKR_SESSION_READ_ONLY_EXISTS          0x000000B7
+#define CKR_SESSION_READ_WRITE_SO_EXISTS      0x000000B8
+
+#define CKR_SIGNATURE_INVALID                 0x000000C0
+#define CKR_SIGNATURE_LEN_RANGE               0x000000C1
+#define CKR_TEMPLATE_INCOMPLETE               0x000000D0
+#define CKR_TEMPLATE_INCONSISTENT             0x000000D1
+#define CKR_TOKEN_NOT_PRESENT                 0x000000E0
+#define CKR_TOKEN_NOT_RECOGNIZED              0x000000E1
+#define CKR_TOKEN_WRITE_PROTECTED             0x000000E2
+#define CKR_UNWRAPPING_KEY_HANDLE_INVALID     0x000000F0
+#define CKR_UNWRAPPING_KEY_SIZE_RANGE         0x000000F1
+#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT  0x000000F2
+#define CKR_USER_ALREADY_LOGGED_IN            0x00000100
+#define CKR_USER_NOT_LOGGED_IN                0x00000101
+#define CKR_USER_PIN_NOT_INITIALIZED          0x00000102
+#define CKR_USER_TYPE_INVALID                 0x00000103
+
+/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES
+ * are new to v2.01 */
+#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN    0x00000104
+#define CKR_USER_TOO_MANY_TYPES               0x00000105
+
+#define CKR_WRAPPED_KEY_INVALID               0x00000110
+#define CKR_WRAPPED_KEY_LEN_RANGE             0x00000112
+#define CKR_WRAPPING_KEY_HANDLE_INVALID       0x00000113
+#define CKR_WRAPPING_KEY_SIZE_RANGE           0x00000114
+#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT    0x00000115
+#define CKR_RANDOM_SEED_NOT_SUPPORTED         0x00000120
+
+/* These are new to v2.0 */
+#define CKR_RANDOM_NO_RNG                     0x00000121
+
+/* These are new to v2.11 */
+#define CKR_DOMAIN_PARAMS_INVALID             0x00000130
+
+/* These are new to v2.0 */
+#define CKR_BUFFER_TOO_SMALL                  0x00000150
+#define CKR_SAVED_STATE_INVALID               0x00000160
+#define CKR_INFORMATION_SENSITIVE             0x00000170
+#define CKR_STATE_UNSAVEABLE                  0x00000180
+
+/* These are new to v2.01 */
+#define CKR_CRYPTOKI_NOT_INITIALIZED          0x00000190
+#define CKR_CRYPTOKI_ALREADY_INITIALIZED      0x00000191
+#define CKR_MUTEX_BAD                         0x000001A0
+#define CKR_MUTEX_NOT_LOCKED                  0x000001A1
+
+#define CKR_VENDOR_DEFINED                    0x80000000
+
+
+/* CK_NOTIFY is an application callback that processes events */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)(
+  CK_SESSION_HANDLE hSession,     /* the session's handle */
+  CK_NOTIFICATION   event,
+  CK_VOID_PTR       pApplication  /* passed to C_OpenSession */
+);
+
+
+/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec
+ * version and pointers of appropriate types to all the
+ * Cryptoki functions */
+/* CK_FUNCTION_LIST is new for v2.0 */
+typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST;
+
+typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR;
+
+typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR;
+
+
+/* CK_CREATEMUTEX is an application callback for creating a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)(
+  CK_VOID_PTR_PTR ppMutex  /* location to receive ptr to mutex */
+);
+
+
+/* CK_DESTROYMUTEX is an application callback for destroying a
+ * mutex object */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_LOCKMUTEX is an application callback for locking a mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_UNLOCKMUTEX is an application callback for unlocking a
+ * mutex */
+typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)(
+  CK_VOID_PTR pMutex  /* pointer to mutex */
+);
+
+
+/* CK_C_INITIALIZE_ARGS provides the optional arguments to
+ * C_Initialize */
+typedef struct CK_C_INITIALIZE_ARGS {
+  CK_CREATEMUTEX CreateMutex;
+  CK_DESTROYMUTEX DestroyMutex;
+  CK_LOCKMUTEX LockMutex;
+  CK_UNLOCKMUTEX UnlockMutex;
+  CK_FLAGS flags;
+  CK_VOID_PTR pReserved;
+} CK_C_INITIALIZE_ARGS;
+
+/* flags: bit flags that provide capabilities of the slot
+ *      Bit Flag                           Mask       Meaning
+ */
+#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001
+#define CKF_OS_LOCKING_OK                  0x00000002
+
+typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR;
+
+
+/* additional flags for parameters to functions */
+
+/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */
+#define CKF_DONT_BLOCK     1
+
+/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10. 
+ * CK_RSA_PKCS_OAEP_MGF_TYPE  is used to indicate the Message 
+ * Generation Function (MGF) applied to a message block when 
+ * formatting a message block for the PKCS #1 OAEP encryption 
+ * scheme. */
+typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE;
+
+typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR;
+
+/* The following MGFs are defined */
+#define CKG_MGF1_SHA1         0x00000001
+
+/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10. 
+ * CK_RSA_PKCS_OAEP_SOURCE_TYPE  is used to indicate the source
+ * of the encoding parameter when formatting a message block 
+ * for the PKCS #1 OAEP encryption scheme. */
+typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE;
+
+typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR;
+
+/* The following encoding parameter sources are defined */
+#define CKZ_DATA_SPECIFIED    0x00000001
+
+/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10.
+ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the 
+ * CKM_RSA_PKCS_OAEP mechanism. */
+typedef struct CK_RSA_PKCS_OAEP_PARAMS {
+	CK_MECHANISM_TYPE hashAlg;
+	CK_RSA_PKCS_MGF_TYPE mgf;
+	CK_RSA_PKCS_OAEP_SOURCE_TYPE source;
+	CK_VOID_PTR pSourceData;
+	CK_ULONG ulSourceDataLen;
+} CK_RSA_PKCS_OAEP_PARAMS;
+
+typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR;
+
+/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11.
+ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the
+ * CKM_RSA_PKCS_PSS mechanism(s). */
+typedef struct CK_RSA_PKCS_PSS_PARAMS {
+	CK_MECHANISM_TYPE    hashAlg;
+	CK_RSA_PKCS_MGF_TYPE mgf;
+	CK_ULONG             sLen;
+} CK_RSA_PKCS_PSS_PARAMS;
+
+typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR;
+
+/* CK_EC_KDF_TYPE is new for v2.11. */
+typedef CK_ULONG CK_EC_KDF_TYPE;
+
+/* The following EC Key Derivation Functions are defined */
+#define CKD_NULL                 0x00000001
+#define CKD_SHA1_KDF             0x00000002
+
+/* CK_ECDH1_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms,
+ * where each party contributes one key pair.
+ */
+typedef struct CK_ECDH1_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+} CK_ECDH1_DERIVE_PARAMS;
+
+typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR;
+
+
+/* CK_ECDH2_DERIVE_PARAMS is new for v2.11.
+ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the
+ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */
+typedef struct CK_ECDH2_DERIVE_PARAMS {
+  CK_EC_KDF_TYPE kdf;
+  CK_ULONG ulSharedDataLen;
+  CK_BYTE_PTR pSharedData;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+} CK_ECDH2_DERIVE_PARAMS;
+
+typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR;
+
+/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the 
+ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */
+typedef CK_ULONG CK_X9_42_DH_KDF_TYPE;
+typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR;
+
+/* The following X9.42 DH key derivation functions are defined: */
+#define CKD_NULL                 0x00000001
+#define CKD_SHA1_KDF_ASN1        0x00000003
+#define CKD_SHA1_KDF_CONCATENATE 0x00000004
+
+/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the 
+ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party
+ * contributes one key pair */
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+} CK_X9_42_DH1_DERIVE_PARAMS;
+
+typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR;
+
+/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11.
+ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the 
+ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation
+ * mechanisms, where each party contributes two key pairs */
+typedef struct CK_X9_42_DH2_DERIVE_PARAMS {
+  CK_X9_42_DH_KDF_TYPE kdf;
+  CK_ULONG ulOtherInfoLen;
+  CK_BYTE_PTR pOtherInfo;
+  CK_ULONG ulPublicDataLen;
+  CK_BYTE_PTR pPublicData;
+  CK_ULONG ulPrivateDataLen;
+  CK_OBJECT_HANDLE hPrivateData;
+  CK_ULONG ulPublicDataLen2;
+  CK_BYTE_PTR pPublicData2;
+} CK_X9_42_DH2_DERIVE_PARAMS;
+
+typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR;
+
+/* CK_KEA_DERIVE_PARAMS provides the parameters to the
+ * CKM_KEA_DERIVE mechanism */
+/* CK_KEA_DERIVE_PARAMS is new for v2.0 */
+typedef struct CK_KEA_DERIVE_PARAMS {
+  CK_BBOOL      isSender;
+  CK_ULONG      ulRandomLen;
+  CK_BYTE_PTR   pRandomA;
+  CK_BYTE_PTR   pRandomB;
+  CK_ULONG      ulPublicDataLen;
+  CK_BYTE_PTR   pPublicData;
+} CK_KEA_DERIVE_PARAMS;
+
+typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR;
+
+
+/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and
+ * CKM_RC2_MAC mechanisms.  An instance of CK_RC2_PARAMS just
+ * holds the effective keysize */
+typedef CK_ULONG          CK_RC2_PARAMS;
+
+typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR;
+
+
+/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC
+ * mechanism */
+typedef struct CK_RC2_CBC_PARAMS {
+  /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for
+   * v2.0 */
+  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
+
+  CK_BYTE       iv[8];            /* IV for CBC mode */
+} CK_RC2_CBC_PARAMS;
+
+typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR;
+
+
+/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC2_MAC_GENERAL mechanism */
+/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC2_MAC_GENERAL_PARAMS {
+  CK_ULONG      ulEffectiveBits;  /* effective bits (1-1024) */
+  CK_ULONG      ulMacLength;      /* Length of MAC in bytes */
+} CK_RC2_MAC_GENERAL_PARAMS;
+
+typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \
+  CK_RC2_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and
+ * CKM_RC5_MAC mechanisms */
+/* CK_RC5_PARAMS is new for v2.0 */
+typedef struct CK_RC5_PARAMS {
+  CK_ULONG      ulWordsize;  /* wordsize in bits */
+  CK_ULONG      ulRounds;    /* number of rounds */
+} CK_RC5_PARAMS;
+
+typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR;
+
+
+/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC
+ * mechanism */
+/* CK_RC5_CBC_PARAMS is new for v2.0 */
+typedef struct CK_RC5_CBC_PARAMS {
+  CK_ULONG      ulWordsize;  /* wordsize in bits */
+  CK_ULONG      ulRounds;    /* number of rounds */
+  CK_BYTE_PTR   pIv;         /* pointer to IV */
+  CK_ULONG      ulIvLen;     /* length of IV in bytes */
+} CK_RC5_CBC_PARAMS;
+
+typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR;
+
+
+/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the
+ * CKM_RC5_MAC_GENERAL mechanism */
+/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef struct CK_RC5_MAC_GENERAL_PARAMS {
+  CK_ULONG      ulWordsize;   /* wordsize in bits */
+  CK_ULONG      ulRounds;     /* number of rounds */
+  CK_ULONG      ulMacLength;  /* Length of MAC in bytes */
+} CK_RC5_MAC_GENERAL_PARAMS;
+
+typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \
+  CK_RC5_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_MAC_GENERAL_PARAMS provides the parameters to most block
+ * ciphers' MAC_GENERAL mechanisms.  Its value is the length of
+ * the MAC */
+/* CK_MAC_GENERAL_PARAMS is new for v2.0 */
+typedef CK_ULONG          CK_MAC_GENERAL_PARAMS;
+
+typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR;
+
+
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */
+/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS {
+  CK_ULONG      ulPasswordLen;
+  CK_BYTE_PTR   pPassword;
+  CK_ULONG      ulPublicDataLen;
+  CK_BYTE_PTR   pPublicData;
+  CK_ULONG      ulPAndGLen;
+  CK_ULONG      ulQLen;
+  CK_ULONG      ulRandomLen;
+  CK_BYTE_PTR   pRandomA;
+  CK_BYTE_PTR   pPrimeP;
+  CK_BYTE_PTR   pBaseG;
+  CK_BYTE_PTR   pSubprimeQ;
+} CK_SKIPJACK_PRIVATE_WRAP_PARAMS;
+
+typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \
+  CK_SKIPJACK_PRIVATE_WRAP_PTR;
+
+
+/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the
+ * CKM_SKIPJACK_RELAYX mechanism */
+/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */
+typedef struct CK_SKIPJACK_RELAYX_PARAMS {
+  CK_ULONG      ulOldWrappedXLen;
+  CK_BYTE_PTR   pOldWrappedX;
+  CK_ULONG      ulOldPasswordLen;
+  CK_BYTE_PTR   pOldPassword;
+  CK_ULONG      ulOldPublicDataLen;
+  CK_BYTE_PTR   pOldPublicData;
+  CK_ULONG      ulOldRandomLen;
+  CK_BYTE_PTR   pOldRandomA;
+  CK_ULONG      ulNewPasswordLen;
+  CK_BYTE_PTR   pNewPassword;
+  CK_ULONG      ulNewPublicDataLen;
+  CK_BYTE_PTR   pNewPublicData;
+  CK_ULONG      ulNewRandomLen;
+  CK_BYTE_PTR   pNewRandomA;
+} CK_SKIPJACK_RELAYX_PARAMS;
+
+typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \
+  CK_SKIPJACK_RELAYX_PARAMS_PTR;
+
+
+typedef struct CK_PBE_PARAMS {
+  CK_BYTE_PTR      pInitVector;
+  CK_UTF8CHAR_PTR  pPassword;
+  CK_ULONG         ulPasswordLen;
+  CK_BYTE_PTR      pSalt;
+  CK_ULONG         ulSaltLen;
+  CK_ULONG         ulIteration;
+} CK_PBE_PARAMS;
+
+typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR;
+
+
+/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the
+ * CKM_KEY_WRAP_SET_OAEP mechanism */
+/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */
+typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS {
+  CK_BYTE       bBC;     /* block contents byte */
+  CK_BYTE_PTR   pX;      /* extra data */
+  CK_ULONG      ulXLen;  /* length of extra data in bytes */
+} CK_KEY_WRAP_SET_OAEP_PARAMS;
+
+typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \
+  CK_KEY_WRAP_SET_OAEP_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_RANDOM_DATA {
+  CK_BYTE_PTR  pClientRandom;
+  CK_ULONG     ulClientRandomLen;
+  CK_BYTE_PTR  pServerRandom;
+  CK_ULONG     ulServerRandomLen;
+} CK_SSL3_RANDOM_DATA;
+
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS {
+  CK_SSL3_RANDOM_DATA RandomInfo;
+  CK_VERSION_PTR pVersion;
+} CK_SSL3_MASTER_KEY_DERIVE_PARAMS;
+
+typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \
+  CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_OUT {
+  CK_OBJECT_HANDLE hClientMacSecret;
+  CK_OBJECT_HANDLE hServerMacSecret;
+  CK_OBJECT_HANDLE hClientKey;
+  CK_OBJECT_HANDLE hServerKey;
+  CK_BYTE_PTR      pIVClient;
+  CK_BYTE_PTR      pIVServer;
+} CK_SSL3_KEY_MAT_OUT;
+
+typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR;
+
+
+typedef struct CK_SSL3_KEY_MAT_PARAMS {
+  CK_ULONG                ulMacSizeInBits;
+  CK_ULONG                ulKeySizeInBits;
+  CK_ULONG                ulIVSizeInBits;
+  CK_BBOOL                bIsExport;
+  CK_SSL3_RANDOM_DATA     RandomInfo;
+  CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial;
+} CK_SSL3_KEY_MAT_PARAMS;
+
+typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR;
+
+
+typedef struct CK_KEY_DERIVATION_STRING_DATA {
+  CK_BYTE_PTR pData;
+  CK_ULONG    ulLen;
+} CK_KEY_DERIVATION_STRING_DATA;
+
+typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \
+  CK_KEY_DERIVATION_STRING_DATA_PTR;
+
+
+/* The CK_EXTRACT_PARAMS is used for the
+ * CKM_EXTRACT_KEY_FROM_KEY mechanism.  It specifies which bit
+ * of the base key should be used as the first bit of the
+ * derived key */
+/* CK_EXTRACT_PARAMS is new for v2.0 */
+typedef CK_ULONG CK_EXTRACT_PARAMS;
+
+typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR;
+
+/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10.
+ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to 
+ * indicate the Pseudo-Random Function (PRF) used to generate 
+ * key bits using PKCS #5 PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE;
+
+typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR;
+
+/* The following PRFs are defined in PKCS #5 v2.0. */
+#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001
+
+
+/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10.
+ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the 
+ * source of the salt value when deriving a key using PKCS #5 
+ * PBKDF2. */
+typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE;
+
+typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR;
+
+/* The following salt value sources are defined in PKCS #5 v2.0. */
+#define CKZ_SALT_SPECIFIED        0x00000001
+
+/* CK_PKCS5_PBKD2_PARAMS is new for v2.10.
+ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the 
+ * parameters to the CKM_PKCS5_PBKD2 mechanism. */
+typedef struct CK_PKCS5_PBKD2_PARAMS {
+	CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE           saltSource;
+	CK_VOID_PTR                                pSaltSourceData;
+	CK_ULONG                                   ulSaltSourceDataLen;
+	CK_ULONG                                   iterations;
+	CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf;
+	CK_VOID_PTR                                pPrfData;
+	CK_ULONG                                   ulPrfDataLen;
+	CK_UTF8CHAR_PTR                            pPassword;
+	CK_ULONG_PTR                               ulPasswordLen;
+} CK_PKCS5_PBKD2_PARAMS;
+
+typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR;
+
+#endif
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/zlib/zconf.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/zlib/zconf.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/zlib/zconf.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_          z_deflateInit_
+#  define deflate               z_deflate
+#  define deflateEnd            z_deflateEnd
+#  define inflateInit_          z_inflateInit_
+#  define inflate               z_inflate
+#  define inflateEnd            z_inflateEnd
+#  define deflateInit2_         z_deflateInit2_
+#  define deflateSetDictionary  z_deflateSetDictionary
+#  define deflateCopy           z_deflateCopy
+#  define deflateReset          z_deflateReset
+#  define deflateParams         z_deflateParams
+#  define deflateBound          z_deflateBound
+#  define deflatePrime          z_deflatePrime
+#  define inflateInit2_         z_inflateInit2_
+#  define inflateSetDictionary  z_inflateSetDictionary
+#  define inflateSync           z_inflateSync
+#  define inflateSyncPoint      z_inflateSyncPoint
+#  define inflateCopy           z_inflateCopy
+#  define inflateReset          z_inflateReset
+#  define inflateBack           z_inflateBack
+#  define inflateBackEnd        z_inflateBackEnd
+#  define compress              z_compress
+#  define compress2             z_compress2
+#  define compressBound         z_compressBound
+#  define uncompress            z_uncompress
+#  define adler32               z_adler32
+#  define crc32                 z_crc32
+#  define get_crc_table         z_get_crc_table
+#  define zError                z_zError
+
+#  define alloc_func            z_alloc_func
+#  define free_func             z_free_func
+#  define in_func               z_in_func
+#  define out_func              z_out_func
+#  define Byte                  z_Byte
+#  define uInt                  z_uInt
+#  define uLong                 z_uLong
+#  define Bytef                 z_Bytef
+#  define charf                 z_charf
+#  define intf                  z_intf
+#  define uIntf                 z_uIntf
+#  define uLongf                z_uLongf
+#  define voidpf                z_voidpf
+#  define voidp                 z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+#  define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+#  define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+#  ifndef WIN32
+#    define WIN32
+#  endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+#  if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+#    ifndef SYS16BIT
+#      define SYS16BIT
+#    endif
+#  endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+#  ifndef STDC
+#    define STDC
+#  endif
+#  if __STDC_VERSION__ >= 199901L
+#    ifndef STDC99
+#      define STDC99
+#    endif
+#  endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+#  define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+#  define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC)    /* iSeries (formerly AS/400). */
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const       /* note: need a more gentle solution here */
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            (1 << (windowBits+2)) +  (1 << (memLevel+9))
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+#  if defined(M_I86SM) || defined(M_I86MM)
+     /* MSC small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef _MSC_VER
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#  if (defined(__SMALL__) || defined(__MEDIUM__))
+     /* Turbo C small or medium model */
+#    define SMALL_MEDIUM
+#    ifdef __BORLANDC__
+#      define FAR _far
+#    else
+#      define FAR far
+#    endif
+#  endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+   /* If building or using zlib as a DLL, define ZLIB_DLL.
+    * This is not mandatory, but it offers a little performance increase.
+    */
+#  ifdef ZLIB_DLL
+#    if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+#      ifdef ZLIB_INTERNAL
+#        define ZEXTERN extern __declspec(dllexport)
+#      else
+#        define ZEXTERN extern __declspec(dllimport)
+#      endif
+#    endif
+#  endif  /* ZLIB_DLL */
+   /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+    * define ZLIB_WINAPI.
+    * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+    */
+#  ifdef ZLIB_WINAPI
+#    ifdef FAR
+#      undef FAR
+#    endif
+#    include <windows.h>
+     /* No need for _export, use ZLIB.DEF instead. */
+     /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+#    define ZEXPORT WINAPI
+#    ifdef WIN32
+#      define ZEXPORTVA WINAPIV
+#    else
+#      define ZEXPORTVA FAR CDECL
+#    endif
+#  endif
+#endif
+
+#if defined (__BEOS__)
+#  ifdef ZLIB_DLL
+#    ifdef ZLIB_INTERNAL
+#      define ZEXPORT   __declspec(dllexport)
+#      define ZEXPORTVA __declspec(dllexport)
+#    else
+#      define ZEXPORT   __declspec(dllimport)
+#      define ZEXPORTVA __declspec(dllimport)
+#    endif
+#  endif
+#endif
+
+#ifndef ZEXTERN
+#  define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+#  define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+#  define ZEXPORTVA
+#endif
+
+#ifndef FAR
+#  define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char  Byte;  /* 8 bits */
+#endif
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+   /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void const *voidpc;
+   typedef void FAR   *voidpf;
+   typedef void       *voidp;
+#else
+   typedef Byte const *voidpc;
+   typedef Byte FAR   *voidpf;
+   typedef Byte       *voidp;
+#endif
+
+#if 0           /* HAVE_UNISTD_H -- this line is updated by ./configure */
+#  include <sys/types.h> /* for off_t */
+#  include <unistd.h>    /* for SEEK_* and off_t */
+#  ifdef VMS
+#    include <unixio.h>   /* for off_t */
+#  endif
+#  define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+#  define SEEK_SET        0       /* Seek from beginning of file.  */
+#  define SEEK_CUR        1       /* Seek from current position.  */
+#  define SEEK_END        2       /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+#  define z_off_t long
+#endif
+
+#if defined(__OS400__)
+#  define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+#  define NO_vsnprintf
+#  ifdef FAR
+#    undef FAR
+#  endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+#   pragma map(deflateInit_,"DEIN")
+#   pragma map(deflateInit2_,"DEIN2")
+#   pragma map(deflateEnd,"DEEND")
+#   pragma map(deflateBound,"DEBND")
+#   pragma map(inflateInit_,"ININ")
+#   pragma map(inflateInit2_,"ININ2")
+#   pragma map(inflateEnd,"INEND")
+#   pragma map(inflateSync,"INSY")
+#   pragma map(inflateSetDictionary,"INSEDI")
+#   pragma map(compressBound,"CMBND")
+#   pragma map(inflate_table,"INTABL")
+#   pragma map(inflate_fast,"INFA")
+#   pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/zlib/zlib.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/zlib/zlib.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Mayaqua/zlib/zlib.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.2.3, July 18th, 2005
+
+  Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  jloup@gzip.org          madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms will be added later and will have the same
+  stream interface.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The compressed data format used by default by the in-memory functions is
+  the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+  around a deflate stream, which is itself documented in RFC 1951.
+
+     The library also supports reading and writing files in gzip (.gz) format
+  with an interface similar to that of stdio using the functions that start
+  with "gz".  The gzip format is different from the zlib format.  gzip is a
+  gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+     This library can optionally read and write gzip streams in memory as well.
+
+     The zlib format was designed to be compact and fast for use in memory
+  and on communications channels.  The gzip format was designed for single-
+  file compression on file systems, has a larger header than zlib to maintain
+  directory information, and uses a different, slower check method than zlib.
+
+     The library does not install any signal handler. The decoder checks
+  the consistency of the compressed data, so the library should never
+  crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    char     *msg;      /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: binary or text */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+     gzip header information passed to and from zlib routines.  See RFC 1952
+  for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+    int     text;       /* true if compressed data believed to be text */
+    uLong   time;       /* modification time */
+    int     xflags;     /* extra flags (not used when writing a gzip file) */
+    int     os;         /* operating system */
+    Bytef   *extra;     /* pointer to extra field or Z_NULL if none */
+    uInt    extra_len;  /* extra field length (valid if extra != Z_NULL) */
+    uInt    extra_max;  /* space at extra (only when reading header) */
+    Bytef   *name;      /* pointer to zero-terminated file name or Z_NULL */
+    uInt    name_max;   /* space at name (only when reading header) */
+    Bytef   *comment;   /* pointer to zero-terminated comment or Z_NULL */
+    uInt    comm_max;   /* space at comment (only when reading header) */
+    int     hcrc;       /* true if there was or will be a header crc */
+    int     done;       /* true when done reading gzip header (not used
+                           when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   If zlib is used in a multi-threaded application, zalloc and zfree must be
+   thread safe.
+
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH    2
+#define Z_FULL_FLUSH    3
+#define Z_FINISH        4
+#define Z_BLOCK         5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_RLE                 3
+#define Z_FIXED               4
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_TEXT     1
+#define Z_ASCII    Z_TEXT   /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+    deflate compresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce some
+  output latency (reading input without producing any output) except when
+  forced to flush.
+
+    The detailed semantics are as follows. deflate performs one or both of the
+  following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+  decide how much data to accumualte before producing output, in order to
+  maximize compression.
+
+    If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+  flushed to the output buffer and the output is aligned on a byte boundary, so
+  that the decompressor can get all input data available so far. (In particular
+  avail_in is zero after the call if enough output space has been provided
+  before the call.)  Flushing may degrade compression for some compression
+  algorithms and so it should be used only when necessary.
+
+    If flush is set to Z_FULL_FLUSH, all output is flushed as with
+  Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+  restart from this point if previous compressed data has been damaged or if
+  random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+  compression.
+
+    If deflate returns with avail_out == 0, this function must be called again
+  with the same value of the flush parameter and more output space (updated
+  avail_out), until the flush is complete (deflate returns with non-zero
+  avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+  avail_out is greater than six to avoid repeated flush markers due to
+  avail_out == 0 on return.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  the value returned by deflateBound (see below). If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() sets strm->adler to the adler32 checksum of all input read
+  so far (that is, total_in bytes).
+
+    deflate() may update strm->data_type if it can make a good guess about
+  the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+  (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+  fatal, and deflate() can be called again with more input and more output
+  space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+   the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+   value depends on the compression method), inflateInit determines the
+   compression method from the zlib header and allocates all data structures
+   accordingly; otherwise the allocation will be deferred to the first call of
+   inflate.  If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+   use default allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+   version assumed by the caller.  msg is set to null if there is no error
+   message. inflateInit does not perform any decompression apart from reading
+   the zlib header if present: this will be done by inflate().  (So next_in and
+   avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+    inflate decompresses as much data as possible, and stops when the input
+  buffer becomes empty or the output buffer becomes full. It may introduce
+  some output latency (reading input without producing any output) except when
+  forced to flush.
+
+  The detailed semantics are as follows. inflate performs one or both of the
+  following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+  Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+  output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+  if and when it gets to the next deflate block boundary. When decoding the
+  zlib or gzip format, this will cause inflate() to return immediately after
+  the header and before the first block. When doing a raw inflate, inflate()
+  will go ahead and process the first block, and will return when it gets to
+  the end of that block, or when it runs out of data.
+
+    The Z_BLOCK option assists in appending to or combining deflate streams.
+  Also to assist in this, on return inflate() will set strm->data_type to the
+  number of unused bits in the last byte taken from strm->next_in, plus 64
+  if inflate() is currently decoding the last block in the deflate stream,
+  plus 128 if inflate() returned immediately after decoding an end-of-block
+  code or decoding the complete header up to just before the first byte of the
+  deflate stream. The end-of-block will not be indicated until all of the
+  uncompressed data from that block has been written to strm->next_out.  The
+  number of unused bits may in general be greater than seven, except when
+  bit 7 of data_type is set, in which case the number of unused bits will be
+  less than eight.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster approach
+  may be used for the single inflate() call.
+
+     In this implementation, inflate() always flushes as much output as
+  possible to the output buffer, and always uses the faster approach on the
+  first call. So the only effect of the flush parameter in this implementation
+  is on the return value of inflate(), as noted below, or when it returns early
+  because Z_BLOCK is used.
+
+     If a preset dictionary is needed after this call (see inflateSetDictionary
+  below), inflate sets strm->adler to the adler32 checksum of the dictionary
+  chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+  strm->adler to the adler32 checksum of all output produced so far (that is,
+  total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+  below. At the end of the stream, inflate() checks that its computed adler32
+  checksum is equal to that saved by the compressor and returns Z_STREAM_END
+  only if the checksum is correct.
+
+    inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+  deflate data.  The header type is detected automatically.  Any information
+  contained in the gzip header is not retained, so applications that need that
+  information should instead use raw inflate, see inflateInit2() below, or
+  inflateBack() and perform their own processing of the gzip header and
+  trailer.
+
+    inflate() returns Z_OK if some progress has been made (more input processed
+  or more output produced), Z_STREAM_END if the end of the compressed data has
+  been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+  preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+  corrupted (input stream not conforming to the zlib format or incorrect check
+  value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+  if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+  output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+  inflate() can be called again with more input and more output space to
+  continue decompressing. If Z_DATA_ERROR is returned, the application may then
+  call inflateSync() to look for a good compression block if a partial recovery
+  of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+                                     int  level,
+                                     int  method,
+                                     int  windowBits,
+                                     int  memLevel,
+                                     int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library.
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer). It should be in the range 8..15 for this
+   version of the library. Larger values of this parameter result in better
+   compression at the expense of memory usage. The default value is 15 if
+   deflateInit is used instead.
+
+     windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+   determines the window size. deflate() will then generate raw deflate data
+   with no zlib header or trailer, and will not compute an adler32 check value.
+
+     windowBits can also be greater than 15 for optional gzip encoding. Add
+   16 to windowBits to write a simple gzip header and trailer around the
+   compressed data instead of a zlib wrapper. The gzip header will have no
+   file name, no extra data, no comment, no modification time (set to zero),
+   no header crc, and the operating system will be set to 255 (unknown).  If a
+   gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match), or Z_RLE to limit match distances to one (run-length
+   encoding). Filtered data consists mostly of small values with a somewhat
+   random distribution. In this case, the compression algorithm is tuned to
+   compress them better. The effect of Z_FILTERED is to force more Huffman
+   coding and less string matching; it is somewhat intermediate between
+   Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+   Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+   parameter only affects the compression ratio but not the correctness of the
+   compressed output even if it is not set appropriately.  Z_FIXED prevents the
+   use of dynamic Huffman codes, allowing for a simpler decoder for special
+   applications.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+   method). msg is set to null if there is no error message.  deflateInit2 does
+   not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the compression dictionary from the given byte sequence
+   without producing any compressed output. This function must be called
+   immediately after deflateInit, deflateInit2 or deflateReset, before any
+   call of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and can be
+   predicted with good accuracy; the data can then be compressed better than
+   with the default empty dictionary.
+
+     Depending on the size of the compression data structures selected by
+   deflateInit or deflateInit2, a part of the dictionary may in effect be
+   discarded, for example if the dictionary is larger than the window size in
+   deflate or deflate2. Thus the strings most likely to be useful should be
+   put at the end of the dictionary, not at the front. In addition, the
+   current implementation of deflate will use at most the window size minus
+   262 bytes of the provided dictionary.
+
+     Upon return of this function, strm->adler is set to the adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.) If a raw deflate was requested, then the
+   adler32 value is not computed and strm->adler is not set.
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent (for example if deflate has already been called for this stream
+   or if the compression method is bsort). deflateSetDictionary does not
+   perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+                                      int level,
+                                      int strategy));
+/*
+     Dynamically update the compression level and compression strategy.  The
+   interpretation of level and strategy is as in deflateInit2.  This can be
+   used to switch between compression and straight copy of the input data, or
+   to switch to a different kind of input data requiring a different
+   strategy. If the compression level is changed, the input available so far
+   is compressed with the old level (and may be flushed); the new level will
+   take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+                                    int good_length,
+                                    int max_lazy,
+                                    int nice_length,
+                                    int max_chain));
+/*
+     Fine tune deflate's internal compression parameters.  This should only be
+   used by someone who understands the algorithm used by zlib's deflate for
+   searching for the best matching string, and even then only by the most
+   fanatic optimizer trying to squeeze out the last compressed bit for their
+   specific input data.  Read the deflate.c source code for the meaning of the
+   max_lazy, good_length, nice_length, and max_chain parameters.
+
+     deflateTune() can be called after deflateInit() or deflateInit2(), and
+   returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+                                       uLong sourceLen));
+/*
+     deflateBound() returns an upper bound on the compressed size after
+   deflation of sourceLen bytes.  It must be called after deflateInit()
+   or deflateInit2().  This would be used to allocate an output buffer
+   for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     deflatePrime() inserts bits in the deflate output stream.  The intent
+  is that this function is used to start off the deflate output with the
+  bits leftover from a previous deflate stream when appending to it.  As such,
+  this function can only be used for raw deflate, and must be used before the
+  first deflate() call after a deflateInit2() or deflateReset().  bits must be
+  less than or equal to 16, and that many of the least significant bits of
+  value will be inserted in the output.
+
+      deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      deflateSetHeader() provides gzip header information for when a gzip
+   stream is requested by deflateInit2().  deflateSetHeader() may be called
+   after deflateInit2() or deflateReset() and before the first call of
+   deflate().  The text, time, os, extra field, name, and comment information
+   in the provided gz_header structure are written to the gzip header (xflag is
+   ignored -- the extra flags are set according to the compression level).  The
+   caller must assure that, if not Z_NULL, name and comment are terminated with
+   a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+   available there.  If hcrc is true, a gzip header crc is included.  Note that
+   the current versions of the command-line version of gzip (up through version
+   1.3.x) do not support header crc's, and will report that it is a "multi-part
+   gzip file" and give up.
+
+      If deflateSetHeader is not used, the default gzip header has text false,
+   the time set to zero, and os set to 255, with no extra, name, or comment
+   fields.  The gzip header is returned to the default state by deflateReset().
+
+      deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+                                     int  windowBits));
+
+     This is another version of inflateInit with an extra parameter. The
+   fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+   before by the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library. The default value is 15 if inflateInit is used
+   instead. windowBits must be greater than or equal to the windowBits value
+   provided to deflateInit2() while compressing, or it must be equal to 15 if
+   deflateInit2() was not used. If a compressed stream with a larger window
+   size is given as input, inflate() will return with the error code
+   Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+   determines the window size. inflate() will then process raw deflate data,
+   not looking for a zlib or gzip header, not generating a check value, and not
+   looking for any check values for comparison at the end of the stream. This
+   is for use with other formats that use the deflate compressed data format
+   such as zip.  Those formats provide their own check values. If a custom
+   format is developed using the raw deflate format for compressed data, it is
+   recommended that a check value such as an adler32 or a crc32 be applied to
+   the uncompressed data as is done in the zlib, gzip, and zip formats.  For
+   most applications, the zlib format should be used as is. Note that comments
+   above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+     windowBits can also be greater than 15 for optional gzip decoding. Add
+   32 to windowBits to enable zlib and gzip decoding with automatic header
+   detection, or add 16 to decode only the gzip format (the zlib format will
+   return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is
+   a crc32 instead of an adler32.
+
+     inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+   is set to null if there is no error message.  inflateInit2 does not perform
+   any decompression apart from reading the zlib header if present: this will
+   be done by inflate(). (So next_in and avail_in may be modified, but next_out
+   and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+                                             const Bytef *dictionary,
+                                             uInt  dictLength));
+/*
+     Initializes the decompression dictionary from the given uncompressed byte
+   sequence. This function must be called immediately after a call of inflate,
+   if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+   can be determined from the adler32 value returned by that call of inflate.
+   The compressor and decompressor must use exactly the same dictionary (see
+   deflateSetDictionary).  For raw inflate, this function can be called
+   immediately after inflateInit2() or inflateReset() and before any call of
+   inflate() to set the dictionary.  The application must insure that the
+   dictionary that was used for compression is provided.
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+    Skips invalid compressed data until a full flush point (see above the
+  description of deflate with Z_FULL_FLUSH) can be found, or until all
+  available input is skipped. No output is provided.
+
+    inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+                                    z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.
+
+     This function can be useful when randomly accessing a large stream.  The
+   first pass through the stream can periodically record the inflate state,
+   allowing restarting inflate at those points when randomly accessing the
+   stream.
+
+     inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+                                     int bits,
+                                     int value));
+/*
+     This function inserts bits in the inflate input stream.  The intent is
+  that this function is used to start inflating at a bit position in the
+  middle of a byte.  The provided bits will be used before any bytes are used
+  from next_in.  This function should only be used with raw inflate, and
+  should be used before the first inflate() call after inflateInit2() or
+  inflateReset().  bits must be less than or equal to 16, and that many of the
+  least significant bits of value will be inserted in the input.
+
+      inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+                                         gz_headerp head));
+/*
+      inflateGetHeader() requests that gzip header information be stored in the
+   provided gz_header structure.  inflateGetHeader() may be called after
+   inflateInit2() or inflateReset(), and before the first call of inflate().
+   As inflate() processes the gzip stream, head->done is zero until the header
+   is completed, at which time head->done is set to one.  If a zlib stream is
+   being decoded, then head->done is set to -1 to indicate that there will be
+   no gzip header information forthcoming.  Note that Z_BLOCK can be used to
+   force inflate() to return immediately after header processing is complete
+   and before any actual data is decompressed.
+
+      The text, time, xflags, and os fields are filled in with the gzip header
+   contents.  hcrc is set to true if there is a header CRC.  (The header CRC
+   was valid if done is set to one.)  If extra is not Z_NULL, then extra_max
+   contains the maximum number of bytes to write to extra.  Once done is true,
+   extra_len contains the actual extra field length, and extra contains the
+   extra field, or that field truncated if extra_max is less than extra_len.
+   If name is not Z_NULL, then up to name_max characters are written there,
+   terminated with a zero unless the length is greater than name_max.  If
+   comment is not Z_NULL, then up to comm_max characters are written there,
+   terminated with a zero unless the length is greater than comm_max.  When
+   any of extra, name, or comment are not Z_NULL and the respective field is
+   not present in the header, then that field is set to Z_NULL to signal its
+   absence.  This allows the use of deflateSetHeader() with the returned
+   structure to duplicate the header.  However if those fields are set to
+   allocated memory, then the application will need to save those pointers
+   elsewhere so that they can be eventually freed.
+
+      If inflateGetHeader is not used, then the header information is simply
+   discarded.  The header is always checked for validity, including the header
+   CRC if present.  inflateReset() will reset the process to discard the header
+   information.  The application would need to call inflateGetHeader() again to
+   retrieve the header from the next gzip stream.
+
+      inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+                                        unsigned char FAR *window));
+
+     Initialize the internal stream state for decompression using inflateBack()
+   calls.  The fields zalloc, zfree and opaque in strm must be initialized
+   before the call.  If zalloc and zfree are Z_NULL, then the default library-
+   derived memory allocation routines are used.  windowBits is the base two
+   logarithm of the window size, in the range 8..15.  window is a caller
+   supplied buffer of that size.  Except for special applications where it is
+   assured that deflate was used with small window sizes, windowBits must be 15
+   and a 32K byte window must be supplied to be able to decompress general
+   deflate streams.
+
+     See inflateBack() for the usage of these routines.
+
+     inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+   the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+   be allocated, or Z_VERSION_ERROR if the version of the library does not
+   match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+                                    in_func in, void FAR *in_desc,
+                                    out_func out, void FAR *out_desc));
+/*
+     inflateBack() does a raw inflate with a single call using a call-back
+   interface for input and output.  This is more efficient than inflate() for
+   file i/o applications in that it avoids copying between the output and the
+   sliding window by simply making the window itself the output buffer.  This
+   function trusts the application to not change the output buffer passed by
+   the output function, at least until inflateBack() returns.
+
+     inflateBackInit() must be called first to allocate the internal state
+   and to initialize the state with the user-provided window buffer.
+   inflateBack() may then be used multiple times to inflate a complete, raw
+   deflate stream with each call.  inflateBackEnd() is then called to free
+   the allocated state.
+
+     A raw deflate stream is one with no zlib or gzip header or trailer.
+   This routine would normally be used in a utility that reads zip or gzip
+   files and writes out uncompressed files.  The utility would decode the
+   header and process the trailer on its own, hence this routine expects
+   only the raw deflate stream to decompress.  This is different from the
+   normal behavior of inflate(), which expects either a zlib or gzip header and
+   trailer around the deflate stream.
+
+     inflateBack() uses two subroutines supplied by the caller that are then
+   called by inflateBack() for input and output.  inflateBack() calls those
+   routines until it reads a complete deflate stream and writes out all of the
+   uncompressed data, or until it encounters an error.  The function's
+   parameters and return types are defined above in the in_func and out_func
+   typedefs.  inflateBack() will call in(in_desc, &buf) which should return the
+   number of bytes of provided input, and a pointer to that input in buf.  If
+   there is no input available, in() must return zero--buf is ignored in that
+   case--and inflateBack() will return a buffer error.  inflateBack() will call
+   out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].  out()
+   should return zero on success, or non-zero on failure.  If out() returns
+   non-zero, inflateBack() will return with an error.  Neither in() nor out()
+   are permitted to change the contents of the window provided to
+   inflateBackInit(), which is also the buffer that out() uses to write from.
+   The length written by out() will be at most the window size.  Any non-zero
+   amount of input may be provided by in().
+
+     For convenience, inflateBack() can be provided input on the first call by
+   setting strm->next_in and strm->avail_in.  If that input is exhausted, then
+   in() will be called.  Therefore strm->next_in must be initialized before
+   calling inflateBack().  If strm->next_in is Z_NULL, then in() will be called
+   immediately for input.  If strm->next_in is not Z_NULL, then strm->avail_in
+   must also be initialized, and then if strm->avail_in is not zero, input will
+   initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+     The in_desc and out_desc parameters of inflateBack() is passed as the
+   first parameter of in() and out() respectively when they are called.  These
+   descriptors can be optionally used to pass any information that the caller-
+   supplied in() and out() functions need to do their job.
+
+     On return, inflateBack() will set strm->next_in and strm->avail_in to
+   pass back any unused input that was provided by the last in() call.  The
+   return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+   if in() or out() returned an error, Z_DATA_ERROR if there was a format
+   error in the deflate stream (in which case strm->msg is set to indicate the
+   nature of the error), or Z_STREAM_ERROR if the stream was not properly
+   initialized.  In the case of Z_BUF_ERROR, an input or output error can be
+   distinguished using strm->next_in which will be Z_NULL only if in() returned
+   an error.  If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+   out() returning non-zero.  (in() will always be called before out(), so
+   strm->next_in is assured to be defined if out() returns non-zero.)  Note
+   that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+     All memory allocated by inflateBackInit() is freed.
+
+     inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+   state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+    Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+     1.0: size of uInt
+     3.2: size of uLong
+     5.4: size of voidpf (pointer)
+     7.6: size of z_off_t
+
+    Compiler, assembler, and debug options:
+     8: DEBUG
+     9: ASMV or ASMINF -- use ASM code
+     10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+     11: 0 (reserved)
+
+    One-time table building (smaller code, but not thread-safe if true):
+     12: BUILDFIXED -- build static block decoding tables when needed
+     13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+     14,15: 0 (reserved)
+
+    Library content (indicates missing functionality):
+     16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+                          deflate code when not needed)
+     17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+                    and decode gzip streams (to avoid linking crc code)
+     18-19: 0 (reserved)
+
+    Operation variations (changes in library functionality):
+     20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+     21: FASTEST -- deflate algorithm with only one, lowest compression level
+     22,23: 0 (reserved)
+
+    The sprintf variant used by gzprintf (zero is best):
+     24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+     25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+     26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+    Remainder:
+     27-31: 0 (reserved)
+ */
+
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level and memory usage,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest,   uLongf *destLen,
+                                 const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least the value returned
+   by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest,   uLongf *destLen,
+                                  const Bytef *source, uLong sourceLen,
+                                  int level));
+/*
+     Compresses the source buffer into the destination buffer. The level
+   parameter has the same meaning as in deflateInit.  sourceLen is the byte
+   length of the source buffer. Upon entry, destLen is the total size of the
+   destination buffer, which must be at least the value returned by
+   compressBound(sourceLen). Upon exit, destLen is the actual size of the
+   compressed buffer.
+
+     compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+   memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+   Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+     compressBound() returns an upper bound on the compressed size after
+   compress() or compress2() on sourceLen bytes.  It would be used before
+   a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+                                   const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+   Huffman only compression as in "wb1h", or 'R' for run-length encoding
+   as in "wb1R". (See the description of deflateInit2 for more information
+   about the strategy parameter.)
+
+     gzopen can be used to read a file which is not in gzip format; in this
+   case gzread will directly read from the file without decompression.
+
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).  */
+
+ZEXTERN gzFile ZEXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+     Dynamically update the compression level or strategy. See the description
+   of deflateInit2 for the meaning of these parameters.
+     gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+   opened for writing.
+*/
+
+ZEXTERN int ZEXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT    gzwrite OF((gzFile file,
+                                   voidpc buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA   gzprintf OF((gzFile file, const char *format, ...));
+/*
+     Converts, formats, and writes the args to the compressed file under
+   control of the format string, as in fprintf. gzprintf returns the number of
+   uncompressed bytes actually written (0 in case of error).  The number of
+   uncompressed bytes written is limited to 4095. The caller should assure that
+   this limit is not exceeded. If it is exceeded, then gzprintf() will return
+   return an error (0) with nothing written. In this case, there may also be a
+   buffer overflow with unpredictable consequences, which is possible only if
+   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+      Writes the given null-terminated string to the compressed file, excluding
+   the terminating null character.
+      gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+      Reads bytes from the compressed file until len-1 characters are read, or
+   a newline character is read and transferred to buf, or an end-of-file
+   condition is encountered.  The string is then terminated with a null
+   character.
+      gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzputc OF((gzFile file, int c));
+/*
+      Writes c, converted to an unsigned char, into the compressed file.
+   gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT    gzgetc OF((gzFile file));
+/*
+      Reads one byte from the compressed file. gzgetc returns this byte
+   or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT    gzungetc OF((int c, gzFile file));
+/*
+      Push one character back onto the stream to be read again later.
+   Only one character of push-back is allowed.  gzungetc() returns the
+   character pushed, or -1 on failure.  gzungetc() will fail if a
+   character has been pushed but not read yet, or if c is -1. The pushed
+   character will be discarded if the stream is repositioned with gzseek()
+   or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT    gzseek OF((gzFile file,
+                                      z_off_t offset, int whence));
+/*
+      Sets the starting position for the next gzread or gzwrite on the
+   given compressed file. The offset represents a number of bytes in the
+   uncompressed data stream. The whence parameter is defined as in lseek(2);
+   the value SEEK_END is not supported.
+     If the file is opened for reading, this function is emulated but can be
+   extremely slow. If the file is opened for writing, only forward seeks are
+   supported; gzseek then compresses a sequence of zeroes up to the new
+   starting position.
+
+      gzseek returns the resulting offset location as measured in bytes from
+   the beginning of the uncompressed stream, or -1 in case of error, in
+   particular if the file is opened for writing and the new starting position
+   would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT    gzrewind OF((gzFile file));
+/*
+     Rewinds the given file. This function is supported only for reading.
+
+   gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT    gztell OF((gzFile file));
+/*
+     Returns the starting position for the next gzread or gzwrite on the
+   given compressed file. This position represents a number of bytes in the
+   uncompressed data stream.
+
+   gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+     Returns 1 when EOF has previously been detected reading the given
+   input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+     Returns 1 if file is being read directly without decompression, otherwise
+   zero.
+*/
+
+ZEXTERN int ZEXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+     Clears the error and end-of-file flags for file. This is analogous to the
+   clearerr() function in stdio. This is useful for continuing to read a gzip
+   file that is being written concurrently.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+                                          z_off_t len2));
+/*
+     Combine two Adler-32 checksums into one.  For two sequences of bytes, seq1
+   and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+   each, adler1 and adler2.  adler32_combine() returns the Adler-32 checksum of
+   seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running CRC-32 with the bytes buf[0..len-1] and return the
+   updated CRC-32. If buf is NULL, this function returns the required initial
+   value for the for the crc. Pre- and post-conditioning (one's complement) is
+   performed within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+     Combine two CRC-32 check values into one.  For two sequences of bytes,
+   seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+   calculated for each, crc1 and crc2.  crc32_combine() returns the CRC-32
+   check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+   len2.
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+                                     const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+                                      int windowBits, int memLevel,
+                                      int strategy, const char *version,
+                                      int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+                                      const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+                                         unsigned char FAR *window,
+                                         const char *version,
+                                         int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+                      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+        inflateBackInit_((strm), (windowBits), (window), \
+        ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char   * ZEXPORT zError           OF((int));
+ZEXTERN int            ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table    OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/Sen/Sen.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/Sen/Sen.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/Sen/Sen.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,293 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// 本ソフトウェアを本オープンソース・プロジェクトの運営主体以外が改変した場合、
+// それを複製、配布、販売することは GPL ライセンスに基づいて可能ですが、
+// その場合、"SoftEther UT-VPN" の名前を勝手に騙り使用することはできません。
+// 事前にソフトイーサ株式会社に許諾を求めるか、または、別の名称として
+// ソフトウェアを配布、販売してください。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// 不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+/*
+**   File Name: Sen.h
+** Description: Sen.c のヘッダ
+*/
+
+#ifndef	SEN_H
+#define	SEN_H
+
+
+// 識別文字列 (NDIS)
+#define	NDIS_SEN_HARDWARE_ID				"VPN Client Adapter - %s"
+#define	NDIS_SEN_DEVICE_NAME				"\\Device\\SEN_%s_DEVICE"
+#define	NDIS_SEN_DEVICE_NAME_WIN32			"\\DosDevices\\SEN_%s_DEVICE"
+#define	NDIS_SEN_DEVICE_FILE_NAME			"\\\\.\\SEN_SENADAPTER_%s_DEVICE"
+#define	NDIS_SEN_EVENT_NAME					"\\BaseNamedObjects\\SEN_EVENT_%s"
+#define	NDIS_SEN_EVENT_NAME_WIN32			"Global\\SEN_EVENT_SENADAPTER_%s"
+
+// 定数
+#define	SEN_MAX_PACKET_SIZE			1560
+#define	SEN_MAX_PACKET_SIZE_ANNOUNCE	1514
+#define	SEN_MIN_PACKET_SIZE			14
+#define	SEN_PACKET_HEADER_SIZE		14
+#define	SEN_MAX_FRAME_SIZE			(SEN_MAX_PACKET_SIZE - SEN_MIN_PACKET_SIZE)
+#define	SEN_MAX_SPEED_DEFAULT		1000000
+#define	SEN_MAC_ADDRESS_SIZE		6
+#define	SEN_MAX_MULTICASE			32
+
+
+// IOCTL 定数
+#define	SEN_IOCTL_SET_EVENT			CTL_CODE(0x8000, 0, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define	SEN_IOCTL_PUT_PACKET		CTL_CODE(0x8000, 1, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define	SEN_IOCTL_GET_PACKET		CTL_CODE(0x8000, 2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+// パケットデータ交換関係
+#define	SEN_MAX_PACKET_EXCHANGE		256			// 一度に交換できるパケット数
+#define	SEN_MAX_PACKET_QUEUED		4096		// キューに入れることができるパケット数
+#define	SEN_EX_SIZEOF_NUM_PACKET	4			// パケット数データ (UINT)
+#define	SEN_EX_SIZEOF_LENGTH_PACKET	4			// パケットデータの長さデータ (UINT)
+#define	SEN_EX_SIZEOF_LEFT_FLAG		4			// まだパケットが残っていることを示すフラグ
+#define	SEN_EX_SIZEOF_ONE_PACKET	1600		// 1 つのパケットデータが占有するデータ領域
+#define	SEN_EXCHANGE_BUFFER_SIZE	(SEN_EX_SIZEOF_NUM_PACKET + SEN_EX_SIZEOF_LEFT_FLAG +	\
+	(SEN_EX_SIZEOF_LENGTH_PACKET + SEN_EX_SIZEOF_ONE_PACKET) * (SEN_MAX_PACKET_EXCHANGE + 1))
+#define	SEN_NUM_PACKET(buf)			(*((UINT *)((UCHAR *)buf + 0)))
+#define	SEN_SIZE_OF_PACKET(buf, i)	(*((UINT *)((UCHAR *)buf + SEN_EX_SIZEOF_NUM_PACKET + \
+									(i * (SEN_EX_SIZEOF_LENGTH_PACKET + SEN_EX_SIZEOF_ONE_PACKET)))))
+#define	SEN_ADDR_OF_PACKET(buf, i)	(((UINT *)((UCHAR *)buf + SEN_EX_SIZEOF_NUM_PACKET + \
+									SEN_EX_SIZEOF_LENGTH_PACKET +	\
+									(i * (SEN_EX_SIZEOF_LENGTH_PACKET + SEN_EX_SIZEOF_ONE_PACKET)))))
+#define	SEN_LEFT_FLAG(buf)			SEN_SIZE_OF_PACKET(buf, SEN_MAX_PACKET_EXCHANGE)
+
+
+
+// デバイスドライバとしてコンパイルする際に必要な定義
+#ifdef	SEN_DEVICE_DRIVER
+
+// OS 判定
+#ifdef	WIN32
+#define	OS_WIN32	// Microsoft Windows
+#else
+#define	OS_UNIX		// UNIX / Linux
+#endif
+
+
+// 型宣言
+#ifndef	WINDOWS_H_INCLUDED
+#ifndef	WIN9X
+typedef	unsigned long		BOOL;
+#endif	// WIN9X
+#define	TRUE				1
+#define	FALSE				0
+#endif
+typedef	unsigned long		bool;
+#define	true				1
+#define	false				0
+typedef	unsigned long long	UINT64;
+typedef	signed long long	INT64;
+typedef	unsigned short		WORD;
+typedef	unsigned short		USHORT;
+typedef	signed short		SHORT;
+typedef	unsigned char		BYTE;
+typedef	unsigned char		UCHAR;
+typedef signed char			CHAR;
+typedef	unsigned long		DWORD;
+#define	INFINITE			0xFFFFFFFF
+
+#define	LESS(a, max_value)	((a) < (max_value) ? (a) : (max_value))
+#define	MORE(a, min_value)	((a) > (min_value) ? (a) : (min_value))
+#define	INNER(a, b, c)		(((b) <= (c) && (a) >= (b) && (a) <= (c)) || ((b) >= (c) && (a) >= (c) && (a) <= (b)))
+#define	OUTER(a, b, c)		(!INNER((a), (b), (c)))
+#define	MAKESURE(a, b, c)		(((b) <= (c)) ? (MORE(LESS((a), (c)), (b))) : (MORE(LESS((a), (b)), (c))))
+#define	MIN(a, b)			((a) >= (b) ? (b) : (a))
+#define	MAX(a, b)			((a) >= (b) ? (a) : (b))
+
+#ifdef	OS_WIN32
+// NDIS 5.0 関係
+#include "NDIS5.h"
+#endif	// OS_WIN32
+
+// ロック
+typedef struct _SEN_LOCK
+{
+#ifdef	OS_WIN32
+	NDIS_SPIN_LOCK spin_lock;
+#endif
+} SEN_LOCK;
+
+// イベント
+typedef struct _SEN_EVENT
+{
+#ifdef	OS_WIN32
+#ifndef	WIN9X
+	KEVENT *event;
+	HANDLE event_handle;
+#else	// WIN9X
+	DWORD win32_event;
+#endif	// WIN9X
+#endif
+} SEN_EVENT;
+
+// パケットキュー
+typedef struct _SEN_QUEUE
+{
+	struct _SEN_QUEUE *Next;
+	UINT Size;
+	void *Buf;
+} SEN_QUEUE;
+
+// ステータス
+typedef struct _SEN_STATUS
+{
+	UINT NumPacketSend;
+	UINT NumPacketRecv;
+	UINT NumPacketSendError;
+	UINT NumPacketRecvError;
+	UINT NumPacketRecvNoBuffer;
+} SEN_STATUS;
+
+// NDIS パケットバッファ
+typedef struct _PACKET_BUFFER
+{
+	void *Buf;							// バッファ
+	NDIS_PACKET *NdisPacket;			// NDIS パケット
+	NDIS_BUFFER *NdisBuffer;			// NDIS パケットバッファ
+	NDIS_HANDLE PacketPool;				// パケットプール
+	NDIS_HANDLE BufferPool;				// バッファプール
+} PACKET_BUFFER;
+
+// コンテキスト
+typedef struct _SEN_CTX
+{
+	SEN_EVENT *Event;					// パケット受信通知イベント
+	BOOL Opened;						// Open されているか否かのフラグ
+	BOOL Inited;						// 初期化フラグ
+	BOOL Initing;						// 起動中フラグ
+	volatile BOOL Halting;				// 停止中フラグ
+	BYTE MacAddress[6];					// MAC アドレス
+	BYTE padding[2];					// padding
+	SEN_QUEUE *PacketQueue;				// 送信パケットキュー
+	SEN_QUEUE *Tail;					// 送信パケットキューの末尾
+	UINT NumPacketQueue;				// パケットキュー数
+	SEN_LOCK *PacketQueueLock;			// 送信パケットキュー用ロック
+	SEN_STATUS Status;					// ステータス
+	BOOL Connected, ConnectedOld;		// ケーブル接続状態
+	BOOL ConnectedForce;				// 接続状態強制通知
+#ifdef	OS_WIN32
+	NDIS_HANDLE NdisWrapper;			// NDIS ラッパーハンドル
+	NDIS_HANDLE NdisControl;			// NDIS コントロールハンドル
+	NDIS_HANDLE NdisMiniport;			// NDIS ミニポートハンドル
+	NDIS_HANDLE NdisContext;			// NDIS コンテキストハンドル
+	NDIS_HANDLE NdisConfig;				// NDIS Config ハンドル
+	DEVICE_OBJECT *NdisControlDevice;	// NDIS コントロールデバイス
+	PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION];
+	PACKET_BUFFER *PacketBuffer[SEN_MAX_PACKET_EXCHANGE];		// NDIS パケットバッファ
+	NDIS_PACKET *PacketBufferArray[SEN_MAX_PACKET_EXCHANGE];	// NDIS パケットバッファ配列
+	NDIS_HARDWARE_STATUS HardwareStatus;	// ハードウェア状態
+	char HardwareID[MAX_SIZE];			// ハードウェア ID
+	char HardwareID_Raw[MAX_SIZE];		// 元のハードウェア ID
+	char HardwarePrintableID[MAX_SIZE];	// ハードウェア ID (表示用)
+#endif
+} SEN_CTX;
+
+extern SEN_CTX *ctx;
+
+
+// Sen.c ルーチン
+void SenNewStatus(SEN_STATUS *s);
+void SenFreeStatus(SEN_STATUS *s);
+BOOL SenInit();
+void SenShutdown();
+void SenInitPacketQueue();
+void SenFreePacketQueue();
+void SenClearPacketQueue();
+void SenLockPacketQueue();
+void SenUnlockPacketQueue();
+SEN_QUEUE *SenGetNextQueue();
+void SenFreeQueue(SEN_QUEUE *q);
+void SenInsertQueue(void *buf, UINT size);
+UINT SenGetNumQueue();
+void SenStartAdapter();
+void SenStopAdapter();
+void SenRead(void *buf);
+void SenWrite(void *buf);
+
+// 共通ルーチン (プラットフォーム依存)
+void *SenMalloc(UINT size);
+void *SenZeroMalloc(UINT size);
+void SenFree(void *p);
+void SenCopy(void *dst, void *src, UINT size);
+void SenZero(void *dst, UINT size);
+SEN_LOCK *SenNewLock();
+void SenLock(SEN_LOCK *lock);
+void SenUnlock(SEN_LOCK *lock);
+void SenFreeLock(SEN_LOCK *lock);
+SEN_EVENT *SenNewEvent(char *name);
+SEN_EVENT *SenCreateWin9xEvent(DWORD h);
+void SenFreeEvent(SEN_EVENT *event);
+void SenSet(SEN_EVENT *event);
+void SenReset(SEN_EVENT *event);
+BOOL SenIsKernelAddress(void *addr);
+
+#endif	// SEN_DEVICE_DRIVER
+
+
+#endif	// SEN_H
+
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnclient/utvpnclient.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnclient/utvpnclient.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnclient/utvpnclient.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,129 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// utvpncsvc.c
+// SoftEther UT-VPN Client サービスプログラム
+
+#define	VPN_EXE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+// プロセス開始関数
+void StartProcess()
+{
+	// クライアントの開始
+	InitCedar();
+	CtStartClient();
+}
+
+// プロセス終了関数
+void StopProcess()
+{
+	// クライアントの停止
+	CtStopClient();
+	FreeCedar();
+}
+
+// WinMain 関数
+int main(int argc, char *argv[])
+{
+#ifdef	OS_WIN32
+	return MsService("UTVPNCLIENT", StartProcess, StopProcess, ICO_MACHINE);
+#else	// OS_WIN32
+#ifdef	NO_VLAN
+	printf("I'm very sorry, but this version of UT-VPN Client doesn't support your operating system.\n");
+	printf("However, UT-VPN Server supports this operating system. Please use 'utvpnserver' command.\n");
+	printf("\n");
+	printf("The latest version of UT-VPN Client may support this operating system.\n");
+	printf("Please go to http://utvpn.tsukuba.ac.jp/ and check the latest information.\n");
+	printf("Of course, your porting source code contribution to UT-VPN Project is very welcome.\n");
+	printf("\n");
+	printf("Thanks.\n");
+	exit(1);
+#endif	// NO_VLAN
+	return UnixService(argc, argv, "UTVPNCLIENT", StartProcess, StopProcess);
+#endif	// OS_WIN32
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnclient/utvpnclient.h
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnclient/utvpnclient.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnclient/utvpnclient.h	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,91 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// utvpncsvc.h
+// utvpncsvc.c のヘッダ
+
+#ifndef	VPNCSVC_H
+#define	VPNCSVC_H
+
+// 関数プロトタイプ
+int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, char *CmdLine, int CmdShow);
+void StartProcess();
+void StopProcess();
+
+
+#endif	// VPNCSVC_H
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpncmd/utvpncmd.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpncmd/utvpncmd.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpncmd/utvpncmd.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,168 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// utvpncmd.c
+// SoftEther UT-VPN コマンドライン管理ユーティリティ
+
+#ifdef	WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#endif	// WIN32
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+// main 関数
+int main(int argc, char *argv[])
+{
+	wchar_t *s;
+	UINT ret;
+
+#ifdef	OS_WIN32
+	SetConsoleTitleA("SoftEther UT-VPN Command Line Utility");
+#endif	// OS_WIN32
+
+	InitMayaqua(false, false, argc, argv);
+	LoadTable(DEFAULT_TABLE_FILE_NAME);
+	InitCedar();
+
+	s = GetCommandLineUniStr();
+
+	if (s == NULL)
+	{
+		s = CopyUniStr(L"");
+	}
+
+	if (UniStrCmpi(s, L"exit") != 0)
+	{
+		UINT size = UniStrSize(s) + 64;
+		wchar_t *tmp;
+
+		tmp = Malloc(size);
+		UniFormat(tmp, size, L"utvpncmd %s", s);
+		ret = CommandMain(tmp);
+
+		Free(tmp);
+	}
+
+#ifdef	OS_WIN32
+	{
+		UINT i;
+		LIST *o = MsGetProcessList();
+		bool b = false;
+
+		for (i = 0;i < LIST_NUM(o);i++)
+		{
+			MS_PROCESS *p = LIST_DATA(o, i);
+
+			if (EndWith(p->ExeFilename, "\\cmd.exe") || EndWith(p->ExeFilename, "\\command.com"))
+			{
+				b = true;
+				break;
+			}
+		}
+
+		MsFreeProcessList(o);
+
+		if (b == false)
+		{
+			if (ret != ERR_NO_ERROR)
+			{
+				SleepThread(1000);
+			}
+		}
+	}
+#endif	// OS_WIN32
+
+	Free(s);
+
+	FreeCedar();
+	FreeMayaqua();
+	return ret;
+}
+
+
Index: Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnserver/utvpnserver.c
===================================================================
--- Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnserver/utvpnserver.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
+++ Dev/utvpn/utvpn-unix-v101-7101-public/src/utvpnserver/utvpnserver.c	(revision a1bae3ebcd5b813618d88ce3886ee70f73cc87c0)
@@ -0,0 +1,129 @@
+// SoftEther UT-VPN SourceCode
+// 
+// Copyright (C) 2004-2010 SoftEther Corporation.
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.
+// Copyright (C) 2003-2010 Daiyuu Nobori.
+// All Rights Reserved.
+// 
+// http://utvpn.tsukuba.ac.jp/
+// 
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+// 
+// このファイルは GPL バージョン 2 ライセンスで公開されています。
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。
+// 
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって
+// ホストされています。
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、
+// および、試験または研究のために利用が行われることを想定して配布
+// しています。
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に
+// あります。
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース
+// に組み込みさせていただきます。
+// 
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。
+// 
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意
+// ください。
+// 
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、
+// 公益保護にご協力いただきますようお願い申し上げます。
+// 
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客
+// を保護するための努力を行います。
+// 
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/
+// 日本国内の脆弱性情報届出受付公的機関:
+//         独立行政法人 情報処理推進機構
+//         http://www.ipa.go.jp/security/vuln/report/
+// 
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。
+// 連絡先: http://www.softether.co.jp/jp/contact/
+
+// -----------------------------------------------
+// [ChangeLog]
+// 2010.05.20
+//  新規リリース by SoftEther
+// -----------------------------------------------
+
+// utvpnserver.c
+// SoftEther UT-VPN Server サービスプログラム
+
+#define	VPN_EXE
+
+#ifdef	WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include "../PenCore/resource.h"
+#endif	// WIN32
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+// プロセス開始関数
+void StartProcess()
+{
+	// サーバーの開始
+	InitCedar();
+	StInit();
+	StStartServer(false);
+}
+
+// プロセス終了関数
+void StopProcess()
+{
+	// サーバーの停止
+	StStopServer();
+	StFree();
+	FreeCedar();
+}
+
+// WinMain 関数
+int main(int argc, char *argv[])
+{
+#ifdef	OS_WIN32
+	return MsService("UTVPNSERVER", StartProcess, StopProcess, ICO_CASCADE);
+#else	// OS_WIN32
+	return UnixService(argc, argv, "UTVPNSERVER", StartProcess, StopProcess);
+#endif	// OS_WIN32
+}
+
